Hugonweb Annotated Link Bibliography

MacPaint Art From The Mid-80s Still Looks Great Today

https://blog.decryption.net.au/posts/macpaint.html

This 1-bit art is so good!

Simple live reload for developing static sites

https://leanrada.com/notes/simple-live-reload/

I could use this backend-agnostic script. Right now I just spam Ctrl-R!

Build123d

https://build123d.readthedocs.io/en/latest/index.html

Python-based parametric CAD modeling software.

There seem to be a lot of nice features. It seems more like Fusion360 than OpenSCAD does, in that you create 2D sketches and then extrude or revolve them into 3D models.

See: Awesome build123d

Monitoring tiny web services

https://jvns.ca/blog/2022/07/09/monitoring-small-web-services/

I've been trying to decide if I want to move my small dynamic websites to a VPS from Heroku or just use simple PHP and basic web hosting. My main problem with VPS is I don't want to deal with maintaining it. Simple monitoring like updown.io or Uptime Robot hooked up to email could help.

git notes

https://tylercipriani.com/blog/2022/11/19/git-notes-gits-coolest-most-unloved-feature/

You can add notes to commits, branches, and all kinds of things in git. The only problem is they aren't easy to view on anything except commits via git log. GitHub doesn't show them at all, but I think Forgejo/codeberg.org does show them and let you add/edit them (see PR4753 and PR6025).

stack overflow: how to push git notes to a central server:

git push origin 'refs/notes/*'

and

git fetch origin 'refs/notes/*:refs/notes/*'

See also the git website doc on git notes

ArUco: Camera position detection using square markers

https://www.uco.es/investiga/grupos/ava/portfolio/aruco/

ArUco is a library using OpenCV (see at the OpenCV website here) that allows one to detect QRCode-like markers and estimate their or the camera's location in space.

A related project, UcoSLAM, does simultaneous location and mapping.

Code smell: boolean blindness

https://runtimeverification.com/blog/code-smell-boolean-blindness

This post points out that it's often difficult to tell what a function does when passed true (or false). The given example of the ubiquitous "filter" function is great; does true or false make you keep a list element? Renaming filter to "select" and/or "discard" makes the boolean clearer.

The author points out that substituting a function that returns the Haskell Maybe type makes makes more sense in some "filter" scenarios.

mapMaybe :: (a -> Maybe b) -> [a] -> [b]

builds a list with only entries where the given function returns Just b

See Data.Maybe.mapMaybe for lists and the more general Data.Witherable.mapMaybe.

Related: the wrong abstraction

Modules for Experiments in Stellar Astrophysics (MESA)

https://docs.mesastar.org/en/latest/

Modules for Experiments in Stellar Astrophysics (MESA) is an advanced, open-source 1D stellar evolution code. The code is developed and maintained by a globally distributed team of researchers. MESA is written primarily in Fortran with a modular, flexible design that facilitates easy interfacing.

It seems to be for both research and teaching.

Pressure Stall Information

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/Documentation/accounting/psi.rst?h=v6.15.3

Found in /proc/pressure/ are cpu, memory, and io, text files that contain info on the fraction of processes "stalled" due to contention for the given resource.

Other links:

https://facebookmicrosites.github.io/psi/docs/overview

https://lwn.net/Articles/759781/

The misunderstood Kelly criterion

https://entropicthoughts.com/the-misunderstood-kelly-criterion

To maximise something which grows geometrically, choose the course of action that maximises the expected log-wealth of the thing.

The author wrote a related post When is insurance worth it? that I enjoyed as well.

Faster RANLUX Pseudo-Random Number Generators

https://christoph-conrads.name/faster-ranlux-pseudo-random-number-generators/

RANLUX is highly regarded in the particle physics simulation community, but as far as I remember, we used the Mersene Twister in the Compact Muon Solenoid experiment. It must have been because it was faster.

The linked post is an effort to modernize RANLUX and make it faster.

Generative AI runs on gambling addiction

