<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>gpk blog</title><link>https://blog.gpkb.org/</link><description>Recent content on gpk blog</description><generator>Hugo</generator><language>en-gb</language><lastBuildDate>Tue, 13 Jan 2026 08:15:00 +0000</lastBuildDate><atom:link href="https://blog.gpkb.org/index.xml" rel="self" type="application/rss+xml"/><item><title>Resetting an Ideal Halo Zigbee Thermostat</title><link>https://blog.gpkb.org/posts/reset-ideal-halo-thermostat/</link><pubDate>Thu, 27 Nov 2025 20:59:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/reset-ideal-halo-thermostat/</guid><description>&lt;p>I recently bought a house with an Ideal boiler and a wireless thermostat called a
&amp;ldquo;Halo&amp;rdquo;. The boiler has a &amp;ldquo;Halo Smart Interface&amp;rdquo; fitted into it, which should tell the
boiler when to fire. The Halo itself contains the thermostat and communicates with the
Smart Interface using Zigbee.&lt;/p>
&lt;p>During some decorating work the thermostat became disconnected from the boiler. This
really confused the boiler, causing it to remain on, burning gas, indefinitely. This is
quite concerning and doesn&amp;rsquo;t give me much faith in the system, but that&amp;rsquo;s a future
problem. Right now I just need it to work.&lt;/p></description></item><item><title>My Homelab</title><link>https://blog.gpkb.org/posts/homelab-2025/</link><pubDate>Sun, 26 Oct 2025 22:25:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/homelab-2025/</guid><description>&lt;p>It&amp;rsquo;s been about eight years since I started running network services in my home. It all
started with &lt;a href="https://pi-hole.net/" target="_blank">Pi-hole&lt;/a>, which I ran not on a Raspberry Pi, but an Atom-powered Dell Mini
&amp;ldquo;thin client&amp;rdquo; I acquired from eBay. Today I run a lot more and it&amp;rsquo;s become what is now
known as a Homelab.&lt;/p>
&lt;p>I&amp;rsquo;m quite fond of it all, so thought I might as well write about it.&lt;/p>
&lt;div class="pictures">
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/homelab-2025/pc.jpeg" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/homelab-2025/pc.jpeg-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/homelab-2025/pc.jpeg"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/homelab-2025/nas.jpeg" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/homelab-2025/nas.jpeg-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/homelab-2025/nas.jpeg"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/homelab-2025/server.jpeg" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/homelab-2025/server.jpeg-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/homelab-2025/server.jpeg"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
&lt;/div>

