Author: Andy Balaam

  • Rust 101 – 38: Exercises for module E (q1a)

    Writing our own multi-producer-single-consumer (MPSC) queue using async Rust. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Async): 34: What is…

  • Rust 101 – 37: Async runtimes

    We talked about how Futures have poll methods, but who calls them? That is the job of the runtime. We talk about how to launch your async code and how to choose the right runtime, and then we have a very brief look at some Web frameworks that are based on async Rust. Series: Language…

  • Rust 101 – 37: Async runtimes

    We talked about how Futures have poll methods, but who calls them? That is the job of the runtime. We talk about how to launch your async code and how to choose the right runtime, and then we have a very brief look at some Web frameworks that are based…

  • Rust 101 – 36: What async and await really do

    Attempting to explain as slowly as possible what actually happens when the compiler finds an async function containing awaits: it writes a poll method for you to create something that implements Future. The generated poll method polls the Futures you asked to await, in order. The interesting bit is that this generated thing that implements…

  • Rust 101 – 36: What async and await really do

    Attempting to explain as slowly as possible what actually happens when the compiler finds an async function containing awaits: it writes a poll method for you to create something that implements Future. The generated poll method polls the Futures you a…

  • Rust 101 – 35: Futures

    Exploring what a Future is in async Rust and how we could manually write code that polls futures. Normally, we avoid this manual work by using the `async` and `await` keywords, but looking into this helps us understand what those keywords really do. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and…

  • Rust 101 – 35: Futures

    Exploring what a Future is in async Rust and how we could manually write code that polls futures. Normally, we avoid this manual work by using the async and await keywords, but looking into this helps us understand what those keywords really do. Serie…

  • Rust 101 – 34: What is async?

    What async programming is and what it looks like in Rust. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async This section (Async): 34: What is async?, 35: Futures, 36: async/await, 37: Runtimes, 38: Exercise E1a, 39: Exercise E1b, 40: Exercise E2a, 41: Exercise E2b Links: Slides: Rust…

  • Rust 101 – 34: What is async?

    What async programming is and what it looks like in Rust. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Async): 34: What is async?, 35: Futures…

  • Rust 101 – 33: Exercises for module D (q3)

    Following through an exercise using a trait object with dynamic dispatch to choose different behaviour at runtime. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async This section (Trait objects): 28: Dynamic dispatch, 29: Object safety, 30: Patterns, 31: Exercise D1, 32: Exercise D2, 33: Exercise D3 Links:…

  • Rust 101 – 33: Exercises for module D (q3)

    Following through an exercise using a trait object with dynamic dispatch to choose different behaviour at runtime. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Uns…

  • Elected to the Matrix Foundation Governing Board!

    I am really excited to say I was elected to the Governing Board of the Matrix Foundation! I was really surprised because there were lots of people standing, and the quality of the candidates was very high, but I am one of the lucky ones. I hope I can do a decent job of helping…

  • Elected to the Matrix Foundation Governing Board!

    I am really excited to say I was elected to the Governing Board of the Matrix Foundation! I was really surprised because there were lots of people standing, and the quality of the candidates was very high, but I am one of the lucky ones. I hope I can d…

  • Rust 101 – 32: Exercises for module D (q2)

    Trying out the typestate pattern by tracking the state of a 3D printer by changing our type instead of updating a variable whenever it changes. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and paralleli…

  • Rust 101 – 31: Exercises for module D (q1)

    Some good patterns to follow in your code e.g. “newtype”, “typestate” and one to avoid. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Trait obj…

  • Rust 101 – 30: Good patterns and not so good

    Some good patterns to follow in your code e.g. “newtype”, “typestate” and one to avoid. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Trait obj…

  • Rust 101 – 29: Trait objects and object safety

    Trying to explain why the rules for object safety are the way they are, and how to create and use a trait objects. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Uns…

  • Rust 101 – 28: Dynamic dispatch

    Explaining how to hold on to something even when we don’t know its exact type, just what trait it implements. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe T…

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

    Huge thanks to Micah Scott for hosting my videos on diode.zone until recently. My videos are moving to video.infosec.exchange/a/andybalaam – please update all your feeds. (Thanks to Jerry Bell for running that – please donate!) You can follow this blog…

  • Why I won’t link to AI resources

    I received a very kind email today from someone who had found my page Resources for year 6 teachers on coding and programming helpful, and wanted to suggest another link for me to add, about AI resources. I’m sure it was a helpful and useful link, but …

  • Rust 101 – 27: Exercises for module C (q2)

    Implementing a simplified form of Mutex. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Concurrency and parallelism): 24: Parallelism, 25: Threa…

  • Rust 101 – 26: Exercises for module C (q1)

    Searching across multiple documents in parallel with Rayon. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Concurrency and parallelism): 24: Par…

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

    Update: I just discussed this with my son and I really want to emphasise: It does make a difference who is in power. The previous Labour government significantly improved primary education and many other public services. Don’t lose hope! Here are the c…

  • Rust 101 – 25: Threads, Mutexes, channels, Send and Sync

    How to spawn threads and deal with lifetimes, how to send or share state across threads, and what Send and Sync mean. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, …

  • Rust 101 – 24: Parallelism and Rayon

    What concurrency and parallelism are, a brief intro to Rayon, and a quick note on closures. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Concu…

  • Rust 101 – 23 Exercises for module B (q3)

    Testing, benchmarking and optimising a small program that plays FizzBuzz. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Building applications):…

  • Rust 101 – 22 Exercises for module B (q2)

    Building a command-line quiz application to bed in our knowledge about crates, modules and serialisation. All done using test-driven development. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and paralle…

  • Rust 101 – 21 Exercises for module B (q1)

    Going through an exercise on serialization with serde. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Building applications): 18: Dependencies, …

  • Rust 101 – 20: Unit, integration and benchmark tests

    How to write unit tests in your Rust code, and some quick pointers on writing integration and benchmark tests. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe …

  • Standing for the Matrix Governing Board

    I have decided to stand for election to the Matrix Governing Board, which is a brand new body which advises and oversees the work of the Matrix Foundation. I will stand as an Individual Member, not representing a company or project. Contents: Purpose …

  • Rust 101 – 19: Creating a nice API

    Tips and rules for writing good APIs that are easy for other people to use. Try to make them Unsurprising, Flexible, and Obvious. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait obje…

  • Rust 101 – 18: Dependencies and Cargo.toml

    How to describe details of your Rust project with a Cargo.toml file, and how to find and add dependencies (other people’s code). Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objec…

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

    Finishing off the exercises on Rust traits, designing a customised version of Vec. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Traits and gen…

  • Automated backups from Signal to Nextcloud

    DON’T DO THIS: the Signal app has the ability to make daily backups of your messages, and when you choose a folder to backup into, you can choose “Nextcloud” as the device, then choose a Nextcloud folder to back up to. Don’t do that. Although the above…

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

    Going through some exercises on Rust traits, designing a customised version of Vec. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Traits and ge…

  • One import per line is best

    Rust has a feature where if you import two things from the same module you can abbreviate it like this: use mypkg::{MyStruct1, MyStruct2}; If you prefer, you can keep them separate, like this: use mypkg::MyStruct1; use mypkg::MyStruct2; I do prefer. St…

  • Rust 101 – 15: Lifetime bounds

    This time we tackle one of the most tricky areas for a new Rust programmer: lifetimes. The key point is that when we add lifetime bounds (‘a or similar) to a function signature, this is not to help Rust compile our function: it’s to help Rust understan…

  • Rust 101 – 14: Some standard library traits

    A tour of some of the most interesting traits in the standard library including Add etc. to overload operators, Sized, Sync and Send for telling the compiler special things about your type, Clone and Copy for copying things, Into and From for convertin…

  • Rust 101 – 13: Type Parameters and Associated Types

    Following on from video 12, looking at how to add type information to traits, to make them flexible enough to describe generic code with different types, for example how to add a u32 to a u64 and return a u128, without defining a whole new trait for ev…

  • Rust 101 – 12: Traits

    Explaining what a trait is, and how to use it. A trait is a bit like an Interface in Java or Go, or an Abstract Base Class in C++ or Python, but it can be used to define behaviour at compile-time as well as at run-time. We go through an example of why …

  • Rust 101 – 11: Exercises for module A2

    Going through some exercises on Rust ownership, references, slices and error handling. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (More synta…

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

    Update: as confirmed in the bug I logged, this was fixed in Firefox 123! See also: Keep your Indexed DB keys and values small if you want good performance! and Don’t store arrays of numbers in Indexed DB – use base64 instead. We had performance problem…

  • Don’t store normal arrays of numbers in Indexed DB – use UInt8Array instead

    Following on from Keep your Indexed DB keys and values small if you want good performance!, here is another thing I’ve learned about Indexed DB performance (in July 2024): Update: Thanks to richvdh, we now know UInt8Array is much better than base64! If…

  • Rust 101 – 10: Strings

    What a String is in Rust, and how they differ from &str. Strings are resizeable arrays of bytes that are guaranteed to be in UTF-8 format. &strs are references to chunks of bytes that are also guaranteed to be in UTF-8 format. If you want to le…

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

    In our work recently on Element Web (specifically attempting to replace our encryption code with our cross-platform Rust implementation) we’ve noticed some strange behaviour with the performance of our Indexed DB queries. We’ve been aware of some slowd…

  • Rust 101 – 9: Vecs, Boxes and slices

    Explanation of some of the most commonly used types in Rust: Vecs, which store lists of items, Boxes that allow us to own things that we keep on the heap, and slices that are a way of referring to parts of Vecs or arrays without owning them. Series: L…

  • Rust 101 – 8: Writing methods using impl blocks

    This time we discuss how to add methods to structs and enums, using impl blocks. Methods work similarly to other languages, but it might be a surprise that they can be defined inside separate blocks, and in fact they can be defined in multiple differen…

  • Rust 101 – 7: Error handling with panic and Result

    We learnt about enums and generics last time, which means we’re ready to talk about Result, which is a really nice way of handling errors in Rust, that allows you to be very explicit about what went wrong, but also with a very compact syntax using the …

  • Letter to my MP: using starvation as a weapon

    Dear Ben Spencer, The behaviour of Hamas on 7th October and afterwards is inexcusable, and is rightly condemned by our government. I believe that the ongoing behaviour of the Israeli government in response to these attacks is inexcusable, and should be…

  • Santa Circles 0.3 is out!

    Santa Circles 0.3 is all new and shiny! santacircles.artificialworlds.net (It’s a secret-santa-style gift exchange web site.) Don’t worry, it looks exactly how it did last year, except there is a tiny “Forgot password?” link you can click if you need …

  • Follow this blog on the fediverse!

    If I’ve set it up right, you can now follow this blog on Mastodon and other fediverse platforms! Search for this user: @blog@www.artificialworlds.net

  • Rust 101 – 6: Structs and Enums

    Continuing our review of the things you need in Rust to write programs – grouping together data using structs, and allowing multiple possibilities with enums. We look at how to decide which thing you’ve got with the match keyword, and review a very pop…

  • Rust 101 – 5: References

    Starting some more advanced Rust programming ideas by looking at references – the ability to “borrow” values and refer to them without taking ownership. We look at mutable and immutable references, and the rules about references that prevent us ever ha…

  • Rust 101 – 4: Exercises for module A1

    Going through some exercises on basic Rust syntax and ownership. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Language basics): 1: Intro, 2: L…

  • Rust 101 – 3: Memory and ownership

    Continuing on Rust programming basics by looking at ownership and memory management, including the stack and the heap: what they are, how they differ, and why you need to care. For more help on ownership and the stack and the heap, try Chapter 4 of th…

  • Rust 101 – 2: Language basics

    An introduction to the Rust language basics. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Language basics): 1: Intro, 2: Language basics, 3: M…

  • Rust 101 – 1: Course intro

    Introducing the Rust 101 series and how to install Rust. Series: Language basics, More syntax, Traits and generics, Building applications, Concurrency and parallelism, Trait objects, Async, Unsafe This section (Language basics): 1: Intro, 2: Language …

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

    Combining interfaces/objects with & When you combine two types in TypeScript with & (ampersand), it is called an Intersection Type. For example: interface Particle { mass: number; } interface Wave { wavelength: number; } type Both = P…

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

    I use Podman to provide Docker-like stuff on my dev machine without effectively being root. Talking to the container host in Docker There is a little trick for accessing HTTP services on the container host in Docker: you add –add-host host.docker.inte…

  • Why I’m voting tactically against you – letter to my Conservative MP

    Here’s the letter I just sent to my MP. Feel free to use it in full or in part. Dear Ben Wallace, Last night I made the decision to vote tactically against you at the next election, and I felt I owed you an explanation. I now feel that any of the likel…

  • Rust WASM hello world – no need for webpack!

    Up to now I’ve been following the official guide and using webpack to package my Rust+WASM code to run in a browser. But today I found out there is no need for webpack at all! This makes development much faster, with many fewer dependencies. Setup Befo…

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

    I was recently asked what I thought of using time-based estimates when tracking software tasks. TLDR: I think it’s a terrible idea that can hurt your software by introducing bugs and burning out developers. I think using time-based estimates is pretty …

  • Maths: The Fun Parts – Graphs video

    More of my series about my favourite bits of Maths. This time, Graphs: Slides for Maths: The Fun Parts – Graphs

  • Maths: The Fun Parts – Groups video

    More of my series about my favourite bits of Maths. This time, Groups: Slides for Maths: The Fun Parts – Groups

  • Maths: The Fun Parts – Sets video

    I’ve been wanting to make series about the cool bits of Maths for years and I’m finally getting around to it. It’s called “Maths: The Fun Parts” and the first part is on Sets: Slides for Maths: The Fun Parts – Sets

  • GitHub API GraphQL snippets

    Every time I try to use GitHib’s GraphQL API I find myself totally lost, so here are some snippets I have found useful. All of these can be pasted into the GitHub GraphQL API Explorer, which can run the code as your logged-in user in the browser withou…

  • Live code reviews make life better

    I’ve just got off a call with a colleague. During that call I: learned a lot about how the work he is doing fits in with what my team is working on understood the specific code we were discussing much better than if I’d looked at it alone helped him f…

  • Air-Source Heat Pump – 1 year later

    10 months ago I wrote a blog post Air-Source Heat Pump – our experience so far, 2 months in about our new air source heat pump. Have a look back at that for photos of the device itself and more detail about installation etc. Less energy We used a lot l…

  • Deleted my Twitter account

    Update: my twitter archive is here: artificialworlds.net/tweets. Update: you can see the hacky scripts I used to build this, based on twitter-archive-parser. This evening I deleted my Twitter account. I’m feeling surprisingly unsettled by doing it, to …

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

    Geeks don’t like to be formal, but we do like to be precise. That is the contrast that comes to mind as I attend my first IETF meeting, IETF 115 in London in November 2022. Like most standards bodies, IETF appears to have been formed as a reaction to s…

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

    The Selection API is confusing and weird. But, here’s what I’ve discovered: just use setBaseAndExtend, and when (rarely) needed, extend. Summary Every selection in a browser consists of: an “anchor” – the beginning, where you started dragging, and a “…

  • Tips for contenteditables

    I’ve been working a bit with contenteditable tags in my HTML, and learnt a couple of things, so here they are. Update: See also my demo of how to select text in various ways in a contenteditable. Why can’t I see the cursor inside an empty contenteditab…

  • Outreachy August 2022 update

    I had the pleasure of being a mentor this summer for an Outreachy internship for the Matrix organisation. Outreachy provides internships to people subject to systemic bias and impacted by underrepresentation in the technical industry where they are liv…

  • Transcoding video files for playback in a browser

    ffmpeg -i original.mkv -c:v libx264 -c:a aac -ac 2 -ab 384000 -ar 48000 new.mp4 (Short answer: use the above ffmpeg command line. Read on for how I did this in Tdarr.) I recently discovered Jellyfin, which gives me a Netflix-like UI for viewing my own …

  • Matrix is a Distributed Real-time Database Video

    Curious to know a bit more about Matrix? This video goes into the details of what kinds of requests you need to send to write a Matrix client, and why it’s interesting to write a Matrix server. Slides: Matrix is a Distributed Real-time Database Slides…

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

    One of the advantages of writing code in Rust is that it can be re-used in other places. Both iOS and Android allow using native libraries within your apps, and Rust compiles to native. Web pages can now use WebAssembly (WASM), and Rust can compile to …

  • Deporting desperate people from the UK

    Letter to my MP on deporting refugees to Rwanda, 2022-06-06. Dear Ben Spencer, Please do what you can to reverse the policy of sending asylum seekers to Rwanda. We are breaking our proud tradition of commitment to refugees. This policy seems to have th…

  • Improving my vimrc live on stream

    I was becoming increasingly uncomfortable with how crufty my neovim config was getting, and especially how I didn’t understand parts of it, so I decided to wipe it clean and rebuild it from scratch. I did it live on stream, to make it feel like a worth…

  • Comparison of Matrix events before and after “Extensible Events”

    [Updated 2022-11-17 based on the new draft of the MSC, notably removing backwards compatibility and the abbreviated forms.] (Background: Matrix is the awesome open standard for messaging that I get to work on now that I work at Element.) The Extensible…

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

    [Update: see also Air-Source Heat Pump – 1 year later.] Summary: less energy, more money 2 months ago, we replaced our gas boiler with an air-source heat pump, which uses electricity to heat our home and boiler. This is a report of our experience so fa…

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

    [Previous: Self-hosting maps on my laptop] In the previous post I showed how to run OSM tile server stack locally. Now I’ve managed to connect a MapLibre GL JS front end to my local tile server and it’s showing maps! Sharing a location in Element Web (…

  • Self-hosting maps on my laptop

    [See also: Providing MapLibre-compatible style JSON from openstreetmap-tile-server] As part of my research for working on location sharing for Element Web, the Matrix-based instant messenger, I have been learning about tile servers. I managed to get OS…

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

    Simulcasting RTMP using NGINX I want people to be able to watch my Matrix and Rust live coding streams using free software, so I’d like to simulcast to PeerTube as well as Twitch. This is possible using NGINX and its RTMP module. It does involve buildi…

  • New game: Tron – frantic multiplayer retro action

    My newest game is out now on Smolpxl Games – Tron: Play at smolpxl.gitlab.io/tron. It’s a frantic multiplayer retro pixellated thingy playable in your browser. Try to stay alive longer than everyone else! This version allows many players (up to 16 if …

  • Preventing Virgin Media hijacking my DNS

    Yesterday I learned that Virgin Media is inserting itself into some of my DNS requests. Much as I am not a fan of how powerful Cloudflare are, if they are telling the truth about their DNS, then it’s safe, so I followed their instructions on how to use…

  • Letter to my MP about climate emergency

    [Introduction including details about my own air source heat pump install, and mention of the ending of the RHI funding in April 2022.] After I have installed an air source heat pump, I will pay more money to heat my home, even though I am using less e…

  • New Job at Element (Matrix)

    I started a new job today at Element! It has been a long-standing ambition of mine to work in Free and Open Source software, and I am very excited to work for a company that is the main developer of a really important project: the Matrix communication …

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

    Update: caching $RUSTUP_HOME and $CARGO_HOME does not work for me – I removed them. When building your project with Gitlab CI or a similar build tool, you can end up spending a lot of time watching your build repeat the same steps over and over. This i…

  • Printing the version of a Maven project

    To print a Maven project’s version number, try: mvn help:evaluate -Dexpression=project.version -q -DforceStdout -q suppresses all output(!) -DforceStdout unsuppresses the actual thing you asked to be printed. I will refrain from commenting on how diffi…

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

    The Kotlin docs describe some things you need in your pom.xml to create a project that is a mix of Kotlin and Java code, but there is no complete example, so here is mine: pom.xml:<project> <modelVersion>4.0.0</modelVersion> &lt;g…

  • Importing/migrating from one peertube server to another

    My Peertube server is shutting down, so I need to move my videos to another one. The official scripts don’t seem to cover this case very well, so here is what I did. My script fetches videos and their details and uploads them to the new server via the …

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

    My new game, Rightwaves, is out now! It’s a tribute to the great classic R-Type. The entire implementation, including all the graphics, is contained within a single ~5000-line JavaScript file. Why? This is a terrible idea Let me start by saying I do n…

  • Matrix is the only (chat) game in town

    On my phone and computer I use WhatsApp, Signal, Slack, Keybase, Discord, IRC, XMPP/Jabber and Element/Matrix. In addition, I occasionally use the messaging features of Mastodon, Twitter and even LinkedIn. I’ve never used Telegram, Line, WeChat, Sessio…

  • Writing Snake in Terraform Video

    This was quite a challenge, and I nearly gave up, but I managed to write a Snake game in Terraform: Slides: artificialworlds.net/presentations/snake-terraform Source code: gitlab.com/andybalaam/snake Slides source code: gitlab.com/andybalaam/videos-sn…

  • Suspending the computer using Kupfer

    I have recently started using Kupfer again as my application launcher in Ubuntu MATE, and I found it lacked the ability to suspend the computer. Here is the plugin I wrote to support this. To install it, quit Kupfer, create a directory in your home dir…

  • Uploading to PeerTube from the command line

    PeerTube’s API documentation gives an example of how to upload a video, but it is missing a couple of important aspects, most notably how to provide multiple tags use form-encoded input, so my more complete script is below. Use it like this: # First, m…

  • Republishing Bartosz Milewski’s Category Theory lectures

    Category Theory is an incredibly exciting and challenging area of Maths, that (among other things) can really help us understand what programming is on a fundamental level, and make us better programmers. By far the best explanation of Category Theory…

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

    It’s hard to believe it’s already a year since the release of RFC 8771 (The Internationalized Deliberately Unreadable Network NOtation), which for me at least made me think about IP addresses in a whole new way. So, it seems fitting for the anniversary…

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

    Lots of people are filling in the extremely detailed UK government COVID test result page twice every week. It asks you to fill in a very large list of details, most of which are the same every time, but it doesn’t remember what you typed last time. I …

  • Toggle window decorations on Linux GTK3 with Python3

    The Internet is full of outdated Python code for doing things with windows, so here is what I got working today in a Python 3, GTK 3 environment. This script toggles the window decorations on the active window on and off. I have it bound to Ctrl+NumPad…