Articles

A visit to the Crossness pumping station
Pictures from my recent visit to Crossness, a Victorian pumping station for London’s sewers.

Four ways to underline text inLaTeK
I’m very picky about the way underlines look, and have spent a lot of time trying to get the perfect underline inLaTeK.
Zero
An essay about the number zero that I wrote for school.
Darwin, pancakes and birthdays
Looking at whether Darwin ever missed out on birthday cake for pancakes
Automatic Pinboard backups
A script for automatically backing up bookmarks from Pinboard
Finding untagged posts on Tumblr
Finding untagged posts on Tumblr, redux
Skeletor!
Getting plaintextLaTeK from Wolfram Alpha
Thoughts on Overcast
Some thoughts on Marco Arment’s new podcast player, Overcast.
A quick Alfred workflow for opening recent screenshots
Updates to my site for finding untagged Tumblr posts
My new standing desk
A standing desk that I built solely from IKEA parts.
Playing with 404 pages
Notes on Tumblr
Unpacking sets and ranges from a single string
Skeletors All the Way Down
Acronyms
Kitchen sink security
Adding checkboxes to lists
A bookmarklet to add checkboxes to lists in the browser.
Tidying up my 1Password
Pygmentizr
A web app for applying syntax highlighting to code using the Pygments library.
Some exam advice
Some advice for students sitting technical exams
Cloning GitHub’s Contributions chart
I made a clone of GitHub’s Contributions graph to use as a motivational tool.
Useful Git features: a per-clone exclude file (.git/info/exclude)
Another way to ignore untracked files in Git.
Safer file copying in Python
A Python script for non-destructive file copying/moving.
Persistent IPython notebooks in Windows
Configuring an IPython notebook server that is always running and easily accessible in Windows.
Useful Bash features: exit traps
Finding even more untagged posts on Tumblr
A new version of my site for finding untagged Tumblr posts.
Review: Effective Python
A review of Effective Python, by Brett Slatkin.
Quick shell access for Docker containers
A Bash function for quickly getting shell access to Docker containers.
Python and the BBC micro:bit
Playing with a tiny computer that runs Python.
Export a list of URLs from Safari Reading List
A Python script for getting a list of URLs from Safari Reading List.
Backups and Docker
The Docker folder on your computer can quickly fill up space. Don’t forget to exclude it from backups.
Pretty printing JSON and XML in the shell
The Skeletor clip loop, 2015 edition
Updating the Skeletor clip loop chart for the 2015 Clip Show.
How I use TextExpander to curb my language
I have some TextExpander snippets that I use to cut out words I don’t want to write.
Exclusively create a file in Python 3
If you want to create a file, but only if it doesn’t already exist, Python 3 has a helpful new file mode
x.Get images from the iTunes/App/Mac App Stores with Alfred
Using Alfred and a Python script to retrieve artwork from the iTunes, App and Mac App Stores.
Treat regular expressions as code, not magic
Regexes have a reputation for being unreadable monsters, but it doesn’t have to be that way.
Safely deleting a file called ‘-rf *’
If for some reason you create a file called
-rf *, it’s possible to delete it safely. But really, don’t create it in the first place.A Python smtplib wrapper for Fastmail
A quick python-smtplib wrapper for sending emails through Fastmail.
Finding 404s and broken pages in my Apache logs
A Python script for finding 404 errors in my Apache web logs - and by extension, broken pages.
Introduction to property-based testing
Testing with randomly generated examples can be a good way to uncover bugs in your code.
Reading web pages on my Kindle
A Python script I wrote that let me sends web pages from my Mac and my iPhone to my Kindle.
Clearing disk space on OS X
A few tools and utilities I’ve been using to help clear disk space on my Mac.
Python snippets: Chasing redirects and URL shorteners
A quick Python function to follow a redirect to its eventual conclusion.
Python snippets: Cleaning up empty/nearly empty directories
A pair of Python scripts I’ve been using to clean up my mess of directories.
Live captioning at conferences
Live captioning of conference talks was an unexpected bonus at this year’s PyCon UK.
Silence is golden
PyCon had a dedicated quiet room for people to get some downtime, and I think it’s a great idea.
aspell, a command-line spell checker
My travelling tech bag
A shell alias for tallying data
A way to count records on the command-line.
Why I use py.test
Why py.test is my unit test framework of choice in Python.
Tiling the plane with Pillow
Using the Python Imaging Library to draw regular tilings of squares, triangles and hexagons.
Creating low contrast wallpapers with Pillow
Take a regular tiling of the plane, apply a random colouring, and voila: a unique wallpaper, courtesy of the Python Imaging Library.
Use keyring to store your credentials
If you need to store passwords in a Python application, use the keyring module to keep them safe.
Some low-tech ways to get more ideas
A few suggestions for "low tech devices" that aid in the process of generating ideas.
Another example of why strings are terrible
Pop quiz: if I lowercase a string, does it still have the same length as the original string?
Experiments with AO3 and Python
AO3 doesn’t have an official API for scraping data - but with a bit of Python, it might not be necessary.
A Python interface to AO3
AO3 doesn’t have an official API for scraping data - but with a bit of Python, it might not be necessary.
Accessibility at AlterConf
For accessibility and inclusion, AlterConf sets a high bar to beat.
Listing keys in an S3 bucket with Python
A short Python function for getting a list of keys in an S3 bucket.
Backing up content from SoundCloud
Backing up full-page archives from Pinboard
A Rust utility for saving local copies of my full-page archives from Pinboard.
A Python module for lazy reading of file objects
I wrote a small Python module for lazy file reading, ideal for efficient batch processing.
Ode to docopt
Why I love docopt as a tool for writing clean, simple command-line interfaces.
Some useful Git commands for CI
A couple of Git commands that I find useful in builds and CI.
Using pip-tools to manage my Python dependencies
How I use pip-tools to ensure my Python dependencies are pinned, precise, and as minimal as possible.

A day out to the Forth Bridge
Photographs from a trip to North Queensferry to see the Forth Bridge, the Forth Road Bridge, and an unexpected light tower.