&lt;section class="outline-1">
&lt;h2 id="nas">NAS&lt;/h2>
&lt;p>I built my NAS around five years ago. At the time my PC was in a &lt;a href="https://www.fractal-design.com/products/cases/node/node-804/black" target="_blank">Fractal Design Node 804&lt;/a>
case, but I decided this was much more suitable for use as a NAS, so I transplanted my
PC into a smaller case and used the Node for my NAS. The specs are as follows:&lt;/p></description></item><item><title>Run AI Agents in Lightweight Sandboxes</title><link>https://blog.gpkb.org/posts/ai-agent-sandbox/</link><pubDate>Sun, 31 Aug 2025 12:18:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/ai-agent-sandbox/</guid><description>&lt;p>Currently, &amp;ldquo;AI agents&amp;rdquo; like Claude Code are all the rage for software development.
These programs facilitate feeding context into LLMs directly from your codebase and
environment by empowering the LLM to read/write files and run arbitrary code on your
system.&lt;/p>
&lt;p>If you&amp;rsquo;re at all security conscious, the above should make you very uncomfortable. An
intentionally non-deterministic model running arbitrary code and reading arbitrary
files? No thanks. What&amp;rsquo;s worse is programs like Claude Code are not even open source. As
a rule I go to lengths to avoid proprietary software, but I decided to cave on Claude
Code just to see what all the fuss is about.&lt;/p></description></item><item><title>Think Twice about Boolean Fields in your Data Model</title><link>https://blog.gpkb.org/posts/no-booleans-in-normalised-model/</link><pubDate>Sun, 31 Aug 2025 11:50:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/no-booleans-in-normalised-model/</guid><description>&lt;p>The SQL standard includes a &lt;code>boolean&lt;/code> type which, unsurprisingly, represents a Boolean
value. This can be useful, but I&amp;rsquo;m going to argue that it should almost never be used in
a normalised data model.&lt;/p>
&lt;section class="outline-1">
&lt;h2 id="the-problems-with-boolean">The Problems with Boolean&lt;/h2>
&lt;p>Here are few of the problems you&amp;rsquo;ll inevitably run into if you use &lt;code>boolean&lt;/code> in a
normalised data model:&lt;/p>
&lt;section class="outline-2">
&lt;h3 id="it-s-not-really-binary">It&amp;rsquo;s not really binary&lt;/h3>
&lt;p>So you&amp;rsquo;re chatting to your domain expert and he says something like &amp;ldquo;books are either
hardback or paperback&amp;rdquo;. Something twigs in your mind: two options&amp;hellip; binary&amp;hellip; that&amp;rsquo;s a
Boolean! So you duly write:&lt;/p></description></item><item><title>Just Send Me the Prompt</title><link>https://blog.gpkb.org/posts/just-send-me-the-prompt/</link><pubDate>Thu, 31 Jul 2025 09:41:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/just-send-me-the-prompt/</guid><description>&lt;p>If you are thinking about using an LLM to communicate with me, you will be glad to hear
I&amp;rsquo;ve just developed an exciting new technique which will save us both time. Rarely are
such wins possible, so this is surely cause for a celebration.&lt;/p>
&lt;p>The technique goes as follows:&lt;/p>
&lt;ol>
&lt;li>Type up your LLM prompt,&lt;/li>
&lt;li>(Here&amp;rsquo;s where it gets really exciting), instead of sending your prompt to an LLM,
just send the prompt directly to me!&lt;/li>
&lt;/ol>
&lt;p>&amp;ldquo;What?&amp;rdquo; I hear you crying, &amp;ldquo;My prompt doesn&amp;rsquo;t contain all the information you need!&amp;rdquo;&lt;/p></description></item><item><title>Automating Metabase Upgrades on Kubernetes with Flux</title><link>https://blog.gpkb.org/posts/automate-metabase-flux/</link><pubDate>Tue, 27 May 2025 21:04:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/automate-metabase-flux/</guid><description>&lt;p>&lt;a href="https://github.com/metabase/metabase" target="_blank">Metabase&lt;/a> is a really nice free software business intelligence tool. It&amp;rsquo;s quite easy to
deploy; they provide a &lt;a href="https://hub.docker.com/r/metabase/metabase" target="_blank">Docker image&lt;/a> and all you really need for a production instance is
your own database.&lt;/p>
&lt;p>I use &lt;a href="https://fluxcd.io/" target="_blank">Flux&lt;/a> to manage my cluster so I thought it would be nice to utilise
&lt;a href="https://fluxcd.io/flux/components/image/" target="_blank">image update automation&lt;/a> to keep up to date
with updates automatically. But Metabase makes this slightly difficult because it
doesn&amp;rsquo;t use proper semantic versioning on the image tags.&lt;/p></description></item><item><title>Clean Domain Models with SQLAlchemy</title><link>https://blog.gpkb.org/posts/clean-domain-models-sqlalchemy/</link><pubDate>Sun, 08 Dec 2024 21:42:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/clean-domain-models-sqlalchemy/</guid><description>&lt;p>One of the most tried and tested techniques in programming is to build components that
map closely to the real-world problems you are trying to solve. In &lt;a href="https://en.wikipedia.org/wiki/Domain-driven_design" target="_blank">domain-driven design&lt;/a>
(DDD), one of the key tenets is to have a &lt;em>domain model&lt;/em> at the centre of your
application.&lt;/p>
&lt;p>The domain model should be built in close collaboration with domain experts and,
crucially, should consist purely of high-level domain logic and be completely free of
low-level application logic like databases, GUIs, web frameworks etc.&lt;/p></description></item><item><title>Talos Linux on XCP-ng</title><link>https://blog.gpkb.org/posts/talos-linux-xcp-ng/</link><pubDate>Sat, 09 Nov 2024 16:19:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/talos-linux-xcp-ng/</guid><description>&lt;p>Talos Linux is a minimal Linux distribution designed purely for running Kubernetes
nodes. It&amp;rsquo;s pretty neat, check out its website here: &lt;a href="https://www.talos.dev/" target="_blank">https://www.talos.dev/&lt;/a>&lt;/p>
&lt;p>I use XCP-ng in my homelab for running virtual machines and decided to set up a Talos
cluster there. I followed the excellent &lt;a href="https://www.talos.dev/v1.8/introduction/getting-started/" target="_blank">Getting Started guide&lt;/a> but there are a few
additional things I wanted to do right from the start:&lt;/p>
&lt;ol>
&lt;li>Have the Xen Guest Tools (aka Xen Guest Utilities,
xe-guest-utilities. xen-guest-agent etc.) installed on the nodes,&lt;/li>
&lt;li>Have static IP addresses.&lt;/li>
&lt;/ol>
&lt;p>I also had to configure the installation disk as mentioned in the guide, to &lt;code>/dev/xvda&lt;/code>.&lt;/p></description></item><item><title>Hillshading on my Static Maps</title><link>https://blog.gpkb.org/posts/hillshading-static-maps/</link><pubDate>Tue, 15 Oct 2024 21:43:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/hillshading-static-maps/</guid><description>&lt;p>In a &lt;a href="https://blog.gpkb.org/posts/hugo-static-site-maps/">previous article&lt;/a> I wrote about adding maps to my blog, which is a static site. I
use these maps to write about walks I&amp;rsquo;ve done. These maps can be dragged, rotated and
zoomed, but there is no backend tileserver supporting it, it all comes from a single
static file. This is thanks to the PMTiles format and support by the frontend renderer
maplibre-gl.&lt;/p>
&lt;p>In the original article I took a pre-made pmtile file of the world from the Protomaps
project and extracted a smaller part using the pmtiles CLI. Later I ended up making my
own pmtiles directly from OpenStreetMap data, which I&amp;rsquo;ll describe below. This provides a
lot of geographic data like coastlines, forests, roads etc., but what I really wanted
was hillshading, which I&amp;rsquo;ve now figured out.&lt;/p></description></item><item><title>West Highland Way</title><link>https://blog.gpkb.org/posts/west-highland-way/</link><pubDate>Thu, 10 Oct 2024 22:33:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/west-highland-way/</guid><description>&lt;p>The West Highland Way is a waymarked, long-distance path in Scotland. It starts just
north of Glasgow and ends at Fort William in the Highlands. It is probably the most
famous of Scotland&amp;rsquo;s Great Trails (similar to the National Trails in England and
Wales). In September 2024 I walked the West Highland Way over seven days with my partner
&lt;a href="https://www.peregrinavicki.com/" target="_blank">Vicki&lt;/a>.&lt;/p>
&lt;div class="pictures">
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240905_164951.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240905_164951.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240905_164951.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240904_151647.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240904_151647.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240904_151647.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240904_160025.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240904_160025.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240904_160025.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240906_201455.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240906_201455.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240906_201455.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240903_150815.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240903_150815.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240903_150815.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240906_101020.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240906_101020.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240906_101020.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240906_094106.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240906_094106.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240906_094106.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
&lt;/div>

