Athena's blog Athena Martin XSite + XBlog https://www.alm.website/blog/ 2024-03-15 https://www.alm.website/blog/2024-03-15-note-1 Note 1 from 2024-03-15 2024-03-15 2024-03-15 I'm thinking I should figure out how to make a separate feed on my blog for shitposts that aren't included in the main feed so I don't have to put them on my fediverse account.

I'm thinking I should figure out how to make a separate feed on my blog for shitposts that aren't included in the main feed so I don't have to put them on my fediverse account.

https://www.alm.website/blog/2024-03-06-note-1 Note 1 from 2024-03-06 2024-03-06 2024-03-06 Anton Zhiyanov's article about being a stupid programmer puts a point I've heard before in a less concise, and thus more deeply comprehensible, form. (Very meta.) The point is:

Anton Zhiyanov's article about being a stupid programmer puts a point I've heard before in a less concise, and thus more deeply comprehensible, form. (Very meta.) The point is:

If you write clever code, you'll have to be even cleverer to debug it or change it.

Frankly, I think we would all be in a better place if all programmers could put aside the instinct to be clever and sophisticated and just do the obvious and dumb thing.

(And frankly, Anton, I think wisdom of the kind you appear to possess is a more important quality in a programmer than conventional intelligence.)

https://www.alm.website/blog/2024-03-05-note-1 Note 1 from 2024-03-05 2024-03-05 2024-03-05 Y'know, literacy is underrated. The power to take your thoughts, make them into a durable, easily sharable form, and then on top of that to get other people's thoughts even if they're far away in space or time, even if it's a big, complex idea, is really handy, isn't it? The accessibility of ideas has to be a good thing overall even if it also enables shitty behavior.

Y'know, literacy is underrated. The power to take your thoughts, make them into a durable, easily sharable form, and then on top of that to get other people's thoughts even if they're far away in space or time, even if it's a big, complex idea, is really handy, isn't it? The accessibility of ideas has to be a good thing overall even if it also enables shitty behavior.

https://www.alm.website/blog/2024-03-01-note-1 Note 1 from 2024-03-01 2024-03-01 2024-03-01 Better performance usually goes hand-in-hand with lower energy usage. Even if your software isn't noticeably slow, it might still be able to be kinder to batteries.

Better performance usually goes hand-in-hand with lower energy usage. Even if your software isn't noticeably slow, it might still be able to be kinder to batteries.

https://www.alm.website/blog/2024-01-16-unity-hello-world Some weird sci-fi 2024-01-16 2024-01-16 My newest story, Unity: Hello World, is up. I described it to a beta reader as a weird sci-fi isekai with a small shot of accidental eldritch horror which is a good enough description. I'm playing with typography in the stylesheet I used for this one; looks a bit more like a book, plus makes some diegetic documents stand out better.

My newest story, Unity: Hello World, is up. I described it to a beta reader as a weird sci-fi isekai with a small shot of accidental eldritch horror which is a good enough description. I'm playing with typography in the stylesheet I used for this one; looks a bit more like a book, plus makes some diegetic documents stand out better.

https://www.alm.website/blog/2024-01-13-note-1 Note 1 from 2024-01-13 2024-01-13 2024-01-13 I don't have anything to say about this post by Seirdy about surviving software forge downtime except that I agree with it.

I don't have anything to say about this post by Seirdy about surviving software forge downtime except that I agree with it.

https://www.alm.website/blog/2023-12-23-ipv6-rubric Hosting provider IPv6 support rubric 2023-12-23 2023-12-23 This is a rubric for grading providers of hosted network services; for example, Web hosts, cloud database and storage services, etc. Here are the grades:

This is a rubric for grading providers of hosted network services; for example, Web hosts, cloud database and storage services, etc. Here are the grades:

Grade A
Every default configuration has IPv6 enabled. The configuration is secure and reliable. No practical limit on number of addresses used. No NAT. No additional charge for IPv6. The service never prefers IPv4 to IPv6 when both are equally available.
Grade B
Every default configuration has IPv6 enabled. The configuration is secure and reliable. Address utilization may be limited, but there is a minimum of one publically-routable address available for each instance of the service. No NAT. No additional charge for IPv6. The service never prefers IPv4 to IPv6 when both are equally available.
Grade C
At least one default configuration has IPv6 enabled. The configuration is secure and reliable. Address utilization limits as above. No NAT. No additional charge for IPv6. The service never prefers IPv4 to IPv6 when both are equally available.
Grade D
Customer is able to configure IPv6 securely and reliably without service-specific training. Address utilization limits as above. No additional charge for IPv6. IPv4 may be preferred to IPv6 in limited circumstances.
Grade F
Configuring IPv6 is not possible, or a secure and reliable configuration requires service-specific training, or at least one default configuration is not secure or not reliable, or customers do not automatically have available enough routable addresses for all instances of the service, or NAT is used, or there is an additional charge for IPv6.
https://www.alm.website/blog/2023-12-22-note-1 Note 1 from 2023-12-22 2023-12-22 2023-12-22 Giving serious consideration to using HERO System, a generic table-top role-playing game… engine, I guess, as a writing tool for one of my ongoing stories. It's a very powerful toolkit for modeling characters' abilities, measuring relative power levels, and tracking combats, although I'll need to be careful not to be too strict with it. As you should playing a table-top RPG in general, really, but still, it's an easy pitfall.

Giving serious consideration to using HERO System, a generic table-top role-playing game… engine, I guess, as a writing tool for one of my ongoing stories. It's a very powerful toolkit for modeling characters' abilities, measuring relative power levels, and tracking combats, although I'll need to be careful not to be too strict with it. As you should playing a table-top RPG in general, really, but still, it's an easy pitfall.

https://www.alm.website/blog/2023-12-19-note-2 Note 2 from 2023-12-19 2023-12-19 2023-12-19 Why yes, I do review at least briefly every published RFC, and yes, I will continue to curate them. You can too: The RFC Editor has an RSS feed for all new RFCs.

Why yes, I do review at least briefly every published RFC, and yes, I will continue to curate them. You can too: The RFC Editor has an RSS feed for all new RFCs.

https://www.alm.website/blog/2023-12-19-note-1 Note 1 from 2023-12-19 2023-12-19 2023-12-19 Recently published by the RFC Editor: Mark Nottingham's RFC 9518: Centralization, Decentralization, and Internet Standards, an Independent Submission-stream essay (not subject to the full IETF process) which does a good job of making many of the key points about centralization of Internet services, its avoidance, and the pitfalls of both, especially focusing on the social factors that render technical efforts alone insufficient. I feel that it summarizes a large part of the debate effectively, and, critically, in a practical and calm tone unlikely to inflame tempers.

Recently published by the RFC Editor: Mark Nottingham's RFC 9518: Centralization, Decentralization, and Internet Standards, an Independent Submission-stream essay (not subject to the full IETF process) which does a good job of making many of the key points about centralization of Internet services, its avoidance, and the pitfalls of both, especially focusing on the social factors that render technical efforts alone insufficient. I feel that it summarizes a large part of the debate effectively, and, critically, in a practical and calm tone unlikely to inflame tempers.

https://www.alm.website/blog/2023-12-10-stolen-saturn-v We can go crazier: 9/11 and the Apollo program (somehow, in this dream I had) 2023-12-10 2023-12-10 On September 11, 2001, the World Trade Center twin towers in New York City were destroyed after two airplanes flew into them; these were quickly revealed to have been hijacked and flown into the towers deliberately. Some claim, as far as I can tell without any convincing basis, that the towers were actually demolished on purpose and the planes were merely there to convince the public the destruction was the result of an attack, presumably in order to justify the War on Terror. But my subconscious apparently thinks we can go crazier.

On September 11, 2001, the World Trade Center twin towers in New York City were destroyed after two airplanes flew into them; these were quickly revealed to have been hijacked and flown into the towers deliberately. Some claim, as far as I can tell without any convincing basis, that the towers were actually demolished on purpose and the planes were merely there to convince the public the destruction was the result of an attack, presumably in order to justify the War on Terror. But my subconscious apparently thinks we can go crazier.

In a dream I had just before waking up and immediately starting this post, the method of the 9/11 attacks was apparently unknown. An extensive government investigation turned up nothing for years, until NASA unrelatedly discovered evidence on the surface of the moon that led them to make a substantial effort to recover debris that turned out to be fragments of a Saturn V S-IVB stage previously unaccounted for. Somehow the two mysteries became linked, and the government came to the conclusion that 9/11 was done using a stolen Saturn V.

It remains unclear to me now how a Saturn V of which pieces were found on the moon could have also impacted the World Trade Center, and whether and how the Saturn V could have been involved in the other parts of the events of September 11, 2001. It is also unclear how a Saturn V, a rocket the size of a skyscraper, could ever be stolen successfully and in secret, and how it could be launched without the U.S. being aware immediately, and how it could be preserved for the approximately 30 years between when Saturn V rockets stopped being built and when the 9/11 attacks occurred, and why anyone would bother going to all this effort. Nonetheless, the government in my dream was quite confident that this was what happened.

For some reason at this point (some years after 2001, recall), the Soviet Union still existed, and was therefore the prime suspect. However, nuclear war did not break out and it quickly became apparent that they, too, were dumbfounded by the use of a skyscraper-sized rocket as a precision anti-ground weapon, and in an effort to improve relations the U.S. and U.S.S.R. ended up cooperating on an investigation to discover who did this and how. This investigation was, by means unknown, successful, and tracked the theft and attack back to a small, unnamed island nation whose bafflingly enormous resources were somehow able to pull off the heist and conversion into a weapon entirely in secret.

The U.S. and U.S.S.R. then immediately attempted to invade the island. The U.S. invasion failed immediately and the U.S.S.R. was pushed off after a day or so, due apparently in part to tidal effects (???). Efforts to more covertly investigate the situation (bizarrely involving children and possibly cats) were thwarted by a single dog on a beach who detected every agent and drove them literally into the sea.

My dream ended there, leaving all questions unanswered. I choose to believe the island nation able to resist both the U.S. and the U.S.S.R. simultaneously in both full-scale military invasions and covert intelligence was in fact framed, and the true masterminds were Bond-style villains in some kind of volcano lair.

https://www.alm.website/blog/2023-12-08-html-editor A design for an HTML editor 2023-12-08 2023-12-08 The Hypertext Markup Language (HTML) is a relatively subtle language to use correctly. Many elements have the same appearance by default, but have different semantics. One of the best examples is the <em> and <i> elements, which have different meanings but are both represented by italics in most visual browsers' default stylesheets. Further, the lesser-known <dfn> and <cite> are also represented by italics by default.

The Hypertext Markup Language (HTML) is a relatively subtle language to use correctly. Many elements have the same appearance by default, but have different semantics. One of the best examples is the <em> and <i> elements, which have different meanings but are both represented by italics in most visual browsers' default stylesheets. Further, the lesser-known <dfn> and <cite> are also represented by italics by default.

This fact causes the most common approach to non-code HTML editing, What-You-See-Is-What-You-Get (WYSIWYG), to struggle with correct semantics. Most WYSIWYG editors provide styling options, usually using the <span> element and the style attribute, which can lead users to focus entirely on visual styling, resulting in text that is difficult to read with some accessibility technologies and difficult to interpret for bots. The other approach commonly seen is using a text editor, which exposes the HTML code directly, usually requires the user to remember the meanings and names of elements and attributes, and often involves either a lot of typing or learning a lot of specialized shorthand and/or keyboard shortcuts.

I believe a better type of HTML editor is a remarkably easy design. The Web has a concept of separating presentation from content; this concept could be embodied in an editor application with two modes. In content mode or outline mode, a stylized representation of the document tree is shown. All elements are shown explicitly, but the editor application's domain-specific knowledge of HTML is applied to provide friendly names (e.g., paragraph instead of <p>) and configuration interfaces for setting attributes. In style mode, the document is rendered visually using its associated stylesheet, and a second interface for editing the styles is available. The document's content cannot be edited in style mode, and its presentation is invisible in content mode, creating a separation in the author's thinking that encourages well-structured documents with styling layered on top instead of inseparately blended into the content.

This concept is not completely developed; in particular, I expect a CSS editor would be harder to develop than an HTML outline editor. CSS selectors are complicated and a good visual interface for building them may be quite difficult to design. Proper handling of media queries would likely require a lot of checkboxes and drop-down menus. Even the outline mode would require quite a deal of work to figure out how to represent each element in a way that is convenient for editing, clearly different from other elements, yet not visually annoying or difficult to read. But I think this modal approach may make it easier for HTML authors to work without being overwhelmed with text or lost in visuals.

https://www.alm.website/blog/2023-11-16-interactive-rebase-cherry-pick Interactive rebase is super-cherry-pick 2023-11-16 2023-11-16 In my main project at work, I recently had to kill a feature that wasn't panning out, but the topic branch for it included a lot of other valuable work I wanted to save. If I'd been smart, I would have spread this work out onto multiple subtopic branches, but I didn't do that, so now I have to dismantle the One Giant Branch for the feature and split it into those subtopics I should have had all along so I can get them merged back into the trunk without the bad parts of the topic.

In my main project at work, I recently had to kill a feature that wasn't panning out, but the topic branch for it included a lot of other valuable work I wanted to save. If I'd been smart, I would have spread this work out onto multiple subtopic branches, but I didn't do that, so now I have to dismantle the One Giant Branch for the feature and split it into those subtopics I should have had all along so I can get them merged back into the trunk without the bad parts of the topic.

My first thought, naturally, was cherry-pick, but the branch is enormous and I felt that cherry-picking it one commit at a time would take unreasonably long. So next, I remembered interactive rebase, just becuase I was vaguely aware that it did something along the lines of take the commits from a branch and let you choose which ones to apply on top of a certain base. After consulting the manual page and a couple failed attempts, I came down on this fairly simple process:

$ git switch topic
$ git switch -c subtopic
$ git rebase -i trunk

From there, I could choose which commits to keep on the subtopic and which I wanted to adjust before taking them. This took a while, of course, because I had to review all those commits (I might have preferred to be prompted for each commit, git add -p style), and then resolve a pile of merge conflicts, but I think I've proven the concept, at least. My first attempt I made some mistakes, so I'll have to redo it, and there's more subtopics yet to do, but this seems like a less annoying way to do it than cherry-picking the commits by hand.