Getting a tint colour from an image with Python and k‑means
I want to display text next to an image that looks visually similar to the image, so I need to extract a tint colour.
Using hooks for custom behaviour in requests
I often have code I want to run against every HTTP response (logging, error checking) — event hooks give me a nice way to do that without repetition.
Displaying tweets in Keynote
Slides for showing tweets that look like tweets on slides in Keynote and PowerPoint.
Lightning talks
Why I like the lottery system used to select lightning talks at PyCon UK this year.
Using privilege to improve inclusion
In the tech industry, how can we be more aware of our privilege, and use that to build inclusive cultures?
A plumber’s guide to Git
How does Git work under the hood? How does it store information, and what’s really behind a branch?
Don’t tap the mic, and other tips for speakers
Tapping the microphone to test it can be bad for all sorts of reasons – and other advice from the Nine Worlds speaker guidelines.
My favourite WITCH story
As the WITCH computer celebrates five years since its reboot at TNMoC, a fun story of how it was left to run at Christmas.
Downloading logs from Amazon CloudWatch
A detailed breakdown of how I wrote a Python script to download logs from CloudWatch.
Pruning old Git branches
Two commands for managing Git branches: one for deleting branches which have already been merged, one for deleting branches which were deleted on a remote.
Your repo should be easy to build, and how
Making your repo easy to clone and build is very important. This post explains why, and how I’m using Make and Docker to achieve that goal.
Using Loris for IIIF at Wellcome
How we use Loris to provide a IIIF Image API for browsing our collections at Wellcome–how it runs in AWS, store our high-resolution images, and monitor the service.
IP and DNS addresses for documentation
If you’re writing technical docs and need placeholder IP addresses or DNS hostnames, there are some special values just for you!
Listing keys in an S3 bucket with Python, redux
Python functions for getting a list of keys and objects in an S3 bucket.
Getting every message in an SQS queue
Code for saving every message from an SQS queue, and then saving the messages to a file, or resending them to another queue.
Getting helpful CloudWatch alarms in Slack
How we use AWS Lambda to send messages about our CloudWatch alarms to Slack, and some ways we add context and information to make those messages as helpful as possible.
Keep an overnight bag in the office
Although hopefully never needed, I think it’s worth keeping an overnight bag in your workplace.
The Hypothesis continuous release process
How we do continuous releases of hypothesis-python, and why.
Notes on A Plumber’s Guide to Git
Git is a fundamental part of many modern developer workflows – but how does it really work under the hood? In this workshop, we’ll learn about the internals of Git.
(Anti) Social Media
Slides and notes for a talk about online harassment, and why you should always design with an abusive ex in mind.
Two shortcuts for using S3 in the shell
Two shell functions for editing and inspecting S3 objects as if they were local files.
Beware of logged errors from subprocess
If you use Python’s subprocess module, be careful you don’t leak sensitive information in your error logs.
Creating a data store from S3 and DynamoDB
A new storage layer for large records in the Catalogue pipeline.
Drawing ASCII bar charts
A Python snippets for drawing bar charts in command-line applications.
My favourite iMac accessory
Adding a USB extension cable to my iMac makes a world of difference.
A robot leaked my SSH keys
A cautionary tale of a daft incident where I leaked a set of SSH keys to GitHub.
Moving my calendars from iCloud to FastMail
I recently discovered that iCloud was deleting my old calendar entries, so I switched to FastMail.
Ideas for inclusive conferences and events
A collection of ideas and suggestions for running conferences which are more inclusive and accessible. Based on my experiences at AlterConf, PyCon UK, and similar events.
Avoiding the automatic redirect on Tumblr posts
I see an intermittent 303 Redirect when trying to navigate to a Tumblr ‘permalink’; changing the User-Agent seems to fix it.
Implementing parallel scan in DynamoDB with Scanamo
Prototype code for running a parallel scan against a DynamoDB table, and using Scanamo to serialise rows as Scala case classes.
Making the venue maps for PyCon UK
A quick braindump of my thoughts from drawing some venue maps for PyCon UK.
A basic error logger for Python Lambdas
A snippet to make it a bit easier to debug errors in AWS Lambda functions written in Python.
Signs of the time
A few lessons I learned while doing the signage for this year’s PyCon UK.
Building trust in an age of suspicious minds
Notes and slides from my PyCon UK 2018 keynote. In a world where people are less and less trusting, how can we take steps to make ourselves more trustable?
Assume worst intent (designing against the abusive ex)
How do we design services and platforms to reduce the risk of harassment and abuse from other users?
Custom 404 responses in Finatra
A snippet for returning a custom 404 response in a Finatra app when somebody requests a missing page.
Peering through MRI scans of fruit and veg
What do you see when you pass fruit and vegetables through an MRI scanner? And how many animated GIFs can you make?
Finding SNS topics without any subscriptions
I’m trying out Go, and I wrote a tool to help me find SNS topics that don’t have any subscriptions.
My visit to the Aberdulais Falls
Pictures from my trip to the waterfalls and former tin plating works at Aberdulais.
Keeping track of my book recommendations
The three lists I use to manage my book recommendations.
A script for backing up Tumblr posts and likes
Since Tumblr users are going on a mass deletion spree (helped by the Tumblr staff), some scripts to save content before it’s too late.
Getting credentials for an assumed IAM Role
A script that creates temporary credentials for an assumed IAM role, and stores them in ~/.aws/credentials.
Iterating in fixed-size chunks in Python
A snippet for iterating over an arbitrary iterable in chunks, and returning a smaller chunk if the boundaries don’t line up.
Notes on reading a UTF-8 encoded CSV in Python
Some notes on trying to do this in a way that supports both Python 2 and 3, and the frustration of doing so.
Notes from You Got This 2019
Notes from the inaugural ‘You Got This’ conference, a conference about creating a healthy and sustainable work life.
Monki Gras 2019: The Curb Cut Effect
Slides and notes for my talk ‘The Curb Cut Effect’. Making something better for disabled people can make it better for everybody.
Working with really large objects in S3
Code for processing large objects in S3 without downloading the whole thing first, using file-like objects in Python.
Checking Jekyll sites with HTMLProofer
Atomic, cross-filesystem moves in Python
Explaining some code for moving files around in a way that’s atomic and works across filesystem boundaries.
Finding the latest screenshot in macOS Mojave
Creating a GitHub Action to auto-merge pull requests
Saving myself the trouble of clicking that pesky "merge" button.
Getting a transcript of a talk from YouTube
Using the auto-generated captions from a YouTube video as a starting point for a complete transcript.
Some tips for conferences
Reversing a t.co URL to the original tweet
Twitter uses t.co to shorten links in tweets, so I wrote some Python to take a t.co URL and find the original tweet.
Creating a locking service in a Scala type class
Breaking down some tricky code that allows us to lock over concurrent operations.
Falsehoods programmers believe about Unix time
It’s not quite the number of seconds since 1 January 1970.
Questions to ask when writing a trans inclusion policy
Notes on common themes and ideas in a variety of trans inclusion policies, as we start thinking about writing a policy at Wellcome.
A script for getting cover images from mobi ebooks
Hey Apple, cycle tracking isn’t just for women
At WWDC, I was disappointed to see Apple pitch period tracking exclusively towards women, and not in a more gender-inclusive way.
Converting Acorn images on the command-line
I wrote some AppleScript to help me do batch conversion of Acorn images into formats like PNG and JPEG.
Reading a Chinese dictionary / 读一本中文字典
Although paper dictionaries are mostly a thing of the past, knowing how to use a Chinese dictionary helps me learn the rest of the language.
A Jekyll filter for obfuscating email addresses
The original Markdown implementation would do randomised hex/decimal encoding to help obscure email addresses, and I do the same in Jekyll.
An inescapable conclusion
After months of introspection and soul-searching, I’ve had some big realisations about my identity.
Ten braille facts / ⠼⠁⠚⠀⠃⠗⠁⠊⠇⠇⠑⠀⠋⠁⠉⠞⠎
Where does braille come from? How was braille originally written? What can you write in braille today? And more.
Listing even more keys in an S3 bucket with Python
Python functions for getting a list of keys and objects in an S3 bucket.
Creating preview thumbnails of PDF documents
Finding divisors of a number with Python
Using unique prime factorisations and itertools to find all the divisors of a number.