https://pivot-to-ai.com/2025/06/05/generative-ai-runs-on-gambling-addiction-just-one-more-prompt-bro/

That is: generative AI works the same way as gambling addiction. Spin the gacha! Just one more spin, bro, I can feel it!

Large language models work the same way as a carnival psychic. Chatbots look smart by the Barnum Effect — which is where you read what’s actually a generic statement about people and you take it as being personally about you. The only intelligence there is yours.

Linux dd vs cp

https://unix.stackexchange.com/questions/558262/why-use-dd-instead-of-cp-to-create-bootable-disk

Tutorials and instructions usually recommend dd over cp for copying disc images to devices (like USB sticks). It seems that this is mostly superstition.

The main benefit is that dd lets you specify the block size used for copying, but cp automatically selects the block size at least as well as I would.

The other benefit of dd is a progress display. Piping the output of the pv command to the destination disc may be a better option.

Luciole math

https://luciole-vision.com/en/math.html

A "typeface for visual impairment" that even includes mathematical symbols. It seems to be developed by some groups in France and Switzerland.

Street smarts: how a hawk learned to use traffic signals to hunt more successfully

https://www.frontiersin.org/news/2025/05/23/street-smarts-hawk-use-traffic-signals-hunting

A hawk learning that an audio pedestrian walk signal at a traffic light leads to backed up cars it can use as cover to approach prey.

The published paper is here: https://doi.org/10.3389/fetho.2025.1539103

Ardux

https://inkeys.wiki/en/keymaps/ardux

An evolution of Artsey, with the addition of larger key layouts.

Artsey

https://artsey.io

An Easy, Fast, Open One-Handed Keyboard System

The layout diagrams are really nice!

On ad-hoc datatypes

https://jaspervdj.be/posts/2016-05-11-ad-hoc-datatypes.html

Adding an enum datatype can simplify code. Don't be afraid to add module-internal ones.

rr debugger

https://rr-project.org/

rr aspires to be your primary C/C++ debugging tool for Linux, replacing — well, enhancing — gdb. You record a failure once, then debug the recording, deterministically, as many times as you want. The same execution is replayed every time.

This seems like it could be really useful, especially for intermittent bugs e.g. race conditions.

Lightstream sqlite replicator

https://litestream.io

Continuously stream SQLite changes to AWS S3, Azure Blob Storage, Google Cloud Storage, SFTP, or NFS. Quickly recover to the point of failure if your server goes down.

Type safety back and forth

https://www.parsonsmatt.org/2017/10/11/type_safety_back_and_forth.html

If pushing responsibility forward means accepting whatever parameters and having the caller of the code handle possibility of failure, then pushing it back is going to mean we accept stricter parameters that we can’t fail with.

An example of the former is:

uncons :: [a] -> Maybe (a, [a])

and of the latter is:

head :: NonEmpty a -> a

Working with the latter pushes error handling to the data input code and cleans up all the rest.

Cron vs SystemD timers

https://unix.stackexchange.com/a/688512

A really nice explanation of how to use SystemD timers to replace cron.

Simplify: Move code into database functions

https://sive.rs/pg

Keep as much logic in the database, using constraints, stored procedures, and functions (Postgres even lets you write them in Python) as possible.

This reduces duplication of logic between the DB and external code, and allows the external code to change without issue.

Find and replace in a codebase

https://will-keleher.com/posts/5-Useful-Bash-Patterns.html

I never really have figured this out before. Here is a way:

grep -l pattern | xargs sed -ri 's|pat(tern)|\1s are birds|g'

The -l option to grep (and ripgrep) makes it just output filenames containing matches. The sed option -r enables extended regex (-E may alternatively be used like in grep), and -i replaces in place.

If any filenames contain spaces, newlines, or quotes, then xargs can get messed up. Terminating lines with null characters fixes that:

grep -lZ pattern | xargs -0 sed -ri 's|pat(tern)|\1s are birds|g'

or

rg -l0 pattern | xargs -0 sed -ri 's|pat(tern)|\1s are birds|g'

Linux is built for control but not for people

