All articles

2024

Mini-rust in Rust 008: Refactoring our parser -

Mini-rust in Rust 007: Evaluating an operation -

Mini-rust in Rust 006: Parsing an operation -

Message order in Matrix: right now, we are deliberately inconsistent -

Mini-rust in Rust 005: Making our lexer an iterator -

Mini-rust in Rust 004: Refactoring our lexer -

Mini-rust in Rust 003: Much prettier errors -

Mini-rust in Rust 002: Errors while lexing -

Mini-rust in Rust 001: Lexing an int -

Rust 101 - 53: Exercises for module G (q4) -

Rust 101 - 52: Exercises for module G (q3) -

Rust 101 - 51: Exercises for module G (q2) -

Rust 101 - 50: Exercises for module G (q1) -

Rust 101 - 49: Foreign function interfaces (interacting with other languages) -

19 years of blogging -

Deployment is important -

Rust 101 - 48: Exercises for module F (q3) -

Rust 101 - 47: Exercises for module F (q2) -

Heads-up: moving away from WordPress -

Rust 101 - 46: Exercises for module F (q1) -

Rust 101 - 45: Unsafe types and examples -

Rust 101 - 44: Undefined behaviour -

Rust 101 - 43: The two meanings of "unsafe" in Rust -

Rust 101 - 42: Why do we need unsafe? -

Rust 101 - 41: Exercises for module E (q2b) -

Rust 101 - 40: Exercises for module E (q2a) -

Rust 101 - 39: Exercises for module E (q1b) -

Rust 101 - 38: Exercises for module E (q1a) -

Rust 101 - 37: Async runtimes -

Rust 101 - 36: What async and await really do -

Rust 101 - 35: Futures -

Rust 101 - 34: What is async? -

Rust 101 - 33: Exercises for module D (q3) -

Elected to the Matrix Foundation Governing Board! -

Rust 101 - 32: Exercises for module D (q2) -

Rust 101 - 31: Exercises for module D (q1) -

Rust 101 - 30: Good patterns and not so good -

Rust 101 - 29: Trait objects and object safety -

Rust 101 - 28: Dynamic dispatch -

New home for my videos: video.infosec.exchange -

Why I won't link to AI resources -

Rust 101 - 27: Exercises for module C (q2) -

Rust 101 - 26: Exercises for module C (q1) -

Choosing who to vote for in the 2024 UK General Election -

Rust 101 - 25: Threads, Mutexes, channels, Send and Sync -

Rust 101 - 24: Parallelism and Rayon -

Rust 101 - 23 Exercises for module B (q3) -

Rust 101 - 22 Exercises for module B (q2) -

Rust 101 - 21 Exercises for module B (q1) -

Rust 101 - 20: Unit, integration and benchmark tests -

Standing for the Matrix Governing Board -

Rust 101 - 19: Creating a nice API -

Rust 101 - 18: Dependencies and Cargo.toml -

Rust 101 - 17: Exercises for module A3 (part 2) -

Automated backups from Signal to Nextcloud -

Rust 101 - 16: Exercises for module A3 (part 1) -

One import per line is best -

Rust 101 - 15: Lifetime bounds -

Rust 101 - 14: Some standard library traits -

Rust 101 - 13: Type Parameters and Associated Types -

Rust 101 - 12: Traits -

Rust 101 - 11: Exercises for module A2 -

[Fixed in FF 123] Deleting an Indexed DB store can be incredibly slow on Firefox -

Don't store normal arrays of numbers in Indexed DB - use UInt8Array instead -

Rust 101 - 10: Strings -

Keep your Indexed DB keys and values small if you want good performance! -

Rust 101 - 9: Vecs, Boxes and slices -

Rust 101 - 8: Writing methods using impl blocks -

Rust 101 - 7: Error handling with panic and Result -

2023

Letter to my MP: using starvation as a weapon -

Santa Circles 0.3 is out! -

Follow this blog on the fediverse! -

Rust 101 - 6: Structs and Enums -

Rust 101 - 5: References -

Rust 101 - 4: Exercises for module A1 -

Rust 101 - 3: Memory and ownership -

