All posts

This is every post I’ve ever written, organised by category. You can subscribe to my posts as an Atom feed. Enjoy!

Most recent 10 posts

27 May Getting every item from a DynamoDB table with Python
24 May Showing human-friendly dates in JavaScript
17 May The Sachsenhausen concentration camp
16 May Moving messages between SQS queues
15 May Downloading the AO3 fics that I’ve saved in Pinboard
14 May Letter to my MP about Liz Truss and medical treatment for trans youth
13 May Social media as a growth culture for opinions
12 May Taking tuple unpacking to terrible places
11 May Red heart The friends I lost along the way
10 May Make it safe to admit mistakes


Amazon Web Services

May 2020 Getting every item from a DynamoDB table with Python
May 2020 Moving messages between SQS queues
May 2020 Illustrating lifecycle transitions in Amazon S3
Apr 2020 Using DynamoDB as a calculator
Mar 2020 Finding the size and cost of each of your S3 buckets
Jan 2020 A deletion canary: testing your S3 bucket permissions
Jan 2020 Finding the CPU and memory bottlenecks in an ECS cluster
Nov 2019 An AWS costs graph that works for me
Sep 2019 Streaming large objects from S3 with ranged GET requests
Jul 2019 Listing even more keys in an S3 bucket with Python
Feb 2019 Red heart Working with really large objects in S3
Dec 2018 Getting credentials for an assumed IAM Role
Nov 2018 Finding SNS topics without any subscriptions
Sep 2018 A basic error logger for Python Lambdas
Aug 2018 Red heart Implementing parallel scan in DynamoDB with Scanamo
Apr 2018 Two shortcuts for using S3 in the shell
Jan 2018 Red heart Getting every message in an SQS queue
Jan 2018 Listing keys in an S3 bucket with Python, redux
Nov 2017 Red heart Downloading logs from Amazon CloudWatch
Jul 2017 Listing keys in an S3 bucket with Python

Blogging about blogging

Apr 2020 Getting word count stats for my blog
Mar 2020 A Jekyll filter for adding non-breaking spaces
Jun 2019 A Jekyll filter for obfuscating email addresses
Feb 2019 Checking Jekyll sites with HTMLProofer
Oct 2017 What happens when you overengineer a static site?
May 2016 Finding 404s and broken pages in my Apache logs
Dec 2014 RSS linkposts in Pelican
Sep 2014 Playing with 404 pages

Build automation and build systems

Mar 2019 Red heart Creating a GitHub Action to auto-merge pull requests
Aug 2018 Finding slow builds in Travis
Aug 2018 Selective sudo on Travis
Mar 2018 The Hypothesis continuous release process
Dec 2017 Your repo should be easy to build, and how

Digital preservation

Feb 2020 Storing multiple, human-readable versions of BagIt bags
Feb 2020 Red heart Building Wellcome Collection’s new archival storage service
Oct 2019 Digital preservation at Wellcome Collection

Diversity, inclusion and accessibility

Mar 2020 Inclusion can’t be an afterthought
Feb 2020 Red heart A remote-controlled oven is a safety nightmare
Oct 2019 Adding religious holidays to my calendar
Jul 2019 Section 28, and LGBTQ+ people in UK schools
Jun 2019 Red heart An inescapable conclusion
Jun 2019 Hey Apple, cycle tracking isn’t just for women
May 2019 Red heart Questions to ask when writing a trans inclusion policy
Feb 2019 Red heart More advice on running inclusive and welcoming events
Oct 2018 Open consultation on the Gender Recognition Act
Sep 2018 Content warnings
Aug 2018 Red heart Ideas for inclusive conferences and events
Nov 2017 How I ask about gender
Oct 2017 NPR: Graduation Readers At MIT Go The Extra Mile To Pronounce Names Correctly
Apr 2017 Accessibility at AlterConf
Feb 2016 How I use TextExpander to curb my language


Mar 2018 Notes on A Plumber’s Guide to Git
Nov 2017 Pruning old Git branches
Nov 2017 Red heart A plumber’s guide to Git
Sep 2017 Some useful Git commands for CI
Jun 2015 Useful Git features: a per-clone exclude file

Glitch apps

May 2020 How long is my data? 💾
Jan 2020 An interactive map of British railway stations 🚂
Jan 2020 Generating pride-themed Norse valknuts with Python 🌈


Jan 2020 A Docker image to run LaTeX
Oct 2017 Red heart Four ways to underline text in LaTeX


Apr 2020 Red heart Storing language vocabulary as a graph
Jul 2019 Ten braille facts / ⠼⠁⠚⠀⠃⠗⠁⠊⠇⠇⠑⠀⠋⠁⠉⠞⠎
Jun 2019 Red heart Reading a Chinese dictionary / 读一本中文字典

Organising PyCon UK

Sep 2018 Signs of the time
Sep 2018 PyCon UK 2018
Aug 2018 Making the venue maps for PyCon UK
Oct 2017 Lightning talks
Sep 2016 Silence is golden
Sep 2016 Live captioning at conferences


May 2020 Red heart The friends I lost along the way
Apr 2020 Red heart Adventures in euphoria and embodiment