https://fireborn.mataroa.blog/blog/i-want-to-love-linux-it-doesnt-love-me-back-post-1-built-for-control-but-not-for-people/

A story about using Linux blind. It makes me sad that accessibility in Linux has severely declined over the last 15 or so years!

fdfind

https://github.com/sharkdp/fd

Intuitive to use version of the find program.

fdfind -e py # finds all Python files in current directory
fdfind pattern -t d # finds all directories matching pattern

ncdu: NCurses Disk Usage

https://dev.yorhel.nl/ncdu

ncurses-based disk usage program. It seems fast and easy to use.

Watchexec

https://github.com/watchexec/watchexec

watchexec can rerun a command when a set of files is modified and is designed for ease of use. Two examples from the README are:

$ watchexec -e js,css,html npm run build

$ watchexec -r -e py -- python server.py

Frustratingly, it's not a Debian package. Installation with cargo install --locked watchexec-cli isn't hard, but you don't have much control over 300+ dependencies.

Types as assertions

https://jerf.org/iri/post/2025/fp_lessons_types_as_assertions/

Using custom types wherever there is some concept of validity can help make a codebase free from checking validity everywhere. It only must be done in the constructor and errors handled by the caller of the constructor.

So look through a codebase for functions that take string, int, and float!

Design for 3D printing

https://blog.rahix.de/design-for-3d-printing/

A big checklist of tips. I hadn't heard of making holes tear-drop shaped before. Also:

R1.5 — Use large cross sections. Prefer thick shapes over thin shapes.

R3.7 — Keep surface area minimal. Design voluminous. Do not make cutouts in an attempt to save material.

Modern LaTeX

https://github.com/mrkline/modern-latex

"A short guide to LaTeX that avoids legacy cruft."

OpenFlexure Microscope

https://openflexure.org/projects/microscope/

An open-hardware microscope. Make with 3D-printed parts!

The Field Guide to 3D Printing in Optical Microscopy for Life Sciences

https://doi.org/10.1002/adbi.202100994

Paper about 3D printers applied to microscopy. Some interesting projects and observations about 3D printing.

Quadlet: Running Podman containers under systemd

https://mo8it.com/blog/quadlet/

This lets you run containers using systemd, rather than having a complex, resource-hungry Kubernetes or Docker daemon manage them.

Podman is also capable of updating containers automatically, so the combination is something like Heroku.

The one ring problem: abstraction and our quest for power

https://www.tedinski.com/2018/01/30/the-one-ring-problem-abstraction-and-power.html

image

"Design is figuring out how to find a point in the middle."

You cannot make an abstraction more powerful without sacrificing some properties that you used to know about it. Necessarily. You cannot require a new property be true about an abstraction without sacrificing some of its power and flexibility. Always.

The mistake is to forget this. Nearly always, this error happens in one direction. To look on a design, see what cannot be done with it, and attempt to “fix” it. To make it more powerful, and forget that it necessarily becomes more meaningless.

Designing type inference for high quality type errors

https://blog.polybdenum.com/2025/02/14/designing-type-inference-for-high-quality-type-errors.html

A bunch of things to note in designing a type system to make error messages better. I think the examples of bad error messages in languages being due to the type system (C++!) are broadly interesting.

When type annotations are code too

https://blog.polybdenum.com/2022/04/25/when-type-annotations-are-code-too.html

Type annotations affect runtime behavior in statically compiled languages, but not ones where types are bolted-on after the fact (Python).

This makes runtime behavior depend on the type inference algos and can be difficult to reason about.

The example in Haskell is wild!

Common mistakes to avoid in PHP

https://stackoverflow.com/collectives/php/collections/76822501/common-mistakes-to-avoid-in-php

List of Stack Overflow questions about mistakes to avoid in PHP

(The only proper) [PHP] PDO tutorial

https://phpdelusions.net/pdo

A nice tutorial on PDO, the built-in SQL interface for PHP.

In particular, the official documentation doesn't say much about querying, but it's covered well here.