Rust 101 - 2: Language basics -

Rust 101 - 1: Course intro -

Combining two function types with & (ampersand) in TypeScript (intersection) -

Accessing services on the host from a Docker container or a Podman one -

Why I'm voting tactically against you - letter to my Conservative MP -

Rust WASM hello world - no need for webpack! -

Estimating software tasks and stories: avoid time-based estimates -

Maths: The Fun Parts - Graphs video -

Maths: The Fun Parts - Groups video -

Maths: The Fun Parts - Sets video -

GitHub API GraphQL snippets -

Live code reviews make life better -

2022

Air-Source Heat Pump - 1 year later -

Deleted my Twitter account -

IETF115 Trip Report (Can Matrix help messaging standardisation through MIMI?) -

Setting the text selection in a browser: just use setBaseAndExtent -

Tips for contenteditables -

Outreachy August 2022 update -

Transcoding video files for playback in a browser -

Matrix is a Distributed Real-time Database Video -

Building cross-platform Rust for Web, Android and iOS - a minimal example -

Deporting desperate people from the UK -

Improving my vimrc live on stream -

Comparison of Matrix events before and after "Extensible Events" -

Air-Source Heat Pump - our experience so far, 2 months in -

2021

Providing MapLibre-compatible style JSON from openstreetmap-tile-server -

Self-hosting maps on my laptop -

Streaming to Twitch and PeerTube simultaneously using nginx on Oracle cloud -

New game: Tron - frantic multiplayer retro action -

Preventing Virgin Media hijacking my DNS -

Letter to my MP about climate emergency -

New Job at Element (Matrix) -

What to cache when building Rust using Gitlab CI or similar -

Printing the version of a Maven project -

Minimal example of a Maven pom for a mixed Kotlin and Java project -

Importing/migrating from one peertube server to another -

Why write an entire game (including Graphics) in a single, hand-coded JavaScript file? -

Matrix is the only (chat) game in town -

Writing Snake in Terraform Video -

Suspending the computer using Kupfer -

Uploading to PeerTube from the command line -

Republishing Bartosz Milewski's Category Theory lectures -

Announcing I-DUNNO 1.0 and web-i-dunno -

Automatically filling in the UK COVID test results page with Selenium IDE -

Toggle window decorations on Linux GTK3 with Python3 -

Questions about RFC 8771 -

Announcing Rust I-DUNNO -

Letter to my MP on Yemen -

Making Smolpxl work on phones and tablets -

Limiting the number of open sockets in a tokio-based TCP listener -

Recommendation against the use of WhatsApp in your company -

Streaming video with Owncast on a free Oracle Cloud computer -

Pinephone update -

Is your program a function or a service? -

2020

Shutdown order consistency: how Rust helps -

Edge computing providers -

Schema upgrades should be reversible (also other transformations, actually) -

Make levels for Rabbit Escape using the level editor! -

Announcing Smolpxl Scores - a high score table for your game -

Dovecot not working after upgrade to Ubuntu 20.04.1 (dh key too small) -

Letter to my MP on the overseas aid budget. -

Profile a Java unit test (very quickly, with no external tools) -

Why a Free Software web games site? -

Code your first game: Snake in JavaScript (on Raspberry Pi) -

Play and create little retro games at Smolpxl -

shareon.js.org now has a Share to Mastodon button -

Coding a tiny game in JavaScript video -

short - command line tool to truncate lines to fit in the terminal -

Set the date (EXIF) of a photo on Linux -

How to send an SMS using netcat (via SMPP) -

Letter to my MP on racism in the US and UK -

Example Android project with repeatable tests running inside an emulator -

Creating a tiny Docker image of a Rust project -

Keeping track of podcast times with a simple bash script on Linux -

Custom Bash tab completion for my program -

Struggling with Rust to figure out the right types for a function signature -

React Concepts Video -

Converting HTML slides to a PDF with Firefox -

Support the Software Freedom Conservancy -

2019

KotlinJS: First impressions (formed by writing Snake) video -

Dependency Injection frameworks: reasons to avoid them video -

Coding workshop example worksheets -

Building an all-in-one Jar in Gradle with the Kotlin DSL -

