Post
From the bridge

A moody shot taken from the Clifton Suspension Bridge as the morning’s fog began to lift.

Post
Becoming better at writing Hugo templates

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:

  1. Read the Go templates documentation.

  2. Understand how to coax Hugo into telling you what the Go template’s . is at any given location.

  3. 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.

Read More…

Post
Airpods Pro: final thoughts

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?

Read More…

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()

Read More…

Post
How does SSH’s ProxyCommand actually work?

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.

Read More…