Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bdd14db
Extra links
Nov 30, 2023
48a9561
Merge branch 'aalmiray:main' into main
FDelporte Aug 26, 2024
4cd27de
Merge branch 'aalmiray:main' into main
FDelporte Nov 15, 2024
8216d2f
Adding podcasts page to the website
FDelporte Nov 15, 2024
82d2e43
Adding podcasts page to the website
FDelporte Nov 15, 2024
bd6ba7a
Adding podcasts page to the website
FDelporte Nov 15, 2024
83a4f12
Adding podcasts page to the website
FDelporte Nov 15, 2024
a4025f4
Handle merge request remarks
FDelporte Nov 15, 2024
05f39da
Merge branch 'aalmiray:main' into main
FDelporte Nov 21, 2024
e29b987
Update Bluesky for frankdelporte.be
FDelporte Nov 21, 2024
e2ec906
Update Bluesky for frankdelporte.be
FDelporte Nov 21, 2024
ce54e52
Merge branch 'main' into main
FDelporte Jan 25, 2025
3fecf1d
Merge remote-tracking branch 'origin/main'
FDelporte Jan 31, 2025
caf363d
Add a map page, gets lat/long from opencagedata.com
FDelporte Jan 31, 2025
f2ee684
Add a map page, gets lat/long from opencagedata.com
FDelporte Jan 31, 2025
6cdb186
Switch to geocode.maps.co
FDelporte Jan 31, 2025
949d1dc
Cleanup
FDelporte Jan 31, 2025
1bb41e9
Cleanup
FDelporte Jan 31, 2025
a7c14fa
Better parsing
FDelporte Jan 31, 2025
91a45f1
Cleanup
FDelporte Jan 31, 2025
d02334f
Cleanup
FDelporte Jan 31, 2025
550f341
Merge remote-tracking branch 'origin/main' into feature/map
Jan 31, 2025
9d1b676
Fixing merge conflicts
Jan 31, 2025
d10d9c3
Correct JBang command in CONTRIBUTING
Jan 31, 2025
dfc122e
Add link to repository
Jan 31, 2025
a30e257
Tested and working world map with almost all champions. A file gets g…
Feb 3, 2025
531bdfb
Added members map to menu
Feb 3, 2025
d0dbc36
Fix location error
Feb 3, 2025
19e2a7f
Fix unmatched locations
FDelporte Feb 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- name: Parse data
run: |
cd resources
./jbang site.java .. ../site/content/
./jbang site.java .. ../site/content/ ${{ secrets.GEO_API_TOKEN }}

- name: Generate site
run: |
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ output/
site/content/resources/mastodon.csv
site/content/members.adoc
site/content/stats.adoc
site/content/podcasts.adoc
site/content/map.adoc
site/content/not_found_for_map.txt
4 changes: 3 additions & 1 deletion CONTRIBUTING.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ feature-requests and/or ideas.
* JBake
* JBang

Get an API key from https://geocode.maps.co (free for 5000 request/day, max 1/sec).

You may install of these prerequisites with link:https://sdkman.io[Sdkman].

1. `git clone https://github.com/aalmiray/java-champions.git`
2. `cd java-champions/resources`
3. `jbang site.java .. ../site/content/`
3. `jbang site.java .. ../site/content/ GEO_API_TOKEN`
4. `cd ../site`
5. `jbake -b`
6. `jbake -s`
Expand Down
8 changes: 6 additions & 2 deletions java-champions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ members:
year: 2006
country:
nomination: Belgium
residence: USA
social:
twitter: https://twitter.com/gbevin
mastodon: https://uwyn.net/@gbevin
Expand Down Expand Up @@ -780,6 +781,9 @@ members:
year: 2023
country:
nomination: Belgium
residence: Belgium
birth: Belgium
city: Zonnebeke
social:
twitter: https://twitter.com/FrankDelporte
mastodon: https://foojay.social/@frankdelporte
Expand Down Expand Up @@ -3073,7 +3077,7 @@ members:
year: 2018
country:
nomination: The Netherlands
city: Maassluis, South Holland Province
city: Maassluis
social:
twitter: https://twitter.com/royvanrijn
mastodon: https://mastodon.social/@royvanrijn
Expand Down Expand Up @@ -3550,7 +3554,7 @@ members:
country:
nomination: Ukraine
residence: Cyprus
city: Zhytomyr/Limassol
city: Limassol
social:
twitter: https://twitter.com/siruslan
linkedin: https://www.linkedin.com/in/siruslan/
Expand Down
44 changes: 44 additions & 0 deletions resources/map.adoc.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
= Map
Frank Delporte
:jbake-type: page
:jbake-status: published
:linkattrs:

