Caius Theory

Now with even more cowbell…

SoundCloud RSS Feeds

SoundCloud appears to have gained popularity in recent times for hosting podcasts on. As a consumer of their service they're pretty good at everything except having a visible RSS feed on a profile page for a show! If I want to listen to a show in my podcast app of choice, an RSS feed is the easiest way for me to achieve that.

Turns out SoundCloud do have RSS feeds, they're just well hidden and unfindable from the profile page itself. Thankfully, you can construct the URL for it from information on the profile page, and here's a bookmarklet that will do it for you:


Or as a handy link to copy to your bookmarks bar. Simply click/run that when on a SoundCloud profile page and you'll be taken to the RSS Feed URL.

exec(3) in Go

Using exec(3) from Go is simple enough, once you figure out to look in the syscall package and how to pass arguments to the new command.

As a simple example, I'm going to exec /bin/echo with a hardcoded string from the go binary. The program built here is in the gecho (Gecko, geddit?) git repo, which each stage as a commit.

In our main function lets setup some variables we're going to need for arguments to syscall.Exec:

func main() {
  cmdPath := "/bin/echo"
  cmdArgs := []string{"Hello", "World"}
  cmdEnv := []string{}    

(We could use os.Environ() for cmdEnv to take the ENV from the go binary, but we don't require anything from the environmnt here so it doesn't matter that we aren't.)

Now we have the arguments for syscall.Exec, lets add that in and see what happens:

err := syscall.Exec(cmdPath, cmdArgs, cmdEnv)
if err != nil {

And running the file (go run gecho.go compiles & runs for us) gives the following output:


Err, say what now? Where's "Hello" gone?!

Took me a while to figure this out when I originally ran into this. The answer is staring us right in the face if we go look at the syscall.Exec docs. Lets have a look at the function signature, argument names and all:

func Exec(argv0 string, argv []string, envv []string) (err error)

Hmm. The first argument is argv0 (and a string), rather than binaryPath or something similar. The second argument is then argv and an array of strings.

At this point I remember that the first element of argv in other runtimes is the name of the binary or command invoked - $0 in a bash script is the name of the script for example.

The answer is simple. cmdArgs in our script should have /bin/echo as the first element, and then we pass cmdArgs[0], cmdArgs as the first two arguments to syscall.Exec. Lets give that a go:

func main() {
  cmdArgs := []string{"/bin/echo", "Hello", "World"}
  cmdEnv := []string{}

  err := syscall.Exec(cmdArgs[0], cmdArgs, cmdEnv)
  if err != nil {

And running it (go run gecho.go remember) gives the expected output:

Hello World

Excellent. Now I just need to remember argv contains the command name as argv[0] and we're golden.

There is also the os/exec package in the stdlib, which is intended for executing other binaries as child processes from what I can tell. Tellingly, when you create a exec.Cmd struct with exec.Command() you give it the name as first argument, and args as following arguments. Then it has the following snippet in the documentation:

The returned Cmd's Args field is constructed from the command name followed by the elements of arg, so arg should not include the command name itself. For example, Command("echo", "hello")

So cmd := exec.Command("echo", "hello"); cmd.Args would return []string{"echo", "hello"} - which is recognisable as what we have to pass to syscall.Exec!

Changing hostname in SmartOS Zone

Given a non-global zone in SmartOS that we want to change the hostname of, we need to make sure to edit the following files to change it:

A quick way to do that is with sed (renaming "fred" to "beth" here):

sed -e 's/fred/beth/g' -i /etc/hosts /etc/nodename

Then shutdown & start the zone (from my testing a restart doesn't apply it).

Install Rubinius on OS X

Using ruby-install, homebrew building it for use with chruby, here's how I install Rubinius under Yosemite (works for Mavericks as well.)

  1. Make sure llvm is installed

     $ brew install llvm
  2. Prepend the homebrew-installed llvm tools to your path

     $ export PATH="$(brew --prefix llvm)/bin:$PATH"
     # Or, for ZSH
     $ path=( $(brew --prefix llvm)/bin $path )
  3. Install rubinius, v2.3.0 at the time of writing

     $ ruby-install rbx 2.3.0
  4. Open a fresh shell once that's built, and you should be able to switch to rbx!

     $ chruby rbx
     $ ruby -v
     rubinius 2.3.0 (2.1.0 9d61df5d 2014-10-31 3.5.0 JI) [x86_64-darwin14.0.0]

There is also a homebrew tap for rubinius which should also work instead of the above. I couldn't get it working on one of my laptops though, which is why I was installing by hand using the above instead. The tap is at and explains install steps.

Changing root password in global zone

SmartOS mounts /etc/shadow from /usbkey/shadow so we can change the root password for the global zone after install. Here's how:

  1. Fire up a console or ssh session as root in the global zone
  2. Check the existing permissions on the file

     $ ls -l /usbkey/shadow
     -r--------   1 root     root         560 Oct 19 16:45 /usbkey/shadow
  3. Make the file writable

     $ chmod 600 /usbkey/shadow
  4. Fire up vi to edit the file

     $ vi /usbkey/shadow
  5. Edit the line containing root to change the crypted password. See shadow(4) if you need help with the format of /etc/shadow & use /usr/lib/cryptpass to generate a hash for the password you desire. (Remember to clean the bash history!)

  6. Save the file and exit vi

  7. Make the file readonly again

     $ chmod 400 /usbkey/shadow
  8. Double check permissions are correct on the file again

     $ ls -l /usbkey/shadow
     -r--------   1 root     root         560 Oct 19 16:49 /usbkey/shadow

Job done. Verify by logging in as root (invoking /usr/bin/login from an ssh session makes this easy to verify.)

Compiling SmartOS for AMD processors

There's a few community-provided patches for SmartOS that enable KVM on AMD processors amongst other things, and given the HP Microserver has an AMD processor, that's quite useful for turning it into a better lab server. The main list of so called "eait" builds was hiccuping when I tried to download the latest, and all I could find was a 20140812T062241Z image here.

The source code for the eait builds is maintained at, and you can see the patches applied on top of the normal SmartOS master by going to

So here's how to use SmartOS to compile a more up to date AMD-friendly Smartos!

  1. Grab the latest multiarch SmartOS image (which has to be used, or the compile will fail.) The latest at the time of writing was 4aec529c-55f9-11e3-868e-a37707fcbe86, so that's what I'll use.

     imgadm import 4aec529c-55f9-11e3-868e-a37707fcbe86
  2. Spin up a zone for us to build in (the Building SmartOS on SmartOS page has extra info about this):

     echo '{
       "alias": "platform-builder",
       "brand": "joyent",
       "dataset_uuid": "4aec529c-55f9-11e3-868e-a37707fcbe86",
       "max_physical_memory": 32768,
       "quota": 0,
       "tmpfs": 8192,
       "fs_allowed": "ufs,pcfs,tmpfs",
       "maintain_resolvers": true,
       "resolvers": [
       "nics": [
           "nic_tag": "admin",
           "ip": "dhcp",
           "primary": true
       "internal_metadata": {
         "root_pw": "password",
         "admin_pw": "password"
     }' | vmadm create
  3. Login to the created zone:

     zlogin <uuid from `vmadm create` output>
  4. Update the image to the latest packages, etc:

     pkgin -y update && pkgin -y full-upgrade
  5. Install a few images we'll need to compile & package SmartOS:

     pkgin install scmgit cdrtools pbzip2
  6. Grab the source code of the fork containing the patches we want, from arekinath/smartos-live

     git clone
     cd smartos-live
  7. Optional: Edit src/Makefile.defs and change PARALLEL = -j$(MAX_JOBS) to PARALLEL = -j8 to do less at once. (Microserver only has a dual core CPU!)

  8. Copy the configure definition into the right place and start configuration:

     cp {sample.,}configure.smartos

    (You'll probably get asked to accept the java license during configuration, so keep half an eye on it)

  9. Once configure has completed (which doesn't take too long, 15 minutes or so), start building:

     gmake world && gmake live
  10. Once the build is successfully finished, time to package an iso & usb image:

    export LC_ALL=C

Hey presto, you've a freshly built AMD-friendly SmartOS build to flash to a USB key / put on your netboot server and boot your Microserver from!


The People's Triathlon 2014

My first Olympic distance triathlon, and the first time I've ever run 10km to boot.

1500m Open Water (Freshwater Lake) Swim: 00:38:08

Equally happy and upset with my swim. Basically everything went well except my wetsuit, must get a proper swimming one (possibly sleeveless) before my next wetsuit event. Having to get out at the end of each lap and run down the bank to re-enter the water was a bit strange but not too bad. Worst bit of that was diving back in and forgetting to look down - goggles bruised the edge of my eyesocket!

Transition 1: 00:03:53

Took this at a sedate pace, didn't rush but didn't dawdle either. Perhaps could've gone a bit quicker but not unhappy with it. Found bike OK this time, although chain fell off as I went to mount which was slightly annoying.

40km Cycle: 01:28:49

Started off really badly, managed to knock my watch from cycle into Transition 2 before I'd gotten out the car park. Had to reset it quickly into just bike mode from multisport mode which wasn't too bad to be fair, just annoying. Having done the route in training was a big help on the day, I was aiming for about the time I did it in. Didn't push too hard on the two hills (one of which looks deceptively easy). Very happy with my time and more importantly how little effort it was comparatively.

Transition 2: 00:01:28

Quicker than T1, as normal. Got my shit on quickly, didn't forget anything and even managed to get my watch in run mode whilst jogging to the exit of the transition area.

10km Run: 01:18:40

The bit I was dreading the most. Very very happy with my performance here though. Walked about 90 seconds of the whole thing and kept plodding away the rest of the time. Given the furthest I'd run solidly in training was about 5.5km, I was exceptionally happy to just keep plodding the whole time. Managed to not take on liquid for the third lap, which lead to some impressive cramping in my right quad, so making sure I take liquid on is a definite thing to watch out for in future. And amazingly I wasn't even tail end charlie (not that it really matters, given I race the clock, not other people. But still.)

Total: 03:30:51

There's a tiny part of me that's gutted I didn't manage it in under 3:30 hours, but what's 51 seconds over that period of time. More importantly, I completed the bloody thing! Especially happy with the run, enjoyed the cycle even if it was trying to drown us (there was 6" deep standing water on one of the roundabouts by the end), and mostly happy with my swim.

Looking forward to returning next year and beating 3:30!

Solve volume down button not working on iPhone 5

I noticed this morning that my volume down button (-) wasn't working on my iPhone 5 running iOS 7. Pushing the physical button in didn't change the volume. The volume up button increased the volume successfully still.

As is my normal first step debugging iPhone weirdness, I rebooted the phone by turning it off, leaving it off for a few seconds, then booting it back up with the power button. Once powered off and on in this way, the volume down key still didn't decrease the volume.

Fearing a physical button issue at this point, I turned to google for suggestions on what else to try. Running across this thread on Apple's discussion forums, I tried out the solution in there.

  1. Open "Settings"
  2. Scroll down and tap on "General"
  3. Tap on "Accessibility"
  4. Scroll down to the bottom and tap on "AssistiveTouch"
  5. Tap the toggle for AssistiveTouch to turn it on, and you should see a little icon appear on screen (white circle contained in a dark grey rounded square)
  6. Tap the AssistiveTouch icon (was in the top left corner on screen for me)
  7. Tap on "Device"
  8. Tap "Volume Down" a bunch of times and you should see the volume being turned down
  9. Tap outside the AssistiveTouch dialog to close it
  10. Try pushing the physical Volume Down button

In my case, following these steps made my physical volume down button start working again. Makes me wonder if the solution author on the apple discussion thread is right, in that this is a software issue and forcing a volume down action through the on-screen interface makes it remember that there's a physical button to respond to as well.

Either way, I can stop deafening myself whenever I receive a notification now!

Compile & run swift files directly

Turns out you can run a swift file without having to compile it into a binary somewhere and then run that binary. Makes swift behave a bit more like a scripting language like ruby or python when you need it to.

Using the xcrun binary, we can reach into the current Xcode /bin folder and run binaries within there. So xcrun swift lets you run the swift binary to compile files for instance. If you view the help with -h, there's a useful flag -i listed there:

-i    Immediate mode

Turns out immediate mode means "compile & run" in the same command, which is what we're after.

$ cat hello.swift
println("Hello World")

$ xcrun swift -i hello.swift
Hello World

Bingo. But what if we want to make hello.swift executable and call it directly without having to know it needs the swift binary to call it. Unix lets files define their shebang to say how the file needs to be executed, so lets go for that here too!

$ cat hello2.swift
#!/usr/bin/env xcrun swift -i
println("Hello World 2")

$ chmod +x hello2.swift
$ ./hello2.swift
Hello World 2

No more having to fire up Xcode for quick CLI tools, especially ones using the system frameworks!

Cheshire Triathlon 2014

Successfully completed my second Sprint Triathlon of the season in Nantwich.

500m Swim - 00:10:49

Felt good swimming this. Mixed up my usual breaststroke with some front crawl to overtake and use my legs less towards the end. Think I need to put a shorter time down on paper next time though, was in with people who were swimming much slower than me. (Including one chap who was doing doggy paddle in the deep end and walking as soon as his feet touched bottom. Oh well!) Need to continue with front crawl practice, and aim to do next sprint tri entirely crawl.

Transition 1 - 00:02:43

Went well. Ran from pool to bike and felt OK. Kit on without any fuckups. Didn't fall off getting on bike. Winning. Need to practice getting on my bike in shoes at a run though.

20km Bike - 00:42:31

10 minutes quicker than same length course last year. (Although a slightly new route this year.) Lost a minute when my water bottle fell out about 12km in though. Barely saw a soul, got stuck at one pedestrian crossing on red. Felt very good on the bike (and finally beat Liam on the same route & day ). Need to fit a tighter bottle carrier to stop the bottle falling out on bumpy roads.

Transition 2 - 00:01:21

Came off bike well and ran to shoes. Couldn't find where I'd left them, was trying to find Liam's bike as my marker for it, only someone else earlier in the same row had the same bike as him! Wasted 10 seconds looking probably. Need to remember where my stuff is more accurately in future.

5km Run - 00:39:03

Boiling hot by the point I started running; didn't feel great in the first few hundred meters and never really got comfortable after that. Walked about 800m of it in total at a guess, really didn't have much left in my legs. Not convinced pushing less on the bike would've helped my run though. On the plus side, only 7 minutes slower than a training run a couple of weeks ago in similar heat, and this was on grass. Need to continue running at 5km distance, and train on grass as well as tarmac I think.

Total time - 01:36:27

8 minutes slower than York a couple of months ago, and felt much worse on the run. Very happy with my bike & swim though. More run training required!