I recently added a new section to the site: Projects. It’s a quick and dirty rendering of some of my favourite things I’ve built over the last twenty-five years. Go check it out 🧙
Building it reminded me that I have never fully become comfortable with Hugo. I find myself almost constantly copy-and-paste editing, either from my own existing templates or from the Internet. I’ve never dug deeply enough into Hugo templates to become confident writing them.
This post is about how I finally did that digging, so I could bring my ideas to life without pulling out so much hair 😖
The overview of getting back into Hugo (ie, “future-Mike should do this when building new bits of site”) is:
Read the Go templates documentation.
Understand how to coax Hugo into telling you what the Go template’s .
is at
any given location.
Once you know what .
is, how do you look up what you can do with it? We’ll
look at that last.
This last one is useful outside of template debugging, as Hugo’s
documentation references structs like page.Page
but doesn’t always link to
the struct’s documentation.
Let’s take each of those in turn and show how to do them.
A few weeks over five years ago, I wrote AirPods Pro: first impressions.
After five years of daily use, those first AirPods Pro have started to show their age. People complain of “hissing” during video conferences. Sometimes one airpod will have trouble connecting, or will generate its own hiss until I literally hit it. Hardware issues, from what I can tell.
Now we’ve hit the end of their life, it’s time to write some final thoughts.
I finished that previous piece with:
Time will tell how I end up settling long term, but Apple have hit a good balance with these headphones. I suspect the convenience of the true wireless, good-enough noise-cancelling and compact size may make these my go-to headphones most of the time.
So what ended up happening?
I needed to start an application each time I unlocked my Mac. But there didn’t seem to be an obvious way to run something every unlock in macOS.
For example, I found that launchd
has an on-wake event. Great! But that
doesn’t quite work because it also fires on power nap, which is a kind of
mini-wake-up in macOS terms. I didn’t want to run the app each time power nap
happened, or actually even when a normal wake up happened. I only wanted it when
I was actually sitting at and unlocking the machine.
It turns out that Hammerspoon, which I’ve used
for a long time to automate various slightly esoteric things1, has a module
tucked away for this. hs.caffeinate.watcher
had what I needed. I’ll
include the code snippet in the lede, and add a bit more detail below.
function runOnUnlock(eventType)
if (eventType == hs.caffeinate.watcher.screensDidUnlock) then
-- Carry out your unlock event here, eg:
hs.execute("/path/to/shell/script.sh", true)
end
end
local lockWatcher = hs.caffeinate.watcher.new(runOnUnlock)
lockWatcher:start()
I have been writing support for SSH’s ProxyCommand
into a product at work over
the past month or so. I find protocols fascinating, particularly those as old as
/ with the pedigree of SSH.
ProxyCommand
is an interesting corner in the set of (defacto) SSH standards.
It is used to establish a secure connection to a destination host, where that
destination host cannot be directly accessed by the local machine. It is mostly
used when you want to tunnel through a bastion host. It specifies a
command that your SSH client executes to create a proxied connection — hence
the name — to the destination host through the bastion.
I’m writing about it because my experience over the last few months suggests
that ProxyCommand
can be slightly mind-bending. Certainly it took me a little
while to wrap my head around what is going on.
So let’s take a look at how it works.
Gradually, then Suddenly: Upon the Threshold is a good piece to contrast with my previous link to a post that considered the evidence that LLMs may be plateauing
We know AI is a general purpose technology - it will have wide-ranging effects across many industries and areas of our lives. But it is also flawed and prone to errors in some tasks, while being very good at others. Combine this jagged frontier of LLM abilities with their widespread utility and the concept of capability thresholds and you start to see the development of LLMs very differently. It isn’t a steady curve but a series of thresholds that, when crossed, suddenly and irrevocably change aspects of our lives.