Mar 2019 Red heart A day out to the Forth Bridge
Nov 2018 Red heart My visit to the Aberdulais Falls
Jun 2017 Red heart A visit to the Crossness pumping station


May 2020 Letter to my MP about Liz Truss and medical treatment for trans youth


Mar 2020 Sick leave while working from home

Programming and code

May 2020 Showing human-friendly dates in JavaScript
Apr 2020 Exploring an unknown SQL server
Dec 2019 This YAML file will self-destruct in five seconds!
Dec 2019 Some useful spreadsheet functions: FORMULATEXT, MATCH, CONCATENATE and INDIRECT
May 2019 Falsehoods programmers believe about Unix time
Apr 2019 Getting a transcript of a talk from YouTube
Dec 2018 A script for backing up Tumblr posts and likes
Aug 2018 Avoiding the automatic redirect on Tumblr posts
Jul 2018 Red heart A robot leaked my SSH keys
Jul 2017 Backing up full-page archives from Pinboard
Jul 2017 Backing up content from SoundCloud
Feb 2017 A script for backing up your Instapaper bookmarks
Feb 2017 A script for backing up your Goodreads reviews
Dec 2016 A tool for backing up your message history from Slack
Jun 2016 Reading web pages on my Kindle
Apr 2016 Hiding the YouTube search bar
Apr 2016 Red heart Treat regular expressions as code, not magic
Nov 2015 Backups and Docker
Aug 2015 Finding even more untagged posts on Tumblr
May 2015 Cloning GitHub’s Contributions chart
May 2015 Previewing notes from nvALT in Marked
Mar 2015 Pygmentizr
Feb 2015 Adding checkboxes to lists
Feb 2015 Swift 1.2 improves the “let” keyword, and other improvements
Dec 2014 A script for exporting from iMessage
Nov 2014 Unpacking sets and ranges from a single string
Oct 2014 Notes on Tumblr
Aug 2014 Updates to my site for finding untagged Tumblr posts
Aug 2014 A TextExpander snippet for Amazon affiliate links
Aug 2014 A quick Alfred workflow for opening recent screenshots
Jul 2014 Getting plaintext LaTeX from Wolfram Alpha
Jun 2014 Finding untagged posts on Tumblr, redux
Aug 2013 Cleaning up Google Maps
Aug 2013 Finding untagged posts on Tumblr


May 2020 Downloading the AO3 fics that I’ve saved in Pinboard
May 2020 Taking tuple unpacking to terrible places
Apr 2020 A snippet for downloading files with Python
Mar 2020 Creating striped flag wallpapers with Pillow
Dec 2019 November 2019 scripts: downloading podcasts, retrying flaky errors, Azure and AWS
Nov 2019 Saving a copy of a tweet by typing ;twurl
Oct 2019 Red heart Adventures in Python with concurrent.futures
Oct 2019 The rough edges of filecmp
Sep 2019 Experiment: GitHub code search with de-duplication
Sep 2019 Red heart Drawing with triangular coordinates in SVG
Aug 2019 Red heart Getting a tint colour from an image with Python and k-means
Aug 2019 Removing the DRM from my Kindle books
Jul 2019 Finding divisors of a number with Python
Jul 2019 Creating preview thumbnails of PDF documents
Jun 2019 A script for getting cover images from mobi ebooks
Apr 2019 Reversing a URL to the original tweet
Mar 2019 Atomic, cross-filesystem moves in Python
Dec 2018 Notes on reading a UTF-8 encoded CSV in Python
Dec 2018 Iterating in fixed-size chunks in Python
May 2018 Red heart Drawing ASCII bar charts
May 2018 Red heart Beware of logged errors from subprocess
Oct 2017 Using hooks for custom behaviour in requests
Oct 2017 Using pip-tools to manage my Python dependencies
Sep 2017 A Python module for lazy reading of file objects
Mar 2017 Red heart A few examples of extensions in Python-Markdown
Jan 2017 A Python interface to AO3
Jan 2017 Experiments with AO3 and Python
Nov 2016 Use keyring to store your credentials
Oct 2016 Red heart Creating low contrast wallpapers with Pillow
Oct 2016 Red heart Tiling the plane with Pillow
Oct 2016 Why I use py.test
Aug 2016 Python snippet: dealing with query strings in URLs
Aug 2016 Python snippets: Is a URL from a Tumblr post?
Aug 2016 Python snippets: Cleaning up empty/nearly empty directories
Jul 2016 Python snippets: Chasing redirects and URL shorteners
May 2016 A Python smtplib wrapper for FastMail
Mar 2016 Exclusively create a file in Python 3
Nov 2015 Python and the BBC micro:bit
Jun 2015 Persistent IPython notebooks in Windows
Jun 2015 Safer file copying in Python
Mar 2015 Adding Python to the OS X firewall
Feb 2015 A Flask app for taking notes


Apr 2020 Comparing JSON strings when testing in Scala
Sep 2019 Iterating over the entries of a compressed archive (tar.gz) in Scala
May 2019 Red heart Creating a locking service in a Scala type class
Oct 2018 Custom 404 responses in Finatra