Adventures in Python with concurrent.futures
Some examples of how I’ve been using concurrent.futures to speed up my batch scripting in Python.

Building Wellcome Collection’s new archival storage service
How we built the new cloud-based storage system for holding an ever-growing digital archive.
Iterating over the entries of a compressed archive (tar.gz) in Scala
Code to turn an InputStream into an Iterator of entries from a tar.gz file or similar compressed archive in Java/Scala.
Streaming large objects from S3 with ranged GET requests
Reliably reading a large object by stitching together multiple GetObject requests into a single Java InputStream.
Drawing with triangular coordinates in SVG
Some code and trigonometry for drawing shapes that don’t fit neatly into a rectangular grid.
Experiment: GitHub code search with de-duplication
The rough edges of filecmp
The filecmp module has a confusing API, and it just caught me out.
Adding religious holidays to my calendar
Sans I/O programming: what, why and how (PyCon UK talk)
Code that pushes I/O to the boundary is simpler, easier to reuse and easier to test.
Digital preservation at Wellcome Collection
Slides from a presentation about our processes, practices, and tools.
An AWS costs graph that works for me
How I get a Cost Explorer graph for the last 30 days of spending, broken down by service.
Saving a copy of a tweet by typing ;twurl
How I scan and organise my paperwork
My procedure for scanning paper, and organising the scanned PDFs with keyword tagging.
November 2019 scripts: downloading podcasts, retrying flaky errors, Azure and AWS
Some useful spreadsheet functions: FORMULATEXT, MATCH, CONCATENATE and INDIRECT
This YAML file will self-destruct in five seconds!
YAML allows you to execute arbitrary code in a parser, even if you really really shouldn’t.
Finding the CPU and memory bottlenecks in an ECS cluster
Generating pride-themed Norse valknuts with Python 🌈
A web app to generate mashups of Norse valknuts and Pride flags.
An interactive map of British railway stations 🚂
A map I use to plot which railway stations I’ve visited.
A deletion canary: testing your S3 bucket permissions
If you’ve tried to disable deletions in your S3 buckets, how do you know they’re working?

Using DynamoDB as a calculator
Taking advantage of Amazon’s least-loved compute platform.

Illustrating lifecycle transitions in Amazon S3
A picture speaks a thousand words, which is why I always have pen and paper to hand.
Storing multiple, human-readable versions of BagIt bags
How we use the fetch.txt file in a bag to track multiple copies of an object in our digital archive.
Adjusting the dominant colour of an image
Adjusting the hue to get different colour variants of the same image.
A Jekyll filter for adding non-breaking spaces
A way to avoid awkward line breaks in the middle of phrases.
Creating striped flag wallpapers with Pillow
Sick leave while working from home
It’s okay to take sick leave if you’re working from home.
Rich enough to make bad choices
If you’re rich, not only can you invest in good boots, you can also invest in experimental boot-making startups.
Inclusion can’t be an afterthought
Notes from a talk about inclusion in design and unconscious bias.
Storing language vocabulary as a graph
Experimenting with a way to store words and phrases that highlights the connections between them.
A snippet for downloading files with Python
Access to information is a privilege
Adventures in euphoria and embodiment
We all have bodies, and I’ve been trying to become more self-aware and connected with mine.
Comparing JSON strings when testing in Scala
There are lots of ways to format JSON. How do you know if two JSON strings have the same data, just differently formatted?
Complex systems have complex failures
When a complex system fails, it’s usually a combination of problems, not a single person’s mistake.
Thinking about your gender
Cis people are allowed to think about their gender too.
Exploring an unknown SQL server
You’re handed a SQL server which has some data, but you don’t know anything about the schema. What do you do?

How long is my data? 💾
A fun app to calculate the size of your data in terms of floppy disks.