The other pages on the site are good too.

Psalm PHP Static Analyzer

https://psalm.dev

A static analyzer with (optionally very strict) type checking. Developed at Vimeo.

Includes a language server (link to docs)

Packer

https://developer.hashicorp.com/packer

Declarative tool for creating virtual machine images. This way you can bake all of the installed software into an image, rather than having to provision once a virtual machine boots.

This plus it's parent Terraform (open source version: OpenTofu) seem to be the best way to do infrastructure as code, at least at a certain scale.

A similar tool, for bare metal, is goldboot

pyinfra

https://pyinfra.com/

Think ansible but Python instead of YAML, and a lot faster.

This seems more up my alley than ansible.

For a server or two, I'm not sure if this is the way to go or something more complicated like Packer

How to Specify It!: A Guide to Writing Properties of Pure Functions

https://research.chalmers.se/publication/517894/file/517894_Fulltext.pdf

A guide to writing property-based tests. The author, John Hughes, co-wrote QuickCheck in Haskell, the first package for property-based testing.

Published conference paper: http://dx.doi.org/10.1007/978-3-030-47147-7_4

Some quotes:

"Avoid replicating your code in your tests," because it's lot of work and likely to contain the same errors as your code.

"Test your tests," because if your generator and shrinker produce invalid values, everything else will fail too.

Validity testing

Validity testing consists of defining a function to check the invariants of your datatypes, writing properties to test that your generators and shrinkers only produce valid results, and writing a property for each function under test that performs a single random call, and checks that the return value is valid.

Postcondition testing

A postcondition tests a single function, calling it with random arguments, and checking an expected relationship between its arguments and its result.

Metamorphic testing

A metamorphic property tests a single function by making (usually) two related calls, and checking the expected relationship between the two results.

Inductive testing

Inductive properties relate a call of the function-under-test to calls with smaller arguments. A set of inductive properties covering all possible cases together test the base case(s) and induction step(s) of an inductive proof-of-correctness. If all the properties hold, then we know the function is correct–inductive properties together make up a complete test.

Model-based testing

A model-based property tests a single function by making a single call, and comparing its result to the result of a related “abstract operation” applied to related abstract arguments. An abstraction functions maps the real, concrete arguments and results to abstract values, which we also call the “model”.

py-spy Python profiler

https://github.com/benfred/py-spy

A Python profiler that profiles unmodified Python processes from its own process. It can profile production code with little performance impact. It profiles extensions and all threads, which the standard library cprofile can't do.

Inverting a dictionary of lists in Python

https://stackoverflow.com/questions/35491223/inverting-a-dictionary-with-list-values

I've needed to do this countless times in particle physics data analysis and other areas.

What I've done before:

data = {'a' : ['alpha', "beta"], 'b' : ["alpha"]}
result = {}
for key in data:
    for value in data[key]:
        try:
            result[value].append(key)
        except KeyError:
            result[value] = [key]

and the simpler solutions suggested in the link:

data = {'a' : ['alpha', "beta"], 'b' : ["alpha"]}
result = {}
for key in data:
    for value in data[key]:
        result.setdefault(value,[]).append(key)

or

from collections import defaultdict

data = {'a' : ['alpha', "beta"], 'b' : ["alpha"]}
result = defaultdict(list)
for key in data:
    for value in data[key]:
        result[value].append(key)

dict.setdefault and collections.defaultdict are new to me and useful!

Stop writing Python __init__ methods

https://blog.glyph.im/2025/04/stop-writing-init-methods.html

The idea is to just set members in object constructors to keep them simple. Any complex data conversion, or side-effects should be moved to a class-method.

This seems like a great way to deal with constructors taking multiple different inputs.

I do think using traditional constructors has the advantage of following a widely used convention (the principle of least surprise in API design) and can be simpler to use.

Apache SSLPolicy Directive

https://httpd.apache.org/docs/trunk/mod/mod_ssl.html#sslpolicy

Makes configuring SSL simple by enabling a whole set of security policy directives in one command.