Creating a self-signed certificate for Apache and connecting to it from Java -

ACCU Talk "How Kotlin makes your Java code better" -

ACCU Talk "How Git really works" -

Examples of Kotlin making your Java code better video -

What is a Monad? Video -

Build with a different Java version (e.g. 11) using Docker -

Rabbit Escape t-shirts -

Scheduling a task in Java within a CompletableFuture -

Rabbit Escape 0.12 out now, with water -

Convert a video to a GIF with reasonable colours -

Gradle: what is a task, and how can I make a task depend on another task? -

Python Async basics video (100 million HTTP requests) -

Keybase chat bot in 10 lines of bash -

Performance of Java 2D drawing operations (part 3: image opacity) -

Performance of Java 2D drawing operations (part 2: images) -

Performance of Java 2D drawing operations (part 1: types of operation) -

London Python Meetup January 2019 - Async Python and GeoPandas -

Run bash inside any version of Linux using Docker -

Windows missing from grub menu after Ubuntu install -

2018

New home page design -

Code Like a Girl T-shirts -

Poor performance in Chrome (especially on mobile) - caused by SVG background images -

Interesting Characters (UTF-16, utf-8, Unicode, encodings) video -

Elm makes me happy (updated for Elm 0.19) video -

Godot: make new objects at runtime (instancing) video -

You must rewind your incoming buffer when you fail to encode a character in a CharsetEncoder or you'll get an IllegalArgumentException -

Godot: Dragging and dropping physics objects video -

Godot: 2D shapes bouncing off each other video -

Elm JSON decoder examples -

Graft Animation Language on Raspberry Pi -

Worksheet: "Tell a story by making animations with code" -

My experience upgrading to Elm 0.19 -

Bulk adding items to Wunderlist using wunderline on Ubuntu MATE -

Writing a new Flarum extension on Ubuntu -

Ubuntu "compose" key for easy unicode character input -

Redirecting all requests to https and www using .htaccess in Apache -

Example of a systemd service file -

Installing Flarum on Ubuntu 18.04 -

Rabbit Escape 0.11 out now! -

Migrating videos from YouTube to PeerTube inside a Docker container -

How to write a programming language articles -

Allow drag-to-side, but not drag-to-top in Ubuntu MATE (Marco) -

Connecting to Slack from an IRC client using slirc -

Using Matrix to connect to Slack from an IRC client on Ubuntu -

Clever Things People Do In Groovy So You Have To Know About Them video -

Examples of SQL join types (LEFT JOIN, INNER JOIN etc.) -

Fixing Slack emojis in HexChat -

Ideas on how lexing will work in Pepper3 -

Deleting commits from the git history -

Questions and answers about Pepper3 -

Examples of Pepper3 code -

Recording gameplay videos on RetroPie -

2017

TECH(K)NOW Day workshop on "Writing a programming language" -

FileZilla with proxy not working with strange characters in the password -

HTML5 CSS Toolbar + zoomable workspace that is mobile-friendly and adaptive -

maven-assembly-plugin descriptor for a simple tarball with dependencies -

Blog aggregator/planet in WordPress using FeedWordPress -

Adding a day in Python datetimes - use timedelta, not the datetime constructor -

Broken Levels Challenge - Egham Raspberry Pi Jam July 2017 -

Women Who Code workshop on "Write your own programming language" -

Running a virtualenv with a custom-built Python -

Adding a concurrency limit to Python's asyncio.as_completed -

"git what" is "git status" on steroids -

Making 100 million requests with Python aiohttp -

Python - printing UTC dates in ISO8601 format with time zone -

Python 3 - large numbers of tasks with limited concurrency -

Basic ideas of Python 3 asyncio concurrency -

C++ iterator wrapping a stream not 1-1 -

How to write a programming language ACCU talk -

C++ iterator wrapper/adaptor example -

C++ iterator example (and an iterable range) -

Make Android Gradle display unit test failure messages -

Planet Code updates -

A story about magic and how we treat each other -

Annual cost of clean water for every human -

Iterating over the lines of a file in Java -

Raspberry Pi Jam "Chaos Car!" -