Large things living in cold places
Using cold storage tiers to reduce the cost of storing Wellcome’s digital collections in the cloud.
Give your audience time to react
Rehearsing a presentation only tells you the minimum length of time you’ll take. If you’re speaking to a time limit, remember to leave some slack.
Make it safe to admit mistakes
You can’t stop people making mistakes, but you can make it more likely that they’ll admit their next mistake to you.
Taking tuple unpacking to terrible places
I want to assign a bunch of variables to True, but I don’t know how many there are. Reflection to the rescue!
Social media as a growth culture for opinions
Using social media can lead us to have more opinions than we really need. Can we fix that?
Downloading the AO3 fics that I’ve saved in Pinboard
A script that downloads the nicely formatted AO3 downloads for everything I’ve saved in Pinboard.
Moving messages between SQS queues
You can send messages to a DLQ if they fail processing. What if you fix the bug, and you want to resend the failed messages?
The Sachsenhausen concentration camp
Feeling the weight of death in a former concentration camp.
Showing human-friendly dates in JavaScript
What’s a nicer way to show a date than an ISO 8601 timestamp?
Getting every item from a DynamoDB table with Python
A Python function that generates every item in a DynamoDB table.
Finding the months between two dates in Python
Archive monocultures considered harmful
We are better off when the same topic is represented in multiple, different archives.

Wellcome Collection’s approach to digital verification
How we ensure the safety, security and integrity of the files in Wellcome’s digital collections.

How KempisBot works
How I reincarnated a fifteenth-century monk and taught him to use Twitter.
Fat shaming in The Good Place
How many good person points do you lose for making a joke about somebody’s weight?
Using AppleScript to open a URL in Private Browsing in Safari
Changing the accent colour of ICNS icons
Playing with macOS ICNS image files to create colourful new icons.
How to do parallel downloads with youtube-dl
What does \d match in a regex?
It’s more complicated than I thought.
Running concurrent Try functions in Scala
If you have a function that returns Try[_], how do you call it more than once at the same time?
Why do programming languages have a main() function?
Lots of programming languages have a function called main() where code starts executing. Where does this come from?
Getting a Markdown link to a window in Safari
Using fuzzy string matching to find duplicate tags
S3 keys are not file paths
Although an S3 key looks a lot like a file path, they aren’t always the same, and the distinction can trip you up.
S3 prefixes are not directories
Although an S3 prefix looks a lot like a directory path, they aren’t the same. Whether or not you include a trailing slash can change the behaviour.
Two Python functions for getting CloudTrail events
Using qlmanage to create thumbnails on macOS
How you can invoke Quick Look on the command-line to generate high-quality thumbnails.
Replicating Wellcome Collection’s digital archive to Azure Blob Storage
How and why we keep copies of Wellcome’s digital collections in multiple cloud storage providers.
A new README for docstore, my tool for organising scanned paperwork
Although I don’t expect anyone to use it directly, there might be some interesting ideas that could apply elsewhere.
The danger of bad error messages
An Excel mistake shows why learning to write good error messages is a critical skill for software developers.
How do I use my iPhone cameras?
A script to work out which camera I use most often on my iPhone, and whether I’d miss a telephoto lens.
A Python function to ignore a path with .git/info/exclude
If your Python script creates a file that you don’t want to track in Git, here’s how you can ignore it.
Remembering if a <details> element was opened
A JavaScript function that remembers if a details element was reopened, and keeps it open when you reload the page.
Maths is about facing ambiguity, not avoiding it
School tells us that “Maths always has one right answer!”, which is a convenient but unhelpful lie.
How I read non-fiction books
I take notes so I remember more of what I read.
A script to copy images from Docker Hub to Amazon ECR
“Non-technical users”
Creating short-lived, temporary roles for experimenting with AWS IAM policy documents
Create short-lived, temporary roles for experimenting with AWS IAM policy documents
What year is it? (A tale of ISO week dates)
If you use ICU date formatting, make sure you use the right format specifier for year.

Drawing inner/outer strokes in SVG (clips and masks)
Showing how clips and masks work, and how they can be used to draw inner and outer strokes of a shape.

dominant_colours, a CLI tool for finding dominant colours in an image
A new tool for playing with images.
Screaming in the Cloud: Using the Cloud to Preserve the Future
I joined Corey Quinn to discuss my DynamoDB calculator and using the cloud to preserve digital collections.
An AppleScript to toggle Voice Control
Making it slightly easier for me to enable and disable Voice Control quickly.
Creating pairs of interlocking rainbow hearts 🌈
A web app for creating pairs of hearts based on Pride flags.
Building Wellcome Collection’s new unified catalogue search
Collaboration between our digital and collections teams helped to build a single search box for all of our catalogues.
Finding the app/process that’s using Secure Input
A Python script that shows me the name of processes that have Secure Input enabled.
Using AppleScript to detect if a Safari window uses Private Browsing
Drawing coloured squares/text in my terminal with Python
Downloading objects from/uploading files to S3 with progress bars in Python
Making it easier to see how long a file transfer will take, in the terminal.
Visualising how often I write in my journal
A Python script that shows me how often I’ve been journalling, so I can track my progress.
Listing deleted secrets in AWS Secrets Manager with boto3 and the AWS CLI
Diving into the internals of the AWS SDK to find deleted secrets.
A few useful GitHub searches
I have hotkeys to search GitHub in several ways, including by user, by repo, and within the work organisation.
Finding misconfigured or dangling CloudWatch Alarms
A Python script that finds CloudWatch Alarms which are based on a now non-existent source.
Markdown’s gentle encouragement towards accessible images
The Markdown syntax for images reminds us that we need to write alt text.
How to ignore lots of folders in Spotlight
A script that allows me to ignore folders like "target" and "node_modules", so they don’t appear in search results.
Picking perfect planks with Python
How do you pick the right combination of planks to lay a wooden floor? Python and itertools to the rescue!
When is my EventBridge cron expression going to run next?
The AWS console will tell you when your EventBridge rule is going to run… if you know where to look.
Operations on strings don’t always commute
Is uppercasing then reversing a string the same as reversing and then uppercasing? Of course not.
Getting a monthly cloud costs report in Slack
Sending the AWS bill to Slack, so everyone can be more informed and intentional about spending.
An editing toolbar for alexwlchan.net
A bookmarklet that gives me a just-for-me toolbar to make changes to this site.
SeptembRSE: Missing narratives in discussions around diversity and inclusion
How do you work with non-engineers?
Building a relationship founded on trust and respect.
Beware of incomplete PDF redactions
If you’re not careful when redacting PDFs, it’s possible to share more information than you intended.
READMEs for Open Science
Slides for a short talk about READMEs, why they’re important, and what they should contain.
Prevent accidentally copying the prompt character in console code snippets
When I include console commands in a blog post, I don’t want somebody to accidentally copy the command prompt. CSS lets me avoid that.
The Oboe of Optozorax, and Other Objects
A collection of small worldbuilding ideas about magical objects.
Programatically finding the original filename of a photo in the macOS Photos Library
If you’re looking at a UUID’d file in the PhotosLibrary package, how do you find its original filename?

