My run recovery routine

I got my start in running through the Couch to 5k program. It wasn't always easy, but it got me running on a regular basis. As soon I completed my first 5k I wanted to push myself further. However, once I started training for longer distances I was much more sore after my runs. Worse still, I was just as sore the morning after.

After a few too many days walking around with stiff legs, I spent some time researching recovery tips. This isn't medical advice, it's just what I've tested and works for me. I kept t simple so that I'd actually follow through with it.

Stretch when my run is done
I do a slow walk for a minute or two and then stretch my quads and calf muscles.
Drink something containing electrolytes
I've tried a couple of different sports drinks, and most don't taste all that great to me. Coconut water tastes even worse to me, but it contains less sugar than the other choices.
I wait around 30 minutes before showering. This gives me time to cool down so that I'm not still sweating once I'm clean.
Roll my legs with a foam roller
There are some pretty scary looking rollers out there, but so far a simple one has done the trick for me. 60 seconds on each leg is all it takes to work the knots out.
Wear compression socks
This is my favourite part. I got a pair of socks with firm (20-30 mmHg) compression which is fairly tight, but not uncomfortable. Once they're on I'll wear them for the day.
Avoid alcohol for 24 hours
This isn't a strict rule, but I find that booze hits a lot harder if I've run beforehand. It's also a diuretic which will slow re-hydration and recovery. I still have a drink to celebrate finished races though.

Out of all these, I've found compression socks reduce soreness the most - they're like a gentle massage you wear. After races and difficult runs I'll wear a pair of lower pressure socks overnight.

Styling my RSS feed

This is a little xsl stylesheet I put together to make my RSS feed look nicer when viewed in the browser.

RSS feed with styles

Creating the basic feed stylesheet

The full stylesheet lives at, but the basics are below:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="">
  <xsl:output method="html"/>

  <xsl:template match="/">
	<title>rss feed</title>

	  <xsl:element name="a">
	    <xsl:attribute name="href">
	      <xsl:value-of select="/rss/channel/link" />
	    <xsl:value-of select="/rss/channel/title"/>

	<div class="items">
	  <xsl:apply-templates select="/rss/channel/item" />

  <xsl:template match="item">
      <xsl:element name="a">
	<xsl:attribute name="href">
	  <xsl:value-of select="link"/>
	<xsl:value-of select="title" />
	<xsl:value-of select="pubDate" />

The important parts are:

<xsl:template match="/">
This builds the body of the document. It adds a <h1> heading that links to the main site, along with a container for feed items.
<xsl:template match="item">
This displays individual items as post links with the date underneath.

Adding the stylesheet to the feed

The following line goes after the initial <?xml ?> declaration.

<?xml-stylesheet type="text/xsl" href="/feed.xslt.xml" ?>

Adding the feed title

The page title can be added dynamically from the feed by replacing the <title> element with the following:

<xsl:element name="title">
  <xsl:value-of select="/rss/channel/title"/>

Tidying up the appearance

