jmtd → Jonathan Dowland's Weblog
Below are the five most recent posts in my weblog.
- FOSDEM 2025, posted on
- dsafilter 20th Anniversary, posted on
- jungle/acid/etc, posted on
- Progressively enhancing CGI apps with htmx, posted on
- John Carpenter's "The Fog", posted on
You can also see a reverse-chronological list of all posts, dating back to 1999.
I'm going to FOSDEM 2025!
As usual, I'll be in the Java Devroom for most of that day, which this time around is Saturday.
Please recommend me any talks!
This is my shortlist so far:
- no more boot loader: boot using the Linux kernel
- aerc, an email client for the discerning hacker
- Supersonic retro development with Docker
- Raiders of the lost hard drive
- Rediscovering the fun of programming with the Game Boy
- Fixing CVEs on Debian: almost everything you should know about it
- Building the Future: Understanding and Contributing to Immutable Linux Distributions
- Generating immutable, A/B updatable, securely booting Debian images
- a tale of several distros joining forces for a common goal: reproducible builds
- Finding Anomalies in the Debian Packaging System to Detect Supply Chain Attacks
- The State of OpenJDK
- Project Lilliput - Looking Back and Ahead
- (Almost) everything I knew about Java performance was wrong
- Reduce the size of your Java run-time image
- Project Leyden - Past and the Future
- DMARCaroni: where do DMARC reports go after they are sent?
Happy 20th birthday, dsafilter!
dsafilter
is a mail filter I wrote two decades ago to solve a problem I had:
I was dutifully subscribed to
debian-security-announce
to learn of new security package updates, but most were not relevant to me.
The filter creates a new, summarizing mail, reporting on whether the DSA was applicable to any package installed on the system running the filter, and attached the original DSA mail for reference. Users can then choose to drop mails for packages that aren't relevant.
In 2005 I'd been a Debian user for about 6 years, I'd met a few Debian
developers in person and I was interested in getting involved. I started my
journey to Developer later that same year. I published dsafilter
, and I think
I sent an announcement to debian-devel
, but didn't do a great deal to
socialise it, so I suspect nobody else is using it.
That said, I have been for the two decades, and I still am! What's notable to me about that is that I haven't had to modify the script at all to keep up with software changes, in particular, from the interpreter. I wrote it as a Ruby script. If I had chosen Perl, it would probably be the same story, but if I'd chosen Python, there's no chance at all that it would still be working today.
If it sounds interesting to you, please give it a try. I think it might be due some spring cleaning.
I thought it had been a full year since I last shared a playlist, but it's been two! I had a plan to produce more, but it seems I haven't. Instead here's a few tracks I've discovered recently which share a common theme.
In August I stumbled across a Sound on Sound video interviewing Pete Cannon, who creates authentically old-school Jungle music using tools and techniques from the time, including AKAI samplers and the Commodore Amiga computer.
Here's three tracks that I found since then. Some 8-bit Amiga-jungle,
some slower-paced acid house from someone ostensibly based on Whitley Bay,
and a darker piece I heard on the radio.
I was interested in learning about htmx, so I used it to improve the experience of posting comments on my blog.
It seems much of modern web development is structured around having a JavaScript program on the front-end (browser) which exchanges data encoded in JSON asynchronously with the back-end servers. htmx uses a novel (or throwback) approach: it asynchronously fetches snippets of HTML from the back-end, and splices the results into the live page. For example, a htmx-powered button may request a URI on the server, receive HTML in response, and then the button itself would be replaced by the resulting HTML, within the page.
I experimented with incorporating it into an existing, old-school CGI web app: IkiWiki, which I became a co-maintainer of this year, and powers my blog. Throughout this project I referred to the excellent book Server-Driven Web Apps with htmx.
Comment posting workflow
I really value blog comments, but the UX for posting them on my blog was a bit clunky. It went like this:
you load a given page (such as this blog post), which is a static HTML document. There's a link to add a comment to the page.
The link loads a new page which is generated dynamically and served back to you via CGI. This contains a HTML form for you to write your comment.
The form submits to the server via HTTP POST. IkiWiki validates the form content. Various static pages (in particular the one you started on, in Step 1) are regenerated.
the server response to the request in (3) is a HTTP 302 redirect, instructing the browser to go back to the page in Step 1.
First step: fetching a comment form
First, I wanted the "add a comment" link to present the edit box in the current page. This step was easiest: add four attributes to the "comment on this page" anchor tag:
hx-get="<CGI ENDPOINT GOES HERE>"
- suppresses the normal behaviour of the tag, so clicking on it doesn't load a new page.
issues an asynchronous HTTP GET to the CGI end-point, which returns the full HTML document for the comment edit form
hx-select=".editcomment form"
- extract the edit-comment form from within that document
hx-swap=beforeend
andhx-target=".addcomment"
- append (courtesy of
beforeend
) the form into the source page after the "add comment" anchor tag (.addcomment
)
Now, clicking "comment on this page" loads in the edit-comment box below it without moving you away from the source page. All that without writing any new code!
Second step: handling previews
In the traditional workflow, clicking on "Preview" loaded a new page containing the edit form (but not the original page or any existing comments) with a rendering of the comment-in-progress below it. I wasn't originally interested in supporting the "Preview" feature, but I needed to for reasons I'll explain later.
Rather than load new pages, I wanted "Preview" to insert a rendering of the comment-in-progress being inserted into the current page's list of comments, marked up to indicate that it's a preview.
IkiWiki provides some templates which you can override to customise your site.
I've long overridden page.tmpl
, the template used for all pages. I needed to
add a new empty div
tag in order to have a "hook" to target with the
previewed comment.
The rest of this was achieved with htmx attributes on the "Preview"
button, similar to in the last step: hx-post
to define a target URI
when you click the button (and specify HTTP POST); hx-select
to filter
the resulting HTML and extract the comment; hx-target
to specify where
to insert it.
Now, clicking "Preview" does not leave the current page, but fetches a rendering of your comment-in-progress, and splices it into the comment list, appropriately marked up to be clear it's a preview.
Third step: handling submitted comments
IkiWiki is highly configurable, and many different things could happen once you post a comment.
On my personal blog, all comments are held for moderation before they are published. The page you were served after submitting a comment was rather bare-bones, a status message "Your comment will be posted after moderator review", without the original page content or comments.
I wanted your comment to appear in the page immediately, albeit marked up to indicate it was awaiting review. Since the traditional workflow didn't render or present your comment to you, I had to cheat.
handling moderated comments
One of my goals with this project was not to modify IkiWiki itself. I had to break this rule for moderated comments. When returning the "comment is moderated" page, IkiWiki uses HTTP status code 200, the same as for other scenarios. I wrote a tiny patch to return HTTP 202 (Accepted, but not processed) instead.
I now have to write some actual JavaScript. htmx emits the htmx:beforeSwap
event after an AJAX call returns, but before the corresponding swap is
performed. I wrote a function that is triggered on this event, filters for
HTTP 202 responses, triggers the "Preview" button, and then alters the
result to indicate a moderated, rather than previewed, comment. (That's why I
bothered to implement previews).
You can read the full function here: jon.js.
Summary
I've done barely any front-end web development for years and I found working with htmx to be an enjoyable experience.
You can leave a comment on this very blog post if you want to see it in action. I couldn't resist adding an easter egg: Brownie points if you can figure out what it is.
Adding htmx to an existing CGI-based website let me improve one of the workflows in a gracefully-degrading way (without JavaScript, the old method will continue to work fine) without modifying the existing application itself (well, almost) and without having to write very much code of my own at all: nearly all of the configuration was declarative.
A gift from my brother. Coincidentally I’ve had John Carpenter’s “Halloween” echoing around my my head for weeks: I’ve been deconstructing it and trying to learn to play it.
Older posts are available on the all posts page.