My favourite books from 2021
Aliens and aces, railroads and racism, dating and disasters – what I enjoyed reading this year.

You should take more screenshots
If you do any sort of creative digital work, screenshots and screen recordings are a great way to remember it.
A tale of two path separators
macOS allows both the slash and colon as path separators, and this caused me no small amount of confusion.
The ever-improving error messages of Rust
An improvement to Rust’s error handling that I almost reported, until I realised it was fixed.
Why is os.sep insufficient for path operations?
Digging into a throwaway comment in the Python documentation.
Creating coloured bookshelf graphics in Rust
Explaining some code that draws coloured rectangles in a way that looks a bit like an upside-down bookshelf.
Creating animated GIFs from fruit and veg
Some Python code for turning MRI scans of fruit and veg into animated GIFs.
Why is Amazon Route 53 named that way?
Digging into the history of Route 53, DNS, and port number assignments.
Closing lots of Safari tabs with JXA
To help me keep my tab count down, I wrote a JXA script to close tabs that can easily be recreated.
A tale of two Twitter cards
Some recent changes I’ve made to fix or improve my Twitter cards.
Beware delays in SQS metric delivery
A mysterious problem with SQS-based autoscaling and an over-eager CloudWatch Alarm.
Checking lots of URLs with curl
A bash script to check the HTTP status code of a bunch of URLs, for simple and portable uptime checking.
Creating a “simple” three-up image layout in CSS
A step-by-step breakdown of how I made a one-left, two-right layout for my images.
Illustrating the cipher wheels of a Lorenz machine
Some old code I wrote to draw cam-accurate illustrations of cipher wheels.
Running a Rust binary in Glitch
Using different targets to build Rust binaries that will run in Glitch.
Find the dominant colours in an image in your web browser
Wrapping my CLI tool for finding dominant colours in a lightweight web app.
Experimenting with jq as a tool for filtering JSON
I wanted to learn jq’s more powerful features, so I tried to filter some JSON from the AWS Secrets Manager CLI.
Creating an Alfred Workflow to open GitHub repos
Automations for my automations.
Fictional phone numbers in For All Mankind
Where did this UK phone number come from?
One small stitch for yarn, one giant leap for yarn-kind
I made a cross-stitch blueprint of the Apollo Moon lander and the Saturn V rocket.
A Martian plaque for a made-up plot
If NASA was the first to land on Mars in For All Mankind, what would the commemorative plaque look like?

Generating art from lattice graphs
Randomly selecting a subset of edge from a graph can make pretty pictures.

The maths cross-stitch that hangs behind me
When I’m on video calls, my backdrop has some maths-related art that I helped to make.
A surprise smattering of stardom
My last post was surprisingly popular; a few reflections on the experience.
Cut the cutesy errors
If your app has just ruined my day, I need help, not humour.
Our Place in Space
You don’t realise how big the solar system is until you’ve walked the length of it.
How to customise the title of Buildkite builds triggered from GitHub deployments
Getting a more descriptive build label than ‘Deployment’.
Drawing a circular arc in an SVG
A Python function to help me draw circular arcs, as part of an upcoming project.
An Egyptian ‘mixtape’ of embroidered material
Repeating geometric patterns make for a colourful and eye-catching piece.
I always want StrictUndefined in Jinja
When I’m writing templates with Jinja, strict behaviour is what I want, even if it’s not the default.
Finding redundant data in our Next.js props
A script that helps us optimise our
__NEXT_DATA__, which in turn helps reduce page size.

"Fixing" the rules of division
If we want to redefine how division works, Ruby is happy to oblige.

Finding a tricky bug in Elasticsearch 8.4.2
Gradually deleting more and more data helped me get a reliable repro for an elusive bug.

A day out at the Bure Valley Railway
My photos from a delightful day on a steam railway with smol trains.

Launching a rocket in the worst possible way
Taking the humble <marquee> tag where no HTML tag has gone before.
My (tiny) contribution to Rust 1.64
A suggestion for a better error message to help people who work in multiple languages.
Some experiments with circle-based art
Casually covering a canvas with coloured circles.
Finding books in nearby library branches
Some web scraping and Python helps me find books that I can borrow immediately.
Agile and iterative project management
Notes from a talk about agile and iterative approaches to project management.
A simple gallery plugin for Obsidian
Making it easier to find all the images in my Obsidian vault.
Saving your alt text from Twitter
Twitter’s archives don’t include the alt text you wrote on images, but you can save a copy with their API.
Ten years of blogging
A decade ago, I registered a domain and started writing.
Changing the macOS accent colour without System Preferences
Updating the accent colour everywhere, with immediate effect, using a script written in Swift.
Redacting sensitive query parameters with koa and koa-logger
Using a custom transporter to modify the log message and remove secret information.

My favourite books from 2022
Romance and rust, gender and grief, horror and the House – what I enjoyed reading this year.