++++
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/MarkerCluster.Default.css" />

<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.markercluster.js"></script>

<div id="map" style="height: 800px;"></div>

<script>
var data = [@LOCATIONS@];

document.addEventListener('DOMContentLoaded', function() {
var map = L.map('map').setView([0, 0], 2);

// Add a tile layer (OpenStreetMap)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);

var markers = L.markerClusterGroup({
maxClusterRadius: 50, // Pixels to cluster markers
disableClusteringAtZoom: 10, // Don't cluster when zoomed in past this level
spiderfyOnMaxZoom: false // Spread out markers instead of zooming
});
data.forEach(champion => {
var marker = L.marker([champion.lat, champion.lng], {
title: champion.name,
alt: champion.name
});
marker.bindPopup(champion.name);
markers.addLayer(marker);
});
map.addLayer(markers);
});
</script>
++++
138 changes: 128 additions & 10 deletions resources/site.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
///usr/bin/env jbang "$0" "$@" ; exit $?

//JAVA 17

//DEPS org.json:json:20250107
//DEPS com.fasterxml.jackson.core:jackson-core:2.16.0
//DEPS com.fasterxml.jackson.core:jackson-databind:2.16.0
//DEPS com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.16.0

import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.json.JSONObject;
import org.json.JSONArray;

