It’s getting bleak outside but as you might have guessed, it does not stop me from getting outside. Last week I managed to increase my Veloviewer maximum square to 40×40 tiles. That is kinda of an online game connected to Strava. I am a big fan of both services. The goal with the squad is to reach as many small tiles as possible from a location and create a square as big as possible. All running, cycling, hiking and swimming activities count and one small tile is one square mile. This is how my square looks like:
Most of it is cycling but also some hiking. Next year it’s going to get though. In the east the open coal mines start and in the south there’s a protected moor area and some tiles are… difficult to get. So I am gonna focus on the north and west.
Ongoing fires in IT world
Twitter, Meta and other big, add driven companies are dumpster fires these days, laying of workers in the thousands. While I feel sad for the people, it’s maybe for the better: Are these companies producing value or just issues? I don’t know. But the recession is reaching others as well. Others, that actually produce something tangible. Yesterday, Ash Kulkarni from Elastic published the linked letter about reducing teams by 13% of people. It feels like hitting close: Elastic is an open source company as well, with a lot of good people and many that I actually do know personally. I always assumed they are an economical wealthy company but alas, less growth than usual and not even losses are quite bad these days.
Earlier this year in June I read a book named “RCE”, by Sibylle Berg. RCE is the successor to GRM and I do recommend both of them:
Gelesen / Read: Sibylle Berg – RCE ⬅️ hervorragend aber keine leichte Kost. Top recherchiert von @SibylleBerg pic.twitter.com/0B0u8PAL59
— Michael Simons (@rotnroll666) June 4, 2022
The predictions in GRM about UK, social descent on the one hand and incredible wealth on the other felt like a prediction come true already and apparently, the things in RCE start happening, too. Why have we IT works thought at all that not having unions, not working together in many cases would do us any good? Why could we have thought just for a second that we aren’t expendables? Curious and frightened how things will continue.
More good reads
But more on the reading side of things. I finished “Sternkinder” by Clara Asscher-Pinkhof. A book from a Holocaust survivor writing about the Holocaust from children’s perspective. Going from Sternkinder to Sternhaus, Sternwüste and finally Sternhölle. It’s all short pieces and beautiful, but simple language, technical easy to read, but heartbreaking. I had to stop several times. But sure, let’s let idiot “musicians” like Mr. West talk about the “good things” Hitler and the Nazis did. Like my father used to say, Ich kann nicht soviel fressen, wie ich kotzen möchte.
Your weekly cup of Java
I am so happy: All PRs in Neo4j-Migrations that in one way or the other deal with JDK or dependency versions closed and dealt with: Upgrades to JDK 17, Spring Boot 3 and the latest and greatest Neo4j Java Driver done. The Quarkus Neo4j extension has just been released as 2.0 as well, including the latest upgrade and based on all of that, Gerrit released Neo4j-OGM 4.0 with support for Neo4j 5.
The last nights I did something else for a change, basically combined sports and Java and created this: Garmin Babel. It is a tool to work with your archive data from Garmin.com respectively Garmin Connect.
What? Let me show you:
I love Java and the ecosystem.
Let me point out some tech I use and the people that I know behind it:
- Effortless parsing JSON, in a streaming fashion, with Jackson, with Tatu Saloranta aka the cowtowncoder aka Dr. Jackson being the master mind behind it.
- Perfect CLIs in minutes, with PicoCLI and Remko Popma
- Dealing with units of measurement, reading and converting which comes from JSR 363 and its implementation driven and promoted by Werner Keil and Teo Bais
- Effortless writing CSV in a wide variety of predefined formats, aiming at easy import in different databases, driven by the ASF
- Helping libraries onto the module path with Moditect by Gunnar and others; I think custom JLink images are awesome, quick and easy to distribute and I want my stuff on the module path. Sadly, not all libraries are there yet.
- Of course, I did use JReleaser and GraalVM again
And wow, I do love the modern HTTP Client in the JDK. Here’s the full async code to download a bunch of data:
private CompletableFuture<Optional<Path>> scheduleDownload(Activity activity, DownloadFormat format, Tokens tokens, Optional<Path> base) { return CompletableFuture .supplyAsync(() -> { // Randomly sleep a bit try { Thread.sleep(ThreadLocalRandom.current().nextInt(10) * 100); } catch (InterruptedException e) { throw new RuntimeException(e); } var uri = switch (format) { case FIT -> "https://connect.garmin.com/download-service/files/activity/%d".formatted(activity.garminId()); default -> "https://connect.garmin.com/download-service/export/%s/activity/%d".formatted(format.name().toLowerCase(Locale.ROOT), activity.garminId()); }; return HttpRequest .newBuilder(URI.create(uri)) .header("Authorization", "Bearer %s".formatted(tokens.backend())) .header("DI-Backend", "connectapi.garmin.com") .header("Cookie", "JWT_FGP=%s".formatted(tokens.jwt())) .header("User-Agent", "garmin-babel") .GET() .build(); }) .thenCompose(request -> httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream())) .thenApply(res -> { if (res.statusCode() != 200) { throw new ConnectException("HTTP/2 %d for %s".formatted(res.statusCode(), res.uri())); } try { var suffix = switch (format) { case FIT -> "zip"; default -> format.name().toLowerCase(Locale.ROOT); }; var filename = "%d.%s".formatted(activity.garminId(), suffix); var targetFile = base.map(v -> v.resolveSibling(filename)).orElseGet(() -> Path.of(filename)); Files.copy(res.body(), targetFile, StandardCopyOption.REPLACE_EXISTING); return Optional.of(targetFile); } catch (IOException e) { throw new RuntimeException(e); } }) .thenApply(path -> { path.ifPresent(v -> System.err.printf("Stored data for %d %s as %s%n", activity.garminId(), activity.name() == null ? "" : "(" + activity.name() + ")", v.toAbsolutePath())); return path; }) .exceptionally(e -> { var prefix = "Error downloading activity %d ".formatted(activity.garminId()); if (e.getCause() instanceof ConnectException connectException) { System.err.println(prefix + connectException.getHttpStatusAndUri()); } else { System.err.println(prefix + e.getMessage()); } return Optional.empty(); }); } |
From scheduleDownload.
Anyway, if you find michael-simons/garmin-babel useful, please let me know. I had a lot of fun writing it, but I realize I am not 30 anymore and hacking away 3 nights straight in a row took its tool. Super happy that my employer Neo4j continued with the 4th Neo4j Global Wellness day in 2022 today and I just can sit down with a cup of coffee and write this piece here.
Before I leave, todays featured biking picture:
Taken during the bleak and dark morning hours, accompanying my kid to school. In that sense, do something nice, not only over the weekend, but also during the week. Time is too short to waste it.
No comments yet
Post a Comment