Upward assignment in Ruby
A deep dive into the internals of Ruby and metaprogramming techniques, in a quest for a cursed operator.
How we do bulk analysis of our Prismic content
By downloading all our Prismic documents, we can run validation rules, fix broken links, and find interesting examples.
Getting an Important Internet Checkmark to follow your cursor
Party like it’s 1996! A trailing checkmark cursor will make your Brand Website feel fun and authentic.
A script to get Live Text from images
Using Apple’s built-in tools to get OCR text from an image, but without going through a GUI.

Cats, cross-stitch, and copyright
In celebration of my favourite apex predator.

Writing a Mac app to review my photos
Dipping my toes into SwiftUI to make a tool for reviewing my photos with just the keyboard.
Beware of transparent backgrounds when using AVIF with ImageMagick 6
You probably want to use version 7.
Changing the bulb in a Meridian Lighting CIR100B ceiling light
A note to my future self. Also, reverse image search is amazing.
A bookmarklet to show which responsive image was chosen
Debugging my <picture> and <source> tags.
How moving to the cloud took Wellcome’s digital collections to new heights
Building our own platform allowed us to make decisions based on what’s best for the collections, and not the limitations of our digital infrastructure.
A Python function to iterate through an S3 Bucket Inventory
Getting something that looks more like the output of the ListObjectsV2 API.
Going through my old school papers
Digitising and pruning my boxes of paper from school. In which I have nostalgia, sadness, and the sense that everything old is new again.
CSS formatting in the console
Did you know you can use
%cto format yourconsole.logmessages?Testing JavaScript without a (third-party) framework
The browser can be a pretty good place to run your JavaScript tests.
Splitting a class into balanced groups
How do you make sure everyone gets to work with everyone else?
Creating a Python dictionary with multiple, equivalent keys
Using collections.UserDict, we can create a dictionary where dict[key1] and dict[key2] always point to the same value.
Filtering out bogus requests from Netlify Analytics
Using redirects to filter out bots trying to hack my non-existent PHP installation.
Filtering AWS CLI output by tags using jq
Using
from_entriesis a nicer way to deal with the list of Name/Value pairs returned by the AWS CLI.Publishing lots and lots of messages to SNS
Careful use of the
PublishBatchAPI makes it quick and easy for me to send thousands of messages into SNS.Using templates in Terraform to document a deployment
Terraform can fill in placeholders with exact values from your deployment, for easy copy/paste instructions.
Getting alerts about flaky ECS tasks in Slack
When ECS is "unable to consistently start tasks successfully", we get a Slack alert that tells us to investigate.
Redecorating my bedroom
Splashing some sunshine in the space where I sleep.
s3tree: viewing a tree of objects in S3 in my terminal
A script to give me a quick overview of some objects in a hierarchical view.
Snippets to manage albums in Photos.app
AppleScript only allows us to add photos to an album; dipping into Swift and PhotoKit lets us both add and remove photos.
Starting Docker just before I need it
I don’t keep Docker running all the time, but intercepting the
dockercommand means it’s always running when I need it.Have a single definition of “now”
Having one function that you always use to get the current time is super handy when debugging issues that only occur at specific times.

A blue plaque for Hester
Making a small memorial to a forgotten secretary who helped pull off one of the most daring deceptions of WWII.

Hyperfocus and hobbies
The power of ADHD-associated hyperfocus and how I’ve become wary of feeding it too often.
Preserving Dates during JSON serialisation with vanilla JS
How to make sure you get a
Dateback when you callJSON.parseandJSON.stringify.Turning off ECS tasks overnight using an EventBridge Schedule
Calling the UpdateService API on a fixed schedule allows us to turn services off in the evening, and back on again the next morning.
Spy for Spy
A two-handed sapphic romance with a clever narrative twist makes for a compelling and thoughtful new play.
My custom <picture> plugin for Jekyll
How I make images that load quickly and look good for readers, and which are easy for me to manage.
My Python snippet for walking a file tree
A function to find all the files in a directory is one of my most-used snippets.
Parsing CloudFront logs with Python
A couple of functions I use to get access to CloudFront logs as easy-to-use iterators.
Tag your infrastructure-as-code resources with a link to their definitions
Applying a default tag that points to the IaC definition makes it easy to go from the console to the code.
Finding a mystery IAM access key
Using the GetAccessKeyInfo and GetAccessKeyLastUsed APIs can help us trace an IAM key back to its source.
How I set up my Obsidian vaults
The tags, folders, and themes I use to manage information in my Obsidian vaults.
Fare-Wellcome Collection
After nearly seven years, it’s time for something new.
Adding locations to my photos from my Apple Watch workouts
My Apple Watch knows where I am, which is handy when I have a camera that doesn’t.
Spotting spam in our CloudFront logs
Looking for search queries that came from robots, not real people.
Finding the biggest items in my Photos Library
A quick script to help move the biggest items out of my main Photos Library.

My favourite books from 2023
Storms and schools, escapes and exorcisms, murders and magic – what I enjoyed reading this year.

Making a PDF that’s larger than Germany
We’re gonna need a bigger printer.
Making the fish shell more forgetful
A few commands that help me keep unwanted entries out of my shell’s autocomplete.
Setting up Fish to make virtualenv easier
I wrote some shell config to smooth out the experience of using virtual environments in Python.
Getting the path to the note I have open in Obsidian
Although Obsidian doesn’t support AppleScript, I can use System Events to find out which note I have open.
What mammal is that?
In which Apple Photos accidentally tells me about a cool new animal.
The Collected Works of Ian Flemingo
A fledgling author uses a theatre trip to leave the nest. (Or: some props I made for a cosplay event.)

Drawing repetitive radial artworks
Using polar coordinates to draw leaf- and flower-like patterns that repeat in circles around a point.