&lt;div class="pictures">
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240907_120515.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240907_120515.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240907_120515.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240905_165805.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240905_165805.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240905_165805.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240907_130253.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240907_130253.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240907_130253.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240903_141207.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240903_141207.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240903_141207.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240903_155620.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240903_155620.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240903_155620.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240906_115821.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240906_115821.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240906_115821.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240905_120155.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240905_120155.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240905_120155.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
&lt;/div>

&lt;div class="pictures">
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240907_100205.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240907_100205.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240907_100205.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240907_122953.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240907_122953.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240907_122953.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240907_122940.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240907_122940.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240907_122940.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/whw/20240905_102117.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240905_102117.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/whw/20240905_102117.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
&lt;/div>

&lt;section class="outline-1">
&lt;h2 id="planning">Planning&lt;/h2>
&lt;p>At 154 km the WHW will take most people between 5-10 days to complete. We didn&amp;rsquo;t fancy
any super long days, so we decided to do it in 7 days.&lt;/p></description></item><item><title>Kubernetes Ingress vs Load Balancer</title><link>https://blog.gpkb.org/posts/k8s-ingress-v-load-balancer/</link><pubDate>Tue, 06 Aug 2024 21:10:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/k8s-ingress-v-load-balancer/</guid><description>&lt;p>I&amp;rsquo;ve been using Kubernetes successfully for a while, but I felt like I still didn&amp;rsquo;t
fully understand the difference between an Ingress and a LoadBalancer. Whenever I tried
to find an explanation I&amp;rsquo;d find some vague thing like &amp;ldquo;they are sort of the same, but
not really&amp;rdquo;.&lt;/p>
&lt;p>The problem is I was thinking about these things wrong. One is not a replacement for
the other; they exist in different planes of abstraction within k8s. For someone who
just wants to deploy a web service, there are three orthogonal concepts you need to
understand in k8s.&lt;/p></description></item><item><title>Make Reading a Habit</title><link>https://blog.gpkb.org/posts/make-reading-habit/</link><pubDate>Sun, 04 Aug 2024 12:18:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/make-reading-habit/</guid><description>&lt;p>Habits are really important. Long-term goals are too but, ultimately, habits are what
you are doing to yourself day in, day out. Your habits determine what goes into your
body (your diet), your physical condition (diet and exercise) and your mental condition
(sleep and everything else).&lt;/p>
&lt;p>I think you should make reading one of your habits.&lt;/p>
&lt;p>The benefits of reading are many. First of all, it&amp;rsquo;s a great form of entertainment. You
can read anywhere; you won&amp;rsquo;t disturb anyone. I love films, but the books are almost
always better than the films. Really. A good book can conjure images in the mind that a
film could never capture and these images never age. You&amp;rsquo;ll never go back to a favourite
book and be disappointed at how bad the CGI looks now.&lt;/p></description></item><item><title> Odd Problem Accessing OPNsense Web UI via "OPT1" Interface</title><link>https://blog.gpkb.org/posts/opnsense-pfsense-reply-to/</link><pubDate>Wed, 24 Apr 2024 21:50:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/opnsense-pfsense-reply-to/</guid><description>&lt;p>I ran into a weird problem where I couldn&amp;rsquo;t access the OPNsense web UI using an OPT1
interface. The fix is easy, but it can be very confusing and it&amp;rsquo;s all caused by an
unintuitive default.&lt;/p>
&lt;div class="tldr">
&lt;div class="tldr-heading">
&lt;p>tl;dr&lt;/p>
&lt;/div>
&lt;p>If you can&amp;rsquo;t access the web UI via an OPT1 interface, try disabling the &amp;ldquo;reply-to&amp;rdquo;
feature: &lt;a href="https://docs.opnsense.org/manual/interfaces.html" target="_blank">https://docs.opnsense.org/manual/interfaces.html&lt;/a>&lt;/p>
&lt;/div>
&lt;p>I&amp;rsquo;ve been playing around with OPNsense inside a VM as I prepare to replace my current
pfSense router which is no longer fast enough. I have a quad network card which is
passed through at the hardware level and, in addition, I have the virtual network
interface provided by the hypervisor, xcp-ng.&lt;/p></description></item><item><title>Git is a Version Control System</title><link>https://blog.gpkb.org/posts/git-is-a-version-control-system/</link><pubDate>Sat, 24 Feb 2024 17:23:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/git-is-a-version-control-system/</guid><description>&lt;p>The title of this post isn&amp;rsquo;t supposed to be provocative. After all, it&amp;rsquo;s simply the
textbook definition of what git is. So why bother stating it? Well, I&amp;rsquo;ve worked with a
fair few junior developers now and I&amp;rsquo;m starting to see a pattern. Many of these
developers have never programmed &lt;em>without&lt;/em> git and they see git simply as &amp;ldquo;the way to
get new code into a repository&amp;rdquo;. A glorified copy, essentially&amp;mdash;but an annoying one
that is prone to going wrong.&lt;/p></description></item><item><title>Norfolk Coast Path</title><link>https://blog.gpkb.org/posts/norfolk-coast-path/</link><pubDate>Thu, 15 Feb 2024 23:33:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/norfolk-coast-path/</guid><description>&lt;p>The Norfolk Coast Path (NCP) is a waymarked, long-distance footpath and &lt;a href="https://www.nationaltrail.co.uk/" target="_blank">National Trail&lt;/a>
in England. It stretches from Hunstanton all the way along the Norfolk coastline to
Hopton. I walked it with my partner &lt;a href="https://www.peregrinavicki.com/" target="_blank">Vicki&lt;/a> over the course of seven days in
September 2022.&lt;/p>
&lt;div class="pictures">
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/ncp/DSC_1821.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1821.JPG-sm.jpeg"
 alt="A view from a hill next to the sea with sea and houses visible."
 title="The view from the Beaston bump."
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1821.JPG"
 alt="A view from a hill next to the sea with sea and houses visible."
 title="The view from the Beaston bump."
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/ncp/DSC_1822.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1822.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1822.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/ncp/DSC_1826.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1826.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1826.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/ncp/DSC_1828.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1828.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1828.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/ncp/DSC_1831.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1831.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1831.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/ncp/DSC_1844.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1844.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1844.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
 
 
 
 
 &lt;figure
 class="pictures-picture"
 x-data="{ open: false, loading: 'lazy' }"
 x-intersect="loading='eager'"
 >
 &lt;a href="https://blog.gpkb.org/web-images/ncp/DSC_1847.JPG" @click.prevent="open = ! open">
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1847.JPG-sm.jpeg"
 alt=""
 title=""
 />
 &lt;/a>
 &lt;span
 class="lightbox"
 x-cloak
 x-show="open"
 x-transition:enter-start="closed"
 x-transition:leave-end="closed"
 @click="open = false"
 >
 &lt;img
 src="https://blog.gpkb.org/web-images/ncp/DSC_1847.JPG"
 alt=""
 title=""
 loading="lazy"
 x-bind:loading="loading"
 />
 &lt;/span>
 &lt;/figure>
 