Automated UI tests on Android -

Submitting a package to F-Droid -

Resources for year 6 teachers on coding and programming -

2016

Setting up a sane Maven project -

Writing a unit test in Elm -

How to write a programming language - Part 3, The Evaluator -

Basic Haskell project setup (unit tests, code, formatting) -

How to write a programming language - Part 2, The Parser -

Mousedown events delayed or sluggish on mobile -

How to write a programming language - Part 1, The Lexer -

Simple example of Netty 4 usage -

Elm resizeable SVG canvas filling the screen -

Ambiguous names in Java due to non-normalised unicode - but all OK in Python -

Gracefully shutting down Firefox, to avoid the crash/session dialog -

Snake in Python 3 + Qt 5 -

Basic Concepts of Christianity video -

Elm Basics Video -

How to analyse a .phd heap dump from an IBM JVM -

Elm makes me happy (old: Elm 0.17) -

What's new in Java 8 -

Which Raspberry Pi photo was funniest? -

Raspberry Pi Funniest Photo Game -

Snake in Elm -

Out-of-school education settings -

2015

New open source project on work time - git-history-data -

Java HTTPS to a server with a self-signed certificate -

Vim as editor for Claws Mail -

Using GitHub and GitLab -

Avoiding postfix error "status=deferred (unable to look up host" -

Finding the download count of GitHub releases -

Android: using a TextView to show rich text in an AlertDialog -

Assassination of individuals by the state -

Difficult merges in Git - don't panic! -

ZX Spectrum BASIC Web Server -

Letter to my MP on UK government assassination of British Citizens in Syria -

Rabbit Escape out now on Android! -

Changing the Docker daemon options in systemd on Ubuntu 15.04 -

Docker fails to start on Ubuntu 15.04 -

Preventing Audacity from crashing when using PulseAudio -

Movie podcast "The Good Robot Andys" -

Code for detecting when you leave an Android app -

Mocks are Bad, Layers are Bad -

Prediction result: corporate Linux -

Detecting whether an Android app is stopping (or starting) -

Order of Android Activity lifecycle events -

Snake in Dart -

Preventing Kupfer switching to existing windows -

Using Kupfer on MATE -

Tweetable Art Code -

Rabbit Escape 0.3.1 - now with zoom! -

Treat warnings as errors in a (Gnu) Makefile -

Switching Xfce to use metacity -

Java game programming: image rendering hints make no difference to rendering time -

Snake in ZX Spectrum BASIC -

fetchmail complaining about GoDaddy SSL certificate -

Encapsulation as passing on responsibility -

Snake in Ruby -

Batch-converting audio files to be louder (on Linux) -

Why Rabbit Escape is Open Source / Free Software -

What is a good company? -

How to make your own levels for Rabbit Escape -

Rabbit Escape v0.1 out now for Linux, Windows and Mac video -

Rabbit Escape (a bit like Lemmings) v0.1 released for Linux, Windows and Mac -

Snake in Groovy -

Programmatic equivalents of web.xml sections for Tomcat -

JAX-RS (using Apache CXF) in embedded Tomcat example -

Vim persistent buffer list combined with saved sessions -

2014

Snowflake Christmas card web page on the Raspberry Pi -

Snowflake Christmas card in Scratch on the Raspberry Pi -

Encoding URLs in Java -

Books that changed my life -

Why I use Linux -

LibreOffice spell check not working in Lubuntu -

Is it ok to represent dates as Unix time (seconds since the epoch) in JSON? -

Using hexdump to represent a binary file in Java source code -

Disabling screensaver on LXDE -

Android development - saving state -

Android development - Rabbit Escape really working on Android -

Showing urgent (flashing) windows on all desktop in LXDE's taskbar (window list) in Lubuntu -

Launch an urgent window using Python and Xlib with the UrgencyHint flag -

Android programming - a non-Android, Android Game -

Android programming - drawing bitmaps in a game loop -

Don't use email auto-forwarding (emails will go missing) -

Fetchmail "mda" option makes emails bypass the spamassassin filter in postfix -

Android programming - a menu using Activities and Intents -

Raspberry Pi Minecraft Python summer project screenshots -