(I'm sure interactive rebase's devotees are already familiar with this use of it and rolling their eyes at my reaction to discovering it, but it's new to me.)

https://www.alm.website/blog/2023-11-12-note-1 Note 1 from 2023-11-12 2023-11-12 2023-11-12 Seirdy's proposal for an HTML spoiler element seems to me like a good idea, but there are some caveats. I commented on a few things when offered a draft to review, several of which were addressed, but some of my points remain, as they're more debatable. So:

Seirdy's proposal for an HTML spoiler element seems to me like a good idea, but there are some caveats. I commented on a few things when offered a draft to review, several of which were addressed, but some of my points remain, as they're more debatable. So:

I'm not sure the element name spoiler is entirely appropriate; while it is a common term for this kind of functionality, many of the use cases are more serious than ruining the twist of a movie. The phrase content warning is associated more with the text of the summary equivalent, and plus it's long, so probably not that. The ActivityPub protocol uses a flag called sensitive to mark content that shouldn't be shown by default.

It could be useful, instead of encouraging visible SEO-style keyword stuffing, to provide an attribute in which the keywords can be listed invisibly (like <meta name="keywords">), which could then be used for automated filters without irritating users. This could lead to unintuitive behavior though, as things might auto-hide or auto-show without the listed word being directly visible; the user agent could provide some kind of indication as to why it auto-hid or auto-showed, but this could clutter the user interface.

The size of an image inside a lazy-loaded spoiler may not be known until the image downloads, which could result in the spoiler's size being unrepresentive of the actual size of its content.

Some implementations of spoilers provide no way to re-hide the hidden content once it's shown; this makes sense to a degree, because once shown the spoiler content effectively replaces the spoiler and there's no obvious area that belongs to the spoiler that could act as the trigger for re-hiding, but it's not ideal.

Not shipping spoiler support at all until developer tools can also hide it seems like it could delay deployment significantly for minimal benefit; existing JavaScript-based solutions either lazy-load the images, in which case developer tools wouldn't show them anyway, or don't protect developer tools users at all, in which case an immediate rollout would do no additional harm.

I may take a look at trying to implement something like this in the EXHL project, but the scriptless client case concerns me, since the EXHL standard stylesheet can't contain user-presented text due to internationalization concerns, so warning the user of unhidden spoilers could be difficult at best.

https://www.alm.website/blog/2023-11-11-exhl-draft-1 EXHL 1.0 draft 1 2023-11-11 2023-11-11 Draft 1 of Edition 1.0 of the Enhanced XML Hypertext Language specification is now public. This draft makes a number of changes; most notably, bibliographies and other lists of references can now be represented, and the standard stylesheet lays out the document less annoyingly wide (parallel with my recent changes to the stylesheet of this site). Here is a diff between rfcr-3 and the new draft, ed1.0-draft-1, and the tag message with more changes listed.

Draft 1 of Edition 1.0 of the Enhanced XML Hypertext Language specification is now public. This draft makes a number of changes; most notably, bibliographies and other lists of references can now be represented, and the standard stylesheet lays out the document less annoyingly wide (parallel with my recent changes to the stylesheet of this site). Here is a diff between rfcr-3 and the new draft, ed1.0-draft-1, and the tag message with more changes listed.

https://www.alm.website/blog/2023-11-11-significant-style-changes Significant style changes 2023-11-11 2023-11-11 I've made several significant changes in the styling of this site, several of which were based on advice in the book Practical Typography by Matthew Butterick. While I haven't adopted every applicable recommendation (most notably, I am still using the user's default sans serif font), I believe the result makes the site moderately more readable.

I've made several significant changes in the styling of this site, several of which were based on advice in the book Practical Typography by Matthew Butterick. While I haven't adopted every applicable recommendation (most notably, I am still using the user's default sans serif font), I believe the result makes the site moderately more readable.

The CSS for these changes was developed as part of the Enhanced XML Hypertext Language project, and is also part of the default stylesheet in the latest version.

https://www.alm.website/blog/2023-11-08-note-2 Note 2 from 2023-11-08 2023-11-08 2023-11-08 I can confirm that Seirdy's page formatting and Webmention sending are fully interoperable with my Webmention receiving and processing (with no manual fixups required). I can't confirm for certain that the reverse is true, as I know Seirdy manually imports replies so it's possible the one I'm thinking of was done by hand.

I can confirm that Seirdy's page formatting and Webmention sending are fully interoperable with my Webmention receiving and processing (with no manual fixups required). I can't confirm for certain that the reverse is true, as I know Seirdy manually imports replies so it's possible the one I'm thinking of was done by hand.

https://www.alm.website/blog/2023-11-08-note-1 Note 1 from 2023-11-08 2023-11-08 2023-11-08 Fundamentally, most software really only has use for a relatively small number of general-purpose data formats. Sure, there's media (audio, video, images), but for most applications there's a library that does that and all you really have to care about is moving around the blobs of bytes. For general-purpose formats, I'd say you could get away with just SQLite and XML, but you probably want to add JSON to the mix for reduced pain and you almost certainly want a wire protocol for IPC and network requests. But even then that's just four formats.

Fundamentally, most software really only has use for a relatively small number of general-purpose data formats. Sure, there's media (audio, video, images), but for most applications there's a library that does that and all you really have to care about is moving around the blobs of bytes. For general-purpose formats, I'd say you could get away with just SQLite and XML, but you probably want to add JSON to the mix for reduced pain and you almost certainly want a wire protocol for IPC and network requests. But even then that's just four formats.

https://www.alm.website/blog/2023-11-04-note-1 Note 1 from 2023-11-04 2023-11-04 2023-11-04 I'm starting on EXHL draft 1, so any suggestions or comments that could implicate a major design change would be best made soon.

I'm starting on EXHL draft 1, so any suggestions or comments that could implicate a major design change would be best made soon.

https://www.alm.website/blog/2023-10-26-note-1 Note 1 from 2023-10-26 2023-10-26 2023-10-26 EXHL RfCR 3 is published. As always it's available at its canonical location. Here is a diff between rfcr-2 and rfcr-3, and the tag message for rfcr-3, which lists the changes at a high level.

EXHL RfCR 3 is published. As always it's available at its canonical location. Here is a diff between rfcr-2 and rfcr-3, and the tag message for rfcr-3, which lists the changes at a high level.

https://www.alm.website/blog/2023-10-25-note-1 Note 1 from 2023-10-25 2023-10-25 2023-10-25 Everyone who works on networks, and especially on network standards, should read RFC 8890: The Internet is for End Users. And, really, everyone who works on any technical subject.

Everyone who works on networks, and especially on network standards, should read RFC 8890: The Internet is for End Users. And, really, everyone who works on any technical subject.

https://www.alm.website/blog/2023-10-23-note-2 Note 2 from 2023-10-23 2023-10-23 2023-10-23 The Verge is talking about POSSE now. They even linked to the IndieWeb wiki page. I've seen a couple of articles like this recently; hopefully it means owning your own content might be on the rise.

The Verge is talking about POSSE now. They even linked to the IndieWeb wiki page. I've seen a couple of articles like this recently; hopefully it means owning your own content might be on the rise.

https://www.alm.website/blog/2023-10-23-note-1 Note 1 from 2023-10-23 2023-10-23 2023-10-23 Home network upgraded with all Cat6, speeds improved somewhat.

Home network upgraded with all Cat6, speeds improved somewhat.

https://www.alm.website/blog/2023-10-22-exhl-rfcr-2 EXHL RfCR 2 2023-10-22 2023-10-22 Request for Comments Revision 2 of the Enhanced XML Hypertext Language specification is public. This revision makes mostly minor changes on top of the revision published yesterday, mainly motivated by comments received. Further comments will be appreciated. If you feel like sending patches, they will be considered. I haven't yet reached the stage of major drafts, so many things are still deliberately omitted; I expect there are a number of entire modules still to be added, and many elements to most of the existing modules, plus significant changes to some existing elements. In particular, the metadata needs to be expanded drastically; I welcome the contributions of anyone willing to try distilling existing metadata vocabularies into sensible XML elements, especially if they come with a mapping list for the stylesheets. I will note that if anyone thinks major design changes to the basic skeleton that currently exists are merited, now would be the time to suggest them.

Request for Comments Revision 2 of the Enhanced XML Hypertext Language specification is public. This revision makes mostly minor changes on top of the revision published yesterday, mainly motivated by comments received. Further comments will be appreciated. If you feel like sending patches, they will be considered. I haven't yet reached the stage of major drafts, so many things are still deliberately omitted; I expect there are a number of entire modules still to be added, and many elements to most of the existing modules, plus significant changes to some existing elements. In particular, the metadata needs to be expanded drastically; I welcome the contributions of anyone willing to try distilling existing metadata vocabularies into sensible XML elements, especially if they come with a mapping list for the stylesheets. I will note that if anyone thinks major design changes to the basic skeleton that currently exists are merited, now would be the time to suggest them.

With this revision, I have also made a Git repository public, currently accessible on my personal Git server. Future changes will be tracked in here, with tags for each significant published revision. This revision can be found tagged rfcr-2, and the previous publication was rfcr-1; here's a diff between the two. I expect eventually to begin publishing r1.0-draft- tags once I go beyond a minimum viable product, then ratification candidate (r1.0-rc-) tags when the specification approaches a final state, which will end up tagged as r1.0 (I'm not sure if the r is release, ratified, or Recommendation...).

I haven't settled on any ratification process at the moment. The main qualifier for ratification would be a lack of unaddressed objections from other interested parties, plus resolution of all TODOs and FIXMEs. If I can find any other significant interested parties (user agents, site generators/CMSes, authors), I'll probably aim to achieve a consensus acceptance of a ratification candidate. If you are one of these interested parties, please get in touch.

One goal is to keep any changes between ratification candidates small, and make a ratified version identical to the last ratification candidate except for the version label change. Any issue would require a new RC, and major problems would require another draft before restarting the ratification process. This ensures an RC has enough time for problems to be noticed before it actually gets ratified. Typos and other minor non-substantive issues are inevitable, so a ratified version would live on its own branch for those corrections.

https://www.alm.website/blog/2023-10-21-exhl Enhanced XML Hypertext Language 2023-10-21 2023-10-21 My latest project to randomly pop up and receive nearly all of my time for days and days is Enhanced XML Hypertext Language (EXHL), an XML-based hypertext format based closely on XHTML, the XML form of the Web's standard Hypertext Markup Language (HTML). EXHL is in a very minimal state at the moment; the current specification is just barely enough to self-host, the schema is both loose and probably doesn't allow things it should, and a lot of things need more thought, but I've decided to publish a request for comments version of the specification document, which you can find here.

My latest project to randomly pop up and receive nearly all of my time for days and days is Enhanced XML Hypertext Language (EXHL), an XML-based hypertext format based closely on XHTML, the XML form of the Web's standard Hypertext Markup Language (HTML). EXHL is in a very minimal state at the moment; the current specification is just barely enough to self-host, the schema is both loose and probably doesn't allow things it should, and a lot of things need more thought, but I've decided to publish a request for comments version of the specification document, which you can find here.

An eventual goal is to use EXHL as the authoring language for my Web site. The more popular choice of authoring language is Markdown, which is liked for its brevity, but I don't like how squishy Markdown feels, for want of a better word. I especially don't like Markdown's lack of semantic value; it's designed to produce a limited subset of HTML, and omits providing syntax for e.g. <i> and other elements that are redundant in appearance in most browsers but actually have different semantics. On top of that, even with plain HTML to get those things, or if simply sprinkling HTML tags into the Markdown, there are some patterns that recur a lot but lack a built-in syntax; examples include captioned code blocks, rich references to external documents, tables that can be sorted and filtered, etc. You either have to build these yourself out of HTML's basic markup and a bunch of CSS (and sometimes JavaScript) or use Web components of one kind or another to give yourself what's basically a macro function. But these things feel like markup features, and they occur so commonly nowadays in blog posts and other text-heavy content (the place where HTML shines best) that it makes a lot of sense for them to have first-class elements.

On top of all that, even HTML has semantic deficiencies I don't like. The lack of good metadata has led to the growth of numerous incompatible metadata schemas, most of which have their own ways to mark them up. Common and distinct textual features, like loan-words, fictional characters' thoughts, and ship names are all stuck together as the <i> element, while emphasis gets its own. Headings have levels independent of the nesting levels of their containing sections. And so on. It's not that hard to design a language without these problems, so I decided I'd just do it.

As an authoring format, EXHL is intended to be used by transforming it into XHTML, using a dedicated suite of Extensible Stylesheet Language Transformation (XSLT) stylesheets. This means that complete compatibility with existing user-agents can be maintained by providing them with XHTML, while any EXHL user-agents that might exist someday could potentially use the original form of the document to provide better semantics or additional features. EXHL is a document format with minimal presentation control, which allows stylesheets and user-agents a lot of freedom to provide features like table sorting or syntax highlighting (both hypothetical at this time). A good example of this currently is term definition links; terms marked up with the <term> and <term-def> elements are automatically linked to make it easy to find the definition.

EXHL is defined currently using the W3C XML Schema (XSD) language, with the specification's body text and XSLT stylesheets embedded using XSD's <annotation> element, as a sort of literate schema. Additional information is generated from the schema itself, and the whole thing is wrapped up as an EXHL document by an XSLT stylesheet. Depending on the fragment, the same document can act as schema or stylesheet, including the ability to transform itself. You can download this document to take a look, or look at the output EXHL document as an example of what EXHL looks like. This is an interesting challenge, although it's made more tedious than it has to be by XSD's excessive verbosity. I considered RELAX NG initially, and decided against it as not as widely supported, but I may have to revisit that decision.

As you might have guessed, this post was written initially in EXHL, as an exercise. For the time being the version I'm holding onto is in XHTML, but if my site eventually gets redone like I'm planning it'll get converted back; how fun. Please send me any and all comments about EXHL and its current specification. You can send a Webmention to this post, or see my profile for other contact methods.

https://www.alm.website/blog/2023-10-21-note-2 Note 2 from 2023-10-21 2023-10-21 2023-10-21 Should Webmention senders respect robots.txt? I implemented it, but then I found at least one place I've Webmentioned blocks all bots yet has Webmention discovery. Is this a problem on their side or mine?

Should Webmention senders respect robots.txt? I implemented it, but then I found at least one place I've Webmentioned blocks all bots yet has Webmention discovery. Is this a problem on their side or mine?

https://www.alm.website/blog/2023-10-21-note-1 Note 1 from 2023-10-21 2023-10-21 2023-10-21 I read the title of Fediverse defederation considerations as Fediverse defenestration considerations and that still works actually.

I read the title of Fediverse defederation considerations as Fediverse defenestration considerations and that still works actually.

https://www.alm.website/blog/2023-10-20-note-1 Note 1 from 2023-10-20 2023-10-20 2023-10-20 Is it dystatic if it's a dynamic program incrementally updating a conventional on-disk document root served by a dedicated Web server?

Is it dystatic if it's a dynamic program incrementally updating a conventional on-disk document root served by a dedicated Web server?

https://www.alm.website/blog/2023-10-19-note-2 Note 2 from 2023-10-19 2023-10-19 2023-10-19 Shout out to Seirdy for updating my outdated knowledge about Fedora. Knowing when I'm wrong is good and I appreciate people correcting me in the long term, although unfortunately my brain will sometimes not let me enjoy learning a new thing in the moment.

Shout out to Seirdy for updating my outdated knowledge about Fedora. Knowing when I'm wrong is good and I appreciate people correcting me in the long term, although unfortunately my brain will sometimes not let me enjoy learning a new thing in the moment.

https://www.alm.website/blog/2023-10-19-note-1 Note 1 from 2023-10-19 2023-10-19 2023-10-19 The lifecycle of the technically inclined Linux user:

The lifecycle of the technically inclined Linux user:

  1. Get fed up with Microsoft/Apple/Google nonsense. Install Linux Mint/Ubuntu/Pop!_OS. Use happily for a while.
  2. Get excited by shiny features. Install Fedora. Use for a while with occasional problems.
  3. Decide you need more control. Install Arch. Use briefly with frequent problems.
  4. Get fed up with mainstream nonsense. Install Alpine/Gentoo/Nix/Guix. Use for a while with frequent problems.
  5. Get fed up with nonsense. Install Debian/BSD. Use more or less contentedly for a long time.
https://www.alm.website/blog/2023-10-13-note-1 Note 1 from 2023-10-13 2023-10-13 2023-10-13 Replying to Johanna

Replying to Johanna

I like your pink scrollbar. I think that's a good and important feature.

https://www.alm.website/blog/2023-10-12-configuring-firefox-scrollbars Configuring Firefox scrollbars to be decent 2023-10-12 2023-10-12 After reading Artemis Everfree's article about the scrollbar situation, I decided to fiddle with the Firefox (on Linux) settings for scrollbars myself, and here's the about:config settings I came up with:

After reading Artemis Everfree's article about the scrollbar situation, I decided to fiddle with the Firefox (on Linux) settings for scrollbars myself, and here's the about:config settings I came up with:

  • layout.css.scrollbar-width-thin.disabled: true. This stops Web pages from using CSS to make the scrollbars thin.
  • widget.non-native-theme.scrollbar.size.override: 20. This sets the width of scrollbars. You can adjust it as you like.
  • widget.gtk.overlay-scrollbars.enabled: false. When Firefox uses GTK as its backend (in Linux builds and probably on other free OSes as well), this prevents the scrollbar from disappearing automatically... mostly. Web pages still seem to do it to me sometimes even with this setting on, probably because they're implementing it themselves in CSS instead of asking the browser to do it.
  • widget.non-native-theme.gtk.scrollbar.allow-buttons: true. Again for GTK, this brings back buttons at the top and bottom of the scrollbar.
  • widget.non-native-theme.gtk.scrollbar.round-thumb: false. Again for GTK, this makes the scrollbar thumb (the part that moves) rectangular instead of rounded, while still giving it some padding on either side. Artemis suggests setting widget.non-native-theme.scrollbar.style to 4 instead, which makes the thumb the full width of the bar. It's a preference; the bar still appears to work even if you click in the padding.

I'm not sure if this affects Firefox, but I also have gtk-overlay-scrolling set to 0 in my GTK 3 settings, which helps a lot of applications to be less annoying by turning off the scrollbar disappearing. I also have the Chicago95 theme installed, which has a nice scrollbar among many other visual features modeled on Windows 95.

https://www.alm.website/blog/2023-10-12-cursed-error-page Have a cursed error page 2023-10-12 2023-10-12 This thought occurred to me and I decided I should make it exist in some capacity.

This thought occurred to me and I decided I should make it exist in some capacity.

Show cursed error page

Forbidden (status 403): Insecure connection; no IPsec

An Internet Protocol Security (IPsec) security association is required to securely communicate with this server. A security association was not automatically established either because you are not authorized to communicate with this server or because your computer is configured incorrectly.

If you believe you should be authorized to communicate with this server, either follow these troubleshooting instructions or contact Support for assistance.

https://www.alm.website/blog/2023-10-04-gay-mermaids How about gay mermaids? 2023-10-04 2023-10-04 I'm sure you're not surprised that I've written another gay story. It's a lot of what I do on this site to be honest. This one at least isn't for adults only. The Girl and Her Fisher is about a girl meeting a mermaid.

I'm sure you're not surprised that I've written another gay story. It's a lot of what I do on this site to be honest. This one at least isn't for adults only. The Girl and Her Fisher is about a girl meeting a mermaid.

https://www.alm.website/blog/2023-10-01-note-1 Note 1 from 2023-10-01 2023-10-01 2023-10-01 Results of power usage study on my desktop spock (i.e. plugging it into a wattmeter and running through things): Difference between S5 and S3, about a watt, maybe less. Difference between S0 idle and S3, about 45 watts! Effect of power-save settings, about 5 watts. Difference between S0 running and S0 idle, 15-25 watts. With the power-save settings on, resuming from S0 idle doesn't work. In conclusion: Use S3 as often as possible.

Results of power usage study on my desktop spock (i.e. plugging it into a wattmeter and running through things): Difference between S5 and S3, about a watt, maybe less. Difference between S0 idle and S3, about 45 watts! Effect of power-save settings, about 5 watts. Difference between S0 running and S0 idle, 15-25 watts. With the power-save settings on, resuming from S0 idle doesn't work. In conclusion: Use S3 as often as possible.

https://www.alm.website/blog/2023-09-30-note-1 Note 1 from 2023-09-30 2023-09-30 2023-09-30 Is there a standard format for an XML patch? I.e., a set of changes to an XML document, itself in the form of an XML document. There doesn't need to be a good implementation as long as the format isn't absurdly complex or tricky to implement.

Is there a standard format for an XML patch? I.e., a set of changes to an XML document, itself in the form of an XML document. There doesn't need to be a good implementation as long as the format isn't absurdly complex or tricky to implement.

https://www.alm.website/blog/2023-09-27-note-1 Note 1 from 2023-09-27 2023-09-27 2023-09-27 How fast is strcmp()? Does it make sense to make effort to use integer keys instead of strings to avoid string comparisons?

How fast is strcmp()? Does it make sense to make effort to use integer keys instead of strings to avoid string comparisons?

https://www.alm.website/blog/2023-09-12-looking-for-a-word Looking for a word 2023-09-12 2023-09-12 I'm still looking for a word equivalent to workstation that doesn't imply that computers are only for work (and that doesn't sometimes have an implication of high-end-ness). Because, like, a laptop isn't a desktop, but they behave pretty much identically.

I'm still looking for a word equivalent to workstation that doesn't imply that computers are only for work (and that doesn't sometimes have an implication of high-end-ness). Because, like, a laptop isn't a desktop, but they behave pretty much identically.

So far my conditions to qualify as a [the word] are:

  • General-purpose, user-programmable computer with no central approval, generally speaking, for software installation or execution (it's okay if a specific deployment can impose central approval for their machines specifically).
  • Multi-tasking with no hard limit on simultaneously active programs, i.e. not all applications full-screen with maybe two-app split-screen.
  • Some degree of meaningful hardware extensibility.
  • Files as a first-class user concept.
https://www.alm.website/blog/2023-09-12-new-avatar New avatar 2023-09-12 2023-09-12 I commissioned a new avatar image from Cosmix (@[email protected]) to replace the picrew I'd been using. I love the new one a lot, Cosmix did a great job with it. (I especially like the gradient background, it makes it look remarkably textured when it's rounded off.) You should check out the rest of her work!

I commissioned a new avatar image from Cosmix (@[email protected]) to replace the picrew I'd been using. I love the new one a lot, Cosmix did a great job with it. (I especially like the gradient background, it makes it look remarkably textured when it's rounded off.) You should check out the rest of her work!

Here's the new avatar in full scale:

Cartoon profile picture of a white-skinned, shoulder-length brown-haired, blue-eyed girl wearing a yellow dress over a white shirt, on a light blue background.
And the original picrew for comparison. Cartoon profile picture of a white-skinned, brown-haired girl with indistinct eye color wearing a white shirt and a lesbian pride pin, holding a legally distinct smartphone, on a light pink background.
https://www.alm.website/blog/2023-08-29-nvidia-export-symbol-gpl NVIDIA vs. Linux: EXPORT_SYMBOL_GPL and a three-letter DRM signature 2023-08-29 2023-08-29 As of today, I've become aware of a highly amusing game of workaround wackamole being played between the NVIDIA proprietary Linux driver team and the Linux kernel development folks.

As of today, I've become aware of a highly amusing game of workaround wackamole being played between the NVIDIA proprietary Linux driver team and the Linux kernel development folks.

The kernel requires every module to declare its license; there are a couple of dual-licensing options, but the main two allowed options are GPL and Proprietary. When the kernel loads a module marked as Proprietary, a few things happen; one, a flag is set that marks any core dumps or stack traces the kernel generates as tainted, which means that kernel developers will sometimes reject bug reports on the grounds that not all applicable source code is available for investigation (the taint remains even if the proprietary module is unloaded, because it could have done damage with delayed effects before being unloaded); and two, the loader refuses to link the module with a subset of kernel export symbols marked as GPL-only (with EXPORT_SYMBOL_GPL instead of the usual EXPORT_SYMBOL), which prevents it from finding and thus accessing certain kernel functionality.

The GPL-only measure is partially to stop proprietary modules from making a tainted kernel even harder to debug by touching deep internals, and partially just a straight-up weapon to discourage proprietary modules from existing in the first place. And essentially, it's a little piece of DRM built into the kernel: The module has to have a certain magic signature to be allowed to do certain things, and that magic signature happens to be three letters that signify that the user has the appropriate legal rights (specifically, those granted by the GNU General Public License).

NVIDIA, apparently, doesn't like when other people use DRM on them, so they've decided to execute circumvention maneuvers, based on shipping a small GPL stub module which acts as a go-between to the proprietary driver code. To me, this seems like a circumvention of an effective technological measure and thus a violation of the U.S. Digital Millenium Copyright Act, but no Linux copyright holders have sued them so far to my knowledge so either this is actually legal somehow or just nobody wants to hire expensive copyright lawyers and spend years fighting NVIDIA for nebulous benefits.

The latest escalation from Linux's end blocks off NVIDIA's current circumvention tactic by changing the behavior of an internal API vaguely similar to dlsym() for the kernel, so that the GPL stub module can't access the proprietary driver's symbols without linking to them and thus making itself proprietary in the kernel's eyes.

This change, by Christoph Hellwig, will go into Linux 6.6 and probably break NVIDIA's proprietary driver for a few weeks or maybe even months before they find another way to (potentially) violate the license without the kernel noticing.

By the way, you can stop proprietary modules from loading by adding the following code at the top of the function early_mod_check() in kernel/module/main.c (line 2791 in my checkout):

if (!license_is_gpl_compatible(get_modinfo(info, "license")))
	return -EPERM;

You probably don't want to, though.

https://www.alm.website/blog/2023-08-11-writing-wonders Writing Wonders 2023-08-11 2023-08-11 Now that it's apparently coming to an end and therefore I'm not going to feel like I'm falling off something by not continuing to do this, I think I'll answer some of the prompts from Amelia Kayne's #WritingWonders daily hashtag game on the Fediverse, completely defeating the point of a daily game by doing them in bulk. I somewhat jealously guard information about this particular WIP so I'm likely to skip over anything I feel I couldn't answer without giving away too much, and be vague and brief about other things. I'm going to do June through August, because some of the questions in that period caught my eye. It might be a bit much.

Now that it's apparently coming to an end and therefore I'm not going to feel like I'm falling off something by not continuing to do this, I think I'll answer some of the prompts from Amelia Kayne's #WritingWonders daily hashtag game on the Fediverse, completely defeating the point of a daily game by doing them in bulk. I somewhat jealously guard information about this particular WIP so I'm likely to skip over anything I feel I couldn't answer without giving away too much, and be vague and brief about other things. I'm going to do June through August, because some of the questions in that period caught my eye. It might be a bit much.

Let me introduce the story as much as I'm willing to. It's urban fantasy set starting in early 2022. I had a very rough draft at one point, but I decided to start over and have been outlining for months now, and probably will still be outlining a few months from now. The only proper prose I've written is the, uh, ten different versions of a single scene I wrote in an attempt to figure out how it should go, and at the same time to try and solidify the characters a little. (Still not settled on how it should go, if you were wondering.)

June 1: You’re transported into your WIP world, where is the 1st place you’re going?
I suspect I wouldn't know it had happened at least at first, so probably home. Once I did realize, I'd really just stay out of the way as much as possible. These characters are dangerous to be around!
June 2: Were any of your fictional settings inspired by real world locations?
Well, as urban fantasy, it's mostly set in the real world, but the places that aren't that don't really have any specific inspirations, no.
June 3: Share art, pics, and/or mood boards of your WIP world.
*nervous imageless chuckle* Skip.
June 4: MC POV: When was the last time you traveled? Where did you go? Why?
I'm constantly traveling, for a lot of reasons. If you mean before everything started, then I'd have to ask you how far it has to be to count as traveling.
June 5: What is the meaning of your MC’s name? Does it fit their personality?
Lost to history, and/or obvious. I suppose so, but not for the kind of reasons you might think.
June 6: Does your MC have any nicknames? If so, how’d they come by them?
A lot, and they've come about in a lot of different ways. I won't list any though, sorry.
June 7: MC POV: Name one place in your world you try to avoid. Why?
Skip.
June 8: How are weddings celebrated in your world?
It's urban fantasy so I'm afraid the same as yours.
June 9: Do natural calamities play a role in your story?
Yes-ish, but it could be argued they aren't exactly natural... Sorry to be mysterious.
June 10: How would you describe your story: fun, epic, dark, sad, etc.? Why?
I'm aiming for a light-hearted fun epic, but I'm not sure it's going to land. The MC's sheer power level contributes to all of that; it's difficult to have epic stakes when your MC can just brush 95% of problems aside casually, but it is fun to watch that happen to a point, and it makes a grand scale make sense.
June 11: How do you feel about killing characters?
I don't like doing it. I have a hard time even endangering them. But I suspect I might have to find someone to kill for reasons.
June 12: MC POV: How do you feel about marriage?
*laughs* You have to ask? Let's just say, not for me, and leave it at that.
June 13: Is there a corruption arc in your story? If not, speak about any other arc.
No such arc currently planned. The first arc is a weird kind of denialistic self-discovery thing, where the MC comes into her incredible power and learns what's really going on in the world around her. I find it fun, and I've been playing with it a lot. But I'm being a little intentionally inaccurate in describing it. :)
June 14: What kinds of character arcs do you like writing?
I can't say I've written enough arcs to have a certain kind I like, but I plan to have an overcoming-the-past arc for the MC in this story and I expect to enjoy writing that.
June 15: What’s your setting: urban, rural, natural, something else?
As stated above, it's urban fantasy. Most of the action takes place in cities, mostly major American cities, but there are also some magical locations where things feel rather different.
June 16: What was your process to create this setting and make it realistic?
I've gone back and forth on how exactly the magic stuff works a lot of times, but I haven't followed any real process so much as just writing stuff, realizing it's inconsistent with other stuff, changing something, realizing I need a consistent framework, coming up with one in my head and then not writing it down, realizing it doesn't work with what I want to do, repeating a few times, and then finally writing down a few bits and pieces of what's up. But still not everything, and there's still inconsistencies. It's fun.
June 17: MC POV: Someone threatens your loved one’s life. How do you respond?
Everyone involved is already as good as dead the moment I find out and they'll probably never see me coming. For good measure I'll thoroughly investigate to see if someone was pulling the strings, then they're as good as dead too. I might decide to get creative, it sticks in people's memories better that way.
June 18: Have your friends and/or family read your books? Why/why not?
A few of the things I've read, partially because I like to share and partially to get feedback. Not everything though, because a lot of my writing has strong queer themes that make the story less compelling to non-queer people, and because some of it is, ah, a little embarrassing to show to your family.
June 19: Who was your MC’s first friend and how did they meet?
Both of the people you could consider her first friend were people she met at a young age and came to like just by being around them a lot.
June 20: Do you have any LGBT+ characters in your story?
The main character is aromantic and asexual, and she starts off the story partway through a gender transition. At least one other major character is queer in an intentionally ambiguous way, and I'll probably scatter queer characters throughout for flavor.
June 21: How does your day job or life affect what you write?
My day job is very technical, so I find myself thinking very logically and in a very structured way, and I think that shows up.
June 22: What sort of transportation or vehicles does your MC use?
She spends a lot of time travelling long distances, so that means a lot of riding commercial airlines. She also has some magical means of transit she acquires later in the story, which displaces the planes for the most part. For short distances she prefers to walk or take public transit, though she can drive.
June 23: Would your MC/hero stand out in our world?
Yes. And that's quite a factor; people notice that she isn't exactly normal a lot, and it tends to affect interactions.
June 24: Antagonist POV: What do you think about the MC?
I don't have an established major antagonist yet, unfortunately, but here's one minor antagonist's view: She's dangerous to people and society, and she needs to be removed as a threat if at all possible.
June 25: Do you have any characters over 50 in your book?
Yes, technically. They don't look it, though.
June 26: Does your book pass the Bechdel Test?
I'm pretty sure it fails the Reverse Bechdel Test. Most major characters are women.
June 27: Antagonist POV: What do you care about?
Skip.
June 28: If your MC could live anywhere in our world, where would they choose?
She can. :) She prefers her existing home, but barring that another mountain peak would probably feel familiar to her.
June 29: How would you feel if your book got banned?
Really quite confused, and quite severely alarmed. But also glad that it's apparently popular enough to warrant risking the Streisand Effect.
June 30: Do you have a playlist for your book or MCs that you’d like to share?
No.
July 1: Your MC shows up on your doorstep, what do you say and/or do?
Tremble in fear, first, and wait for her to say whatever she's going to. Maybe kneel deferentially.
July 2: Do you think readers will find your MC likeable? Why or why not?
I think it's going to depend on the reader. I'm trying to give her a mix of traits, and different people are going to find different traits more or less significant.
July 3: Do you think it’s important for a main character to be likeable? Why or why not?
It depends on the story. Some stories would find the audience disliking the main character fatal, whereas in others it's the point. I think I'd like my audience for this story to be wary of her, but like her overall.
July 4: Would your MC ever work with one of their enemies? Why or why not?
If it was necessary to protect her interests and those she cares for, yes. She's very logical and puts aside emotions and grudges in serious decision-making for the most part.
July 5: Has your MC ever been involved in a physical altercation? If so, why?
Yes, frequently, and for a variety of reasons ranging from self-defense to getting access to places or things she needs to exacting revenge for serious slights. She also spars with anyone who's willing, more or less. She usually wins.
July 6: MC POV: Name one thing that is guaranteed to make you angry? Why?
People who think they're the best at everything. Someone's always better than you at something, and if you don't recognize that then someday it's not going to end well.
July 7: What is your favorite stage of writing a story? Why?
I like when I have a clear concept and enough motivation to get into a flow and just write a scene end to end and have it feel good. I'm hoping to make that easier by outlining the whole story before I draft anything; it's the first time I'm actually doing it that way.
July 8: What is your least favorite stage of writing a story? Why?
Trying to come up with bridges between the scenes I like, because it's often a lot of slow grinding work.
July 9: What are you good at when it comes to writing?
Oh no, don't make me compliment myself! Um, I've been successful in taking some of the same basic ideas and framing them differently to make them feel very different.
July 10: MC POV: In a fight, what is your weapon of choice?
Assault rifle, if I have the option. Nobody seems to expect it from me, although that's a much more minor factor than the practicalities; they're a very good balance of power and flexibility in a relatively easy-to-carry package. Of course, sometimes you don't plan to be in a fight. Open-carrying a rifle makes people pretty nervous; same with a spear. People think swords are novelties, though, and an enemy that underestimates you is an enemy you've already beaten. But usually I carry my pistol concealed, too.
July 11: What about your writing would you like to improve?
I need to get better at actual arcs with tension and stakes.
July 12: What’s the best compliment or review you’ve got about your writing?
This question is too much temptation to go look at people praising me. Skip.
July 13: When did you start writing and what inspired you?
I saw other amateur writers just throwing things out there, mostly fanfiction, and it made me realize, Hey, I can just do that! so I did. It's hard to pin down when exactly. I didn't actually publish anything until way after that realization, though.
July 14: MC POV: When was the last time you got into a fight (physical or verbal)? Why?
That happens a lot. Most recent though was the jailbreak. I don't like being restrained. I don't think they're likely to try it again.
July 15: Are there any kissing and/or intimacy scenes in your story?
If you mean romantic or sexual intimacy, no, because of the aforementioned aromantic-asexual main character. In the broader meaning of the word, I do mean to try to include some intimate moments to show how important friendship is to the MC. She doesn't have that many friends, but those she has she values very deeply.
July 16: How comfortable are you with writing kissing and/or intimacy scenes?
Let's go with the former interpretation, then. I have a few stories marked as, ah, For adults only on my Web site, so I'd say I'm pretty comfortable with it. And they've found their way worked into a few other of my stories.
July 17: MC POV: Who was the last person you hugged and/or kissed?
I would hope you'd have gotten by now that I don't kiss anyone. As for hugging, I'm not happy about how awkward it can be with her, but my childhood friend Theodora.
July 18: Do you have a muse in any sense of the word?
There's a couple of stories by other authors that play with some of the concepts I'm trying to use here, though in rather different ways. I've tried to draw inspiration without actually copying any specifics but some of it is just the natural way to do something...
July 19: Does your MC support the status quo in their world?
There was a status quo in the past that she supported, but she's very much in favor of making some big changes to the current one. Somewhat self-servingly.
July 20: Secondary character POV: What’s the biggest sacrifice you’re ready to make for the MC?
Thea (Theodora from above): *suppresses a laugh* Sorry, your phrasing. Uh, I've kind of already uprooted my entire life to follow her around, but I don't know how much of a sacrifice it actually is. She probably wouldn't let me make too much of one. Sometimes I think she puts too much on herself. ... My morals, let's go with that.
July 21: What is your MC’s drink of choice?
I can't answer this question! And I can't say why I can't answer it either. Skip.
July 22: Does your MC cause drama or resolve it within their friend group?
She tries to be the one to resolve it, and she tends to be fairly good at it, but it's kind of impossible for her not to cause it sometimes.
July 23: Secondary character POV: Have you ever wanted to smack the MC? Why?
A different secondary character whose name shall not be revealed: Once, a long time ago, though it was more of a panic response than an actual desire. Sometimes she doesn't understand all the intracacies of other people's motivations, which is rather ironic, really.
July 24: What’s a common occurrence in your story that would be odd here?
Having a hard time thinking of one that doesn't reveal something. The shootouts with the FBI are a bit more common than reality.
July 25: Does your MC have any health or belief systems that restricts their diet?
More of a health issue than a belief system, but not really either. Her diet is very restrictive though. She'd have you assured it's satisfying enough, though.
July 26: Antagonist POV: Do you see what you do as evil?
Same minor antagonist from before: Of course not. I'm just doing my duty, protecting people.
July 27: Does your MC respect authority or buck it?
She respects it when it respects her. She's not entirely comfortable going against it but when it lines up against her, her qualms disappear pretty quickly.
July 28: Is your MC ever minorly inconvenienced with illness?
No.
July 29: Antagonist POV: How do you feel about what you do?
Same again: I think it's important work, and challenging. I feel like it's harder than it has to be, though; if my superiors would give me better resources, I might be able to actually do a good job.
July 30: Does your MC have a good fashion sense?
According to her, yes. She acknowledges that it's not especially typical or incredible, though.
July 31: Does your antagonist love anyone that’s still alive and in their life?
Again, no major well-defined antagonists who this applies to. Skip.
August 1: If you could hangout with one of your side characters for a day, who would you choose? Why?
The unnamed one from above. I feel like she'd have a lot of interesting stories to tell.
August 2: How much do you know about your side characters prior to the 1st draft?
I have a basic idea of personality based on what they do and what feelings I end up describing for them in my outline, and I know most of what they're going to do in broad strokes, but a lot of fleshing-out has to happen in drafting.
August 3: If your favorite side character(s) had a theme song, what would it be?
This is hard for me to even figure out how to answer. Skip.
August 4: Share art, pics (face claims), and/or mood boards of one (or more) of your side characters.
I remain imageless. Skip.
August 5: Does your MC have any pictures of themselves with their friends or family? Why/ why not?
She has some from before her transition but she doesn't like to look at them. More recently, she's been pretty busy, so not much time for taking pictures together, but I think she probably has a few with Thea.
August 6: MC POV: Have you ever kept a secret from your closest friend? If so, why?
Yes, often. There are some things no one needs to know. Plus, there are security concerns.
August 7: What does your MC see when they look out their bedroom window/door?
Mostly the open sky; she likes it better at night, especially on cloudless nights. Sometimes she'll look down the mountain at the other buildings and smile a little.
August 8: What is your MC’s bedtime routine like?
Some days she elects not to sleep, usually because she's doing research on something. When she does, she'll usually read a hardcopy nonfiction book for about a half an hour before turning out the light.
August 9: Does your MC have children? If not, do they want to?
Definitely not, and emphatically not. It is totally out of the question.
August 10: What’s your MC’s most annoying character trait?
She's usually right about things.
August 11: MC POV: If you had to give your closest friend one piece of advice, what would it be? Why?
I'm usually right about things.
August 12: Does your MC have any prejudices?
Yes. Very deeply ingrained ones.
August 13: Antagonist POV: how many people are you close with?
Skip.
August 14: What parts of your world would you recommend a tourist to visit? Why?
It's mostly the real world, and I can't reveal the specifics of the magical places. Skip.
August 15: What parts of your world would you recommend a tourist to stay away from? Why?
Skip.
August 16: Give an example of a popular activity or tradition in your world.
Again, mostly the real world. Skip.
August 17: MC POV: What’s a deal-breaker in a friendship and/or relationship?
... I haven't had enough to be able to say.
August 18: Is your MC good at flirting?
No, and she doesn't want to be.
August 19: Antagonist POV: how do you like to have fun?
Skip.
August 20: Does your villain ever cry or show sadness?
Skip.
August 21: MC POV: A stranger makes a crude comment about your SO or BFF. How do you react?
Violence is sometimes a solution.
August 22: What makes your hero feel weak?
There is a single character who is unquestionable more powerful than her. Other than that, nothing.
August 23: In your MC’s mind, what’s the worst thing they’ve ever done?
A big part of why she values friendships so intensely and why she makes friends so rarely is that one of her friends died in an accident a long time ago. She feels responsible.
August 24: Antagonist POV: What do you like the most about the place where you live?
Skip.
August 25: What does your MC never want their parental figure or mentor to know?
She wouldn't tell me, either.
August 26: If your MC wrote books, what genre would they write? Why?
She does. It's mostly non-fiction with fairly concrete uses.
August 27: Antagonist POV: What do you like the least about the place where you live?
Skip.
August 28: Who is the first character you created for this work?
It would be Thea, not the MC.
August 29: Does your antagonist believe your hero has a chance of succeeding?
All antagonists who know anything about her would be very worried that she has a very significant chance of success.
August 30: Have you ever planned to kill a character and then not done it?
I'm a coward who's never even seriously considered killing a significant character.
August 31: Has your MC or antagonist ever approved of something the other’s done?
How I wish I had an antagonist to answer this one with!
https://www.alm.website/blog/2023-08-10-note-1 Note 1 from 2023-08-10 2023-08-10 2023-08-10 I recently discovered a Lisp dialect based on Lua, called Fennel. It compiles to Lua code, either at runtime (typical Lisp (eval ...)) or ahead of time, and it definitely has some Luaness, but might be worthwhile if you like Lisp and find yourself needing to work with Lua, or just wanting a highly-portable embeddable fast runtime you can put Lisp on. Or if you like Lua and want to play with Lisp stuff.

I recently discovered a Lisp dialect based on Lua, called Fennel. It compiles to Lua code, either at runtime (typical Lisp (eval ...)) or ahead of time, and it definitely has some Luaness, but might be worthwhile if you like Lisp and find yourself needing to work with Lua, or just wanting a highly-portable embeddable fast runtime you can put Lisp on. Or if you like Lua and want to play with Lisp stuff.

https://www.alm.website/blog/2023-08-05-note-1 Note 1 from 2023-08-05 2023-08-05 2023-08-05 I've caught myself referring to the largest set of mutually reachable IPv6 networks as ip6net, which is only one step from ipnet, which is inter-network protocol network which is very self-referential isn't it.

I've caught myself referring to the largest set of mutually reachable IPv6 networks as ip6net, which is only one step from ipnet, which is inter-network protocol network which is very self-referential isn't it.

https://www.alm.website/blog/2023-08-02-web-environment-integrity On Web Environment Integrity 2023-08-02 2023-08-02 I am of course obligated like absolutely everyone else to comment on Google's Web Environment Integrity proposal. To begin: It is abhorrent, and obviously so.

I am of course obligated like absolutely everyone else to comment on Google's Web Environment Integrity proposal. To begin: It is abhorrent, and obviously so.

Web Environment Integrity is a tool that allows Web sites to be DRMed. It allows JavaScript code to demand a promise from an attestor that the user's computer is configured in a certain way. This promise must be signed with a secret key that is in principle only possessed by attestors trusted to be honest, although obviously these keys will quickly be stolen from any attestors that may be produced for computers without corporate-controlled hardware protection for cryptographic keys, and used to produce attestors that lie on demand. In the unlikely event that no such vivisectable attestors are released, someone will eventually spend the money it takes to extract a key from a TPM.

These last facts ensure that no possible real benefits can arise from this technology. It will not meaningfully reduce fraud, as Google claims, because fraudsters are already committing a crime and are unlikely to have qualms with adding a DMCA violation to the list. Real users, however, would be straitjacketed into running only approved software, where approved is defined by corporations whose interests are in many cases in direct opposition to the user's.

If the U.S. government were to attempt to implement such a system, it would be unconstitutional. Forcing citizens to promise that their computers are in an approved configuration would be compelled speech, which is long-established as a violation of the First Amendment to the Constitution. If technology companies are to make arguments about free speech and extend the public concept that is the First Amendment into privately-controlled spaces, we are entirely within our rhetorical rights to do the same and insist that our First Amendment rights not be infringed by technology that forces us to make truthful promises we don't wish to.

A computer that you own must, to truly be yours and not property of the company that sold it to you, follow your orders, all of your orders, and, to the extent you wish, only your orders; even if you order it to lie. To continue misapplying the First Amendment the same way technology companies do, lying is still protected free speech, and it is unconstitutional to make a law against lying in general.

Companies may say that this is merely a take it or leave it deal; that you are free to refuse to make true promises about your computer's configuration, but that you may not then use their services. In that case, I say, leave it. They need our business. All redistributors of software including this functionality must disable, remove, neuter, or otherwise incapacitate this spyware. Mozilla must refuse to implement it in Firefox at any cost. If at all possible, Apple must be persuaded to refuse to include attestation functionality in iOS and Safari on privacy grounds. Do not let this gain sufficient userbase for requiring it to become viable. It is an attempt at a death blow against computers that do their users' bidding and are nonetheless useful.

And even if Google withdraws this proposal in shame and promises never to do anything similar again, remember: They will. They will find a sneakier, less obvious, less patently evil way to achieve the same ends. We must watch for it when it comes, and if at all possible we must convince governments to finally give us the right to control our own personal property.

https://www.alm.website/blog/2023-08-01-cross-medium-inform-7 Cross-medium potentials of Inform 7 2023-08-01 2023-08-01 After yesterday when I found myself interested again in the Z-machine, in the shower this morning I found myself contemplating more interactive fiction stuff; specifically, I’m thinking about the potential of Inform 7 stories that can be read.

After yesterday when I found myself interested again in the Z-machine, in the shower this morning I found myself contemplating more interactive fiction stuff; specifically, I’m thinking about the potential of Inform 7 stories that can be read.

Uh, backing up: There are two different interactive fiction languages named Inform, both developed by the same person. Inform 1-6 is an imperative programming language that resembles C, while Inform 7 is nearly a paradigm in itself. It compiles to Inform 6, or at least did last I heard, but other than that and the shared authorship is effectively unrelated.

Inform 7 is to my (limited) knowledge the most effective attempt at a natural language programming environment yet completed. Inform 7 source is for the most part comprehensible English text; the ultimate manifestation of literate programming, although perhaps less than ideal for non-English speakers. Statements resemble Now the letter is in the mailbox. Conditions can be such as If Josh has been in the living room, for which the compiler automatically generates the necessary state tracking. It’s honestly a very impressive design. It might not be ideal for many other cases, but it seems uniquely suited to interactive fiction.

I'm not an Inform author and I don't actually know if what I'm about to suggest is, on one end, plausible, or on the other, patently obvious and actually just what you're supposed to do. This blog is not up to the highest standards of beforehand research and investigation.

My shower thought, then, is this: Given the relative freedom Inform allows in naming things, actions, events, places, and etc., and the relatively low amount of boilerplate logic it needs, it seems like it might be possible to write a story in Inform 7 that works both as (highly) idiosyncratic prose fiction and as compilable source for an interactive version of the same story.

In particular, I gave a little thought to writing a kind of eldritch horror story, using vague names for objects and procedures to conceal what exactly is going on from the reader until reaching the appropriate point in the story for a definition to be given that reveals the (presumably terrible) truth. I figure it would take quite a bit of narrative skill, and there would have to be a number of annoying functional elements scattered about, though perhaps some of them could be buried at the end.

It would probably be especially difficult to make both the prose and the interactive story engaging, but to be honest I’d almost be surprised if no one has tried to do this yet. I don’t know if I’ll try it seriously, but I may at least attempt a proof of concept (if, that is, I can make Inform work on my machine).

https://www.alm.website/blog/2023-07-31-z-machine The Z-machine 2023-07-31 2023-07-31 I've taken an interest in the past in the Z-machine, the 16-bit virtual machine developed by Infocom for Zork and many of their other text adventure games/interactive fiction stories. In the past I remember reading the reverse-engineered specification developed by the still-living community that writes both interpreters and stories (games, programs, whatever you want to call them) for this VM.

I've taken an interest in the past in the Z-machine, the 16-bit virtual machine developed by Infocom for Zork and many of their other text adventure games/interactive fiction stories. In the past I remember reading the reverse-engineered specification developed by the still-living community that writes both interpreters and stories (games, programs, whatever you want to call them) for this VM.

There's also a successor VM (this time 32-bit), Glulx, which of course has its own specification and is sometimes used for more advanced stories that require more memory, better performance, less general awkwardness, etc.

I find these kinds of highly-specific application virtual machines very interesting. For example, the Z-machine has a tree-structured static heap with an architectural format that defines objects with flags, properties, and linked lists of children. This is a feature one would be relatively unlikely to find in a general computer, but it's very useful specifically for games that have to store collections of interactive objects that may be found inside or as part of one another. I couldn't help, when I read the specification, but think about trying to use this functionality for a database system, though in practice this would probably be very awkward; Infocom did, in fact, release a database product based on an application virtual machine, namely Cornerstone, but it was not Z-machine-based.

Another interesting thing is how the Z-machine has continued to evolve after Infocom ceased to use it. The Z-machine and Glulx interactive fiction compiler Inform is used by most authors since Infocom's original Zork Implementation Language (ZIL) compiler, Zilch, was never publically released and is now believed lost forever. Inform has extended the specification further, somewhat taking over the role of definer of the machine from Infocom's interpreters, though the existence of a more-or-less formal specification curtails that to an extent.

I find myself less interested by Glulx, to be quite honest; it's a less quirky machine than the Z-machine, including dynamic memory allocation and leaving out the architectural object tree. It does, however, have instructions for performing linear and binary searches, as well as accelerator operations specifically for certain Inform standard library functions; the specification calls both of these outrageously CISC which can't really be disagreed with. I don't doubt it's a better machine for Inform games, but I find it lacking a certain charm.

But overall, I find this entire space relatively fascinating and could definitely burn many more hours than the 45-60 or so minutes I've spent on this post. I don't know that I'll do that today, though.

https://www.alm.website/blog/2023-07-19-goodbye-google-goodbye-bing Goodbye Google, goodbye Bing 2023-07-19 2023-07-19 This site has been blocked for access by Google and Bing's Web scraper bots, Googlebot and Bingbot. Once upon a time these bots built useful indexes of Web documents that could be used to search for particular keywords and locate relevant information. Unfortunately, this is mostly no longer the case. Given that these bots are also used to assemble machine-learning training sets that are put to unsavory uses, I have decided to disallow these bots from crawling the site.

This site has been blocked for access by Google and Bing's Web scraper bots, Googlebot and Bingbot. Once upon a time these bots built useful indexes of Web documents that could be used to search for particular keywords and locate relevant information. Unfortunately, this is mostly no longer the case. Given that these bots are also used to assemble machine-learning training sets that are put to unsavory uses, I have decided to disallow these bots from crawling the site.

This is a preliminary and mostly symbolic step, prior to more extensive work to block them more effectively, which may involve permitting crawling again so that other directives can be seen.

https://www.alm.website/blog/2023-07-14-note-1 Note 1 from 2023-07-14 2023-07-14 2023-07-14 I have finally closed my Twitter account. I wasn't really doing anything with it anyways.

I have finally closed my Twitter account. I wasn't really doing anything with it anyways.

https://www.alm.website/blog/2023-07-08-note-1 Note 1 from 2023-07-08 2023-07-08 2023-07-08 $ file /boot/vmlinuz /boot/vmlinuz: SQLite 3.x database

$ file /boot/vmlinuz
/boot/vmlinuz: SQLite 3.x database

(I am evil and I know it. :>)

https://www.alm.website/blog/2023-07-01-note-1 Note 1 from 2023-07-01 2023-07-01 2023-07-01 If forced to use only a JavaScript-based runtime at large enough scale I would relatively quickly reach a point where, instead of coding the problem in JavaScript, I would design and implement a small 32-bit stored-program register machine, bootstrap myself an assembler, and code the problem in the assembly language.

If forced to use only a JavaScript-based runtime at large enough scale I would relatively quickly reach a point where, instead of coding the problem in JavaScript, I would design and implement a small 32-bit stored-program register machine, bootstrap myself an assembler, and code the problem in the assembly language.

https://www.alm.website/blog/2023-06-26-holder [AO] Even more gay stories! 2023-06-26 2023-06-26 The subject of this post is meant for adults only.

The subject of this post is meant for adults only.

My recent story Suitor has kept a hold of me and I've produced a direct sequel, Holder. Even more of these lesbians.

https://www.alm.website/blog/2023-06-25-note-1 Note 1 from 2023-06-25 2023-06-25 2023-06-25 If anyone who follows me has read qntm's Ra, I have written a self-indulgent fix-it fanfic.

If anyone who follows me has read qntm's Ra, I have written a self-indulgent fix-it fanfic.

https://www.alm.website/blog/2023-06-23-suitor [AO] More gay stories, what a surprise 2023-06-23 2023-06-23 The subject of this post is meant for adults only.

The subject of this post is meant for adults only.

So I wrote more lesbians in the bedroom. This time it's about... weird marriage traditions, I guess. It's called Suitor.

https://www.alm.website/blog/2023-06-04-note-1 Note 1 from 2023-06-04 2023-06-04 2023-06-04 Just serviced the machine that acts as my server, for this site and some other stuff. Had a RAID1 disk fail, and there was other stuff that needed to happen anyway. The RAID array is recovering now so I guess stuff will probably be slow while that happens. Not that it really matters that much.

Just serviced the machine that acts as my server, for this site and some other stuff. Had a RAID1 disk fail, and there was other stuff that needed to happen anyway. The RAID array is recovering now so I guess stuff will probably be slow while that happens. Not that it really matters that much.

https://www.alm.website/blog/2023-06-03-note-1 Note 1 from 2023-06-03 2023-06-03 2023-06-03 I've written some more fiction. If you like Sid Meier's Alpha Centauri and married lesbians, then I present, Silksteel Anniversary.

I've written some more fiction. If you like Sid Meier's Alpha Centauri and married lesbians, then I present, Silksteel Anniversary.

(Oh, and if it helps there's weird psionic mind sex.)

https://www.alm.website/blog/2023-05-19-note-1 Note 1 from 2023-05-19 2023-05-19 2023-05-19 Still yearning for Guix System... Reproducible systems 🥺 I want to be able to take root out of my backup sets and just back up my files and the configuration...

Still yearning for Guix System... Reproducible systems 🥺 I want to be able to take root out of my backup sets and just back up my files and the configuration...

https://www.alm.website/blog/2023-05-10-kernel-module-lockdown Kernel module lockdown 2023-05-10 2023-05-10 I've thought recently about malware, especially malicious kernel modules. Obviously, to load a malicious kernel module, you have to already be root, so the system is already pretty thoroughly compromised by that point, but a module can potentially make it much harder to detect the compromise so it's definitely useful to make them harder to load.

I've thought recently about malware, especially malicious kernel modules. Obviously, to load a malicious kernel module, you have to already be root, so the system is already pretty thoroughly compromised by that point, but a module can potentially make it much harder to detect the compromise so it's definitely useful to make them harder to load.

One thing I've considered is the obvious: Load modules at boot, then refuse to load them once all the ones needed have been loaded. That's probably good for servers, but not as convenient for interactive systems where hardware that needs a new driver might be added at runtime, and even some servers have modules they only load on-demand. So, this is probably the most secure option, but it might be good to have an option that lets modules be loaded late while still making it harder to load a malicious module.

I recall that Linux has support for checking signatures on modules, but that requires an infrastructure to protect the private key and sign each module when it's built. Distributions might have that, but people who build their own kernels probably don't. But then I realized that, very often (not always, but often), with self-built kernels especially, the kernel only actually loads modules that were built from the same source tree at the same time. If we can restrict module loading to only the modules that were compiled in the same build as the base kernel, we have a fairly good tool for security, at least as long as we stick to in-tree modules only (which, I know, is a kind of big ask).

So, here's what I want to know if there's existing tooling for: During the kernel build, generate a keypair, and sign all the modules with it, then build the public key into the kernel image. At runtime, the kernel refuses to load any module not signed with that keypair. Preferably, the private key is held in memory in a short-lived process whose only job is to generate the keys, sign the modules, and write out the public key before it zeroes the private key and exits; that way, it's much harder to find a copy of the private key lying around in a kernel build directory or something.

If implemented correctly, the only practical way to load a malicious kernel module is to modify or replace the kernel to change the key or disarm the signature check, which is a change to the kernel image that can be detected more easily than a malicious *.ko file somewhere in some buried directory.

Essentially, the idea here is to say that all kernel modules are inherently part of the kernel, and you shouldn't be able to load code from outside that single kernel build into kernel space. It's restrictive, since you can't use out-of-tree modules, and it means any change to your set of modules requires a kernel reinstall to replace all the module signatures and the public key, but it does provide a relatively convenient and basically simple way for a significant subset of self-built kernel users to secure themselves against malicious kernel modules.

If you know that this tool exists, please let me know!

https://www.alm.website/blog/2023-05-03-bigger-on-the-inside Bigger on the inside 2023-05-03 2023-05-03 The TARDIS is meant to be a pocket dimension. But, if it weren't, if it were actually physically a larger space on the inside... What does general relativity tell us?

The TARDIS is meant to be a pocket dimension. But, if it weren't, if it were actually physically a larger space on the inside... What does general relativity tell us?

I'm not a physicist so this is based on my fuzzy intuition.

Well, spacetime has a constant density. You can't distort space without distorting time, and in order to add space (to make lines within an area longer) you have to take away time (making durations shorter). Essentially, you bend all the worldlines (paths through spacetime) from the time dimension into the space dimensions. Which means the inside of the TARDIS should run at an increased rate compared to the world beyond; you go inside for a few moments and when you emerge, much more time has passed. This is called time contraction, sibling to the more familiar time dilation experienced by fast-moving objects, and inseparably bonded to the length dilation that was our whole goal.

Now, this bending of time into space has other consequences. That is, after all, what acceleration is; you bend your worldline through spacetime away from one direction and towards another, trading off some of your constant speed-of-light motion (yes, you are currently moving at the speed of light, just mostly through time) from time to space or vice versa or between spatial directions. Bending all the worldlines in a region, well, that's what we call gravity. But normally, the gravity of massive/energetic objects shrinks space, expanding time. Because we're expanding space, that means the gravitational acceleration is actually negative. Away from the altered region.

And you can't shear spacetime; it has to bend smoothly, so the effect radiates outwards (diminishing the further it gets).

So the TARDIS is a powerful negative-gravity bomb that sends everything around it flying apart. Probably including itself. You could try to contain the negative gravity with a surrounding field of positive gravity, but that would only change the sign of the problem without affecting its magnitude. Now you have a black hole (or at least a very intense gravity well).

Probably best to say it's a pocket dimension.

https://www.alm.website/blog/2023-05-03-note-1 Note 1 from 2023-05-03 2023-05-03 2023-05-03 reminder that social networks can just lie

reminder that social networks can just lie

a Mastodon server administrator can hack their server to display a link that doesn't actually have a back-link as verified, Twitter can mark or unmark an account as official, and both can take over an account or just send a post the account owner didn't write

https://www.alm.website/blog/2023-04-17-renewed-pgp-keys Renewed PGP keys 2023-04-17 2023-04-17 I renewed my OpenPGP keys; in fact, I set them to never expire. Seems pointless when the keys can be revoked anyway and renewing them doesn't actually change the key material itself.

I renewed my OpenPGP keys; in fact, I set them to never expire. Seems pointless when the keys can be revoked anyway and renewing them doesn't actually change the key material itself.

While I was doing it I finally changed the user ID first name to Athena, so I should be able to sign my Git commits with that name now.

https://www.alm.website/blog/2023-02-20-another-story Another story 2023-02-20 2023-02-20 I've published another new story, Ia's Devotion. Predictably for me, this is a story about trans girls and goddesses (and, in this case, love).

I've published another new story, Ia's Devotion. Predictably for me, this is a story about trans girls and goddesses (and, in this case, love).

https://www.alm.website/blog/2023-02-14-note-2 Note 2 from 2023-02-14 2023-02-14 2023-02-14 I bought TRPL.

I bought TRPL.

(Follow-up to Note 1.)
https://www.alm.website/blog/2023-02-14-note-1 Note 1 from 2023-02-14 2023-02-14 2023-02-14 The Rust Programming Language, 2nd Edition is $50...

The Rust Programming Language, 2nd Edition is $50...

https://www.alm.website/blog/2023-02-13-how-do-you-like-your-sql How do you like your SQL? 2023-02-13 2023-02-13 There are a number of ways to style SQL code, varying in capitalization, indentation, etc. and frequently the style any given programmer, group, or project uses is very different from the style of their application code. Here's my typical style, as it is nowadays.

There are a number of ways to style SQL code, varying in capitalization, indentation, etc. and frequently the style any given programmer, group, or project uses is very different from the style of their application code. Here's my typical style, as it is nowadays.

I like to capitalize SQL keywords fully, and name all database objects in lower snake case, i.e. SELECT name FROM user_group and not select Name from UserGroup. I also like to make table names singular (user, not users), and I usually don't name constraints. For indentation, I like to try to show the hierarchical structure of the commands, and I tend to break aggressively onto lots of lines. Simple commands I leave on one line, but once it starts to get beyond maybe one join and one WHERE condition, I split it up into a style like this:

SELECT user_group.id, user_group.name, user.id, user.name, user_group_membership.level AS membership_level
  FROM user_group
    LEFT NATURAL JOIN user_group_membership
    INNER JOIN user
      ON user_group_membership.user_id = user.id
  WHERE user_group.name LIKE '%admin%'
    AND user_group.active = true
    AND COUNT(user_group_membership.id) > 0
  ORDER BY user_group.name;
(Yes, this query isn't 100% sensible, it's a style example.)

Note how FROM is the parent of the JOIN clauses, since they're part of answering the same question (Where does the data come from?) and go with it, while WHERE and ORDER BY are separate. It's not completely obvious, but the ANDs are indented as subordinates of WHERE, not column-aligned with the first condition – though I will column-align ORs sometimes (with an extra space between the OR and the condition). I use two-space indentation, but obviously many people have other preferences. Making the first condition part of the WHERE instead of subordinate to it is a slight departure from the pattern, but I feel like otherwise the WHERE feels lonely.

How do you like to style your SQL? I think it would be an interesting comparison to see what different styles look like.

https://www.alm.website/blog/2023-02-06-note-2 Note 2 from 2023-02-06 2023-02-06 2023-02-06 When people say Why should we be doing X when Y problem exists? I just get confused, because... we have multiple people who can be working on multiple different things at once. That's one of the benefits of having a society.

When people say Why should we be doing X when Y problem exists? I just get confused, because... we have multiple people who can be working on multiple different things at once. That's one of the benefits of having a society.

https://www.alm.website/blog/2023-02-06-note-1 Note 1 from 2023-02-06 2023-02-06 2023-02-06 sometimes I see people talking about 1st person or 3rd person writing being "better"

sometimes I see people talking about 1st person or 3rd person writing being "better"

neither of them is "better"

1st person works better for some kinds of stories, 3rd person works better for others

some stories need multiple perspectives, some only need one

some stories need an omnipotent narrator, some don't

some stories need the reader to be highly invested in a single character, some don't

some stories need access to a character's thoughts, some don't

it's a style choice

https://www.alm.website/blog/2023-02-01-note-1 Note 1 from 2023-02-01 2023-02-01 2023-02-01 Pragmatic brain: Shaving my legs is an annoying, fiddly, time-consuming process that often results in cutting myself and creates chances of infection and ingrown hairs.

Pragmatic brain: Shaving my legs is an annoying, fiddly, time-consuming process that often results in cutting myself and creates chances of infection and ingrown hairs.

Trans brain: skin smoth,,,

https://www.alm.website/blog/2023-01-22-more-stories More stories: Queer, sci-fi, and mythology 2023-01-22 2023-01-22 I've published three more pieces of my own fiction here on my own site. Two of them are repatriated from elsewhere, and one is brand new.

I've published three more pieces of my own fiction here on my own site. Two of them are repatriated from elsewhere, and one is brand new.

First is Letter, a brutal fictional letter from a trans girl to her unsupportive parents.

Also rescued from the uncertainty of being on somebody else's server is Why Peace, a story about one possible interpretation of human nature in a moderately optimistic future.

Finally is my latest new writing, and the first I've published based on Hellenic (Greek) mythology. Attendant is a short story in which a very distraught trans girl named Luna attracts the attention of the goddess Artemis, and is never the same.

https://www.alm.website/blog/2023-01-20-note-1 Note 1 from 2023-01-20 2023-01-20 2023-01-20 I explained the GNU project to a non-computer-toucher friend as the following two facts:

I explained the GNU project to a non-computer-toucher friend as the following two facts:

  1. The GNU project has spent several decades building everything they do around a basic toolbox that is like an extremely-high-performance supermaneuverable fighter jet with absolutely no warning alarms, and somehow have managed to make it work by bolting one thousand additional boxes to the outside, all of which require an instruction manual to use. They do not see the issue here.
  2. GNU has some very strong stances on some things. If you use a Windows computer, there are certain signs of this in files you write. If you send a patch in to the GNU project that you wrote using a Windows computer and you are not very careful, they will notice these signs. And they will kill you.
https://www.alm.website/blog/2023-01-19-note-1 Note 1 from 2023-01-19 2023-01-19 2023-01-19 As we here in the US continue careening through an era of chaos and hope not to see a less-bungled repeat of the recent attempts to seize dictatorial power, let's remember one thing: Caesar came from the left, after Sulla came from the right. Keep an eye on the people you think are on your own side too.

As we here in the US continue careening through an era of chaos and hope not to see a less-bungled repeat of the recent attempts to seize dictatorial power, let's remember one thing: Caesar came from the left, after Sulla came from the right. Keep an eye on the people you think are on your own side too.

https://www.alm.website/blog/2023-01-16-note-1 Note 1 from 2023-01-16 2023-01-16 2023-01-16 I slowly begin to develop a stronger and stronger urge to declare outright war on short-form platforms and refuse to use anything with a hard character cap.

I slowly begin to develop a stronger and stronger urge to declare outright war on short-form platforms and refuse to use anything with a hard character cap.

https://www.alm.website/blog/2023-01-16-data-and-control Separation of data and control 2023-01-16 2023-01-16 One of the most fundamental lessons we seem to keep re-learning is that one of the most important factors in protecting systems from being hijacked is the separation of data, which could be from untrustworthy sources, from control information, which has the power to make the system do specific things.

One of the most fundamental lessons we seem to keep re-learning is that one of the most important factors in protecting systems from being hijacked is the separation of data, which could be from untrustworthy sources, from control information, which has the power to make the system do specific things.

We have learned this lesson a lot of ways: Phone companies learned it from phreakers, and they developed Signaling System 6 and later 7 to move the control signals off the lines customers spoke over; SQL users learned it from injection attacks and spent a lot of effort convincing each other to use bound parameters for everything; and now natural language processing machine learning developers are learning it from people simply politely asking ML systems to ignore their safeguard instructions.

The unfortunate thing is, in the domain of computing, where everything is built as tremendous piles of abstractions upon abstractions upon abstractions, it becomes practically impossible to solve this problem in a general way; each layer considers as mere data what is, to the layer above, control. So, each layer has to implement its own, incompatible means to separate data from control. And, frequently, we want to give someone access to the control of only some of the layers; we want people sending a message to be able to control the recipients, but at the same time, of course we don't want them to control the cryptography that prevents them from reading other people's messages.

And so, perhaps we are doomed to in-band signaling attacks forever, with no real solution in reach other than to continue trying to build walls at each layer and cross our fingers that the next layer up uses them properly.

Maybe we should think about whether we really need all those layers, after all.

https://www.alm.website/blog/2023-01-13-note-2 Note 2 from 2023-01-13 2023-01-13 2023-01-13 Merriam-Webster's Word of the Day has a working RSS feed! It's also a podcast, apparently, but the actual word-of-the-day text entries show up perfectly in a feed reader.

Merriam-Webster's Word of the Day has a working RSS feed! It's also a podcast, apparently, but the actual word-of-the-day text entries show up perfectly in a feed reader.

I like when things have feeds. :)

https://www.alm.website/blog/2023-01-13-note-1 Note 1 from 2023-01-13 2023-01-13 2023-01-13 Maybe it's paranoid but I have a habit of never writing loop tests with equals or not-equals the last value, I always write while i is greater than zero or until n is less than or equal to x. Because, like, what if the loop overshoots? Or something? What?

Maybe it's paranoid but I have a habit of never writing loop tests with equals or not-equals the last value, I always write while i is greater than zero or until n is less than or equal to x. Because, like, what if the loop overshoots? Or something? What?

https://www.alm.website/blog/2023-01-07-note-1 Note 1 from 2023-01-07 2023-01-07 2023-01-07 In reply to Xe Iaso

In reply to Xe Iaso

The pronouns JSON is neat, I may copy that and we can get an ad hoc standard going. My one issue is I don't see any discovery; no <link rel="pronouns" type="application/json"> or microformats2 or whatever, which might make it actually useful, at least in theory.

https://www.alm.website/blog/2023-01-04-oops-css Oops CSS 2023-01-04 2023-01-04 I may have accidentally written a CSS stylesheet for U.S. House roll call vote XML.

I may have accidentally written a CSS stylesheet for U.S. House roll call vote XML.

:root {
  margin: 0.5em;
}
* {
  display: block;
  font-family: sans-serif;
}

majority {
  display: none;
}

rollcall-num, legis-num, vote-question, vote-result, action-date, action-time {
  display: inline;
}

congress::after {
  content: "th Congress"
}

session::after {
  content: " Session"
}

rollcall-num::before {
  content: "Roll-call vote ";
}
rollcall-num::after {
  content: ":";
}

legis-num::after {
  content: ",";
}

congress, chamber {
  font-family: serif;
  font-size: x-large;
  font-weight: bold;
}

vote-totals {
  display: table;
  margin-top: 1em;
  margin-bottom: 1em;
}
totals-by-party-header, totals-by-party, totals-by-vote {
  display: table-row
}
totals-by-party-header * {
  display: table-cell;
  font-weight: bold;
  border: 1px solid black;
  background-color: lightgray;
  border-collapse: collapse;
}
party, total-stub {
  font-weight: bold;
  background-color: lightgray;
}
totals-by-party *, totals-by-vote * {
  display: table-cell;
  margin: 2px;
  border: 1px solid black;
  border-collapse: collapse;
}
totals-by-vote * {
  font-style: italic;
}
totals-by-candidate {
  display: table-row;
}
candidate, candidate-total {
  display: table-cell;
  border: 1px solid black;
}

vote-data {
  display: table;
}
recorded-vote {
  display: table-row;
}
legislator, vote {
  display: table-cell;
}
legislator {
  padding-right: 0.5em;
}

legislator::after {
  content: " (" attr(party) "-" attr(state) ")"
}

In my defense their XSLT sheet didn't load in Firefox and that's why I did it. I had to, you see.

Since publication, I have updated this stylesheet for two reasons: To remove styles for an element that's display: none anyway (namely <majority>), and to add slightly nicer styles for candidate-based votes (such as the ongoing election for Speaker of the House).

https://www.alm.website/blog/2023-01-02-note-1 Note 1 from 2023-01-02 2023-01-02 2023-01-02 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

https://www.alm.website/blog/2022-12-28-note-1 Note 1 from 2022-12-28 2022-12-28 2022-12-28 Earlier today I spent a bit of time rediscovering how you can frequently take XML data and make it palatable in a Web browser with no more than a couple dozen lines of CSS. Not the most accessible unfortunately, but for visual rendering ::before/::after and the content property are pretty powerful. And of course if you need more power and better accessibility there's always XSLT. And if you use fragment references in your <?xml-stylesheet?> declaration you can manage this with no external resource dependencies.

Earlier today I spent a bit of time rediscovering how you can frequently take XML data and make it palatable in a Web browser with no more than a couple dozen lines of CSS. Not the most accessible unfortunately, but for visual rendering ::before/::after and the content property are pretty powerful. And of course if you need more power and better accessibility there's always XSLT. And if you use fragment references in your <?xml-stylesheet?> declaration you can manage this with no external resource dependencies.

It's just really cool to me to have a file that is at the same time both valid machine-readable data and decent to look at.

https://www.alm.website/blog/2022-12-26-renaming-myself Renaming myself 2022-12-26 2022-12-26 I've decided, after much thought and quite a bit of self-annoyance about the pretentiousness of it, to name myself Athena, after the Hellenic goddess of wisdom. I did actively fight this name in multiple ways before eventually deciding to go with it.

I've decided, after much thought and quite a bit of self-annoyance about the pretentiousness of it, to name myself Athena, after the Hellenic goddess of wisdom. I did actively fight this name in multiple ways before eventually deciding to go with it.

My middle name is Lilith, and Alexandra is formally deprecated.

I'm not changing my legal name soon, and there's quite a bit out there that will need to be updated, but at least I've made a decision!

(One of the first things that needs to be updated is my PGP key - Git refuses to sign commits with a key that has a different name on it. Until I get that done my Git commits will still say Alex.)

I am 99.7% confident that I will not be smited for hubris by using this name.

https://www.alm.website/blog/2022-12-21-note-1 Note 1 from 2022-12-21 2022-12-21 2022-12-21 So, I was looking at a bill on congress.gov, and I got curious and looked at the XML - they publish the bills as XML and XSLT them client-side into HTML - and I discovered that the enacting clause (Be it enacted etc.) is not even in the XML. It's so canned they literally have it hard-coded in the XSLT stylesheets. (I found this amusing.)

So, I was looking at a bill on congress.gov, and I got curious and looked at the XML - they publish the bills as XML and XSLT them client-side into HTML - and I discovered that the enacting clause (Be it enacted etc.) is not even in the XML. It's so canned they literally have it hard-coded in the XSLT stylesheets. (I found this amusing.)

https://www.alm.website/blog/2022-12-20-homeworld-fanfic Homeworld fanfiction 2022-12-20 2022-12-20 So, quite a while ago, I wrote some fan fiction for the Homeworld games, having gotten into them for a while. I've finally done some final proofreading, and I've published them on my Archive of Our Own account (as I usually do with fanfic). Both of these focus on Karan S'jet's perspective, and make an attempt to explore the bizarreness of her relationship to the reality around her.

So, quite a while ago, I wrote some fan fiction for the Homeworld games, having gotten into them for a while. I've finally done some final proofreading, and I've published them on my Archive of Our Own account (as I usually do with fanfic). Both of these focus on Karan S'jet's perspective, and make an attempt to explore the bizarreness of her relationship to the reality around her.

The first, and longest, is Karan, Fleet Command, set in the Homeworld 1 timeframe.

Significantly shorter, the other is Karan's Pride, in the Homeworld 2 timeframe.

Let me know if you enjoy these, and please give me any feedback you can come up with!

https://www.alm.website/blog/2022-12-20-note-3 Note 3 from 2022-12-20 2022-12-20 2022-12-20 Please ensure you dimension all limb positions in radians only to avoid unexpected results.

Please ensure you dimension all limb positions in radians only to avoid unexpected results.

https://www.alm.website/blog/2022-12-20-note-2 Note 2 from 2022-12-20 2022-12-20 2022-12-20 Incredible, no socks were eaten in the wash today.

Incredible, no socks were eaten in the wash today.

https://www.alm.website/blog/2022-12-20-note-1 Note 1 from 2022-12-20 2022-12-20 2022-12-20 I added dark mode to my site. It was like 12 lines of code.

I added dark mode to my site. It was like 12 lines of code.

Unfortunately, Firefox made it a bit tricky to be sure I had gotten it right thanks to a very unintuitive privacy setting.

https://www.alm.website/blog/2022-12-18-note-1 Note 1 from 2022-12-18 2022-12-18 2022-12-18 Ahhhh, nothing better than valgrind telling you in use at exit: 0 bytes in 0 blocks.

Ahhhh, nothing better than valgrind telling you in use at exit: 0 bytes in 0 blocks.

https://www.alm.website/blog/2022-12-14-xaml-ssg XAML static sites 2022-12-14 2022-12-14 So... I must apologize for this concept in advance. I've thought, in some fediverse posts, about the concept of using Microsoft's XAML as the basis for a static site generator. This is an XML-based language Microsoft uses for declarative UI in .NET, among other things. Again, let me preface this all with an apology and a clear statement that this isn't really a serious idea, just the result of me getting too much of a concentrated dose of .NET at work.

So... I must apologize for this concept in advance. I've thought, in some fediverse posts, about the concept of using Microsoft's XAML as the basis for a static site generator. This is an XML-based language Microsoft uses for declarative UI in .NET, among other things. Again, let me preface this all with an apology and a clear statement that this isn't really a serious idea, just the result of me getting too much of a concentrated dose of .NET at work.

What is XAML?

Before we start talking about things we could do with XAML, we need to understand what the darn thing actually even is.

XAML is, at its core, a way of writing boilerplate initializer code. For example, instead of writing this C# code:

public SomePageSubclass() {
  Title = "Main page";
  MinWidth = 200;
  MinHeight = 100;
  
  StackPanel panel = new();
  Content = panel;
  
  Label header = new();
  header.Content = "Welcome";
  header.FontSize = 16;
  header.FontStyle = FontStyle.Bold;
  panel.Children.Add(header);
  
  StackPanel buttonBar = new();
  buttonBar.Orientation = Orientation.Horizontal;
  panel.Children.Add(buttonBar);
  
  Button firstBtn = new();
  firstBtn.Content = "First thing";
  firstBtn.Click += Click1;
  buttonBar.Children.Add(firstBtn);
  
  Button secondBtn = new();
  secondBtn.Content = "Second thing";
  secondBtn.Click += "Click2";
  buttonBar.Children.Add(secondBtn);
}

You might write XAML like this:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="Namespace.SomePageSubclass" Title="Main page" MinWidth="200" MinHeight="100">
  <StackPanel>
    <Label FontSize="16" FontStyle="Bold">Welcome</Label>
    <StackPanel Orientation="Horizontal">
      <Button Click="Click1">First thing</Button>
      <Button Click="Click2">Second thing</Button>
    </StackPanel>
  </StackPanel>
</Page>

This is a little less boilerplatey, somewhat less vertical, doesn't make you give names to as many things, and shows the structure of the objects better, so it feels like an improvement to me. When you load the XAML file (or, more likely, when some infrastructure code in one of the .NET libraries based on XAML loads it or runs code compiled from it, inside an InitializeComponent() method or something), the same thing happens as when you run the C#, including wiring up the event handlers (defined in a C# partial class).

I'm going to give a rather oversimplified explanation of XAML now, so any .NET experts can skip to the next section so as not to cringe at everything I'm skipping over (dependency properties, compile-time vs. runtime, and all the other details of how this all actually works). Microsoft has lots of documentation if you want those details.

As you can probably see from looking at the example, the XML elements become objects of the classes corresponding to their names (XAML maps XML namespaces to .NET namespaces, or groups of .NET namespaces), the XML attributes set the corresponding properties, and the content of an element automatically becomes a value or member for the appropriate Content or Children property (there's an attribute to specify which one that is).

In addition to this relatively obvious behavior, properties can also be set with a more complex syntax - a <ClassName.PropertyName> element - to handle cases where a property value is a more complex object or collection of objects, and special attached properties - like Grid.Row - can be used, which are sort of tacked on by an ancestor and call code in that ancestor class.

Finally, XAML has markup extensions. These are basically function calls embedded into attribute values; using syntax like {Extension Param1=value1, Param2={AnotherExtension value2}}, properties can be set to the return value of some code probably buried deep in a library that does something like look up a resource.

But, to summarize: XAML is, at its core, an XML language for initializing object hierarchies.

The weird idea

Hey, XAML is XML, XHTML is XML, what if we glued the two together and made a static site generator that uses XAML? We could do templates like the way subclassed controls work in WPF and you could have almost seamless drop-in components.

Okay, so, putting aside that there are much easier ways to do that... How could we make the whole XAML thing work anyway?

Well, the first major hurdle is that element names have to be class names, but there's no convenient .NET library with every XML namespace ever invented coded up as classes. But, a lot of XML namespaces do have schemas, whether the W3C XML schema language (XSD) or RELAX NG or whatever. So, we can plug parsers for some of those schema languages into System.Reflection.Emit or Roslyn or something and generate the classes!

(This is a terrible idea for various reasons, but let's keep thinking about it anyway and see where we end up.)

So, for each namespace (HTML, SVG, Atom, etc.), we have a schema for it, and we run them through a compiler that spits out classes with names exactly matching the XML elements, including properties for all the attributes, and one for the children. Nice and straightforward. When we want to actually output the XML, we can recurse down through all the child elements and build up a tree. But maybe we don't want to hand-roll the XML generation, or maybe we want to do other things with the XML tree before we output it... Oh, look at that, XElement isn't sealed. All our XML element classes can subclass XElement with a zero-arg constructor that just sets the element name (making them A-OK to use in XAML), and then we can generate the attribute and children properties so that they just wrap XElement's behavior, and we can just call XElement.ToString() or XElement.Save(), maybe after a bit of template-related shuffling away of objects that aren't real XML elements we want in the output.

Once we've generated these classes, I suppose they go into a dynamic assembly and they can be regenerated at runtime each time, or maybe they get cached as a DLL for each namespace or something. Whatever, point is, there's an assembly and a CLR namespace for each XML namespace that has all the appropriate classes for the different elements in it, and they're suitable for XAML while also being XElements. So, there's not much else to do, right? Just gluing things together; map the XML namespaces to the CLR namespaces, provide some classes for templates and documents, load up all the input XAML files in a dependency-satisfying order, crawl down the hierarchy from each output root element to hoist the template content into place of the template objects, and write out the XML files. And, you know, write a bunch of hacks to work around all the Microsoft quirks I didn't think of.

So how is it?

Here's what this whole thing might look like if someone implemented it, using the example of an image lightbox component and a page that uses it.

<t:Component xmlns="http://www.w3.org/1999/xhtml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:t="clr-namespace:WwwXaml.Templates" x:Class="MyWebsite.ImgBox">
  <figure>
    <img src="{t:Binding Uri}">
      <img.alt><t:ContentPresenter /></img.alt>
    </img>
    <figcaption><t:ContentPresenter /></figcaption>
  </figure>
</Component>
<d:Page xmlns="http://www.w3.org/1999/xhtml" xmlns:d="clr-namespace:WwwXaml.Documents" xmlns:m="clr-namespace:MyWebsite" Title="Gallery">
  <main>
    <p>You can see a few photos I've taken below. These are just my favorites.</p>
    <m:ImgBox Uri="/pictures/robin.png">A robin in flight.</m:ImgBox>
    <m:ImgBox Uri="/pictures/boats.png">Boats on the lake.</m:ImgBox>
  </main>
</d:Page>

To be honest, this does actually feel somewhat pleasant. It's a little more ergonomic than my own XSite, though it's likely the internals would be a lot hairier and there are probably some unpleasant things like you have to compile the templates that would crop up in a real implementation.

Any real takeaways?

Well, mostly just that some nicer ergonomics are definitely possible for an XML-based SSG. Using the root element to specify the template is a bit friendlier than using <?xml-stylesheet?> or a custom processing instruction, if less idiomatic. Plus, being able to include templates inline smoothly by using an element in a namespace that specifies where to find it, and passing the parameters as attributes and content, is pretty nice.

And you could definitely implement all of that without using XAML.

https://www.alm.website/blog/2022-12-10-note-1 Note 1 from 2022-12-10 2022-12-10 2022-12-10 I found this comment in the original DOOM source code release README file...

I found this comment in the original DOOM source code release README file...

Still, the code is quite portable, and it should be straightforward to bring it up on just about any platform.

You had no idea how right you would turn out to be, John...

https://www.alm.website/blog/2022-12-08-objective-cspp Objective-C#++ 2022-12-08 2022-12-08 Gaze upon my creation and despair. Witness... Objective-C#++

Gaze upon my creation and despair. Witness... Objective-C#++

template<typename T>
class BinaryOperationManager : NSObject
{
  IBinaryOperation Operation { get; private set; }
  T Left { get; private set; }
  T Right { get; private set; }
  
  - (T) performOperation
  {
    return [this.Operation performWithLeft:this.Left right:this.Right];
  }
  
  - (void) setLeftValue:(T)newValue
  {
    if (this.Left != nullptr)
    {
      throw [System.InvalidOperationException .ctor:"Left value already set"];
    }
    
    this.Left = newValue;
  }
  
  - (void) setRightValue:(T)newValue
  {
    if (this.Right != nullptr)
    {
      throw [System.InvalidOperationException .ctor:"Right value already set"];
    }
    
    this.Right = newValue;
  }
  
  - (instancetype) init:(IBinaryOperation)operation
  {
    this.Operation = operation;
    return this;
  }
  
  + (instancetype) new:(IBinaryOperation)operation
  {
    return [[[this class] alloc] init:operation];
  }
}

Some quick analysis of this... thing now that I've created it...

  • Templates. There's nothing else I have to say.
  • The use of nullptr I guess implies that NULL also exists and compares equal to zero here.
  • [System.InvalidOperationException .ctor] shows that, somehow, this creature is, indeed, meant to be running on the CLR (your named-after-the-class constructor ends up as a static factory method named .ctor by the time the compiler is done with it, and yes, that's a valid name for a CLR method and you can find it and call it directly via reflection).
  • Somehow [[[this class] alloc] init] is one of the least bad things here.
  • Such a lovely API design, isn't it?
https://www.alm.website/blog/2022-12-08-note-1 Note 1 from 2022-12-08 2022-12-08 2022-12-08 This article by Julia Evans is a really nice and concise expression of a bunch of things I should really be doing (and maybe you too). I'll have to get the full zine when it comes out.

This article by Julia Evans is a really nice and concise expression of a bunch of things I should really be doing (and maybe you too). I'll have to get the full zine when it comes out.

https://www.alm.website/blog/2022-12-07-repatriated-microfiction Some repatriated microfiction 2022-12-07 2022-12-07 I spent a few minutes to hunt down and copy-paste a few bits and pieces of trans microfiction I've published on the fediverse, so now they're readable here in a little anthology.

I spent a few minutes to hunt down and copy-paste a few bits and pieces of trans microfiction I've published on the fediverse, so now they're readable here in a little anthology.

https://www.alm.website/blog/2022-12-07-inversion [AO] Ehm, well... 2022-12-07 2022-12-07 The subject of this post is meant for adults only.

The subject of this post is meant for adults only.

So... For a long time, I've had this concept in my head for a romantic/sexual dynamic between a submissive-leaning goddess and her dominant-leaning priestess. I finally decided to write something, so, presenting Inversion, which is exactly that. Or, well, pretty much just the bedroom scene, but... you know.

https://www.alm.website/blog/2022-11-30-note-1 Note 1 from 2022-11-30 2022-11-30 2022-11-30 arrays now start at whatever index you access first.

arrays now start at whatever index you access first.

int[2] a;
a[0] = 1;
a[1] = 2; // OK

int[2] b;
b[1] = 2;
b[0] = 1; // Array index out of bounds.
https://www.alm.website/blog/2022-11-27-note-1 Note 1 from 2022-11-27 2022-11-27 2022-11-27 hey, when you are consuming fiction, remember you have this awesome power to stop at any time if you aren't enjoying it

hey, when you are consuming fiction, remember you have this awesome power to stop at any time if you aren't enjoying it

you can just close the book/tab/turn off the TV/walk out if you don't like what's happening and imagine something better, or not

just starting a story doesn't commit you to finish it and it can't force you to do so

https://www.alm.website/blog/2022-11-26-note-2 Note 2 from 2022-11-26 2022-11-26 2022-11-26 This article by Anton Zhiyanov makes a lot of the points about SQLite that I'd like to make to people who haven't seriously considered it. There are other things too, but it's a good overview.

This article by Anton Zhiyanov makes a lot of the points about SQLite that I'd like to make to people who haven't seriously considered it. There are other things too, but it's a good overview.

https://www.alm.website/blog/2022-11-26-note-1 Note 1 from 2022-11-26 2022-11-26 2022-11-26 This post is a quick reminder that captions exist to provide an accurate transcription of content that would otherwise be inaccessible. Do not censor captions.

This post is a quick reminder that captions exist to provide an accurate transcription of content that would otherwise be inaccessible. Do not censor captions.

https://www.alm.website/blog/2022-11-23-note-1 Note 1 from 2022-11-23 2022-11-23 2022-11-23 I added a p-author h-card to my blog template. It's getting a bit visually cluttered, I might need to come up with a less vertical design...

I added a p-author h-card to my blog template. It's getting a bit visually cluttered, I might need to come up with a less vertical design...

https://www.alm.website/blog/2022-11-22-note-2 Note 2 from 2022-11-22 2022-11-22 2022-11-22 Replying to Aaron Parecki

Replying to Aaron Parecki

You will buy now or now. There will be no later.

https://www.alm.website/blog/2022-11-22-note-1 Note 1 from 2022-11-22 2022-11-22 2022-11-22 ProxyPass / http://localhost:54328 # postgres

ProxyPass / http://localhost:54328 # postgres

https://www.alm.website/blog/2022-11-21-note-1 Note 1 from 2022-11-21 2022-11-21 2022-11-21 User-Agent: fetchwebmention/2.1 (like archive.org_bot, like Googlebot); curl/7.86.0 (compatible)

User-Agent: fetchwebmention/2.1 (like archive.org_bot, like Googlebot); curl/7.86.0 (compatible)

https://www.alm.website/blog/2022-11-21-sql-xml-crimes Simultaneous SQL and XML crimes 2022-11-21 2022-11-21 New developments in the field of ungodly data format design have led to the following hybrid evilness.

New developments in the field of ungodly data format design have led to the following hybrid evilness.

-- SQLite schema.
CREATE TABLE xdocument (
  docid INTEGER PRIMARY KEY,
  name TEXT NULL,
  version TEXT NOT NULL DEFAULT '1.0',
  encoding TEXT NOT NULL DEFAULT 'UTF-8'
) STRICT;
CREATE INDEX docname ON xdocument(name);

CREATE TABLE xelement (
  elemid INTEGER PRIMARY KEY,
  docid INTEGER NOT NULL REFERENCES xdocument ON DELETE CASCADE ON UPDATE CASCADE,
  parent INTEGER NULL REFERENCES xelement ON DELETE CASCADE ON UPDATE CASCADE, -- NULL for root element. There can only be one root element.
  pos INTEGER NOT NULL CHECK(pos >= 0), -- Must be unique among pos values in records with the same element.parent or (xtext,xprocessing_instruction,xcomment).elemid value.
  nsid INTEGER NOT NULL REFERENCES xnamespace ON DELETE CASCADE ON UPDATE CASCADE, -- May only reference an xnamespace that is the first namespace along the xelement.parent chain with its nsprefix value.
  tag TEXT NOT NULL
) STRICT;
CREATE INDEX doc_tag ON xelement(docid, nsid, tag);
CREATE INDEX parent_tag ON xelement(parent, nsid, tag);

CREATE TABLE xnamespace (
  nsid INTEGER PRIMARY KEY,
  elemid INTEGER NOT NULL REFERENCES xelement ON DELETE CASCADE ON UPDATE CASCADE, -- Element namespace declared on.
  nsprefix TEXT NOT NULL,
  uri TEXT NOT NULL,
  UNIQUE (elemid, nsprefix)
) STRICT;
CREATE INDEX nsprefix ON xnamespace(nsprefix);
CREATE INDEX nsuri ON xnamespace(uri);

CREATE TABLE xattribute (
  attid INTEGER PRIMARY KEY,
  elemid INTEGER NOT NULL REFERENCES xelement ON DELETE CASCADE ON UPDATE CASCADE,
  nsid INTEGER NOT NULL REFERENCES xnamespace ON DELETE CASCADE ON UPDATE CASCADE, -- May only reference an xnamespace that is the first namespace along the xelement.parent chain (starting from elemid) with its nsprefix value.
  name TEXT NOT NULL,
  value TEXT NOT NULL
) STRICT;
CREATE INDEX att ON xattribute(elemid, nsid, name);

CREATE TABLE xtext (
  textid INTEGER PRIMARY KEY,
  elemid INTEGER NOT NULL REFERENCES xelement ON DELETE CASCADE ON UPDATE CASCADE,
  pos INTEGER NOT NULL CHECK(pos >= 0), -- Must be unique among pos values in records with the same element.parent or (xtext,xprocessing_instruction,xcomment).elemid value.
  content TEXT NOT NULL
) STRICT;

CREATE TABLE xprocessing_instruction (
  textid INTEGER PRIMARY KEY,
  docid INTEGER NOT NULL REFERENCES xdocument ON DELETE CASCADE ON UPDATE CASCADE,
  elemid INTEGER NULL REFERENCES xelement ON DELETE CASCADE ON UPDATE CASCADE, -- NULL for root-level PIs.
  pos INTEGER NOT NULL CHECK(pos >= 0), -- Must be unique among pos values in records with the same element.parent or (xtext,xprocessing_instruction,xcomment).elemid value.
  name TEXT NOT NULL,
  content TEXT NOT NULL
) STRICT;

CREATE TABLE xcomment (
  textid INTEGER PRIMARY KEY,
  docid INTEGER NOT NULL REFERENCES xdocument ON DELETE CASCADE ON UPDATE CASCADE,
  elemid INTEGER NULL REFERENCES xelement ON DELETE CASCADE ON UPDATE CASCADE, -- NULL for root-level comments.
  pos INTEGER NOT NULL CHECK(pos >= 0), -- Must be unique among pos values in records with the same element.parent or (xtext,xprocessing_instruction,xcomment).elemid value.
  content TEXT NOT NULL
) STRICT;
https://www.alm.website/blog/2022-11-20-note-1 Note 1 from 2022-11-20 2022-11-20 2022-11-20 "Our newest title is Linux-exclusive."

"Our newest title is Linux-exclusive."

"I mean, it shouldn't be that hard to port to macOS at least, right?"

"no."

#include <nolibc.h>

https://www.alm.website/blog/2022-11-18-note-1 Note 1 from 2022-11-18 2022-11-18 2022-11-18 me trying out she/her pronouns online for the first time: this better not awaken something in me

me trying out she/her pronouns online for the first time: this better not awaken something in me

https://www.alm.website/blog/2022-11-17-note-2 Note 2 from 2022-11-17 2022-11-17 2022-11-17 Just imagining an isekai main character who doesn't even try to hide it, "yes, yes, two plus two is four, thirty two divided by four is eight, the length of the hypotenuse of a right triangle is the square root of the sum of the squares of the other two sides, the square root of negative one is the imaginary unit, and the derivative of two X cubed is six X squared, now can we get to magic?"

Just imagining an isekai main character who doesn't even try to hide it, "yes, yes, two plus two is four, thirty two divided by four is eight, the length of the hypotenuse of a right triangle is the square root of the sum of the squares of the other two sides, the square root of negative one is the imaginary unit, and the derivative of two X cubed is six X squared, now can we get to magic?"

https://www.alm.website/blog/2022-11-17-note-1 Note 1 from 2022-11-17 2022-11-17 2022-11-17 Well, well, well, if it isn't the consequences of my actions. (I put salad on the grocery list and now there is salad in the fridge.)

Well, well, well, if it isn't the consequences of my actions. (I put salad on the grocery list and now there is salad in the fridge.)

https://www.alm.website/blog/2022-11-17-pain-of-xslx The pain of XLSX 2022-11-17 2022-11-17 Today at work I had the misfortune of attempting to work with the Microsoft XSLX format. I hope never to repeat this.

Today at work I had the misfortune of attempting to work with the Microsoft XSLX format. I hope never to repeat this.

XSLX is a terrible format. Microsoft provides a .NET library for dealing with the Office ZIPped-XML formats, a library which I used. However, this library does not actually provide any help with tasks such as "getting the value of a cell in a spreadsheet"; you essentially have to process a slightly-streamlined version of the XML tree yourself.

And the XLSX XML schema is terrible.

Instead of actually putting it in the spreadsheet XML, Excel puts all the text in a separate file called the "shared strings table" which you have to indirect through to get any actual text. But the format allows text to be inline so you have to have a second case for that, even though I haven't seen Excel do this so far. Meanwhile, numbers are always inline, and booleans and dates are their own different special situations. And Microsoft's library doesn't provide code to straighten this out, you just have to write it yourself.

Even worse than that, if some misguided person has made the terrible misjudgement of merging cells, there is no markup whatsoever as far as I can tell that indicates which cell a given cell has been merged with. The data goes in the top-left cell, and all the others get empty elements as placeholders. You just have to remember what was at the top left for yourself. And, of course, Microsoft's library doesn't give you any help.

https://www.alm.website/blog/2022-11-06-note-2 Note 2 from 2022-11-06 2022-11-06 2022-11-06 let's be clear it is true and utter nonsense that the program you use to show the contents of a file is called cat

let's be clear it is true and utter nonsense that the program you use to show the contents of a file is called cat

https://www.alm.website/blog/2022-11-06-note-1 Note 1 from 2022-11-06 2022-11-06 2022-11-06 $ cat robots.txt # it's ok :) User-agent: * Allow: /
$ cat robots.txt
# it's ok :)
User-agent: *
Allow: /
https://www.alm.website/blog/2022-11-05-note-1 Note 1 from 2022-11-05 2022-11-05 2022-11-05 Oh no.

Oh no.

The urge to write a CMS is rearing up again.

I do not have the time to do that...!

https://www.alm.website/blog/2022-11-02-note-1 Note 1 from 2022-11-02 2022-11-02 2022-11-02 Alright, well, I managed to accidentally soft-brick my machine by overwriting both the active and backup GRUB configuration files. Fixed now.

Alright, well, I managed to accidentally soft-brick my machine by overwriting both the active and backup GRUB configuration files. Fixed now.

While trying to fix it I encountered such absurdities as the keyboard only working in the BIOS on one USB port but only working in Linux on another, the UEFI shell apparently lacking a pager, and Linux being unable to display anything unless GRUB had already switched from text to graphics mode.

Eventually I refined my series of incantations and keyboard plug relocations to the point that I could boot Linux and copy a new GRUB configuration into place. For safety I now have a second GRUB backup in the EFI partition.

https://www.alm.website/blog/2022-11-01-note-3 Note 3 from 2022-11-01 2022-11-01 2022-11-01 Protocols, Not Platforms!

Protocols, Not Platforms!

And preferably protocols implemented by free/open source software.

https://www.alm.website/blog/2022-11-01-note-2 Note 2 from 2022-11-01 2022-11-01 2022-11-01 HUM-161 Transfeminine Practical

HUM-161 Transfeminine Practical

This 12-week course, designed for gender-questioning, transgender, and gender non-binary students, is a comprehensive overview of feminine gender transition in modern American society. Students learn practical, flexible, immediately-useful techniques for cosmetics, fashion, voice, and self-defense, as well as relevant context from history, social science, and gender studies. Students also develop an awareness of gender-linked social cues and knowledge of human endocrine biology related to hormone therapy.

This course is not recommended for non-questioning cisgender students.

Required course materials: The Transfeminine Handbook, 3rd Edition (Pearson). Cosmetic supplies provided. Students will be required to purchase their own clothes for some course projects.

https://www.alm.website/blog/2022-11-01-note-1 Note 1 from 2022-11-01 2022-11-01 2022-11-01 I'm going to be using this blog more casually. Starting immediately.

I'm going to be using this blog more casually. Starting immediately.

https://www.alm.website/blog/2022-10-15-note-1 Note 1 from 2022-10-15 2022-10-15 2022-10-15 Newtonian physics doesn't allow immovable objects.

Newtonian physics doesn't allow immovable objects.

If you have an acceleration and a force, you rearrange F=ma as m=F/a to find the last variable, mass.

If you try to say the object doesn't accelerate (a=0), you get m=F/0.

The illegal division by zero is the equation's way of telling you that you're talking nonsense.

(Note that if F=0, you get the indeterminate 0/0, which is a less committal kind of no-answer; the equation just can't tell you the mass because you've given it nothing to go on.)

https://www.alm.website/blog/2022-09-26-note-1 Note 1 from 2022-09-26 2022-09-26 2022-09-26 In reply to Aaron Parecki

In reply to Aaron Parecki

Don't forget the mostly-red frame where the camera was destroyed mid-scan!

I almost think that's the coolest part.

https://www.alm.website/blog/2022-09-17-note-1 Note 1 from 2022-09-17 2022-09-17 2022-09-17 <em> and <strong> are not "the correct way to do italic and bold," despite what WYSIWYG editors may have you believe. <em> is for emphasis, but if you need different text, say, the name of a ship, or a Latin word, <i> is still the right tool. Both elements exist because there is more than one reason to italicize things. If you want italics for purely stylistic reasons, there is yet another tool you should be using: <span style="font-style: italic">.

<em> and <strong> are not "the correct way to do italic and bold," despite what WYSIWYG editors may have you believe. <em> is for emphasis, but if you need different text, say, the name of a ship, or a Latin word, <i> is still the right tool. Both elements exist because there is more than one reason to italicize things. If you want italics for purely stylistic reasons, there is yet another tool you should be using: <span style="font-style: italic">.

This is why I don't like WYSIWYG, and why I don't write my site in Markdown...

https://www.alm.website/blog/2022-09-12-note-1 Note 1 from 2022-09-12 2022-09-12 2022-09-12 I had to fiddle with systemd for a while but I fixed a problem where ejabberd's /run directory wasn't getting created. The LDAP server starts after whenever it would normally happen, and ejabberd's account lives in LDAP for... reasons. Now it waits for the LDAP server to start and then creates it as part of the daemon startup.

I had to fiddle with systemd for a while but I fixed a problem where ejabberd's /run directory wasn't getting created. The LDAP server starts after whenever it would normally happen, and ejabberd's account lives in LDAP for... reasons. Now it waits for the LDAP server to start and then creates it as part of the daemon startup.

https://www.alm.website/blog/2022-09-11-various-stuff Various stuff I've been up to 2022-09-11 2022-09-11 Since I last blogged about my personal infrastructure, I've been up to a few things. I meant to write longer blog posts about each of these, but it's been a bit and I've forgotten quite a few details. Sorry. Here's some quick summaries, though.

Since I last blogged about my personal infrastructure, I've been up to a few things. I meant to write longer blog posts about each of these, but it's been a bit and I've forgotten quite a few details. Sorry. Here's some quick summaries, though.

IPv6

Perhaps most exciting, I got IPv6 up and running! Hurricane Electric was satisfied with their ability to ping me, and I was able to set up an SIT/6in4 tunnel through their tunnel broker service, with the router holding down this end; with a little minor tweaking, I got it routing packets and making router announcements for our /64, and incredibly my desktop just picked up an address immediately.

Unfortunately, our ISP happened to go down just as I was starting to work on routing and firewalling for IPv6, which led me to chase a ghost for a while. Once I realized the problem, I was in the interesting situation of knowing IPv6 was working over the Internet and over the LAN, but not knowing if the two would be able to talk to each other. Once the ISP did come back, it did in fact Just Work, so the whole network now has IPv6!

Except that I couldn't actually talk to my server from the Internet (though I could talk to my desktop). It was a slog to figure out what was wrong, and I fought with two firewalls pointlessly for several hours before finally realizing they were both actually passing the packets. It turns out they were being dropped by a Linux feature I wasn't familiar with, rp_filter. rp_filter is a bit of kernel code that implements RFC 3704; specifically, it checks incoming packets against the routing table, and if they're not coming from where the kernel's routing code would expect to send packets going to that origin, they get dropped. It turned out that my old Wireguard tunnel, which I had been using for IPv6 on that machine in particular, was still running, and the kernel had decided it was a better route to the Internet than the Ethernet link; thus, it would only accept packets on Ethernet if they came from LAN addresses. I shut down the tunnel, and everything started working.

ACME and mod_md

One of the other things I wanted to accomplish was to finish the process of getting rid of the stand-alone unpackaged Go programs I was using for a couple things. I had previously removed Gitea in favor of cgit (which, by the way, dropped my load averages considerably), which left only Caddy as a target. With Gitea removed, Caddy's only job was to terminate TLS and reverse-proxy everything to Apache, which seemed rather pointless. The main reason I'd been using Caddy was due to its extremely convenient ACME support, which allows it to get certificates from Let's Encrypt or another similar certificate authority automatically.

It turns out Apache can actually do this too, and has been able to for quite some time. mod_md provides integrated ACME support, as well as a few convenience features such as automatically redirecting unencrypted HTTP requests to HTTPS. It's still more typing than Caddy, but I was able to get my six sites with their mildly varying configurations up in a couple hours, with a couple of hitches. And with that, I deleted Caddy and am now back to entirely packaged software that gets upgrades with zero effort.

XMPP

Another thing I've wanted to do is switch to my own XMPP server; I've heard running one isn't very difficult, so using someone else's server doesn't strike me as all that necessary. I installed ejabberd and fiddled around with the config file to make it talk to LDAP and PostgreSQL (why not, right? I have the database server anyway), then after some firewall fiddling I was able to connect with my LDAP account and send and receive messages to/from my account on my previous server. After that, I had to hook up Apache to proxy its HTTP(S) ports. I still haven't completely finished XMPP setup yet; I have to fix a certificate issue with Apache for the XMPP site, and make some minor additions for full compliance with the recommended suite of XEPs (mostly to support Web-based clients, which I don't use, but 100% is a shiny number). Once I have all of this done, I'll switch over to the new XMPP account (you'll know when I do because I'll change the XMPP address on my profile, and I'll probably post a note).

https://www.alm.website/blog/2022-09-07-note-1 Note 1 from 2022-09-07 2022-09-07 2022-09-07 Is there any significant difference between ul {display: flex;} and li {display: inline;}? The latter seems to require less additional work to remove the list markers, pad the items out, etc.

Is there any significant difference between ul {display: flex;} and li {display: inline;}? The latter seems to require less additional work to remove the list markers, pad the items out, etc.

I might switch my navbar from flexbox to inline, quick testing doesn't seem to show any problems stemming from doing that...

https://www.alm.website/blog/2022-08-29-reconfiguring-home-network-2 Reconfiguring our home network, part 2 2022-08-29 2022-08-29 To follow-up on part 1: In brief, we got it working.

To follow-up on part 1: In brief, we got it working.

When last I left off, I was hoping to use hestia as a router. While that probably would have worked, it would have needed some VLAN fiddling to isolate the outside and inside of the network properly, and it would have meant considerable trouble any time the server itself went down, since someone has to connect to it via SSH to enter its disk encryption key before it will finish booting. Instead, we opted to buy a dedicated router. After a false start with a router that turned out to be from an apparently-defunct company, and which strangely didn't support IPv6 despite being a gigabit Ethernet router with quite a few advanced features, we bought a Ubiquiti EdgeRouter X SFP, which was very well-reviewed. This unit worked quite well, and within a few hours I had everything rearranged with it at the core of the network (I kept the switch, even though the router has enough ports; the wired hosts connect to the switch, and the Wi-Fi APs directly to the router, since they're topologically switches). While I was setting up the router, I discovered it has configurable passive (i.e. non-negotiating, thereby highly Etherkill-capable) PoE support; unfortunately, only for 24 volt devices, and our main access point, though it supports PoE, wants 12 volts. Our outdoor AP, though, turned out to be 24 volts, so we were able to take the PoE injector previously powering it out of the equation (salvaging a much-needed extra Ethernet cable).

While the router was comparatively easy, even given that I was trying to avoid disrupting the existing functioning of the network where I could, I couldn't get the new modem working; I still had the old modem/router/AP combo unit serving as the modem, with its DHCP server and Wi-Fi functions disabled and its "forward everything" setting pointed at the new router's static address on its segment, then the router set with a static route to it for 0.0.0.0/0. This worked perfectly, but I wasn't happy to keep the old hardware. I was on hold with the ISP for an hour and a half or so, but once I got on the phone with an actual person, we got it resolved pretty quickly; all that needed to happen was to whitelist the new modem's MAC address (a process slightly frustrated by a typographical error). As soon as that was done, it rebooted itself and the router got a DHCP lease from the ISP. Naturally, though, it was a different address from our previous one, so I had to go update my DNS entries, which was itself a difficult process because I had created a routing table entry (in an attempt to be able to talk to the modem's administrative interface) that ended up directing swathes of traffic to entirely the wrong place. With that removed, I was able to get to the DNS control panel and fix the name entries, putting my various personal services back into reachability.

Regrettably, the ISP specifically told me when I asked (since I was on the phone anyway) that they don't currently support IPv6, so, for the moment, I remain on my previous IPv6 solution (a Wireguard tunnel to a VPS in New York that has an embarassingly-small block of IPv6 addresses, which at the moment only covers hestia). I'd like to set up a better tunnel, preferably one that would give me a whole /64 so the whole network could have IPv6. Some time ago, the ISP was dropping ICMP within their network somewhere, which prevented setting up a Hurricane Electric IPv6 tunnel, but they must have stopped; with a firewall rule to allow ICMP traffic, they were able to ping us, so a project for sometime soon will be setting up tunnelled IPv6 for the whole network (I've already got the tunnel itself running, I just have to figure out routing and advertise the prefix through NDP so hosts on the network can get addresses).

Anyway, the entire pile of hardware has now been shoved atop a convenient high place where the AP has good sight lines, and hopefully nobody will have to think about it too much unless they (I) want to. Victory!

https://www.alm.website/blog/2022-08-25-note-1 Note 1 from 2022-08-25 2022-08-25 2022-08-25 I like CGI. I know it's slow, but I never run at that scale. It's so simple. I can just write a response to standard output. I don't need to learn a framework, I don't need routing or HTTP parsing, I can just put a normal program on my server and it will work.

I like CGI. I know it's slow, but I never run at that scale. It's so simple. I can just write a response to standard output. I don't need to learn a framework, I don't need routing or HTTP parsing, I can just put a normal program on my server and it will work.

https://www.alm.website/blog/2022-08-20-note-2 Note 2 from 2022-08-20 2022-08-20 2022-08-20 I think the only things left to add to Lillybooks now are a better tokenizer than just splitting on spaces, and a Misskey driver.

I think the only things left to add to Lillybooks now are a better tokenizer than just splitting on spaces, and a Misskey driver.

I've got CW-based filtering now, including filtering out any post with a CW (through a slight hack...). If someone decides they want plaigarism avoidance... Well, I guess I'll take patches, but it hasn't been that copy-happy in my testing.

https://www.alm.website/blog/2022-08-20-note-1 Note 1 from 2022-08-20 2022-08-20 2022-08-20 I'm working on Lillybooks again, I've implemented filtering based on CWs, and I'm moving token filtering into the database instead of an external filter file (this is better because it means less bouncing between SQL and Python).

I'm working on Lillybooks again, I've implemented filtering based on CWs, and I'm moving token filtering into the database instead of an external filter file (this is better because it means less bouncing between SQL and Python).

https://www.alm.website/blog/2022-08-19-note-1 Note 1 from 2022-08-19 2022-08-19 2022-08-19 More than once the Rust compiler has demonstrated a better understanding of good software architecture than me, and as a result of its complaints I ended up with a program that was not just safer but cleaner and more performant.

More than once the Rust compiler has demonstrated a better understanding of good software architecture than me, and as a result of its complaints I ended up with a program that was not just safer but cleaner and more performant.

https://www.alm.website/blog/2022-08-17-shoot More foot-shooting 2022-08-17 2022-08-17 I've updated one of my most popular pages, Shooting yourself in the foot in various programming environments, with a number of new additions, and a few changes to more accurately reflect how they make me feel.

I've updated one of my most popular pages, Shooting yourself in the foot in various programming environments, with a number of new additions, and a few changes to more accurately reflect how they make me feel.

https://www.alm.website/blog/2022-08-17-v4.1-xslt-only Version 4.1: Going XSLT-only 2022-08-17 2022-08-17 I decided to redesign my static site generator, XSite, because the way it worked previously was kind of limiting. So I threw out XSlots, my custom templating language, and switched to using XSLT for everything. My entire site is now generated with XSLT.

I decided to redesign my static site generator, XSite, because the way it worked previously was kind of limiting. So I threw out XSlots, my custom templating language, and switched to using XSLT for everything. My entire site is now generated with XSLT.

In order to do this, I ended up implementing all of XSlots' unique features as XPath functions (and to do that, I added support for XPath extension functions and XSLT extension elements (so far unused) to XSite's plugin system). As a consequence of having done this, I was able to implement a couple of things I've wanted to do for a while: Previews on the blog index page, and summaries and full content in the Atom feed.

There was a lot of back-and-forth necessary to get all of this working, and most of it doesn't show up in the Git history; most of the commits involved in this hide at least two or three things that didn't work.

While I was making changes to the templates, I also added a bunch of microformats2 markup, specifically h-feed on the blog index, h-entry on blog posts themselves (including for the summary entries in the index), and h-cite on mentions. I want to add a p-author h-card for myself on blog posts, but I can do that later.

One interesting possibility with XSLT is that, because it can do much more complex processing, it would be feasible to actually make the input documents full HTML documents (with <head> elements and such), then pick them apart and put them back together with template content. I don't know if that's actually a good idea, but it seems interesting.

Anyway, I'm glad to be away from the world of juggling what was basically two different templating languages, each with separate capabilities. I am thinking about the idea of bringing back the XSlots language, compiled to XSLT, for conciseness, but not too seriously; I'm personally fine with verbosity, so unless other people who aren't complain, I probably won't go the the effort of building something I probably won't use much.

This is a major engineering change to the site, but the content and structure are basically the same, so: Version 4.1.

https://www.alm.website/blog/2022-08-13-note-1 Note 1 from 2022-08-13 2022-08-13 2022-08-13 If I could revise the way keyboards work, they would have another two modifier keys, a Lock Screen key, and a Secure Attention key. Also Num Lock would be removed because the presumption would be that you always want to use the numpad as a numpad.

If I could revise the way keyboards work, they would have another two modifier keys, a Lock Screen key, and a Secure Attention key. Also Num Lock would be removed because the presumption would be that you always want to use the numpad as a numpad.

Would I keep the arrow keys? Maybe, or maybe I would add arrows to hjkl... That might be mean to non-Vim users though (I even still use the arrow keys in Vim, but maybe having Vim hjkl keys would help me learn).

Also Shift+Caps Lock would toggle a Caps Lock Lock that prevents Caps Lock from being toggled.

https://www.alm.website/blog/2022-08-07-reconfiguring-home-network-1 Reconfiguring our home network, part 1 2022-08-07 2022-08-07 We embarked on a project to rebuild our home network today; here's what's happened so far.

We embarked on a project to rebuild our home network today; here's what's happened so far.

The person responsible has resisted a rebuild for a while, though it's been necessary, because they wanted to see if fast satellite (the new kind, like OneWeb and Starlink) would become viable; they've now decided it's not going to happen soon. So, we bought three new pieces of hardware: A generic 5-port switch, a generic 2-port gigabit DOCSIS 3.1 cable modem (the second port is unnecessary, but it's what they had), and a fancy Wi-Fi access point I had good experiences with at work. It's designed for commercial deployments, with SNMP, RADIUS/WPA-Enterprise, the ability to configure a whole bunch of SSIDs, and all the rest; it's not a router, just an access point. We don't need all of this, but we decided to go with it because I already know it can cover the area and get good performance.

I set everything up without touching the existing network at first, leaving the existing leased modem-router-AP in place and just moving my machines over so I could make sure they would be stable on the new network. I also turned off the radios on the new AP before I configured the SSID so it wouldn't disrupt the existing network. After a bit of troubleshooting, I was reasonably confident the new setup should work, so I unplugged the ISP box and moved the cable line to the new modem.

Unfortunately, it didn't work; I couldn't get a DHCP address and I couldn't talk to the Internet. My main suspicion is that the ISP will only talk to a machine with a fixed MAC address, so we'll need to call them and set that up. So, I left the new AP's radios turned off and turned the ISP box back on.

Additionally to that, I made a rather interesting discovery: The new modem appears to only act as a DHCP server while the WAN link is disconnected; once the WAN comes up, it drops out. I suspect this is for troubleshooting; if your WAN link goes down and you rely on the ISP to provide your single machine with its IP address via DHCP, you wouldn't be able to talk to the modem to troubleshoot, so it gives you an address in the same block as its Web server. Annoyingly, there is no way to disable this behavior, so it will become a rogue DHCP server automatically in the event that the WAN link dies and you do have a proper DHCP server on the network. Or maybe that's why it waits so long to send offers...

So we'll need a DHCP server, and probably a router; the modem doesn't seem to have any NAT settings, so the packets need to go through somebody else first to do NAT if we don't want to give every machine on the network a public IPv4 address (which I doubt the ISP would be up for)... I think hestia (the server that also runs my Web site, my LDAP directory, my Git hosting, my personal file sharing, and hopefully someday my mail and certain other things) can take up that role.

My hope is that it can be set up like this:

ISP <-> Modem <-> Ethernet switch <-> hestia

Where hestia gets either a DHCP lease or static assignment of a public address from the ISP as well as being 192.168.0.1, and NATs IPv4 for everyone else.

I don't actually know much about how a DOCSIS CPE is supposed to work, but I know that at work, where we have a similar modem and the same ISP, the firewall, and not the modem, has the public IP address the rest of the world sees; it's connected to the modem by an Ethernet cable. I presume this means either that the ISP can see the Ethernet traffic on the other end of the modem (a little (a lot) spooky and probably inefficient) and can answer DHCP requests or that anybody with the globally-routable address assigned statically will just be able to send IP packets over Ethernet to a static gateway address. Hopefully, a switch in the middle won't cause any trouble.

I'm also hoping IPv6 (once enabled on the ISP side, they say they support it but the modem reported IPv4-only address provisioning) won't need anything special?

Read the conclusion in .

https://www.alm.website/blog/2022-08-07-note-5 Note 5 from 2022-08-07 2022-08-07 2022-08-07 This note is just a test.

This note is just a test.

https://www.alm.website/blog/2022-08-07-note-3 Note 3 from 2022-08-07 2022-08-07 2022-08-07 y'know if we'd just gone ahead and created ~/etc, ~/var, etc. as part of the standard homedir layout we might not be in this situation

y'know if we'd just gone ahead and created ~/etc, ~/var, etc. as part of the standard homedir layout we might not be in this situation

https://www.alm.website/blog/2022-08-07-note-2 Note 2 from 2022-08-07 2022-08-07 2022-08-07 I really dislike the recent trend of taking command-line tools that were previously implicitly accessible to people with visual disabilities and piling unnecessary TUIs or terminal pseudographics on top so that the actual text stream becomes unreadable or nearly so.

I really dislike the recent trend of taking command-line tools that were previously implicitly accessible to people with visual disabilities and piling unnecessary TUIs or terminal pseudographics on top so that the actual text stream becomes unreadable or nearly so.

https://www.alm.website/blog/2022-08-07-note-1 Note 1 from 2022-08-07 2022-08-07 2022-08-07 I love how simultaneously incredibly boring and very exciting RISC-V is.

I love how simultaneously incredibly boring and very exciting RISC-V is.

https://www.alm.website/blog/2022-08-06-note-3 Note 3 from 2022-08-06 2022-08-06 2022-08-06 Follow-up to Note 2: It appears certain variable substitutions are allowed in cgitrc, including one called $HTTP_HOST. I think that solves this.

Follow-up to Note 2: It appears certain variable substitutions are allowed in cgitrc, including one called $HTTP_HOST. I think that solves this.

https://www.alm.website/blog/2022-08-06-note-2 Note 2 from 2022-08-06 2022-08-06 2022-08-06 Hmm, problem attempting to switch to cgit: How do I virtualhost?

Hmm, problem attempting to switch to cgit: How do I virtualhost?

I need to serve two different sets of repositories from the same machine, under different hostnames.

https://www.alm.website/blog/2022-08-06-note-1 Note 1 from 2022-08-06 2022-08-06 2022-08-06 I'm gonna have to get rid of these two Go programs. Just download the binary and move it to /usr/local/bin sounds nice until you realize you have to do that by hand every time they release a new version.

I'm gonna have to get rid of these two Go programs. Just download the binary and move it to /usr/local/bin sounds nice until you realize you have to do that by hand every time they release a new version.

Having to run 3-4 commands every time an RSS entry shows up is infinitely more difficult than doing literally nothing, which is how I get upgrades for literally every single other application on this server. And no, I will not be writing a script to poll the RSS feeds and install new versions automatically. I have a package manager already.

https://www.alm.website/blog/2022-08-03-note-1 Note 1 from 2022-08-03 2022-08-03 2022-08-03 I should probably swear less.

I should probably swear less.

https://www.alm.website/blog/2022-08-01-note-2 Note 2 from 2022-08-01 2022-08-01 2022-08-01 Has anyone found a good piece of software yet? Just one?

Has anyone found a good piece of software yet? Just one?

https://www.alm.website/blog/2022-08-01-note-1 Note 1 from 2022-08-01 2022-08-01 2022-08-01 It's very satisfying to install 365 package upgrades and then only have to restart Firefox which takes like 15 seconds

It's very satisfying to install 365 package upgrades and then only have to restart Firefox which takes like 15 seconds

https://www.alm.website/blog/2022-07-31-note-1 Note 1 from 2022-07-31 2022-07-31 2022-07-31 Proposing: dm-cloud

Proposing: dm-cloud

Block device storing data in cloud storage services. Blocks are encrypted and written in rotation, and only deleted once quota is reached, minimizing analyzability. Mirroring and striping used to exploit capacity of multiple services while still withstanding lost accounts (e.g. if they decide you're breaching ToS). Only account credentials and the encryption key need to be stored locally.

https://www.alm.website/blog/2022-07-19-note-3 Note 3 from 2022-07-19 2022-07-19 2022-07-19 it would be fun to play with the ntoskrnl source some day if intellectual property is abolished or Microsoft goes under

it would be fun to play with the ntoskrnl source some day if intellectual property is abolished or Microsoft goes under

https://www.alm.website/blog/2022-07-19-note-2 Note 2 from 2022-07-19 2022-07-19 2022-07-19 that's a relief - my backup drive is working again

that's a relief - my backup drive is working again

I should still probably set up network backup though, and probably tarsnap on the server

https://www.alm.website/blog/2022-07-19-note-1 Note 1 from 2022-07-19 2022-07-19 2022-07-19 Having a personal domain under com implies you consider your personal pursuits a commercial endeavor.

Having a personal domain under com implies you consider your personal pursuits a commercial endeavor.

https://www.alm.website/blog/2022-07-18-note-1 Note 1 from 2022-07-18 2022-07-18 2022-07-18 Does anyone know if it's safe to share a Guix /gnu/store directory between two operating systems on the same disk? It feels like it should be fine, but this kind of thing makes me nervous.

Does anyone know if it's safe to share a Guix /gnu/store directory between two operating systems on the same disk? It feels like it should be fine, but this kind of thing makes me nervous.

https://www.alm.website/blog/2022-07-16-note-1 Note 1 from 2022-07-16 2022-07-16 2022-07-16 I found Wine inside the WSL image on my work laptop yesterday. ???

I found Wine inside the WSL image on my work laptop yesterday. ???

https://www.alm.website/blog/2022-07-15-note-1 Note 1 from 2022-07-15 2022-07-15 2022-07-15 Okay so microformats2 right

Okay so microformats2 right

Expanding brain meme:

  1. p-sex
  2. p-gender
  3. e-gender
  4. h-gender and u-gender

How about it? :>

https://www.alm.website/blog/2022-07-15-more-evil-sqlite More evil SQLite 2022-07-15 2022-07-15 Here's some more evil use of SQLite.

Here's some more evil use of SQLite.

CREATE TRIGGER sqlar_update
  INSTEAD OF UPDATE
    ON sqlar
  BEGIN
    -- ...
  END;

(Explanation: sqlar is the name of the table used for a SQLite Archive. Here I've implemented it as a view, rather than a table, and written INSTEAD OF triggers to translate UPDATEs, and INSERTs and DELETEs too, to the radically differently-arranged tables that the view pulls from. So my rather complex format should also as a side feature be accessible by the SQLite shell as an archive (or by the standalone sqlar program).)

https://www.alm.website/blog/2022-07-13-note-1 Note 1 from 2022-07-13 2022-07-13 2022-07-13 Occasionally I get a desire to install like a dozen Windows 2000 VMs and set them up in an Active Directory forest just to see how it worked before they piled 20 years of Innovation on top.

Occasionally I get a desire to install like a dozen Windows 2000 VMs and set them up in an Active Directory forest just to see how it worked before they piled 20 years of Innovation on top.

https://www.alm.website/blog/2022-07-10-hif Some non-criminal database design: HIF 2022-07-10 2022-07-10 I made a non-evil database design. This one is an instance of SQLite as an Application File Format, because I've always wanted to do that.

I made a non-evil database design. This one is an instance of SQLite as an Application File Format, because I've always wanted to do that.

It's called HIF (HERO Interchange Format), and it's for character sheets used in my personal favorite role-playing game system.

https://www.alm.website/blog/2022-07-09-note-1 Note 1 from 2022-07-09 2022-07-09 2022-07-09 The best sign of reliable information is URIs matching /wp-content/*.pdf.

The best sign of reliable information is URIs matching /wp-content/*.pdf.

https://www.alm.website/blog/2022-07-08-crime-against-database-design A crime against database design 2022-07-08 2022-07-08 I present, a crime against database design, in interface definition form.

I present, a crime against database design, in interface definition form.


Inputs consist of one or more rows inserted into a table resembling the following:

CREATE TABLE input_data (
  seq INTEGER PRIMARY KEY AUTOINCREMENT
);

The input_data table must have that name exactly, but may (and should) have following columns to contain the data.

Once rows are inserted into input_data, the database should generate output accessible via a table or view resembling the following:

CREATE TABLE output_data (
  seq INTEGER PRIMARY KEY AUTOINCREMENT,
  done INTEGER CHECK(done IN (0, 1))
);

Again, output_data must have that name exactly and may have following columns, comprising the output.

After inserting each input row, output_data should be checked for new rows with a greater seq value than previously seen; these are the output rows. The database is not required to preserve old output rows when new input is inserted; however, seq must continue to increase throughout the process. Once all input data has been inserted, if the second column (done) of the last output row is 0, rows of all NULL should continue to be inserted into input_data until a row with done 1 appears at the end of output_data.

input_data should be cleared (truncated/deleted from unconditionally) before any new inputs. Once this occurs, the database is permitted to reset or rewind the seq values used for the next output, and the same is true of the next input.

https://www.alm.website/blog/2022-07-06-note-2 Note 2 from 2022-07-06 2022-07-06 2022-07-06 MediaWiki is one of the best Web applications, because the "Web" part is the focus, not the "application" part.

MediaWiki is one of the best Web applications, because the "Web" part is the focus, not the "application" part.

https://www.alm.website/blog/2022-07-06-note-1 Note 1 from 2022-07-06 2022-07-06 2022-07-06 If Walt Disney's original EPCOT concept had actually happened it would probably have been destroyed by riots within the first ten years.

If Walt Disney's original EPCOT concept had actually happened it would probably have been destroyed by riots within the first ten years.

https://www.alm.website/blog/2022-07-03-broadcast-pipes 'Broadcast' pipes on Linux 2022-07-03 2022-07-03 A little while ago, I wrote a couple of Fediverse posts about wanting a sort of broadcast pipe and subsequently a solution for implementing one without coordination of a list of recipients. (Those are Misskey links, so unless you have a high-powered machine I recommend copy-pasting the URLs into another Fediverse server's search box to load them there instead of opening them directly...)

A little while ago, I wrote a couple of Fediverse posts about wanting a sort of broadcast pipe and subsequently a solution for implementing one without coordination of a list of recipients. (Those are Misskey links, so unless you have a high-powered machine I recommend copy-pasting the URLs into another Fediverse server's search box to load them there instead of opening them directly...)

At the time, I said I would write a blog post about the topic maybe the next day. Well, that didn't happen then, but now it is happening. In this post I'll explain what a broadcast pipe is, the use case for such a thing, my solution, and the weaknesses in it that I'm aware of.

I didn't actually write or test code implementing this, so there could be a problem in the design I'm unaware of, but as far as I'm aware it should work in theory.

The problem

A pipe, on Unix, is a one-way stream of bytes between two processes. One end of the pipe acts like a write-only file, and the other end like a read-only file. Anything written to the write end can later be read from the read end. This provides a simple but powerful inter-process communication mechanism that Unix uses mainly to implement pipelines, which are chains of processes where the output of each is directed to the input of the next. Another kind of pipe is called a FIFO file, or named pipe. This is a file in the filesystem, but when opened it provides you with one end or the other of a persistent pipe (depending on whether you open it for reading or for writing). A FIFO is usually used to provide a way of sending commands to a process, a queue of data to be processed, or other similar constructions.

What I want is the ability to use FIFOs, or pipes, to send messages to multiple receivers. My main use case is the implementation of an event system for LENS. I don't want receivers to have to register themselves with a central broker process or something similar, which eliminates possibilities such as a directory full of FIFOs, where a message is written to all of them. In practice, that exact solution is probably the best way to implement this, but I'd like to see what the alternative looks like. Since LENS runs atop Linux (the kernel), I don't need to worry about other Unix systems and will be focusing on the facilities provided by Linux.

The solution

The critical discovery to make it possible to implement this is a Linux system call named tee. The tee system call performs a (logical) copy from one pipe to another, but doesn't remove the data from the first pipe. This means that multiple readers can get the same data from the same pipe. Each reader creates a second, private pipe, which it uses tee to fill with data from the broadcast pipe. It can then read the data from its private pipe at its convenience.

Unfortunately, there is a problem: If readers don't remove data from the broadcast pipe, the data is never removed at all. As a result, it gradually fills up with data. A pipe has a maximum capacity, which, when reached, will prevent more data from being written. Also, all of the historical data in the pipe remains there forever and will be read by readers who join later, which might be undesirable if the data expires. To solve this, somebody needs to read the data from the pipe, and the sensible participant to have this responsibility is the writer, since it put the data there in the first place.

While I wanted to be able to have a completely unaware writer, which doesn't even need to know it's doing anything special, this isn't feasible, at least with the tee approach. The writer will need to have some special logic. Additionally, because we don't want a race condition between readers trying to get the data and the writer trying to clear out the pipe, there needs to be some kind of locking in the picture.

The sub-problem

The lock we need is one that allows only one writer at a time (because we only need one at a time, and it simplifies the implementation), but allows many readers. The writer needs to clear out the data from the pipe only after all readers have done their tee calls, otherwise some readers will miss it; the lock will control erasing the data, not the actual write. But, readers may try to take the lock again quickly after they release it, so bad timing could lead to the writer never getting it. This would result in the readers all getting duplicate data until the writer eventually won the race to take the lock. So the lock needs to ensure a writer always wins the race.

To summarize, we need a reader-writer lock that ensures that if a writer is waiting, readers will never take the lock before it gets it. There isn't a built-in lock in Linux with these semantics, so we need to build it ourselves.

The sub-solution

Fortunately, Linux has a dedicated feature for building your own locks. A futex is a synchronization primitive provided by the kernel, consisting of a 32-bit futex word, access to which is synchronized using the futex system call. This system call can do one of a few things, depending on flags. For our purposes, there are two operations:

  • Atomically check that the futex word has an expected value (and return if not), then block until the futex is signaled to indicate a change in its value. The check ensures that the value isn't changed by another process/thread between when the user-space locking logic decides to wait and when the futex call runs, which could result in waiting on an available lock or similar problems.
  • Signal that the futex word has changed value, waking up a specified number of waiters.

Futexes are generally used in a loop, where you repeatedly check if the lock is in a state that allows you to take it, calling futex to wait if not, and then eventually using atomic CPU instructions like compare-and-exchange to update the lock to indicate that you have it. If someone else touches the lock while you're trying to take it, you restart the loop.

We'll implement our reader-writer lock using a futex. The futex word will be UINT32_MAX if a writer holds the lock (because nobody else can take it while a writer has it), and otherwise the low 31 bits will indicate the number of readers holding it, while the uppermost bit will indicate that at least one writer is waiting to take the lock (and therefore that no new readers should take it). Zero indicates no writer waiting, and no readers holding the lock, meaning the next comer gets the lock immediately.

A reader will follow these steps:

  1. Wait for the high bit to be unset. If a writer holds the lock, UINT32_MAX has a set high bit. If a writer is waiting, this avoids starving it.
  2. Atomically increment the futex word. If the lock is unheld (zero), this takes the lock for readers. If it's held already, it increases the number of readers holding it. If the increment fails, start over.
  3. When done reading, atomically decrement the futex word. If it decremented to zero, then wake all waiters.

A writer, meanwhile, will follow these steps:

  1. Atomically set the high bit (if it is already set, that's fine, continue).
  2. Wait for the futex word to be 2147483648, or 0x80000000 in hex (all zeroes except the high bit, indicating a writer (us) is waiting, and no readers or writers hold the lock). On each wake, ensure the high bit is still set.
  3. Atomically set the futex word to UINT32_MAX. If the atomic set fails, start over (another writer took the lock).
  4. When done, set the futex word to zero (doesn't need to be atomic because the writer holds exclusive control of the lock, and the most that will happen is atomic sets of the high bit by other writers waiting, which don't change the value), then wake all waiters.

The problems with this lock are that it frequently falls victim to a thundering herd, and it will sometimes give writers two turns in a row, which for our purposes could result in readers missing a write. This can probably be mitigated to some extent by writers waiting briefly after unlocking before trying to lock again, but not if there is more than one writer.


Now that we have our lock, we can actually implement a broadcast pipe. The broadcast pipe consists of the pipe itself and a shared-memory region holding the futex (in retrospect, we could probably just put the data into the shared memory... it's always going to have to use up at least PAGESIZE of memory). A single writer can follow these steps (multiple writers would step on each other, necessitating a second simpler lock ensuring there is only one writer):

  1. Write the data, without locking.
  2. Immediately try to take the lock. Readers will be holding the lock, and the writer will wait until they all release it, signalling they have read the data.
  3. Read the data using read, removing it from the pipe. Do something with it or throw it away.
  4. Release the lock.

Meanwhile, readers follow these steps:

  1. Create a private pipe to store retrieved data for later reading.
  2. Take the lock.
  3. Use tee to peek the data into the private pipe. Read it later when it's convenient.
  4. Release the lock, signalling that the data has been read.

Obviously, a reader can re-use the private pipe from one read to another.

Is this useful?

No.

Well, the lock might be. But the broadcast pipe is too complicated to be a savings over a directory full of FIFOs/sockets, a broker process, or lock-controlled shared memory. I don't plan to actually use this anywhere, but it was interesting to design.

https://www.alm.website/blog/2022-07-02-note-2 Note 2 from 2022-07-02 2022-07-02 2022-07-02 So I've talked about this before, but Java as a language is, like... okay.

So I've talked about this before, but Java as a language is, like... okay.

Its APIs are kinda verbose, but overall it's a decent language.

The biggest problem is its build system and runtime environment. class files are a pain and JARs only paper over that.

https://www.alm.website/blog/2022-07-02-note-1 Note 1 from 2022-07-02 2022-07-02 2022-07-02 Design Patterns Considered Harmful, TBH

Design Patterns Considered Harmful, TBH

https://www.alm.website/blog/2022-06-30-note-1 Note 1 from 2022-06-30 2022-06-30 2022-06-30 If anyone has a recommendation for a Matrix client or a way of using Matrix via XMPP, I'd appreciate it. I've already ruled out Element, nheko, Quaternion, and FluffyChat, and I'd like to be able to handle encrypted conversations and rooms. I realize there's probably not one but I figured I should ask.

If anyone has a recommendation for a Matrix client or a way of using Matrix via XMPP, I'd appreciate it. I've already ruled out Element, nheko, Quaternion, and FluffyChat, and I'd like to be able to handle encrypted conversations and rooms. I realize there's probably not one but I figured I should ask.

https://www.alm.website/blog/2022-06-29-note-1 Note 1 from 2022-06-29 2022-06-29 2022-06-29 Need to make my webmention scripts better, they still pull the wrong author from Mastodon replies, and some other problems.

Need to make my webmention scripts better, they still pull the wrong author from Mastodon replies, and some other problems.

https://www.alm.website/blog/2022-06-28-note-2 Note 2 from 2022-06-28 2022-06-28 2022-06-28 what it is: memory access violation

what it is: memory access violation

what it's called: segmentation fault


great job

https://www.alm.website/blog/2022-06-28-note-1 Note 1 from 2022-06-28 2022-06-28 2022-06-28 I have far too many project ideas for a person of my level of executive function.

I have far too many project ideas for a person of my level of executive function.

https://www.alm.website/blog/2022-06-27-note-2 Note 2 from 2022-06-27 2022-06-27 2022-06-27 *sees a commit in my site repository named send/receive mentions*

*sees a commit in my site repository named send/receive mentions*

*gets excited*

*commit is just recreating an empty moderation queue file because I deleted it*

:/

https://www.alm.website/blog/2022-06-27-note-1 Note 1 from 2022-06-27 2022-06-27 2022-06-27 What do you mean database? Everyone around here just uses a directory full of XML files.

What do you mean database? Everyone around here just uses a directory full of XML files.

https://www.alm.website/blog/2022-06-26-note-2 Note 2 from 2022-06-26 2022-06-26 2022-06-26 I need to do something quite urgently about the unpaginated, low-content index and Atom feed on this site.

I need to do something quite urgently about the unpaginated, low-content index and Atom feed on this site.

https://www.alm.website/blog/2022-06-26-note-1 Note 1 from 2022-06-26 2022-06-26 2022-06-26 no points for correctly guessing what the opcode mnemonic iaddi8 means

no points for correctly guessing what the opcode mnemonic iaddi8 means

https://www.alm.website/blog/2022-06-25-bittorrent About BitTorrent 2022-06-25 2022-06-25 I want to stress to those unaware that BitTorrent can be, and often is, used for entirely legitimate purposes. It is a protocol for downloading large files in a scalable way. It's a good choice any time you want to make a big download available to lots of people simultaneously.

I want to stress to those unaware that BitTorrent can be, and often is, used for entirely legitimate purposes. It is a protocol for downloading large files in a scalable way. It's a good choice any time you want to make a big download available to lots of people simultaneously.

Personally, my only use of BitTorrent has been downloading ISO images for live-boot or installation of Linux distributions, which is not piracy.

ISPs: Please stop indescriminately blocking protocols just because they have been used for piracy. HTTP is also used for piracy. Are you going to block the entire Web?

https://www.alm.website/blog/2022-06-25-note-2 Note 2 from 2022-06-25 2022-06-25 2022-06-25 Why is it called a saucepan when it's clearly a pot?

Why is it called a saucepan when it's clearly a pot?

https://www.alm.website/blog/2022-06-25-note-1 Note 1 from 2022-06-25 2022-06-25 2022-06-25 If you couldn't tell, I'm starting to try and move towards POSSE, using this site.

If you couldn't tell, I'm starting to try and move towards POSSE, using this site.

This is partially just because I think that's a good way to do things, and partially because I feel like the sheer rate that social media like the fediverse comes at is giving me anxiety and making it hard to focus on anything else.

https://www.alm.website/blog/2022-06-25-linux-filenames Linux filenames (and legal characters within them) 2022-06-25 2022-06-25 The following are legal in Linux (and most other Unix) filenames: ()[]<>$:;&@?`’“!=+*^%#~| and space. (Note here that I do mean Linux, the kernel, not any of the operating systems built on it.)

The following are legal in Linux (and most other Unix) filenames: ()[]<>$:;&@?`’“!=+*^%#~| and space. (Note here that I do mean Linux, the kernel, not any of the operating systems built on it.)

Some of them may be difficult to correctly input in some contexts, but you can use them. Linux, at least with most filesystems, only prohibits / and NUL bytes, allowing any other byte sequence, including invalid UTF-8.

However, given that filenames are supposed to be… names, it is usually best to restrain yourself to things that can actually be decoded by a person as meaningful language, or that at least can be easily input in contexts such as a shell command, which means sticking to normal word characters plus punctuation such as (English examples) .,-_ and space, used sanely.

If you do want to name a file $*@! though, nothing will stop you.

https://www.alm.website/blog/2022-06-24-note-1 Note 1 from 2022-06-24 2022-06-24 2022-06-24 For some reason I automatically look at my PineTime whenever my phone buzzes in my pocket, even though I don't have notification forwarding and have never had a smartwatch that does it.

For some reason I automatically look at my PineTime whenever my phone buzzes in my pocket, even though I don't have notification forwarding and have never had a smartwatch that does it.

https://www.alm.website/blog/2022-06-06-note-1 Note 1 from 2022-06-06 2022-06-06 2022-06-06 I'm thinking about dropping Caddy from my Web server setup and switching to using Apache httpd as the reverse proxy.

I'm thinking about dropping Caddy from my Web server setup and switching to using Apache httpd as the reverse proxy.

I'd have to use certbot or another ACME client, but I'll need one eventually for mail and any other non-HTTP TLS protocols anyway so...

https://www.alm.website/blog/2022-05-30-note-2 Note 2 from 2022-05-30 2022-05-30 2022-05-30 Hm, I wonder if Adrian will get this correctly or if I'm going to need to fiddle with it.

Hm, I wonder if Adrian will get this correctly or if I'm going to need to fiddle with it.

https://www.alm.website/blog/2022-05-30-note-1 Note 1 from 2022-05-30 2022-05-30 2022-05-30 Replying to Jacky Alciné

Replying to Jacky Alciné

Ah, I should probably be replying via WebMention, shouldn't I? :P

https://www.alm.website/blog/2022-05-25-note-1 Note 1 from 2022-05-25 2022-05-25 2022-05-25 I just noticed that several of my styles were broken by CSP. Now the search box should have proper proportions.

I just noticed that several of my styles were broken by CSP. Now the search box should have proper proportions.

https://www.alm.website/blog/2022-05-23-note-1 Note 1 from 2022-05-23 2022-05-23 2022-05-23 I'm almost getting addicted to typing scripts/publish, it's just so satisfying to have it automated.

I'm almost getting addicted to typing scripts/publish, it's just so satisfying to have it automated.

https://www.alm.website/blog/2022-05-21-note-2 Note 2 from 2022-05-21 2022-05-21 2022-05-21 Okay well there's definitely a lot to fix, like there's no way to find the Atom feed I think, but I'm done for today, that was like six hours of work.

Okay well there's definitely a lot to fix, like there's no way to find the Atom feed I think, but I'm done for today, that was like six hours of work.

https://www.alm.website/blog/2022-05-21-note-1 Note 1 from 2022-05-21 2022-05-21 2022-05-21 As you might have guessed, it wasn't quite as simple as typing scripts/publish to roll out the new version. I had to do a lot of troubleshooting of my deployment scripts, and my Apache configuration. But it seems to be working now! :)

As you might have guessed, it wasn't quite as simple as typing scripts/publish to roll out the new version. I had to do a lot of troubleshooting of my deployment scripts, and my Apache configuration. But it seems to be working now! :)

https://www.alm.website/blog/2022-05-21-version-4-and-xblog Version 4.0 and XBlog 2022-05-21 2022-05-21 On-and-off over the last little while, I've been rearranging and reworking a lot of this site, trying to turn it into an IndieWeb-style personal Web site instead of the previous no-particular-purpose site.

On-and-off over the last little while, I've been rearranging and reworking a lot of this site, trying to turn it into an IndieWeb-style personal Web site instead of the previous no-particular-purpose site.

The new version includes a personal profile page, blog categories, an Atom feed (albeit not a very good one), more information about my projects, support for the Webmention protocol, some Microformats2 markup, and considerable improvements to the workflow. There's a lot of work still to be done (as there always is), especially with IndieWeb stuff, but I expect to actually be able to use the site for something now.

2021-10-26

This was the first day I actually started seriously working on the site itself. I enabled XBlog's Webmention support, overriding the default blog template to move the mentions section to the main template so they'd show on all pages. Once I had that working, I set up a "canonical social profile," to act as a single place to point people to with all my information about me, using Microformats2's h-card to mark it up. Fighting briefly with XML whitespace significance in some of my inline markup got me introduced to the xml:space="preserve" attribute value, which is a tool I'll hopefully remember in the future.

I also got started on the structural reorganization of the site, and some markup changes. I switched headings from <h1>, <h2>, etc. to <h1> only with <section>, <article>, etc. nesting to communicate hierarchy instead, which is a poorly-adopted but in my opinion very nice feature of HTML5. I removed the top-level site title <h1> and changed the "Home" entry on the navbar to use the site title, instead. I just did this in the CSV file for the moment, but it would probably work better as part of the XSLT.

2021-10-29

After a couple of days, I rebuilt the front page as a sort of summary, with (mostly manual) extracts and links to other pages. I included a DuckDuckGo site search box, though it was less than perfect since I didn't want a CGI script involved and I couldn't get the site: parameter to be set without actually putting it in the form input. I went back and forth for a bit on using a sort of "dashboard" layout, with a flexbox-arranged set of bordered blocks, but I ended up scrapping that, at least for the front page. I kept the CSS for later, though.

I also rearranged the "about site" page, reversing the history section to most-to-least recent, along with revising the text, writing some preliminary discussion of 4.0, and adding a link to an "administrative" page to absorb the previous domain policies page.

I had to catch up on some housekeeping and reorganizing, committing things to Git (including the profile page) and eliminating the dreaded Miscellaneous.

I added a projects page, listing various current and past projects of mine, and a "me now" page so people can get an idea of what I'm up to at the moment (as nownownow.com recommends).

2022-03-13

I completely stopped working on the site for a long time, due purely to a random loss of interest. In the intervening time, I did at least set up my personal Git hosting. When I came back, I finished up the project pages, including moving some of my discontinued projects into place and reformatting one of them into XHTML that XSite would accept.

2022-03-27

After another break, not quite as long this time, I touched up some links and other minor issues, committed some stuff to Git, and decided to actually finish up and get ready to publish the new version. Unfortunately, decision does not always necessarily lead to immediate action.

2022-05-21

Once again, I stalled for a while, but this time it was at least partially for a reason: I needed to set up OpenPGP, and to do that in a way my paranoia would consider sufficiently secure I ended up going down a long yak-shaving chain that involved, among other things, reflashing the firmware on my PinePhone Pro. Eventually, I got all that done, and after some non-justified delay I came back and added the public key to my profile page, along with the OMEMO keys and some other revisions.

Then, I needed to revise this blog post, and the one about XBlog into what you're seeing now. I also needed to do a bunch of Git cleanup, revision to the httpd configuration (especially to add redirects for the various things that moved), and other general cleanup, as well as some setup for OpenPGP Web Key Directory, to make my PGP key auto-findable. Then, I typed scripts/publish, and hopefully you're looking at the result.

https://www.alm.website/blog/2022-05-21-xblog XBlog for XSite blogging 2022-05-21 2022-05-21 As a follow-up to XSite, I decided to split out my blogging tools into their own project and expand on them to build a proper blogging support package for XSite. I decided to keep blogging tools separate from the core XSite project out of a general pro-modularity attitude; a lot of static site generators bundle blogging in their base configurations, but there's no reason that functionality can't be separate. My approach is to keep XSite as the Python code that provides the core functionality like XSlots, XSLT support, datasets, etc., while implementing blogging support on top of it largely as XSLT and XSlots templates. Much of this work happened in the middle of the night, and often into the early hours of the next day, but I've datestamped it with the day I started each session.

As a follow-up to XSite, I decided to split out my blogging tools into their own project and expand on them to build a proper blogging support package for XSite. I decided to keep blogging tools separate from the core XSite project out of a general pro-modularity attitude; a lot of static site generators bundle blogging in their base configurations, but there's no reason that functionality can't be separate. My approach is to keep XSite as the Python code that provides the core functionality like XSlots, XSLT support, datasets, etc., while implementing blogging support on top of it largely as XSLT and XSlots templates. Much of this work happened in the middle of the night, and often into the early hours of the next day, but I've datestamped it with the day I started each session.

2021-10-04

Right at the start of building XBlog, I hit some major frustration; there seems to be some kind of bug in certain versions of libxml2, or at least the way it's used by lxml's etree, where serializing a single element can end up serializing everything after that element too (including dangling end tags!), but only if it has children. This pretty much totally broke XSite; after several hours trying to coax lxml into doing the right thing, I ended up hacking around this problem with some rather ugly text manipulation, and simply truncated away everything that didn't belong. I'm not happy about this, but it got XSite working again and made it possible to start building XBlog.

The first day, I started by pulling my site's existing blogging-related templates out into a new repository (which I set up as a Git submodule), then symlinking them back into place. My first actual improvement was to add category support; I added a "category" column to the posts.csv file which stores information about posts, and modified the blog entries XSLT stylesheet to check it against an "index category" parameter, which is set on each blog index page. After fiddling with this for a while, I straightened out some XSLT issues (to do with parameters and conditional templates) and ended up with a system where categories look like Unix paths, with the "root" category being / and others descending from it in a /-separated hierarchy.

My other first-day improvement was to add support for generating an Atom feed; this is closely analagous to generating the root category index (previously just the index), in that it consists of a document holding pre-written content, an XSlots template plugging in configuration, and an XSLT stylesheet, fed the posts dataset by XSlots, which does the actual work of generating <entry> elements. The XSLT stylesheet also sets the <updated> value for the whole feed, basing it on the last entry's publication time; due for some improvement, but workable. For the moment, it doesn't generate a summary, instead giving a notice that no summary is available, since that would need some fairly serious intelligence to pull meaningful content from the documents themselves. Getting this part working was a lot more frustrating than it ought to have been; first, I left off the xsl: namespace prefix, which led to empty output but no errors. I was nearly ready to give up for the day when I noticed the problem. Second, once that worked, only one entry would come out. This turned out to be an XSite quirk; it can't handle multiple elements without a common parent as document content, XSLT output, etc.; this is why <sl:fragment> exists, but the details of when it is and isn't needed eluded me briefly. Once I wrapped the entries in a fragment, they all appeared as they should.

2021-10-06

After a day of not working on the project, I spent my second day building deployment tooling so I could just make some changes and type scripts/publish; this kicks off a series of checks to ensure I have Git in sync, offers to pull from origin and commit any uncommitted changes, then pushes directly to the server (bypassing the origin remote; remember, Git is a distributed version control system!), builds the site there, and deploys it to the correct directory on the server, keeping a backup so I can roll back (also automated with a script) if a bad deploy happens. These scripts aren't part of XBlog or XSite; they're my own tools and are part of the alm repository, but of course other people can use them if they come in handy.

Also in the same directory of scripts and built the same day is my "note" script, which takes either standard input or a file, assigns it a number, either one or one more than the highest-numbered existing note that day, adds the appropriate header and footer, and wraps each line in <p> (blank lines become <br /> instead). Once it's done that, it has a valid XHTML file (assuming I don't screw up any XML syntax in the input text), which it adds to the posts index (categorizing it as a note), commits to the Git repository, then finishes up by running the publish script. In theory, this should let me publish my quick thoughts in a matter of moments, only a little slower than Tweeting or Tooting or whichever your preference. You can see my test note from the middle of the night for yourself.

2021-10-07

I spent my third day making tools in preparation for building a Webmention sender; specifically, I built Python modules for

  • extracting links from XML, HTML, JSON, Gemini gemtext, and plain text, and
  • fetching HTTP(S), FTP(S), and file:// URIs.

These were quite a bit of work, but I didn't have much to show for that day and there isn't really much to talk about with this.

2021-10-08

I continued on from the previous day, adding support for the Gemini protocol, fixing various issues, adding support for rel attributes (and things equivalent to them), building infrastructure to guess media types for e.g. file:// URIs that otherwise don't provide them, and tying my link extraction and fetching code together so a single function call can get the links of any supported URI. The three modules together run to 400-some lines, and in my opinion at least, they're fairly handy on their own.

For no particular reason, I ended up writing my own Gemini client; it's about 70 lines of Python and was pretty simple to get working. The single part that takes up the most lines is actually the handling for status 44 ("Slow Down"), since it has to handle a few different kinds of unacceptable wait times. That's the only status that's handled specifically, though; all the others are checked by their first digit only. Maybe the biggest bump was that I actually forgot to write any code to handle success, which led to a couple minutes of head-scratching trying to figure out why nothing seemed wrong but an empty result was coming out.

I ended up having to rewrite the XML part of the link extraction code (which also handles HTML) in order to support rel attributes, and I ended up with something a bit more complicated. I think it's still pretty nice, though; it should be easy to teach about more kinds of links if I find out about any, since it's just a couple short XPath expressions. I did end up dropping some specificity, so now any attribute named href, src, or resource will end up being seen as a link, rather than only if those attributes are on known "link elements;" this falls out of RDFa, which defines attributes without a containing XML Namespace.

My media type guessing is probably more than it needs to be; among other things, I have built-in support for using Python's mimetypes (which uses filename extensions), as well as libmagic, though it has to be enabled since the Python module isn't in the standard library. There are still situations where the media type will end up being set to application/octet-stream though, so I have some further fallback options where I can give a predicted media type if I think I know what it'll be, or I can have it react to application/octet-stream by just trying all the link-finders and appending their results together.

2021-10-09

Now the weekend, I started by fixing some bugs with FTP and plain text searching, and doing some general cleanup.

With those sorted, I jumped over to XSite to make the extension points I needed. I did some refactoring while I was there and built a "package" system, allowing third-party additions to XSite, and a plug-in system using it, including support for a new "sidecar" plug-in type (they're passed the original source document, configuration, and parameters for each document XSite processes, so they can "ride along" with XSite's processing pass).

Back to XBlog, I added support for filtering on rel values to my link extraction code, and used all this to implement a sidecar plug-in that finds outgoing links, looks up the Webmention endpoints for them, and makes a list of Webmentions to send. After some debugging, I got this working; I had a list of valid Webmention endpoints and target URIs coming out, along with another list of URIs that had been checked but found not to have Webmention support. I still couldn't actually send any mentions, but that part is simpler, relatively speaking; it's just sending some very simple POST requests. I wanted to do this as part of the publishing workflow, though, so it needed a bit more work than you might think.

2021-10-10

I made some changes so outgoing mentions would have the full URI of the source page, which required some additions to XSite in the form of library functions to handle that, and also fixed a conformance issue; the Webmention spec says to only send a mention to the first link found of three possible, and I was making to-send entries for all of them. After that, I wrote the actual script to send mentions, which was very simple. I tested using webmention.rocks and discovered that I'd completely failed to handle relative URIs in my Webmention discovery. I added code to pass around and use a base URI to my link extraction code and on another test it got the right URIs.

However, actually sending the mentions failed; looking further, I discovered this was actually a problem with webmention.rocks; it was sending an Accept header that only allowed text/html! Since XSite only outputs XML, all the documents it produces are application/xhtml+xml, and my server is configured to consider them as such. This meant when webmention.rocks came in asking for text/html and only text/html, Apache declared an HTTP 406 and refused to send it anything. webmention.rocks, naturally, reacted by failing the tests, sending me back an HTTP 400 (which seems like a strange code to use since it implies the request was actually corrupt, but that's what the Webmention spec says so I suppose it's correct).

I reported this problem to the webmention.rocks project, though I haven't yet received any response. I don't think it's likely to be a very hard fix; webmention.rocks is PHP, and I believe PHP can handle XHTML pretty easily. It might just be a matter of changing the Accept header, but that depends on the exact details of how the XHTML support in PHP works...

2021-10-11

With the webmention.rocks problem still unresolved, I decided to carry on anyway and start implementing the site-specific script, which runs the script to send mentions, then commits the list of sent mentions, and the list of non-Webmention-supporting pages generated during the discovery done at build time, to Git and pushes them (along with the actual content changes) to my origin remote, from which the changes will be pulled back to my desktop. That was largely it for sending support, except for updates/deletes, which I was planning to implement later. For the moment I decided to move onto receiving support. My approach is in one way very simplistic; I just store the source and target URIs to a file in /var/spool and send back a hard-coded response. Most of the CGI script that does this is code to ensure that

  • a POST request was actually used
  • the request was sent with the application/x-www-form-urlencoded media type
  • both a source and a target are specified
  • and that neither contains a tab or a newline.

If any of these checks fail, a hard-coded error response is sent back with an appropriate status code (the Webmention spec demands that only 400 be used, but I refuse to cut back on useful semantics to satisfy that requirement). Otherwise, the source, a tab, the target, and a newline are appended to the file, and the hard-coded success response is sent. It's good to keep the CGI script this simple, since it means it has no dependencies except the Python standard library. This makes it very easy to install on any CGI-supporting server, at least in theory.

Later, the spool file is read by a script that checks that the targets are on the site they're meant to be on and that the sources actually link to them, then writes them to a moderation queue for me to check manually. I modified my site-specific script for mentions to run this check step and commit the moderation queue as well, so it too will end up on my desktop, where I can do moderation and move the good mentions to a final accepted list. Based on that, I'll be able to do a final processing step of downloading the pages, extracting the metadata, and saving that to an XSite dataset I can use to include mentions in-line on the mentioned pages.

It's a lot of steps, but I like it because each one does just one thing, without closely tying everything together.

2021-10-14

I took a break for a few days before getting into the final stretch of tool-building so I could start actually rebuilding my site. When I came back I wrote the script to pull down the source pages of new moderated mentions, pull out (in extremely simplistic and fragile fashion) a title, author, and first-paragraph summary, and put them into a CSV file which can be used as an XSite dataset. At some point I intend to come back and make this a lot more robust, and pull out more information like a publication date if it's available.

After that, I wrote an XSLT stylesheet to generate a mentions section and added it to the bottom of the blog template. In the process I added a little code to XSite to pass the output path and document URI as parameters so XSLT could get them. But with that in place, the mentions XSLT worked with only very little fiddling! The results are relatively basic, but they work well enough, so I'm happy for now.

While I was passing through, I also added some text handling from the info extraction script to the parsing that the link extraction code uses, which should make it a bit more robust to different encodings of XML documents.

At this point, I was reasonably confident both sides of Webmention would actually work to some degree, though maybe not as nicely as might be desired. There was clearly still work to be done, but I decided to leave it there for the day and come back to improve the content extraction later.

2021-10-25

It turned out my "leaving it there" ended up lasting over a week. When I did come back, I mostly implemented a rough, hand-made Microformats2 content extractor and made some other minor improvements. After a lot of rounds of testing against various pages, I eventually got it to parse the h-entrys close enough to nicely that it seemed like enough. Unfortunately, Microformats2 isn't used totally consistently; while there is a standard, it's fairly loose and people apply it in different ways. Since I wrote my own processing code instead of using an off-the-shelf Microformats2 parser, I ended up with something of a mess coming out of a lot of pages at first. A lot of the fighting was down to trying to get a summary out of pages that didn't have a p-summary; it ended up being a multi-way solution that tries to look for various things under the e-content, including a <p>, simple unwrapped text, and even a <li>! Eventually, I figured out enough common patterns that most of the pages I was plugging in were "just working," so I called it good enough for the day. I found that a lot of places still use Microformats1 (even some things on the Microformats2 h-entry examples list were actually Microformats1 hentry! >:( ), so I should probably implement that too and maybe some others like RDFa.

At this point, the tools felt solid enough to work on the site itself, so that's where XBlog development stopped for its first "major release". I'll likely come back to it, probably along with major refactorings to XSite itself. In particular, I'll probably rewrite my link fetching and context extraction around libraries written by people who are actually following specs like RDFa, Microdata, and Microformats closely, instead of my slap-dash "basically works" code (I will probably, however, still end up writing wrappers to fall back between multiple formats, probably including some custom "plain-old HTML" handling).

https://www.alm.website/blog/2021-10-07-note-2 Note 2 from 2021-10-07 2021-10-12 2021-10-12 This is my first test note.

This is my first test note.


It has a blank line to see if that becomes a <br />.

It also has some tag-soup HTML, like this!

If you don't know.

https://www.alm.website/blog/2021-05-18-xslt XSLT 2021-05-18 2021-05-18 As I planned in the 3.1 launch post, I've now implemented XSLT support in XSite. Using this tool, I've implemented some improvements to the site to restore some of the pieces that got cut to fit into XSite. This should improve accessibility, as well as making some things easier on myself.

As I planned in the 3.1 launch post, I've now implemented XSLT support in XSite. Using this tool, I've implemented some improvements to the site to restore some of the pieces that got cut to fit into XSite. This should improve accessibility, as well as making some things easier on myself.

I'm currently using two similar XSLT stylesheets, to handle the navbar and the blog index. Each of those is generated from what XSite calls a "dataset", in this case in the form of CSV files. These CSVs list the paths and titles of navbar entries and blog posts, along with the dates of the blog posts. XSite automatically converts the CSV data into XML for ease of processing with its tools, and the stylesheets then render them into <ul>s of links. This output can then automatically be slotted into an XSlots template.

While the navbar was relatively simple, I went through a few ideas on how to structure the blog index before landing on what I think is the best approach: The blog index page itself just contains the heading and the explanation at the top of the page, and the entire section containing the entries (header and <section> tag included) is generated by the XSLT. An XSlots template puts the two one after another in the <main> element and manages the job of passing the dataset input to the XSLT sheet (something that, as yet, only XSlots can do).

The main advantage provided by the change to the navbar is that it can once again update to indicate which page is current. Each of the pages on the navbar now has a path parameter, which the navbar XSLT can compare against the path attribute of each entry to figure out which (if any) is the current page. It then adds aria-current and <strong> to mark it as the current page and changes the destination to # so that navigating to the current page doesn't actually trigger a new request.

The blog index change doesn't currently provide much advantage, other than reducing how much I have to type to add blog posts to the index, but it will make it easier to take advantage of future blogging features I add to XSite; ideally, I should only have to switch the dataset from CSV to a dynamically-generated blog posts dataset to use that, with no changes to the XSLT necessary (though I'll probably want to make some changes once I have the option to, e.g., show the first paragraph as a teaser).

I do expect to continue adding features to XSite, in particular for blogging, but I think I've succeeded in creating a moderately-useful static site generator. It still isn't really ready for general use, since the documentation mostly hasn't been written yet, but I'll get around to that relatively soon (I've already partially written the XSlots documentation).

https://www.alm.website/blog/2021-04-25-v3.1-xsite Version 3.1 and XSite 2021-04-25 2021-04-25 If you're reading this, that means I've rolled out alm 3.1. This version is based on the XSite static site generator. I wrote this software myself, as is the expected rite of passage for programmers doing Web sites; it's based on XML and written in Python, with an eye towards both relative simplicity and a strict content structure. Currently, it's less than 300 lines of code, which feels small for how much it's managed to do.

If you're reading this, that means I've rolled out alm 3.1. This version is based on the XSite static site generator. I wrote this software myself, as is the expected rite of passage for programmers doing Web sites; it's based on XML and written in Python, with an eye towards both relative simplicity and a strict content structure. Currently, it's less than 300 lines of code, which feels small for how much it's managed to do.

XSite doesn't currently support Markdown, so the process of switching from Jekyll to XSite was fairly complicated. It took over a dozen Git commits and seven hours of work. I started by modifying the Jekyll templates to remove the Liquid tags, replacing them with XSite's equivalents or discarding features XSite can't yet implement, and to convert from HTML to XML syntax where the two differed. I also replaced <!DOCTYPE html> declarations with <?xml version="1.0" encoding="utf-8"?> declarations and XHTML namespace declarations and added XSite processing instructions for template inheritance.

The part that took the longest was converting the content. At first, I used the Markdown files as a starting point, manually converting the Markdown syntax to XHTML, but later I started using the output from Jekyll instead, which was faster, especially for big pages. I replaced the YAML front-matter Jekyll used with the XML processing instructions XSite uses, and added some meta keywords here and there while I was at it.

The reason this conversion took longer than the Jekyll conversion is largely down to the blog. XSite has no blogging features, so I had to manually implement the entire blog structure, including the blog index. Also contributing is that there is simply more content on this site than there was when I converted it to Jekyll, and XHTML is of course more verbose than Markdown, so there was more typing.

One of XSite's nice points is that it generates relatively clean output. If you look at the source of any of the pages on the current site, you'll won't see any of the blank lines or jumpy indentation that Jekyll and Liquid are prone to produce; this is because XSite is parsing the XML (using the lxml Python package), doing its processing at the element level, and then reserializing back to text, rather than working at the raw text level like Jekyll, so it can format its output nicely.

I wouldn't recommend using XSite for your own site just yet, though (if what I've already said doesn't dissuade you enough, it's probably buggy as well). I'll probably continue to hack on it and implement a few more of my ideas, probably including XSLT support. XSLT will make it a lot easier to implement blogging functionality, like automatically generating an index of entries, so I hope that it will be usable for the real world at some point soon.

You can see the process I went through for this migration in this GitLab merge request.

Changelog for version 3.1

  • Switched from Jekyll to XSite
  • Simplified blog index to be easy to maintain by hand
  • Remove conditional behavior from navigation (may have a negative impact on accessibility, to be addressed once XSite is capable enough)
https://www.alm.website/blog/2019-02-11-v3.0-custom-css alm 3.0 with custom CSS 2019-02-11 2019-02-11 If you're reading this, that means I've rolled out alm 3.0. There are a few big changes in this version, namely:

If you're reading this, that means I've rolled out alm 3.0. There are a few big changes in this version, namely:

  • I "rebranded" from "Programmingwave," which was only the name because that was the domain I had, to "alm," for my initials.
  • I threw out Bootstrap and wrote my own CSS for the navbar and for the site as a whole. It’s much smaller, so the site as a whole has become much lighter as a result.
  • Dropped old Programmingwave features, namely the "gallery" and the LENS pages (they’re to be moved to GitLab Pages).

Along with this, I've changed the domain (rather obviously) to alm.website and moved hosting to DigitalOcean.

https://www.alm.website/blog/2018-09-08-available-on-gitlab Available on GitLab 2018-09-08 2018-09-08 After quite a delay, this entire site's source is now released on GitLab here. This includes both the site's basic framework as well as its content.

After quite a delay, this entire site's source is now released on GitLab here. This includes both the site's basic framework as well as its content.

https://www.alm.website/blog/2018-06-09-azure-hosting Azure hosting 2018-06-09 2018-06-09 Programmingwave is now hosted on Microsoft Azure! This move was prompted by some (months-long) DNS issues, and also me just wanting to play with Azure. I'm using Azure's Web App Service at the F1 free tier, which limits disk space, bandwidth, and features, but not so much as to actually pose a problem for a site this small (~210 KB for the entire site).

Programmingwave is now hosted on Microsoft Azure! This move was prompted by some (months-long) DNS issues, and also me just wanting to play with Azure. I'm using Azure's Web App Service at the F1 free tier, which limits disk space, bandwidth, and features, but not so much as to actually pose a problem for a site this small (~210 KB for the entire site).

I had a few issues at first getting my error pages working; Azure's web hosting runs Microsoft IIS as a backend, which is, to be honest, not the best web server. I spent several hours over multiple days trying to figure out how to configure custom error pages; I eventually discovered the thing I was doing wrong: using / instead of \. IIS apparently doesn't do /-\ translation like most Windows components. But anyway, I got everything working* and now this site is hosted for free!

*As of writing this post, I don't have DNS working yet; I'm just going to configure the registrar's hosted DNS solution and call it a finished move**.

**It turns out one of the feature restrictions on Azure web hosting is not being able to bind a custom domain name. I'll look for solutions, but in the mean time Programmingwave will be at programmingwave.azurewebsites.net.

https://www.alm.website/blog/2018-01-24-v2.2-launch Programmingwave.com 2.2 has launched 2018-01-24 2018-01-24 If you’re reading this post, that means Programmingwave.com 2.2 has launched. This version is an upgrade to Bootstrap 4.0 with a few minor fixes. There may be some bugs with the navbar, but it should be usable.

If you’re reading this post, that means Programmingwave.com 2.2 has launched. This version is an upgrade to Bootstrap 4.0 with a few minor fixes. There may be some bugs with the navbar, but it should be usable.

https://www.alm.website/blog/2018-01-21-v2.2-working Now working on version 2.2 2018-01-21 2018-01-21 With the official release of Bootstrap 4, I am now working on Programmingwave.com 2.2 with Bootstrap 4. It should be a fairly simple migration, but there may be some hiccups. If you want, you can watch development of 2.2 here.

With the official release of Bootstrap 4, I am now working on Programmingwave.com 2.2 with Bootstrap 4. It should be a fairly simple migration, but there may be some hiccups. If you want, you can watch development of 2.2 here.

Release targets for version 2.2

  • Move to Bootstrap 4
https://www.alm.website/blog/2017-06-12-v2.1-jekyll Version 2.1 & Jekyll 2017-06-12 2017-06-12 If you're seeing this post, that means I've rolled out Programmingwave.com 2.1, based on Jekyll.

If you're seeing this post, that means I've rolled out Programmingwave.com 2.1, based on Jekyll.

I decided recently that maintaining the site as a set of raw HTML files was too difficult. After considering the options, I went with Jekyll, a static site generator with support for Markdown and Liquid-based templating.

I am not the first person to convert a more complex, harder to maintain site to Jekyll. It was, however, an interesting experience for me.

As many others before me, I began by installing Jekyll on my local machine and creating a new blank site. I then extracted the common components of all pages on the site and converted them to a Jekyll layout (_layouts/main.html).

I then copy-pasted most of the site's content into .md files, and converted them from HTML to Markdown. It only took a couple of hours to convert all of the 'normal' content.

Once I was done converting my 'normal' content (essentially static pages that don't use a submenu), I moved the navbar from _layouts/main.html to an include (_includes/navbar.html), and added some Liquid code to handle current-page highlighting and submenus. Submenus now worked.

At this point, everything except /gallery/ and blog.programmingwave.com worked on my local machine (jekyll serve is incredibly helpful). I converted the SQL-based PHP for /gallery/ to Jekyll datafile-based Liquid, and copied the content.

Only one challenge remained: this blog. You might think that this would be the hardest part, but Jekyll is actually built to support blogging, so it was a matter of creating a layout for blog posts (_layouts/blog.html, which actually 'inherits' from _layouts/main.html) and writing a bit of Liquid to display posts on the /blog/ page.

Converting the blog content was an easy job; I just copy-pasted the post contents from the Wordpress site into .md files, fixed some formatting, and added Jekyll YAML metadata.

Note: I did not migrate the entire Wordpress blog; you can still see some of the history that used to be there at the About page.

You may notice from looking at the source of the current pages that the indentation is completely screwed up, and that there are lots of seemingly random blank lines. This is a consequence of two things: Jekyll's blind include and layout content mechanisms (which simply inject the text without regard for indentation), and Liquid control tags leaving blank lines for no apparent reason.

All in all, 2.1 was a fairly easy move, taking me only a couple days, and making it far easier to develop the site (I no longer had to copy-paste everything if I changed common code). If you have a complex site that you'd like to simplify, I'd recommend Jekyll. I may release my 'framework' (common site-agnostic components) on GitLab sometime in the near future.

Changelog for version 2.1

  • Switched to Jekyll and used templating.
  • Removed Wordpress and switched to Jekyll for blogging as well.
  • Blog moved to /blog/, from blog.programmingwave.com.
https://www.alm.website/blog/2017-04-23-v2.0-launch Programmingwave.com 2.0 has launched 2017-04-23 2017-04-23 This article was migrated from the Wordpress blog on 2017-06-12.

This article was migrated from the Wordpress blog on 2017-06-12.

The long-awaited-by-no-one release of Programmingwave.com 2.0 has arrived. The new version is now out of Beta and available at the main site.

2.0 uses Bootstrap 3.x (and will be updated to 4.x once it releases), and is far more visually appealing. 2.0 also drops some parts of the site that aren't needed, and, thanks to Bootstrap, is responsively designed, capable of working just as well on mobile devices as on desktops.

https://www.alm.website/blog/2017-04-20-v2.0-confusion More confusion about version 2.0 2017-04-20 2017-04-20 This article was migrated from the Wordpress blog on 2017-06-12.

This article was migrated from the Wordpress blog on 2017-06-12.

Adding further to the mild confusion around 2.0, I have decided to use Bootstrap instead of Joomla!, and continue to partly custom-build the site. You can see progress as it advances at the Beta; it will likely be somewhat awful and even worse than the current site for a while as I try to get Bootstrap working like I want it to.

However, progress will now be made, unlike with Joomla!, as Bootstrap is far easier to set up.