Shell scripting

Oct 2016 A shell alias for tallying data
May 2016 Safely deleting a file called ‘-rf *’
Dec 2015 Pretty printing JSON and XML in the shell
Nov 2015 Quick shell access for Docker containers
Jul 2015 Useful Bash features: exit traps


Oct 2019 Red heart Sans I/O programming: what, why and how (PyCon UK talk)
Sep 2019 Slides for PyCon UK 2019 “Sans I/O programming”
Jan 2019 Red heart Monki Gras 2019: The Curb Cut Effect
Sep 2018 Red heart Assume worst intent (designing against the abusive ex)
Sep 2018 Building trust in an age of suspicious minds
Apr 2018 (Anti) Social Media
Nov 2017 Using privilege to improve inclusion
Oct 2017 PyCon UK 2017 resources
Sep 2017 Ode to docopt
Jun 2016 Red heart Introduction to property-based testing


Nov 2019 Preparing for Terraform 0.12: fixing module sources
May 2019 Finding unused variables in a Terraform module
Jan 2019 Debugging a stuck Terraform plan

Working with macOS

Jan 2020 Excluding lots of folders in Backblaze
Jun 2019 Converting Acorn images on the command-line
Mar 2019 Finding the latest screenshot in macOS Mojave
Jul 2016 Clearing disk space on OS X
May 2016 “The document could not be saved”
Mar 2016 Get images from the iTunes/App/Mac App Stores with Alfred
Nov 2015 Export a list of URLs from Safari Reading List
May 2015 One-step paste in the iOS Simulator
Jun 2014 Catching instapaper:// URLs from ReadKit


May 2020 The Sachsenhausen concentration camp
May 2020 Social media as a growth culture for opinions
May 2020 Make it safe to admit mistakes
May 2020 Give your audience time to react
Apr 2020 Thinking about your gender
Apr 2020 Complex systems have complex failures
Apr 2020 Look out for survivor’s guilt
Apr 2020 Red heart Access to information is a privilege
Mar 2020 Rich enough to make bad choices
Feb 2020 Adjusting the dominant colour of an image
Nov 2019 Red heart How I scan and organise my paperwork
Apr 2019 Some tips for conferences
Apr 2019 How I back up my computing devices, 2019 edition
Jan 2019 Notes from You Got This 2019
Jan 2019 How much sunlight affects my mood levels
Jan 2019 Thoughts on privacy and Oyster cards
Jan 2019 A delightful store for speciality spreads: Paul Rothe & Sons
Nov 2018 Keeping track of my book recommendations
Oct 2018 How do you hide a coin for 400 years?
Oct 2018 How to set the clock on a Horstmann Electronic 7 water heater
Aug 2018 Do Not Distract while driving
Jul 2018 Moving my calendars from iCloud to FastMail
Jul 2018 A tip for travel instructions
Jul 2018 My favourite iMac accessory
May 2018 A brief thought on Google Duplex
Apr 2018 24 hours or bust
Mar 2018 Keep an overnight bag in the office
Feb 2018 A working from home experiment
Jan 2018 IP and DNS addresses for documentation
Dec 2017 Armed police officers don’t make me feel safer
Nov 2017 My favourite WITCH story
Nov 2017 Don’t tap the mic, and other tips for speakers
Oct 2017 Displaying tweets in Keynote
Oct 2017 Control Centre: one step forward, two steps back
Dec 2016 Another example of why strings are terrible
Nov 2016 Some low-tech ways to get more ideas
Oct 2016 Red heart The A stands for Asexual
Sep 2016 My travelling tech bag
Sep 2016 aspell, a command-line spell checker
Jun 2016 A subscription for my toothbrush
Mar 2016 Backup paranoia
Feb 2016 Saved by the Prompt
Jan 2016 The Harry Potter Collector’s iPod
Jan 2016 The Skeletor clip loop, 2015 edition
Jan 2016 A cautionary tale about Fusion Drive repairs
Dec 2015 Simpler syndication, by Dr. Drang
Nov 2015 Email with a purpose
Sep 2015 What does “Spotlight Suggestions” turn off?
Sep 2015 Apple quietly adopts HTTP/2
Sep 2015 Review: Effective Python
Mar 2015 Some exam advice
Feb 2015 Tidying up my 1Password
Dec 2014 Kitchen sink security
Dec 2014 Acronyms
Dec 2014 Skeletors All the Way Down
Dec 2014 Lukas Mathis on iOS CarPlay and Android Auto
Oct 2014 “Missing argument at index 2” in fish
Sep 2014 My new standing desk
Jul 2014 Thoughts on Overcast
Jun 2014 Skeletor!
Jun 2014 Some site updates
May 2014 Some Part IA exam advice
May 2014 Brief advice for Part II
Apr 2014 Pulling back the veil
Nov 2013 TextMate 2 and Quick Look
May 2013 Podcast feeds on Tumblr
Mar 2013 Automatic Pinboard backups
Mar 2013 Strange clock bug in OS X
Mar 2013 Candybar and icon recommendations
Feb 2013 Darwin, pancakes and birthdays
Jan 2013 Zero
Dec 2012 Hypercritical