/**
* To be executed with JBang:
* jbang site.java INPUT_DIR OUTPUT_DIR GEO_API_KEY
*
* GEO API key to be generated on https://geocode.maps.co, is free for 5000 request/day, max 1/sec
*
* For example:
* cd resources
* ./jbang site.java .. ../site/content/ ${{ secrets.GEO_API_TOKEN }}
*/
public class site {
private static final Map<String, String> STATUS = new TreeMap<>(Map.of(
"founding-member", "pass:[<i class=\"fa fa-star\" title=\"Founding Member\"></i>]",
Expand Down Expand Up @@ -49,13 +63,14 @@ public class site {
);

public static void main(String... args) throws Exception {
if (null == args || args.length != 2) {
if (null == args || args.length != 3) {
System.out.println("❌ Usage: java site.java [YAML DIRECTORY] [OUTPUT DIRECTORY]");
System.exit(1);
}

var inputDirectory = Path.of(args[0]);
var outputDirectory = Path.of(args[1]);
var geoApiKey = args[2];
var fileMembers = inputDirectory.resolve("java-champions.yml");
var filePodcasts = inputDirectory.resolve("podcasts.yml");

Expand Down Expand Up @@ -127,6 +142,44 @@ public static void main(String... args) throws Exception {
var outputStats = outputDirectory.resolve("stats.adoc");
Files.write(outputStats, statsDoc.getBytes());

// generate map.adoc
var locations = new ArrayList<String>();
var notFound = new ArrayList<String>();
var counter = new AtomicInteger(0);
members.members.forEach(m -> {
var city = m.city;
var country = m.country.residence;
if (country == null || country.isBlank()) {
country = m.country.nomination;
}
if (country != null && !country.isBlank()) {
var location = getLocation(geoApiKey, country, city);
if (location.isPresent()) {
System.out.println("Location " + counter.incrementAndGet() +
" found for " + m.name
+ ": " + city + ", " + country
+ " - " + location.get().lat + "/" + location.get().lon);
locations.add("{lat: " + location.get().lat
+ ", lng: " + location.get().lon
+ ", name: \"" + m.name.replace("\"", "'") + "\""
+ "}");
} else {
notFound.add(m.name + ": " + city + ", " + country);
}
} else {
notFound.add(m.name + ": " + city + ", " + country);
}
if (m.city != null && !m.city.isBlank()) {}
});

var mapDoc = Files.readString(Path.of("map.adoc.tpl"));
mapDoc = mapDoc.replace("@LOCATIONS@", String.join(",\n\t", locations));
var outputMap = outputDirectory.resolve("map.adoc");
Files.write(outputMap, mapDoc.getBytes());
System.out.println("HTML generated for maps");
Files.write(outputDirectory.resolve("not_found_for_map.txt"), String.join("\n", notFound).getBytes());
System.out.println("Didn't find location for " + notFound.size() + " champions. List is saved to not_found_for_map.txt");

// generate fediverse CSV file
var mastodonCsv = new PrintWriter(Files.newOutputStream(outputDirectory.resolve("resources").resolve("mastodon.csv")));
mastodonCsv.println("Account address,Show boosts,Notify on new posts,Languages");
Expand Down Expand Up @@ -156,6 +209,71 @@ public static void main(String... args) throws Exception {
Files.write(outputPodcasts, podcastsDoc.toString().getBytes());
}

private static Optional<Location> getLocation(String apiKey, String country, String city) {
var maxAttempts = 3;
var attempt = 1;
while (attempt <= maxAttempts) {
var location = getLocationFromApi(apiKey, country, city);
if (location.isPresent()) {
return location;
}
attempt++;
}
System.out.println("Couldn't find location for " + city + ", " + country + " after " + maxAttempts + " attempts");
return Optional.empty();
}

private static Optional<Location> getLocationFromApi(String apiKey, String country, String city) {
var q = (city == null ? "" : city + ", ") + country;
try {
Thread.sleep(1000); // GEO API can only be called once per second
URL url = new URL("https://geocode.maps.co/search"
+ "?q=" + URLEncoder.encode(q, StandardCharsets.UTF_8)
+ "&api_key=" + apiKey);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
if (responseCode == 200) {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
// Parse the JSON response to extract latitude and longitude
JSONArray results = new JSONArray(response.toString());
JSONObject result = results.getJSONObject(0);
double latitude = result.getDouble("lat");
double longitude = result.getDouble("lon");
return Optional.of(new Location(latitude, longitude));
} else if (responseCode == 400) {
System.out.println("Error 400 for " + url);
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
System.out.println(response);
} else {
System.out.println("Error: " + responseCode + " for " + q);
}
} catch (Exception e) {
System.out.printf("❌ Unexpected error while getting location for %s: %s%n", q, e.getMessage());
}
return Optional.empty();
}

static class Location {
public double lat;
public double lon;

public Location(double lat, double lon) {
this.lat = lat;
this.lon = lon;
}
}

static class Members {
public List<JavaChampion> members = new ArrayList<>();
}
Expand Down
2 changes: 1 addition & 1 deletion site/content/about.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Andres Almiray

== The Site

This site was created using https://jbake.org[JBake, window="_blank"].
This site was created using https://jbake.org[JBake, window="_blank"] from this https://github.com/aalmiray/java-champions[public GitHub repository, window="_blank"].
3 changes: 2 additions & 1 deletion site/templates/menu.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
<li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>index.html">Home</a></li>
<li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>bylaws.html">Bylaws</a></li>
<li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>members.html">Members</a></li>
<li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>podcasts.html">Podcasts</a></li>
<li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>map.html">Map</a></li>
<li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>stats.html">Stats</a></li>
<li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>podcasts.html">Podcasts</a></li>
<li><a href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>about.html">About</a></li>
</ul>
</div><!--/.nav-collapse -->
Expand Down