emptydir: look for (nearly) empty directories and delete them
I’ve been writing tools in Rust again.
Moving my YouTube Likes from one account to another
Some experimenting with the YouTube API to merge two accounts into one.
Monki Gras 2024: Step… Step… Step…
Swing dancing and prompt engineering are pretty different. But could learning one help us learn the other?
The new Flickr Commons Explorer
A new way to browse the photos in the Flickr Commons programme.
flapi.sh: a tiny command-line tool for exploring the Flickr API
Combining several existing tools to make something that allows for quick experiments and exploration.
The Star-Spangled Ballad
If you listen carefully to the Ballad of Willie Watkins, you might hear another song peeking through.
Getting faster Jekyll builds with caching in plugins
I was able to build my Jekyll site much faster by using the built-in caching API.
Taking regular screenshots of my website
A screenshot a day keeps the bit rot at bay.
What is psephology?
It’s the scientific study of elections and voting, and it comes from the Greek word for "pebble", because pebbles were used for voting in ancient Greece.
What comes after AWS?
Whatever displaces public cloud as the default model for large-scale computing has to be more than “AWS, but 3% better”.
Creating a Safari webarchive from the command line
We can use the
createWebArchiveDatamethod onWKWebViewto write a Swift script that creates Safari webarchive files.Preserving pixels in Paris
I went to France for a conference about archiving the web, and I came back with thoughts and photos.
Documenting my DNS records
Exporting my DNS records as YAML gives me a plaintext file where I can track changes, add comments, and feel more confident about managing my DNS.
The surprising utility of a Flickr URL parser
I made a library that knows how to read lots of different forms of Flickr.com URL, and I used
hyperlinkto do it.Improving millions of files on Wikimedia Commons with Flickypedia Backfillr Bot
The new bot improves metadata for Flickr photos on Wikimedia Commons, and makes it easier to find out which photos have been copied across.

Doodling with the Mac’s command icon
Rotating a looped hook around a central point creates a surprising variety of shapes.

Plates and states
On a recent trip to the US, I learnt a surprising amount from watching the license plates on passing cars.

create_thumbnail: create smaller versions of images
I’ve made a new tool that allows me to reuse my thumbnailing code across all my projects.

Mountaintop moments
The amazing events that let us temporarily escape from our lives, and how to deal with the emotional crash that comes afterward.

Digital decluttering
I’m resisting my temptation towards digital hoarding and "save everything", and trying to be more selective about the data I’m keeping.

Using static websites for tiny archives
I’ve been creating small, hand-written websites to organise my files. It’s a lightweight, flexible approach that I hope will last a long time.
Google is showing outdated results from the UK’s election
Dozens of MPs who were re-elected to their seats are still labelled “former Member of Parliament”, days after the election results.
Going between Finder and the Terminal
A few shell scripts I use to go between the Finder and the Terminal.
Drawing a better bandwidth graph for Netlify
A two-part pie chart lets me see how much bandwidth I’ve used this month, and whether I’m on track to exceed my bandwidth allowance.
Two examples of hover styles on images
When I hover over an image, I can add a border to a link, or change the colours of an SVG icon.
Putting history on the map
Antarctic explorers, northern factories, and Hawaiian industry – I wrote about some of the photos I found using the interactive map in the Flickr Commons Explorer.
Flickr Foundation at iPres 2024
In September, I went to Belgium for a digital preservation conference. I wrote about what I learnt and what I saw for the Flickr.org blog.
Making alt text more visible
I wrote a JavaScript snippet that shows alt text below all of my images, so I can see when it’s missing, and review it while I’m editing.

How I name my computers
What do flaming birds, man-eating giants, and obscure deities have in common?

Not all blog posts are created equal
Splitting my site into "articles" and "today I learned" helped me overcome writer’s block and improve my writing.

My favourite books from 2024
Fires and fighters, heroes and horrors, suicide and surgery – what I enjoyed reading this year.

Unexpected errors in the BagIt area
Exploring the many ways a BagIt bag can be invalid, and how you might want to build a process for validating bags to ensure the quality of your digital archive.
A script to verify my Netlify redirects
I wrote a script that reads my redirect rules, and checks that every redirect takes you to a page that actually exists on my site.
Moving my website from Netlify to Caddy
To avoid getting stung by Netlify’s bandwidth charges, I moved this site to a Linux server running Caddy as my web server.
I deleted all my tweets
I used TweetDeleter to delete about 35,000 tweets, and cut my remaining ties to the site formerly known as Twitter.
How I use the notes field in my password manager
I use notes as a mini-changelog to track the context and history of my online accounts. I write down why I created accounts, made changes, or chose particular settings.
How I test Rust command-line apps with
assert_cmdSome practical examples of how this handy crate lets me write clear, readable tests.
randline: get a random selection of lines in a file using reservoir sampling
I wrote a tiny Rust tool to get random samples in a memory-efficient way, and I learnt a lot while doing it.
Looking at images in a spreadsheet
The
IMAGEandHYPERLINKfunctions allow me to use a spreadsheet as a lightweight, collaborative space for dealing with images.Adding auto-generated cover images to EPUBs downloaded from AO3
I built a handy tool to generate cover images for stories downloaded from AO3, making them easier to browse. Along the way, I learnt about how EPUBs work, the power of static sites, and some gotchas of async JavaScript.
Making inventory spreadsheets for my LEGO sets
Using the Rebrickable database downloads and sqlite-utils, I can quickly create spreadsheets that let me tick off the parts in each set.

How I create static websites for tiny archives
Start with a simple HTML file, then add features like templates, sorting, and filtering as they become useful.

It’s cool to care
Caring deeply – about art, my friends, and shared experiences – has brought me so much joy.

What I’ve Learned by Building to Last
There are patterns in what lasts; people skills matter more than technical skills; long-lasting systems cannot grow forever.