Apache includes policies from the Mozilla organization, including the most secure option: "modern"

Apache mod_md: built-in Let's Encrypt certificate retrieval

https://httpd.apache.org/docs/2.4/mod/mod_md.html

Apache's built-in mod_md can handle automatic retrieval and renewal of Let's Encrypt certificates (or similar with ACME) without external software. Convenient!

ASCIIFlow

https://asciiflow.com/

A web-app for drawing ASCII diagrams.

Muometric positioning system (μPS) with cosmic muons as a new underwater and underground positioning technique (2020)

https://www.nature.com/articles/s41598-020-75843-7

Using the time of flight of relativistic cosmic ray muons to estimate relative position.

There is also a 2024 paper on a more practical, wireless system and another on time synchronization from 2022.

Here is the author, Hiroyuki K.M. Tanaka's inspirehep page.

Neovim

https://neovim.io/

A more modern, but mostly compatible, version of Vim.

After trying Kakoune and Helix, I realized it would be too much work to re-learn a bunch of key-bindings and ways of doing things. I'm not ready to put the effort into a project that isn't very far along. With Neovim, I can always go back to Vim if the project fails.

I've been messing with configuring Neovim for a few days now, and it can be intimidating when you see a bunch of code to configure something in a web search result. I've found my way around that, and have things mostly up and running.

Overall, I think I'm happy to use Neovim for now.

tldr pages

https://tldr.sh

The tldr pages are a community effort to simplify the beloved man pages with practical examples.

They are a really nice set of examples. I especially like the ones for git commands, like git rebase.

Helix text editor

https://helix-editor.com/

2025-04-10 Update: I tried Helix for a few days, and like it, but miss features from Vim and want something more complete. Maybe I'll try to get LSP and completion working in Vim or give NeoVim a shot!

Helix is a Vim and Kakoune inspired editor. It follows Kakoune's philosophy of multiple selections and redesigned keybindings, but brings back Vim's visual mode. It is written in Rust and tries to include what most users would include through Vim plugins, e.g. tree-sitter and language server support (LSP). It doesn't currently have plugin support.

I'm writing this post in Helix. It's nice to have more of the "batteries-included" features like tiling window support and a file manager. I haven't figured out the tree-sitter/LSP integration yet.

A few things are missing, like spell checking (maybe can use a language server?) There does seem to be Git support. It's a nice little colored line between the line numbers and the text. It doesn't work the same as Vim-Fugitive, though, as it only shows the diff from HEAD, not from staged.

Using chroot for Linux system recovery

https://superuser.com/questions/111152/whats-the-proper-way-to-prepare-chroot-to-recover-a-broken-linux-installation

This technique lets you boot your broken installation with a live USB disc, then use chroot to switch the running Linux over to the broken installation. You can then run package manager commands, etc.

arch-chroot is a script that does all of the steps for you and is even available on Debian.

systemd-nspawn can be used in a similar way:

systemd-nspawn --directory /tmp/target-rescue --boot -- --unit rescue.target

It is usually used as a light weight host virtualization technique, and is new to me!

Light bulb shape and size chart

https://www.bulbs.com/learning/shapesandsizes.aspx

Chart for shape and size of light bulbs. A19 is the standard size.

They also have a base chart here. Medium/26mm/E26 is the standard one that goes with A19.

light bulb chart

Freefall webcomic "quark" ice cream

http://freefall.purrsia.com/ff100/fv00023.htm

I've just started reading the long-running webcomic "Freefall." I particularly like this joke about "quark" ice cream:

I thought everyone liked "quark" ice cream. I've got all three colors in all six flavors.

Choose boring technology

https://mcfunley.com/choose-boring-technology

Author: Dan McKinley

The idea is that the more new, exciting, "poorly-understood" things you choose, the more complex and difficult to deal with your system becomes. He advocates for a company to pick three or less non-boring technologies and to pick them where it maximizes your competitive advantage.

This whole article is great!