Android programming - setting up Android Studio -

What is a string? -

Absolute Truth in programming languages -

Options for code reviews with Git -

Desktop sharing not working in Lubuntu 14.04 -

Best GCC warning flags for compiling C++ -

What git server should I use? -

Renewing self-signed certificate for ejabberd -

Letter to my MP on DRIP -

What is node.js? -

A mini mocking framework -

Simple template programming -

Five Quines video -

OpenID security in a REST API -

avconv performance slow in Ubuntu 14.04 trusty -

Does test-driven development harm clarity? -

Token-based security in a REST API -

Avoid mocks by refactoring to functional -

Using the final keyword in interface method parameters does nothing -

Using xscreensaver to lock the screen in Lubuntu -

Security in a REST API -

Searching in a REST API -

2013

Paging in a REST API -

A Basic REST API -

Avoid backslashes anywhere in Java code (Java error "illegal unicode escape") -

What is REST? -

Bash arrays -

Using if:set, unless:set etc. with macrodefs in Ant -

Using if:set, unless:set etc. to execute a task conditionally in Ant -

Vim for Fun -

Working with others in git -

Merging in git -

Behaviour of Java String.split() when some answers are the empty string -

Checking the case of a filename on Windows -

Branches in git -

Passing several values through a pipe in bash -

Goodness in programming languages, part 4 - Ownership & Memory -

How to use git (the basics) -

Using gnome-mplayer to play DVB radio without asking whether you want to resume -

C++14 "Terse" Templates - an argument against the proposed syntax -

setUp and tearDown considered harmful -

Why use git for source control? -

Set the volume in OpenBox/LXDE (or on the command line) with PulseAudio and Ubuntu -

Everybody loves build.xml (test-driven Ant) -

Everybody hates build.xml (code reuse in Ant) -

Dry run mode for Ant (ant -n, ant --dry-run) -

My First Raspberry Pi Game " Part 12 " Scoring, done! -

My First Raspberry Pi Game " Part 11 " Being less rude -

2012

My First Raspberry Pi Game " Part 10 " Red square -

My First Raspberry Pi Game " Part 09 " Lots more words -

My First Raspberry Pi Game " Part 08 " Success and failure -

My First Raspberry Pi Game " Part 07 " A green circle -

Launching an OSGi app on the command line -

My First Raspberry Pi Game " Part 06 " A better class of waiting -

My First Raspberry Pi Game " Part 05 " Say something -

My First Raspberry Pi Game " Part 04 " A small black screen -

Length of Open Source licenses -

My First Raspberry Pi Game " Part 03 " It's like a magic spell -

My First Raspberry Pi Game " Part 02 " Saying hello -

My First Raspberry Pi Game - Part 01 - Before we start -

Running Dojo DOH tests in a browser without a web server -

Bash associative array examples -

Running Dojo 1.7+ DOH unit tests on the command line with Rhino -

Lambda functions timeline -

Goodness in programming languages, part 3 " not doing the same thing more than once -

Tail Call Optimisation in C++ - lightning talk video -

Cool Raspberry Pi Projects -

Scheme 7: Macros video -

Scheme 6: Lambda video -

Tail Call Optimisation in C++ published in Overload journal -

Scheme 5: Quotation video -

Scheme 4: Recursion - how to write functions in Scheme video -

Scheme 3: Closures video -

Scheme 2: Basics - pairs and lists video -

Scheme 1: Feel the cool video -

Generalising tail call optimised C++ -

JavaScript WTFs Videos -

Closures in Scheme -

Performance of tail call optimised C++ -

Tail call optimisation in C++ -

Lighting talk - Tail call optimisation in C++ -

Scheme: pairs, lists and recursion -

What timezone Python thinks I'm in -

Freeview dvb-t scan gives "tuning failed!!!" after 18th April switchover -

Scheme: feel the cool -

JavaScript WTFs -

Goodness in programming languages, part 2 " getting your code running -

Building jEdit from source -

Goodness in programming languages, part 1 - syntax and layout -

Ethernet not working on Ubuntu with Realtek RTL8111/8168B -

2011