This step is totally optional, but I wanted the feed to look a little more appealing. This goes inside the <head> element:

 html {
     background: #eee;

 body {
     max-width: 64em;
     margin: 1em auto;
     font-family: monospace;
     font-size: 1.2em;
     background: white;

 h1 {
     margin: 0;
     background: #f6f6f6;
     padding: 0.5em;

 .items {
     padding: 1em;

 span {
     color: #aaa;
     font-size: 0.8em;

 a {
     color: #0047b5;
     border-bottom: 2px solid transparent;
     text-decoration: none;
     transition: all 150ms ease;

 a:hover {
     color: #005be8;
     border-bottom: 2px solid #005be8;

And finally, I added the following to the <head> element to make the feed mobile-friendly:

<meta name="viewport" content="width=device-width, initial-scale=1" />

I don't think that many people actually visit the feed directly, but with this change it's a little friendlier when they do.

Eight years of Beeminder

Beeminder has been part of my productivity arsenal for over eight years now. Even though that's a really long time to use a tool, it's still something that I struggle to explain. When I tell people that it's a service I pay money to when I don't get things done, the reaction is usually "why on Earth would you want to do that?!" I suppose that's fair.

The Beeminder team has written plenty of articles about the term "Akrasia" and how their software works to combat it. I treat it like corrective lenses; I don't exactly like wearing them, but they help me live my life. I'm not going to stop just because some people think they're weird.

Even though it's been a long time since I wrote it, my advice from "One year with Beeminder" still holds true. I try to automate as many goals as possible, and with few exceptions I don't use "time worked" for my goals.

One change I have made is to try and tie goals to an external data source.

For example, in 2014 I set myself the goal of releasing a game every month. Once I started derailing I resorted to entering dummy data instead of taking the losses. Because the data was limited to what I entered into Beeminder, I could get away with fudging the numbers without anyone knowing.

For new goals I will try to integrate things like repository commits, external API's, or habits that I track via org-mode.

My most successful goals so far:

Run a full marathon

I track all of my runs using RunKeeper, and then link that to a goal to track my miles run. Looking at the graph, it gets steeper around July 2019 when I started my half training. December 2019 has an even sharper increase, followed by a nice jump in March when I ran the full marathon.

There are a few jumps in the red line from when I set my goal to derail unless I ran that day. This was a handy tool for when I had miles built up and was contemplating ditching a training run.

Increase my earnings
My freelance earnings flat-lined towards the end of 2019, so I set up a goal to track my billed hours. It's a little weird, but it's kept me conscious of what I'm working on.
(Almost) write a book

When I started work on "Writing PHP with Emacs" I had a goal to track the number of words written. This was great for getting initial ideas out of my head, but it became less useful over time once I began editing things. I dropped this goal after two months.

After the initial release I stopped writing, which isn't the smartest way to get things done. Since then I've set up two goals: one to track when I publish new versions, and one to track when I make commits to the book's repository. Both of these together ensure that I'm writing and releasing things.

Exercise three times a week
I have an org-mode document that I use to track my workouts, and when a workout is completed it sends a datapoint to Beeminder. I considered tracking individual exercises (such as "do X pushups per week"), but this one has worked really well so far, and I think that tracking exercises could cause me to over train instead of derailing.
Do my GTD weekly review
In the past I struggled to stay on top of my weekly reviews. Since adding this goal I haven't missed a single one and it has made a big difference into how effective my GTD system is.

I've had plenty of derailments - Beeminder's term for failing to meet a deadline - but the value from staying on track far outweighs anything that I've lost.

Since I started I've also become more comfortable with creating short-term goals. Not everything has to be a life-changing habit, and these temporary goals often build into larger ones.

Beeminder is weird, but sometimes the risk of losing $5 is all it takes to get me across the finish line.

Sharing an Emacs configuration across machines

Once I started using Emacs more frequently, I wanted to use it on every machine I owned. But I found it a pain to keep the configuration synchronized between machines; there were always some little changes I'd need on my laptop and not my desktop (and vice versa). Preventing these changes from affecting the wrong machine became a headache, but thankfully there are ways around it with a little bit of elisp.

My current setup now uses the same configuration directory, but with custom setup files that only affect certain users and operating systems.

Here's how it all fits together.


no-littering is a small package that keeps the ~/.emacs.d directory clean and organized. This makes it easier to exclude machine-specific files during synchronization.

It's available on melpa and doesn't require any configuration to get started; a single line is all that's required to use it:

;; Standard load.
(require 'no-littering)

;; or with use-package
(use-package no-littering)


I sync my ~/.emacs.d directory between machines using Dropbox. The following directories are excluded:

  • ~/.emacs.d/auto-save-list/
  • ~/.emacs.d/backup/
  • ~/.emacs.d/etc/
  • ~/.emacs.d/server/
  • ~/.emacs.d/var/

These directories often contain things that are tied to the current machine's directory layout, which can cause issues when they are synchronized. The backup directory in particular generates a lot of files and excluding that cut out a lot of headaches.

Per-user configuration

All of my per-user configuration lives in the ~/.emacs.d/users/{username}/ directory. All files in that directory are loaded last so that they override any default settings.

The following snippet is placed just before (provide 'init) in my ~/.emacs.d/init.el file.

;; Configure the user directory path.
(defvar user-settings-dir
  (concat user-emacs-directory "users/" user-login-name)
  "Settings directory for the current user.")

(defun pn/load-user-init-file (file)
  "Load an init file from FILE."
  (load (format "%s/%s" user-settings-dir file)))

;; Load all elisp files in the current user directory.
(when (file-exists-p user-settings-dir)
  (mapc #'pn/load-user-init-file
	(directory-files user-settings-dir nil "^[^#].*el$")))

Per-OS configuration

The final piece of the puzzle is setting up configuration that only runs on a specific operating system. I use this for setting fonts, paths, and themes.

I put this code in a user-specific init.el file, although it can also go at the end of the main init.el file.

(when (string= "windows-nt" system-type)
  ;; Windows only configuration.

(when (string= "darwin" system-type)
  ;; Mac OS only configuraiton.

(when (string= "gnu/linux" system-type)
  ;; Linux only configuration.

Using all of these techniques together allows me to keep my Emacs configuration in sync with a minimum of fuss.

30 days of blogging kick off

One of my minor goals for 2020 is to try a 30 day trial of blogging every day. The first post on this site was published on June 8th, 2006 (5,254 days ago). Since then I've written 114 posts, which works out at one post every 46 days. I am not a prolific writer.

I've always wondered what would happen if I wrote more often. Would my writing improve? Would more people visit the site? Would I find inner peace? This is my way of finding out.

I am expecting this to be quite difficult, so I set up a goal on Beeminder to help keep me on track. Most of my beeminder goals have a week of mercy after failure, but this one does not, which means if I fail to publish a post I still need to write the next day. I've capped the charge at $5, but if I miss everything it would cost $150. Ouch.

My current list of post ideas has around twenty topics, but I'm expecting to come up with new ideas as I write. So if all goes well, in 30 days time this site will have 144 posts.