What counts as boring? That’s a little tricky. “Boring” should not be conflated with “bad.” There is technology out there that is both boring and bad (we often casually refer to the boring/bad intersection of doom as “enterprise software,” but that terminology may be imprecise). You should not use any of that. But there are many choices of technology that are boring and good, or at least good enough. MySQL is boring. Postgres is boring. PHP is boring. Python is boring. Memcached is boring. Squid is boring. Cron is boring.

The nice thing about boringness (so constrained) is that the capabilities of these things are well understood. But more importantly, their failure modes are well understood.

Emphasis theirs:

One of the most worthwhile exercises I recommend here is to consider how you would solve your immediate problem without adding anything new. First, posing this question should detect the situation where the “problem” is that someone really wants to use the technology. If that is the case, you should immediately abort.

Python range is not an iterator

https://treyhunner.com/2018/02/python-range-is-not-an-iterator/

Counterintuitively, Python's range function isn't an iterator, because you can't call next() on it. It is lazy like iterators but is more like a "lazy collection." Like a collection, you can make an iterator from one with the iter() function.

The wrong abstraction

https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction

A good sign of an abstraction, e.g function, that needs to be replaced by copy-pasted code is one with boolean flag parameters. It's probably better to "inline" the code back to the call site, and then see what parts of it, if any, are still shared and make a new abstraction.

Tayloe Quadrature Product Detector

https://www.norcalqrp.org/files/Tayloe_mixer_x3a.pdf

This simple circuit directly converts from RF down to baseband. Four square waves operating at 4×FRF4 \times F_{RF} and shifted 90° from each other control a multiplexer thus producing four quadrature signals. These can be combined to give I and Q signals. A copy of the PDF is here.

I found this while reading about the Pi Pico Rx, which uses this circuit and a Raspberry Pi Pico to make a software defined radio.

Haskell conditional for

https://entropicthoughts.com/non-obvious-haskell-idiom-conditional-for

To only perform a monadic or applicative action if a value exists, you can use

for_ value $ action

So for example, if x is a Maybe String, you could print it if it exists with:

for_ x $ putStrLn x

I think that's the beauty of Haskell, this thing with a name from lists, when generalized to (Traversable) Applicatives, can do useful things for all kinds of things.

Since for_ is just traverse_ with it's arguments flipped, you could also do:

traverse_ (action) value

Keep in mind for_ and traverse_ are in Data.Foldable and not present in the Prelude.

Also, oddly, is the linked blog post scheduled to be published in the future?

Haskell guard sequence

https://entropicthoughts.com/non-obvious-haskell-idiom-guard-sequence

guard condition *> action -- Perform action if condition is true else fail
guard condition $> value  -- Return value if condition is true else fail
value <$ guard condition  -- Like the 1st line, but switched around

This can effectively make sure a condition is true before doing something or returning a value.

Keep in mind "failure" can mean lots of things depending on the surrounding Applicative. It could mean returning Nothing, or raising an exception.

You will need the following imports to do this:

import Control.Mondad (guard)
import Data.Functor ((*>),($>),(<$))

Picking glibc versions at runtime

https://blogsystem5.substack.com/p/glibc-versions-runtime

How do you test code against a different version of libc than the system default one? You can't reliably use an alternate libc by putting it in LD_LIBRARY_PATH. It will often crash.

You might think that the kernel is somehow responsible for dealing with dynamic libraries, but that’s not the case. Dynamic libraries are a user-space concept and this is precisely where the [ELF] interpreter [ld-linux.so] comes into play.

To summarize, glibc ships both the ld-linux.so dynamic linker and the libc.so.6 shared library. The two are closely coupled. Running a binary against the C library without also using a matching dynamic linker can lead to crashes. But running a binary directly with a specific dynamic linker ensures that the binary picks up the matching C library.

At compile time, you can include the interpreter ld-linux with:

bash gcc -o myexe -Wl,--dynamic-linker=/wherever/ld-linux-x86-64.so.2 mycode.c

At runtime, you can use patchelf to replace the reference to the interpreter in the binary:

bash patchelf --set-interpreter /wherever/ld-linux-x86-64.so.2 myexe

Keep in mind that glibc backwards compatibility means a newer glibc will work with code compiled with an older version, but not the other way around.

PaperWM

https://github.com/paperwm/PaperWM

PaperWM is a scrolling window manager for the GNOME Shell. It's similar to tiling window managers like dwm and XMonad, but instead of tiling windows within the desktop, windows scroll to the right as they are created. So you just navigate left and right to various windows.

I like the conceptual idiom a lot better than normal tiling. I'm not sure if it works for me in practice. I've tried it in Debian 12/GNOME Shell 43.9 and installed the extension from extensions.gnome.org here on my laptop. I usually use each window in full screen on my laptop and alt-tab between them, so I'm not sure how useful the scrolling is for me. After an hour or so of use, it does seem to encourage me to have more than one window at a time on the desktop.

The default keybinding for switch window is super+tab, but I like alt+tab a lot better, so had to add that. The instructions on moving around and re-sizing windows are a bit confusing to me. I'm yet to really figure it-out.

Kakoune text editor

http://kakoune.org/

Kakoune is a Vim-inspired editor. Major differences from Vim include a focus on multiple selections and "orthogonal design", meaning normal-mode keybindings are redesigned to be more orthogonal. It also follows the Unix philosophy by not having much built-in. For example, to format paragraphs into a certain number of columns, I select text, hit | to pipe it to a shell program and run fmt. I'd just run gq in Vim.

I made this post with Kakoune. It took me a while to figure out how to get back to my text buffer from the documentation (type :buffer and then it shows in the autocomplete). In Vim, I tend to select things in visual mode and then perform actions on them. So I do like the selection-verb idiom of Kakoune, but don't like that visual mode is missing. It would take a while to transition from Vim.

Borg Backup Software

https://www.borgbackup.org

Borg seems like the best open source backup solution right now. It deduplicates chunks of data within files across multiple backups, saving a lot of space. Encryption and compression are also supported.

It only works locally or over SSH, and doesn't work on Windows. I wish it had support for parity so it could recover from a bit of storage corruption.

rclone

https://rclone.org

File copy/sync/move to and from the cloud, and even between clouds.

It works with S3 and similar, but also OneDrive, Dropbox, Google Drive, FTP, and SFTP.

Rsync for the cloud sounds useful, as well as copy and move. Two-way sync, bisync, sounds like a mess waiting to happen.

Archaeology of the pork taboo

https://archaeology.org/issues/march-april-2025/letters-from/on-the-origin-of-the-pork-taboo/

For early Israelites and Muslims, the pork taboo seems to be a way to identify with their ancestral origin as herders, where pigs weren't practical.

Beause pigs didn't need a bunch of graising land, government officials couldn't track them. They could live their entire lives in a backyard. This, combined with nice secondary products of ruminants like milk and wool, lead to pigs being a lower-class thing, while ruminants were prized by the wealthy and religious/social elite.

Butterick's practical typography

https://practicaltypography.com

A book worth of info. I need to take his advice for line spacing and heading size into account for this site, among other suggestions.

How to Favicon

https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs

Dozens of images aren't required for a favicon. The article recommends 6, but I would try just .ico at only 32x32 and a SVG.

Includes a description of the files required and why, as well as how to generate them with Inkscape and Gimp.

Magic Wormhole

https://magic-wormhole.readthedocs.io/en/latest/

Peer to peer file sharing protocol. Ideal for sharing ssh keys and similar. Very well regarded cryptography.

The Night Watch

https://www.usenix.org/system/files/1311_05-08_mickens.pdf

Funny musings about how systems programmers are hard-core.

Excerpts:

The systems programmer has traced a network problem across eight machines, three time zones, and a brief diversion into Amish country, where the problem was transmitted in the front left hoof of a mule named Deliverance

A systems programmer will know what to do when society breaks down, because the systems programmer already lives in a world without law.