&lt;/div>

&lt;section class="outline-1">
&lt;h2 id="planning">Planning&lt;/h2>
&lt;p>The NCP is around 135 km (83 miles) long and quite flat. The way is mostly on good, well
trodden paths with some slower sections on sandy and shingle beaches (but you can often
choose to walk inland on firmer ground instead). Fortunately there are no pebbles and
the shingles didn&amp;rsquo;t become too tiring.&lt;/p></description></item><item><title>Emacs Undo Redo</title><link>https://blog.gpkb.org/posts/emacs-undo/</link><pubDate>Thu, 14 Dec 2023 22:18:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/emacs-undo/</guid><description>&lt;p>At first glance, undo seems like a simple thing expected of most software these days and
hardly worth writing about. Indeed, when I say Emacs has a very powerful undo
system&amp;mdash;probably more so than any other text editor&amp;mdash;you may wonder what could make an
undo system powerful. So let&amp;rsquo;s start by considering two big problems most undo systems
have:&lt;/p>
&lt;ol>
&lt;li>If you undo something, make some changes, then change your mind, what you undid is
now lost and unrecoverable,&lt;/li>
&lt;li>If you make changes in two parts of the same file you cannot undo changes in the
first part without undoing changes in the second part too.&lt;/li>
&lt;/ol>
&lt;p>Emacs comes with solutions to each of these out of the box. Read on to understand how it
works and how we can improve upon the defaults even more.&lt;/p></description></item><item><title>Bash History Hacks</title><link>https://blog.gpkb.org/posts/project-local-bash-history/</link><pubDate>Tue, 05 Dec 2023 22:22:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/project-local-bash-history/</guid><description>&lt;p>When you work a lot on the command line, history can be invaluable. I&amp;rsquo;ve lost count of
the number of times I&amp;rsquo;ve forgotten how I ran some earlier command and used my bash
history to find out what it was. This is one of the big advantages of using CLIs over
GUIs.&lt;/p>
&lt;section class="outline-1">
&lt;h2 id="accessing-history">Accessing history&lt;/h2>
&lt;p>The main interface I use to my history is &lt;code>^P&lt;/code> (&lt;code>Ctrl-P&lt;/code>). This recalls the previous
command from history. Subsequent presses step further back and &lt;code>^N&lt;/code> steps forward
again. These keys are set in muscle memory at this point, I use them that much (they
also work in emacs and many other places).&lt;/p></description></item><item><title>A Lament for the Firefox Quick Find Key</title><link>https://blog.gpkb.org/posts/lamenting-firefox-quick-find/</link><pubDate>Thu, 16 Nov 2023 20:14:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/lamenting-firefox-quick-find/</guid><description>&lt;p>For as long as I&amp;rsquo;ve been a Firefox user&amp;mdash;almost 20 years at this point&amp;mdash;it has
featured a &amp;ldquo;quick find&amp;rdquo; bound to the venerable &lt;code>/&lt;/code> (forward slash) key.&lt;/p>
&lt;p>Following a pattern established by other software like &lt;code>less&lt;/code>, &lt;code>man&lt;/code>, and &lt;code>vi&lt;/code> the slash
key was simple: it finds stuff in the current page.&lt;/p>
&lt;p>Common patterns like this are great. It&amp;rsquo;s why everyone has agreed on what &lt;code>Ctrl-C&lt;/code> and
&lt;code>Ctrl-V&lt;/code> (or very similar) should do across all operating systems. The &lt;code>/&lt;/code> key used to
be like this, but not any more.&lt;/p></description></item><item><title>Using Nerd Icons in Org Agenda</title><link>https://blog.gpkb.org/posts/org-agenda-nerd-icons/</link><pubDate>Tue, 14 Nov 2023 23:56:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/org-agenda-nerd-icons/</guid><description>&lt;p>Org mode supports icons in its agenda views. The icons can be given as either file
paths to images (like SVGs), as image data or as a display property. I use a &lt;a href="https://www.nerdfonts.com/" target="_blank">Nerd Font&lt;/a>
along with the &lt;a href="https://github.com/rainstormstudio/nerd-icons.el" target="_blank">nerd-icons&lt;/a> package in my Emacs config, so I thought I might as well
enable icons in my org agenda views.&lt;/p>
&lt;figure>&lt;img src="https://blog.gpkb.org/emacs/org-agenda-icons.png">
&lt;/figure>