Always running
When the fire starts, I am already running for the exit. I run because somebody must show the way.
Good embedded toots
I replaced Mastodon’s native post embeds with lightweight HTML and CSS snippets that are faster to load, more resilient to outages, and support dark mode – and I had fun doing it.
Cosmetic updates to this site
I’ve simplified the palette, changed the font, and given several elements a more consistent visual appearance.
Creating static map images with OpenStreetMap, Web Mercator, and Pillow
I made some simple map visualisations by downloading tiles from OpenStreetMap, then annotating the tiles with Pillow.
An unexpected lesson in CSS stacking contexts
While trying to add some simple overlay labels, I stumbled into a sharp edge of a complex CSS feature called "stacking contexts".
We all lose when art is anonymised
When art loses its creator, we lose the story behind the image – a plea for attribution in our endless scroll culture.
Fast and random sampling in SQLite
I tested four approaches, from
ORDER BY RANDOM()to picking randomrowidvalues in Python, and found one that’s both fast and diverse.Whose code am I running in GitHub Actions?
I wanted to know what third-party code I was using in my GitHub Actions. I was able to use standard text processing tools and shell pipelines to get a quick tally.

Creating a static website for all my bookmarks
To help me keep track of interesting links, I created a static website that keeps all my data locally. Why do I care about bookmarks, and how does my new site work?

Building a personal archive of the web, the slow way
How I built a web archive by hand, the tradeoffs between manual and automated archiving, and what I learnt about preserving the web.
Localising the
<time>with JavaScriptI’m using the
<time>element and some JavaScript to display timestamps as human-readable, localised timestamps. Something likeTue, 15 Apr 2025 at 20:45 BSTis easier to read than2025-04-15T19:45:00Z.Beyond
None: actionable error messages forkeyring.get_password()I have a wrapper for
get_password()so that if it can’t find a password, you get an error that explains how to set the password, and what password you should choose.A flash of light in the darkness
If you’re using an image as your background, remember to set a fallback colour as well, especially if you’re in dark mode.
A faster way to copy SQLite databases between computers
Dumping a SQLite database to a text file can make it much smaller, which means you can download it faster.
Handling JSON objects with duplicate names in Python
It’s possible, although uncommon, for a JSON object to contain the same name multiple times. Here are some ways to handle that in Python.

What I learnt about making websites by reading two thousand web pages
How to write thoughtful HTML, new-to-me features of CSS, and some quirks and relics I found while building my personal web archive.

Recreating the bird animation from Swift.org
The Swift.org website got a redesign, including an animation of a swooping bird, and I read the source code to understand how it works.

Using vcrpy to test HTTP interactions in Python
How I record HTTP requests to get fast, reliable, and consistent tests, and the patterns I use in a production codebase.

The Internet forgets, but I don’t want to
I don’t trust platforms to preserve my memories, so I built my own scrapbook of social media.
My favourite websites from my bookmark collection
Websites that change randomly, that mirror the real world, or even follow the moon and the sun, plus my all-time favourite website design.
Moving my Glitch apps to my own web server
I’ve moved almost all of my Glitch apps to websites running on my own web server, on this domain.
Minifying HTML on my Jekyll website
I compare three different approaches to minifying HTML.
Today was my last day at the Flickr Foundation
I already have a new job lined up, but I’m taking a bit of a break first.
Slipstitch, Queer Craft, and community spaces
Remembering Slipstitch, a queer-friendly yarn shop and the fortnightly crafting meet-ups that were a highlight of my week.
Create space-saving clones on macOS with Python
You can shell out to
cp -cusingsubprocess, or you can make aclonefile()syscall using thectypeslibrary.Resizing images in Rust, now with EXIF orientation support
A new version of Rust’s image crate has support for EXIF orientation, which allows me to resize images without mangling their rotation.
Linking to text fragments with a bookmarklet
I’ve written a bookmarklet that helps me link to specific text on a web page.
Opening all the files that have been modified in a Git branch
You can use Git to find where a branch diverged from
main, what files have changed, then open those files in your editor.Creating a personal wrapper around yt-dlp
I’ve written a new script which calls yt-dlp with my preferred options, so I don’t have to copy my configuration across different projects.
Doing my own syntax highlighting (finally)
I’ve redesigned my syntax highlighting scheme to use a smaller colour palette. Here’s what I’ve changed, how it works, and why I think it’s better.
Why can’t my iPhone play that video?
The answer involves the AV1 video codec, Apple’s chips, and several new web APIs I learnt along the way.
Detecting AV1-encoded videos with Python
I wrote a Python test to find videos that are encoded with AV1, so I can convert them to a codec my iPhone can play.
Cleaning up messy dates in JSON
I wrote a Python script to help me get timestamps in a consistent format in my JSON.
Can you take an ox to Oxford?
Let’s work out exactly when you need to pay Oxford’s new congestion charge.
When square pixels aren’t square
When you want to get the dimensions of a video file, you probably want the display aspect ratio. Using the dimensions of a stored frame may result in a stretched or squashed video.

Hard problems in social media archiving
Preserving social media is easier said than done. What makes it so difficult for institutions to back up the Internet?

Meeting my younger self
I reviewed 150,000 fragments of my online life, and I was reminded of the friends I found, the mistakes I made, and the growth I gained.

My favourite books from 2025
Sapphics and spies, butlers and basketball, prophecy and purpose – what I enjoyed reading this year.

The Good, the Bad, and the Gutters
A step-by-step guide to a movie poster grid that uses CSS Grid, text-wrap balanced titles, and dynamic hover states.
The palm tree that led to Palmyra
Palmyrene is an alphabet that was used to write Aramaic in 300–100 BCE, and I learnt about it while looking for a palm tree emoji.
Adding a README to S3 buckets with Terraform
If you create an S3 bucket in Terraform, you can also create a README to help a future sysadmin understand what the bucket is for.
Drawing Truchet tiles in SVG
Using parametric templates to draw Truchet tiles, then placing them randomly to create generative patterns.
Quick-and-dirty print debugging in Go
I wrote a Go module to help with my print debugging, which logs expressions and values to a separate file.
Where I store my multi-factor recovery codes
Most services give you MFA recovery codes but don’t tell you where to store them. I use an encrypted disk image and a simple HTML file.
The passwords I actually memorise
Password managers promise you only need to remember one password, but I keep eight of them in my head to avoid a single point of failure.
Using perceptual distance to create better headers
I started picking colours for my site headers with a more perceptually uniform approach, so their colours look more correct to the human eye.
Parody posters for made-up movies
I rented movies from Blockbuster, HBO Max-Width and Netflex.