Listen: I’m not saying that other kinds of computer people are useless. I believe (but cannot prove) that PHP developers have souls. I think it’s great that database people keep trying to improve select-from-where, even though the only queries that cannot be expressed using select-from-where are inappropriate limericks from “The Canterbury Tales.” In some way that I don’t yet understand, I’m glad that theorists are investigating the equivalence between five-dimensional Turing machines and Edward Scissorhands. In most situations, GUI designers should not be forced to fight each other with tridents and nets as I yell “THERE ARE NO MODAL DIALOGS IN SPARTA.” I am like the Statue of Liberty: I accept everyone, even the wretched and the huddled and people who enjoy Haskell. But when things get tough, I need mission-critical people; I need a person who can wear night-vision goggles and descend from a helicopter on ropes and do classified things to protect my freedom while country music plays in the background. A systems person can do that. I can realistically give a kernel hacker a nickname like “Diamondback” or “Zeus Hammer.” In contrast, no one has ever said, “These semi- transparent icons are really semi-transparent! IS THIS THE WORK OF ZEUS HAMMER?”

When you debug a distributed system or an OS kernel, you do it Texas-style. You gather some mean, stoic people, people who have seen things die, and you get some primitive tools, like a compass and a rucksack and a stick that’s pointed on one end, and you walk into the wilderness and you look for trouble, possibly while using chewing tobacco. As a systems hacker, you must be prepared to do savage things, unspeakable things, to kill runaway threads with your bare hands, to write directly to network ports using telnet and an old copy of an RFC that you found in the Vatican.

Nothing ruins a Friday at 5 P.M. faster than taking one last pass through the log file and discovering a word-aligned buffer address, but a buffer length of NUMBER OF ELECTRONS IN THE UNIVERSE.

You might ask, “Why would someone write code in a grotesque language that exposes raw memory addresses? Why not use a modern language with garbage collection and functional programming and free massages after lunch?” Here’s the answer: Pointers are real. They’re what the hardware understands. Somebody has to deal with them. You can’t just place a LISP book on top of an x86 chip and hope that the hardware learns about lambda calculus by osmosis.

That being said, if you find yourself drinking a martini and writing programs in garbage-collected, object-oriented Esperanto, be aware that the only reason that the Esperanto runtime works is because there are systems people who have exchanged any hope of losing their virginity for the exciting opportunity to think about hex numbers and their relationships with the operating system, the hardware, and ancient blood rituals that Bjarne Stroustrup performed at Stonehenge.

Triggering Javascript at the Right Moment

https://stackoverflow.com/a/36096571

The best way to run javascript is in the head with the "defer" attribute. That immediately starts fetching the script, but waits to execute it until the whole page is parsed.

<!DOCTYPE html>
<html>
<head>
  <title>Title</title>
  <meta charset="UTF-8">
  <script src="blahblah.js" defer></script>
</head>
<body>

<p>Stuff here</p>

</body>
</html>

Emergence of collective oscillations in massive human crowds

https://doi.org/10.1038/s41586-024-08514-6

Observational study of crowds with interesting modeling and analysis.

Forgejo: Free Software Light-Weight GitHub Alternative

https://forgejo.org

Interesting alternative to GitHub. It's also meant to be much lighter weight than GitLab, which I understand is quite heavy.

The hosted version is https://codeberg.org

TigerBeetle OLTP Database

https://tigerbeetle.com

Interesting architecture for a database specialized for OLTP. Single threaded, and each record is just 128 bytes to fit in a CPU cache line!

OWASP Security Cheat Sheets

https://cheatsheetseries.owasp.org/index.html

Cheet sheets on all kinds of security, from C-based toolchain hardening to HTTP headers.

Stack Overflow Definitive Guide to Form-based Website Authentication

https://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication

A really nice guide to the best, most secure ways to do website authentication. Lots of nice links

The evolution of the web, and a eulogy for XHTML2

https://www.devever.net/~hl/xhtml2

"[The abundance of Javascript on modern web pages] is a bit like as if every single website now used Flash in major part — and we all know how popular that was."