FreeGuide usage stats -

Entertain your baby using your Android phone -

rdesktop swallows keyboard events -

Reclaiming desktop space with Ubuntu's window-picker-applet -

My Address Book 1.9.0 - rewritten from scratch -

Switching workspace in GNOME via the command line -

Anatomy of an interpreter: the Evaluator -

How to ask technical questions in person -

2010

Anatomy of an interpreter: the Parser -

Anatomy of an interpreter: the Lexer -

Subs Scheme Lisp Interpreter -

Scalable Graph Coverage -

Ubuntu Lucid upgrade - a catalogue of disaster and pain -

2009

FreeGuide 0.10.11 -

Don't design for performance until it's too late -

Technorati appear to have broken openid delegation -

NNDB 0.1 -

NNDB's Not a Database -

Diffident 0.3 -

CBeebies and other channels not working with mplayer -

Firefox keyword search for finding C++ keywords -

Flaws in the software patents system -

IGCC - a real-eval-print loop for C/C++ -

Diffident - command line side-by-side diff editor -

Random background in GNOME -

Analog literals -

Separate regular expressions, or one more complex one? -

New Baby -

Talk in code -

2008

Fixing the vertical panel window list on Ubuntu Hardy -

An actual difficult bug fixed -

FreeGuide 0.10.9 -

Wii repaired free! -

Another one -

FreeGuide 0.10.8 -

Debugging memory use and fragmentation on Windows using Address Space Monitor -

C++ is an expert language -

Templated test code? -

Public bzr branch of FreeGuide -

Public git repo for GSSMP -

Finally released last.fm support for GSSMP -

2007

lighttpd on Ubuntu - alias.url doesn't work when included in a module config file -

FreeGuide updated to latest XMLTV, and bug fixes -

duckmaze 0.2 -

Caution: numbers that feel prime may be divisible by 3 -

Announcing Record TV -

FreeGuide 0.10.5 -

FreeGuide SVN now useable -

Heartfelt apologies for the feed URL change -

FreeGuide - putting recording on hold -

New Baby arrived safely -

(Badly wrong) usage statistics for FreeGuide -

Procmail Maildir messages disappearing -

last.fm in GSSMP -

lastfmsubmitd on Ubuntu Dapper -

Obviously, there was a bug -

Watching TV: a simpler way -

GSSMP 1.0 -

Choose channel dialog -

Digital TV on Dapper with my Hauppauge WinTV Nova-T card -

Restoring a backup with Duplicity -

Remote encrypted backup with duplicity -

GSSMP goes beta -

Recording in FreeGuide -

My daily backup -

Creating .deb and RPM packages -

Moved to WordPress -

Two new babies -

2006

New games! -

Linux Journal - Forgiveness -

Another FreeGuide release candidate -

FreeGuide 0.10.4 release candidate -

A Quick and desperate introduction to data recovery -

FreeGuide fan mail -

Over-engineering gone mad -

Keyboard layout change in Ubuntu -

FreeGuide source layout (and SVN migration) -

Letter to Linux Journal -

Linux Journal slides -

Donation -

FreeGuide update -

Faster Poker Analysis -

Poker Analysis -

Podcasts I listen to -

Setting up my ideal email system 4 -

I spawn -

2005

Setting up my ideal email system 3 -

FreeGuide 0.10pre2 -

Setting up my ideal email system 2 -

Setting up my ideal email system -

Just a little bit longer... -

BashPodder -

Python objects in C++ -

CD writing on Fedora Core 3 -

Prince of Persia - The Sands of Time -

Personal stuff is boring -

Sourceforge -

London -

London terrorist attacks -

The dangers of learning to code -

Train gaming -

Constantly changing passwords -

Gaming on the move -

ATV Palm export -

Nearing a new release -

DIYPlanet -

Re-implementing -

Honestly my last post about my viva -

Corrections -

Viva today -

Mnemonic -

FreeGuide's TODO list -

FreeGuide packaging and plugins -

DIYBlog -

RSS working? -

Prediction: corporate Linux -

Guilty Expression -

RSS -

A real job -

What is going on with FreeGuide? -

Google -

Beginning blog -