Imagine you have an app which takes some user input which ends up in a path: $userProvidedData = $_GET [ 'fileName' ]; $path = '/path/to/safe/directory/' . $userProvidedData ; This is no good, if the user sends the value ../../../../etc/passwd then the $path becomes /path/to/safe/directory/../../../../etc/passwd aka /etc/passwd . This is a classic path traversal attack. It's very simple to defeat:…
A couple of weeks back my phone (FairPhone 3) started showing 'failed to save' errors for apps which used the sd-card, things like the Camera and Obsidian. It would just say 'Failed to save', no more information than that, great, thanks 😡 A device reboot would get it working again. What is this, Windows??? I'd recently-ish installed Shelter, and for no good reason I'd assumed that it was…
The game felt lifeless and flat. There was no motion at all other than the player jumping from one block to the next. I thought, rather than having a flat black background I could add some texture in the form of a dark ominous fog, in the pixelated style of course. I tried a couple of different images, tweaking the pattern, colours, brightness, etc. It was definitely better, but using a single…
Lots more progress has been made on the game. One notable improvement is the start page. Until now, starting a new game required manually clearing cookies to get a new session and therefore a new seed. I also wanted the player to be able to enter a seed. I also thought making the seed obvious would be useful for testing and debugging later. It started simple: Seed Generator In an attempt to make…
Ever changed a re-chargeable battery with one you know is charged only to find it to be nearly dead? I have! I keep a small box of rechargeable batteries, various sizes and chemistry, all ready to go. Batteries only ever get put in the box once they are charged. The trouble is that batteries self-discharge. For primary cells (aka non-rechargeable) the process happens over many years, for…
I like to write strictly typed PHP, or at least as much as possible. Primarily this boils down to using PHPStan . One aspect where I find this challenging is Laravel Collections . Specifically creating single-type Collections. For example, a WidgetCollection should guarantee that the collection only ever contains instances of Widget : /** @extends \Illuminate\Support\Collection< Widget > */ class…
This is part 3 of the project, see here for the other parts. Which filesystem to use was fundamental. It affects power, noise and resilience. I planned to use RAID to get resilience, but typical RAID setups prevent disks from spinning down, which means more noise and power ( more than you might think ). I did a bunch of research and found that a combination of SnapRAID and MergerFS was going to be…
JS Rendering The initial plan was that the backend would render everything to an image and send it to the browser. It became clear that this isn't going to work when Iain created an awesome animated bonfire sprite. Animated sprites obviously aren't going to work in a JPEG/PNG. You could maybe do some nonsense by rendering the whole thing to a looping GIF, but that sounds like a whole load of bugs…
This is part 2 of the project, see here for the other parts. I had 6x 1TB HDDs lying around not doing anything. That was partly what gave me the idea to do this project. The first problem is that the Mele Queiter doesn't have any SATA expansion. One option was to replace the NVME drive with an NVME-to-SATA expander, but I didn't want to give up my only NVME slot. Instead, I found some USB-to-SATA…
The very first iteration of the map generator was as basic as it gets. Generate a random width/height, fill with floors tiles, cover the perimeter in walls, select random floor tiles for the player and a chest. It worked, but it obviously didn't make for engaging game play. I wanted the room generation to be deterministic but organic, rooms, corridors, nooks, dead ends, etc. Some research later…
Much has changed since the first iteration of Iron Bloom, but the most noticeable is the art. Art and design are very much not my strong suit, I gave it a go so that I had more than block colours to look at while testing, but it was poor to say the least. Unlike me Iain has some actual skill when it comes to pixel-art and created a proper sprite sheet and made it look awesome . This was exactly…
This is part 1 of the project, see here for the other parts. I thought I would 3d print the HDDs mounts, but it all ended up being too large for my small printer. I opted instead to order a pair of 6mm Aluminium plates. This had the added benefit of acting as a heat sink, not that I'm expecting sleeping drives to get hot. I took my time marking it all out precisely and accurately . It helped that…
I've been thinking of building a NAS for a while now, partly from necessity, partly for the fun of it. I needed to achieve the following: Lots of space for archives, backups, ethical torrents , etc Quiet, preferably silent Low power consumption Compact Reasonable resilience Low maintenance Use my existing Mele Quieter 3Q I could've gone out and bought something pre-made which checked most of the…
I want to use as little Google software as I can get away with. This goes as far as things like the Android GBoard on my phone. I want an opensource keyboard, and there are plenty. None of the ones I tried seem to have an emoji search. This sounds really minor, but given how many emojis there are to scroll through, the only way to find them is by search. FlorisBoard came the closest. It can…
World Bee Day is celebrated on 20 May. On this day Anton Janša, the pioneer of beekeeping, was baptized in 1734. https://en.wikipedia.org/wiki/World_Bee_Day To mark the occassion I've set up another solitary bee hotel, it contains both 6mm and 8mm tubes. The smaller tubes are preferrered by mason bees. The tubes are sealed at one end with tissue, as I learned last year is necessary. I will fill…
A friend and I are developing a game. I'm going to try and keep a dev-log of sorts, share anything interesting and vaguely documenting the process. The Plan We created a DESIGN.md document and pulled together some ideas. We decided on an old-school, pixel-art, top-down, procedurally generated, turn-based, 8-bit, zelda-esk, exploration, dungeon crawler style thing. I'm sure it'll evolve over time,…
For an upcoming post I wanted to include some audio, easy enough, just drop in an < audio > tag, job done. Nah, this sounds like a great oppurtunity for some overengineering! I wanted to an audio visualiser, no not that kind , just a simple waveform visualisation which follows along with the audio. I wanted it to be an enhancement to the native player rather than take over and end up being a…
I usually turn to speedof.me to check my current internet connection speed. I thought it might be fun to create my own CLI version, yes, I know there are already loads of existing CLI speed test tools, but I want to reinvent this particular wheel! I thought it must be possible to achieve by gluing together existing CLI tools rather than turning to full-blown programming language. This is what I…
A while ago I built a little app which allowed me to subscribe to YouTube channels using the official RSS feeds, more about that here . One thing that I wish it did was exclude shorts, but it seemed the only way to do that was to use the YT API or use some hack. Then I happened to come across this post on HackerNews , which pointed out that there is an undocumented URL which contains only…
Ever wondered what sites on the small web send for the x-powered-by header? Wonder no more! There are some real gems in there, my favourite is Gnomes... thousands upon thousands of gnomes... x-powered-by: x-powered-by: - X-Powered-By: x-powered-by: 11ty x-powered-by: <3 x-powered-by: Acorn 5.0.5 (Laravel 12.16.0) x-powered-by: Aegea 11.4 (v4171e) X-Powered-By: Aegea 12.0a (v4259e) x-powered-by:…
Do your bluetooth headphone batteries not last as long as they used to? It might be that they never sleep. With my headphones if the PC is outputting an audio stream, even if that stream is silence, then they won't sleep and quickly drain the battery. On Linux you can run pactl list sinks short , if it shows your device as RUNNING but nothing is playing then there are rouge silent streams running.…
I like to be as strict as possible when writing PHP, it helps avoid whole classes of bugs. This is achieved in PHP by doing two things: declare (strict_types=1) and type declarations wherever possible. This isn't a magic bullet. Even with 100% coverage there are type coercions and loose type checks hiding within in the PHP engine. Switch Statements <?php declare (strict_types=1); switch ( true ) {…
These are some of the useful Bash aliases/functions which I use most days. Repeat repeat <count|inf> <command> [args...] Run a command n times. If the command fails, give up. n can be a number or inf to repeat forever. If the command fails more than n times, the commands' exit code is returned. repeat () { if [ "$#" -lt 2 ]; then echo "Usage: repeat <count|inf> <command> [args...]" return 1 fi…
Just a few lines in ~/.inputrc can make a surprising difference. "\e[A": history-search-backward "\e[B": history-search-forward set show-all-if-ambiguous on set completion-ignore-case on set colored-stats on set colored-completion-prefix on History Prefix Search "\e[A": history-search-backward "\e[B": history-search-forward The first two lines allow you to type a prefix and then pressing up and…
I use hibernation a lot. One annoying thing is that after resuming from hibernation Firefox no longer correctly renders < canvas > elements. This was particularly noticeable on Grafana dashboards and the background of this site. The solution is to restart the Firefox GPU renderer. By default, this means restarting Firefox, which is a PITA, because the renderer process is embedded in the firefox…
I've used the df command thousands of times to check how full disks are. What I find annoying is that 99.999% of the time I'm only interested in the root partition, but I have to scan through a bunch of other loopback and tmpfs devices to find it #firstWorldProblems. What I discovered is that you can pass a path to filter on: df -h / : Filesystem Size Used Avail Use% Mounted on…
I'm a believer in adding as much type information as you can when programming. It gives IDEs and static analysis tools so much power to find bugs or give useful suggestions. I work with PHP, which has historically been a very loose language. It's gotten better over the years and now has typed properties, return types, unions, intersections, DNF , etc. What we don't have is generics: class Thing <…
I bought a DIY Thermocam kit around 10 years ago, it's great have used it on and off since. What isn't great is that I never got the USB-mass storage feature working. I thought that old firmware was to blame, I'd never upgraded it. It was currently running v1.05, the latest is v1.25. Should be simple to upgrade right... Right? The Hunt For Ancient Firmware The first issue was finding copies of the…
I built a simple Wi-Fi thermometer to monitor the temperature of a Hotbin . It uses and ESP32 and sends the data to Prometheus for storage. It's not uncommon for there to be gaps in the data because it is entirely solar-powered. Especially so in the winter months. Recently there was an unusually long gap. Over a week went by with no data. That included some days which I was sure had enough sun to…
I don't print a lot of things which take many hours, I only have a small printer, but when I do, or if it's a risky print, then it's annoying to have to stop what you're doing to go and check on it. This is also a solved problem: add a camera. OctoPrint has supported a webcam feed since forever. I already had a camera lying around which I wanted to use. I couldn't find an existing mount which…
Air rifle power (specifically muzzle energy) is typically measured in either Joules or Ft-Lb. I never understood how these could be equivalent. The crux of the confusion comes from the fact that a pound can describe both a weight and a force. Really it should be called 'foot pound-force' or 'ft-lbf'. From Wikipedia : Pound-force should not be confused with pound-mass (lb), often simply called…
Happy Pi day 2026! I wanted to write a little simulation which (badly) approximates Pi. It's called the Monte Carlo method and simply involves placing a circle inside a square and then randomly placing points anywhere inside the square. The ratio of points outside the circle to inside is ¼π. This isn't an animation, it's a streamed image of the simulation, refresh to get a new run. I love how…
I've been wanting to create a toy implementation of a Markov Chain generator for a while. It's one of those things which I think I understand conceptually, but I wanted to write a simple implementation to solidify it. I also thought it might be fun. How It Works There are 3 stages: Tokenising Build a token map Sampling The idea is to take large chunks of text (I used all the text on this blog),…
I always thought that to read temperature sensors on a Linux machine, you had to reach for a package like sensors . You don't. Like lots of things in Linux, the standard temperature sensor values are exposed as virtual files: cat /sys/class/thermal/thermal_zone*/temp 27800 20000 88000 88000 That will give you the raw sensor value in milli°C, so divide by 1,000 to get °C. You can get the name of…
A reed switch is a pair of metal contacts inside a little glass capsule. When a magnet comes near, the contacts are pulled together and complete a circuit. I thought that the contacts inside had to be aligned with the magnetic field, but this isn't the case. What happens is that the magnetic flux is 'conducted' by the contacts magnetising them, as a result they are attracted to one another. This…
It's been possible to spin down HDDs to save power forever, but does it actually make a meaningful difference? The drives in question are a pair of Western Digital 1TB drives. They're used for long-term storage and get very few reads/writes so could easily be spun down for 99% of the time without me noticing. From 64 W down to 58 W, about a 10% decrease. 3 W per drive, not loads but more than I…
Do you know the difference between composer global config and composer config --global ? Me neither until a couple of days ago! The difference is subtle. composer global config updates ~/.config/composer/composer.json . This is config for the 'global project', the place where global dependencies are installed. composer config --global updates ~/.config/composer/config.json . This is config for…
Directory listings have a bad reputation, they're ugly and are usually used to expose private data. What I love about them is when they are used to distribute software or data. Want to find a specific version of NodeJS, easy: https://nodejs.org/dist/ How about RaspiOS? There's no huge app that takes ages to download, no ads, no JavaScript! It's fast, it's simple, it's elegant, it gets out of your…
I've recently been using GNOME Disks to benchmark some hard disks connected via a USB-SATA adaptor. It was getting results like this: It would start off about where I expected and then slowly taper off to about half. Messing with the benchmark settings made no difference, the graph always had the same shape. Switching to test via dd showed a steady 150MB/s: dd if=/dev/sdf of=/dev/null bs=1M…
There have been a number of times ( eg ) when I've wanted to run a bunch of processes as fast as possible. I needed: A pool of workers - probably matching CPU count Live progress updates - eg % remaining/rate/ETA To capture the process output Be able to resume if stopped I'm sure I could download/compile something purpose-built, but I felt like I should be able to solve this with standard command…
Today I learned there is an informal standard environment variable NO_COLOR which when set to a non-empty string will cause a significant number of CLI tools to not print any ANSI colour in their output. One to bear in mind when using (or writing) CLI tools.
I was gifted a lovely cedar bee-hotel a couple of years ago. It's been really successful, each year it's been mostly filled up. Except last year. Last summer while sat enjoying the sunshine and watching the hotel, I noticed they were acting differently. There were plenty of interested bees, but almost none of them were actually going into any of the tubes. They would get as far as sticking their…
Brendt recently issued a challenge to the PHP community: The goal of this challenge is to parse 100 million rows of data with PHP, as efficiently as possible. The full rules and prizes can be found here . This was somewhat fortunate timing for me as just the day before I had read this excellent article about approaching a similar problem. I didn't expect to win any prizes, but that wasn't why I…
I always set Firefox to 'always ask you where to save files'. However, occasionally when I downloaded a file, it would bypass asking where to save and worse still, automatically open the file?! Turns out there is another section in Firefox's settings which adds special handling for specific file types. To prevent any downloaded files from automatically opening, you need to set all content types to…
I have a number of ESP32-based projects which are battery+solar-powered. If anything goes wrong with them, it can be a real pain to figure out what's wrong. While developing, I always add helpful Serial.print commands in the code. They're not much help when in the field, because the only way I have to read them is a PC. Sometimes you can move the whole thing and get the output, but I thought there…
Ever wanted to 'see' WiFi? With just an LED and a diode you can! When I read this blog post I had to build one. I already had some red LEDs, but I had to buy the special diodes. When they arrived, I quickly soldered them together, making sure the white band on the diode is opposite the flat on the LED. It worked really well. It's a very short range detector and will completely stop working if it's…
I've designed a number of 3D models since I got a 3D printer and discovered OpenSCAD . Most of them were pretty niche, but I wanted to have a public place to share the code/documentation/notes/etc. I started by putting the models on Thingiverse and then into a GitHub repo. Both were a faff, which meant I didn't bother. I also didn't really like that I was always using someone else’s servers. I…
After the success of my last batch of cider , I wanted to make some more. I was also excited to use my new press. I love it. It's so well-built, made with oak and stainless steel. I suspect it will out-last me. Apple Prep I didn't have any more of my own apples, but there was still plenty around. I was easily able to get my hands on 10 kg from neighbours. The apples were quickly washed and then…
When using complex shapes in OpenSCAD I find it's easiest to draw/find an image of the shape I want and then use surface () to convert the image to a 3D shape. It does this by mapping the brightness value of each pixel in the image to a height, AKA a height map. The trouble with surfaces is that OpenSCAD can quickly grind to a halt and eat all your RAM. I've seen 20GB of RAM disappear. Often the…
If you ever implement 6-digit style MFA don't use multiple inputs. It breaks so many ways users interact with forms. The number of times I've gone to put in an MFA code and can't do simple things like paste because the developer only ever tested typing in the code. There are so many ways to interact with inputs. If you try and reimplement them in JS you will miss some: copy/paste, arrow keys,…