&lt;p>The nice thing about using nerd fonts is this works perfectly in text mode too (assuming
you have a nerd font configured for your terminal emulator).&lt;/p></description></item><item><title>Custom Static Vector Maps on your Hugo Static Site</title><link>https://blog.gpkb.org/posts/hugo-static-site-maps/</link><pubDate>Fri, 27 Oct 2023 00:11:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/hugo-static-site-maps/</guid><description>&lt;p>This blog is a static site built with &lt;a href="https://gohugo.io/" target="_blank">Hugo&lt;/a>. Being static means it can be served from a
basic, standard (you might say &lt;em>stupid&lt;/em>) web server with no server-side scripting at
all. In fact, this blog is currently hosted on Github Pages, but it could be anywhere.&lt;/p>
&lt;p>Up until now, if you wanted to include an interactive map on a static site you were
limited to using an external service like Google Maps or Mapbox and embedding their JS
into your page. This would then call to their non-static backend service to produce
some kind of tiles for your frontend.&lt;/p></description></item><item><title>Working on Multiple Web Projects with Docker Compose and Traefik</title><link>https://blog.gpkb.org/posts/multiple-web-projects-traefik/</link><pubDate>Mon, 02 Oct 2023 09:00:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/multiple-web-projects-traefik/</guid><description>&lt;p>Docker Compose is a brilliant tool for bringing up local development environments for
web projects. But working with multiple projects can be a pain due to clashes. For
example, all projects want to listen to port 80 (or perhaps one of the super common
higher ones like 8000 etc.). This forces developers to only bring one project up at a
time, or hack the compose files to change the port numbers.&lt;/p></description></item><item><title>Resolving Private IP Addresses with pfSense DNS Resolver</title><link>https://blog.gpkb.org/posts/pfsense-unbound-private/</link><pubDate>Sun, 01 Oct 2023 23:10:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/pfsense-unbound-private/</guid><description>&lt;p>I use the Unbound DNS resolver built in to pfSense. By default the resolver filters out
any results that are private IP addresses. Normally this makes sense: no public domain
should have a private address. But sometimes it does make sense. For example there are
some useful services like &lt;a href="https://sslip.io/" target="_blank">sslip.io&lt;/a> that will resolve to any IP address that you like.
So &lt;code>127.0.0.1.sslip.io&lt;/code> resolves to to &lt;code>127.0.0.1&lt;/code>. This is can be useful for local
development, especially when working with containers and reverse proxies and the like.&lt;/p></description></item><item><title>Why is Emacs Hanging?</title><link>https://blog.gpkb.org/posts/emacs-hangs-debug/</link><pubDate>Thu, 21 Sep 2023 14:10:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/emacs-hangs-debug/</guid><description>&lt;p>Even after using Emacs for 15 years there&amp;rsquo;s still so much I can learn. I probably should
have already known this, but there&amp;rsquo;s a first time for everything.&lt;/p>
&lt;p>It&amp;rsquo;s rare that Emacs hangs. Exceedingly rare. Which is probably why I didn&amp;rsquo;t know how to
deal with it. Today Emacs started hanging when trying to open files over a remote TRAMP
session (SSH).&lt;/p>
&lt;p>The most important key of all that everyone who uses Emacs knows is &lt;code>C-g&lt;/code>. This is the
universal &amp;ldquo;quit&amp;rdquo; key and it has the power to interrupt any long running processes. What
I didn&amp;rsquo;t know about is &lt;code>M-x toggle-debug-on-quit&lt;/code>. I&amp;rsquo;ve used &lt;code>toggle-debug-on-error&lt;/code>
extensively when programming Elisp (I even have it bound to a key in Elisp
buffers). &lt;code>toggle-debug-on-quit&lt;/code> is similar except the debugger is invoked when you
&lt;code>C-g&lt;/code>.&lt;/p></description></item><item><title>Replacing Strings in an Entire Project</title><link>https://blog.gpkb.org/posts/emacs-regexp-replace/</link><pubDate>Tue, 22 Aug 2023 14:22:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/emacs-regexp-replace/</guid><description>&lt;p>This is a little trick I just applied and thought was cool enough to write down.&lt;/p>
&lt;p>Let&amp;rsquo;s say you want to replace a name that is used throughout a project. Due to various
conventions/restrictions in use the name might appear in several forms like:
&lt;code>MY_COOL_NAME&lt;/code>, &lt;code>my-cool-name&lt;/code>, &lt;code>my_cool_name&lt;/code> etc.&lt;/p>
&lt;p>In Emacs you can invoke regexp replace across an entire project by invoking
&lt;code>project-query-replace-regexp&lt;/code>, by default bound to &lt;code>C-x p r&lt;/code>. This will first prompt
for the regexp to search for, then what to replace it with.&lt;/p></description></item><item><title>My 2023 Emacs Python Setup</title><link>https://blog.gpkb.org/posts/emacs-python-2023/</link><pubDate>Tue, 15 Aug 2023 14:19:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/emacs-python-2023/</guid><description>&lt;p>I&amp;rsquo;ve been using Emacs for almost 15 years now. Somewhat surprisingly, I hadn&amp;rsquo;t touched
my config in three years! It&amp;rsquo;s been working that well. But now that Emacs 29 has been
released I&amp;rsquo;ve decided to take a look at what&amp;rsquo;s new and there have been some big changes,
particularly for Python.&lt;/p>
&lt;section class="outline-1">
&lt;h2 id="goodbye-elpy-goodbye-projectile">Goodbye Elpy, Goodbye Projectile&lt;/h2>
&lt;p>&lt;a href="https://github.com/jorgenschaefer/elpy/" target="_blank">Elpy&lt;/a> has been the primary mode for Python development for me for years now. But sadly,
it looks like the project is no more. The good news is there are better ways to do what
it did. It&amp;rsquo;s bittersweet to say goodbye to it and I will be eternally grateful to the
authors, but progress is progress.&lt;/p></description></item><item><title>Install Calibre without Root</title><link>https://blog.gpkb.org/posts/calibre-rootless-install/</link><pubDate>Sun, 13 Aug 2023 13:23:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/calibre-rootless-install/</guid><description>&lt;p>On Linux, software should generally be installed with your system package manager (apt,
yum, portage etc.) However, Calibre is a bit &amp;ldquo;special&amp;rdquo; in this respect. While
well-loved, it&amp;rsquo;s known to be a bit difficult to package (to say the least) and most
distro packages you&amp;rsquo;ll find are out of date. The &lt;a href="https://calibre-ebook.com/download_linux" target="_blank">official website&lt;/a> recommends against
using any distro packages and instead installing it directly from the site.&lt;/p>
&lt;p>Unfortunately, the official instructions are problematic for a number of reasons. For a
start, copying and pasting commands from the browser is considered dangerous. But
that&amp;rsquo;s easy to fix, in bash do &lt;code>Ctrl-X Ctrl-E&lt;/code> and your preferred text editor will be
opened for you to type your command. This means you can inspect what is pasted before
is run (save the file then exit the editor to run the command). Very important. Always
do this when copy/pasting from the web.&lt;/p></description></item><item><title>Cooking with Make</title><link>https://blog.gpkb.org/posts/cooking-with-make/</link><pubDate>Thu, 03 Aug 2023 00:00:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/cooking-with-make/</guid><description>In which I compare cooking food with building software</description></item><item><title>Arduino Programming with Emacs</title><link>https://blog.gpkb.org/posts/emacs-arduino/</link><pubDate>Mon, 31 Jul 2023 19:30:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/emacs-arduino/</guid><description>&lt;p>If you want to start Arduino programming you&amp;rsquo;ll notice a lot of the documentation and
tutorials are centred around the Arduino IDE. Now, obviously, as an Emacs user you&amp;rsquo;ll
be loath to install something like Arduino IDE, let alone actually use it. The good
news is it&amp;rsquo;s super easy to get started with Arduino with any editor, including Emacs and
even Vim if you so desire.&lt;/p>
&lt;p>All the Arduino IDE is doing is calling a cross-compiler toolchain then using &lt;a href="https://github.com/avrdudes/avrdude" target="_blank">&lt;code>avrdude&lt;/code>&lt;/a>
to communicate with the Arduino to upload software. The Arduino Uno and Nano both use
the Atmel AVR platform so what you need is a toolchain that can target that platform.
Now, you could install your own toolchain and call &lt;code>avrdude&lt;/code> directly. If you know how
to do that then I guess you can stop reading now. But if you don&amp;rsquo;t, or aren&amp;rsquo;t
interested in learning how (it&amp;rsquo;s not very interesting), then read on.&lt;/p></description></item><item><title>Building a Home Cinema on a Shoestring</title><link>https://blog.gpkb.org/posts/shoestring-home-cinema/</link><pubDate>Mon, 24 Jul 2023 14:25:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/shoestring-home-cinema/</guid><description>&lt;p>I love going to the cinema, but I&amp;rsquo;ve always been disappointed that I can&amp;rsquo;t see older
films and I can&amp;rsquo;t see them when it&amp;rsquo;s convenient for me. There have always been ways to
watch films at home, but even today when large screens and high-definition formats are
ubiquitous, it&amp;rsquo;s just not the same as the cinema experience. There&amp;rsquo;s something
completely different about the big screen that a TV in a living room can&amp;rsquo;t replicate.
For that reason I&amp;rsquo;ve wanted my own home cinema for as long as I can remember. The
problem is I don&amp;rsquo;t want to spend a lot of money on it.&lt;/p></description></item><item><title>Writing a Blog with Org-mode</title><link>https://blog.gpkb.org/posts/hugo-org-mode/</link><pubDate>Sat, 15 Jul 2023 13:43:00 +0000</pubDate><guid>https://blog.gpkb.org/posts/hugo-org-mode/</guid><description>&lt;p>I&amp;rsquo;ve always thought I should write a blog, but I just never got around to setting it
up. I know there are services you can simply sign up to and start writing, but that
isn&amp;rsquo;t for me. I have two requirements for this thing:&lt;/p>
&lt;ol>
&lt;li>I can write using tools of my choice,&lt;/li>
&lt;li>I can host it anywhere.&lt;/li>
&lt;/ol>
&lt;p>My tool of choice for writing anything is emacs and, for natural language in particular,
&lt;a href="https://orgmode.org/" target="_blank">org-mode&lt;/a>. This is a bit like markdown, but better. For version control and deployment
I use git.&lt;/p></description></item></channel></rss>