Author Archives: Alex Forbes

Host switch

This blog has just moved from a Rackspace Cloud host to Linode, which offers a lot more specification for the pound (quadruple the ram for one).

At the same time I’ve migrated from CentOS + Apache to an nginx + php-fpm setup, which is not exactly easy for WordPress, but it feels good to be in the modern era!

Let me know if you notice any problems :)

Thanks Apple… iTunes update opens /Users to the world

OSX iTunes security blunderYesterday I noticed something odd when I made a commit:

/Library/Ruby/Site/facter/util/resolution.rb:27: warning: Insecure world writable dir /Users in PATH, mode 040777


I wasn’t sure what the permissions on /Users should be, but it’s fairly safe to assume that world-writable isn’t correct. Assuming that a recent OSX update or corporate management software had done something stupid, I ran disk utility and its “fix permissions” feature, which rectified the problem.

What caught it in this case was a code syntax checker, which runs on every commit. I wouldn’t have seen it otherwise, and most people wouldn’t know it had happened. But the impact is potentially severe if you share your computer with people you don’t trust with all your personal information: any person with a valid user account could take over your User directory and read your files.

The culprit turned out to be iTunes – Apple has fortunately released a fix, so go and download the 250-odd megabyte update again. A quicker, temporary resolution, is to simply run the following from Terminal:

sudo chmod 755 /Users

However, according to the security bulletin, this would be reset on every boot. So updating is the only way to fix it permanently.


RMT tube strike – whose side would you take?

Tube strikes are unfortunately a fairly regular fact of life in London, and so far I’ve been unaware of the reasons the RMT (National Union of Rail, Maritime and Transport workers) feels strike action is necessary. So with the recent announcement of more strikes, I decided to educate myself this time around so I could either support the RMT and accept the inconvenience, happier in the knowledge that it’s for a good cause, or support TFL and just be angry.

Unfortunately, I’m just angry.

I didn’t have to read very much – the RMT press statement is full of hyperbole, rhetoric and emotional statements with little in the way of evidence or fact. When contrasted against a reasonable, fair and down-right sensible letter from TFL… there’s no longer any question in my mind of who I should support.

Exhibit A: Mike Brown’s “Fairness to staff” letter

Exhibit B: Geoff Martin’s press release announcing the strikes

The language in Mike’s letter is reasoned, logical, fair, and uses almost no hyperbole or emotional language. Not only that, it makes real commitments to its staff, and I think any reasonable person must accept that its plans for modernisation are improvements for everyone. Except perhaps the poor sod that now has to be out in the ticket hall instead of sitting on their arse behind a glass window.

Compare this from the RMT (all emphasis mine):

[the talks] were wrecked by a combination of management intransigence and the introduction of additional measures that actually worsened the original toxic package.

Such as???

[the planned cuts] would destroy the safety regime on the tube network and which would wreck the quality of service to passengers at a time of surging tube demand.


About the most hyperbolic statement I could find from Mike Brown referred to TFL’s commitment to “radically” improve customer service.

Also, Mike actually gives examples!

During intensive talks spanning eight weeks and over 40 meetings, LU has changed some of its proposals to reflect the feedback of staff and unions.
For example, all smaller, local stations will now be staffed by a Customer Service Supervisor at all times and no supervisors need ‘reapply for their jobs’.

To be sure, this is not the complete picture. Without being a fly on the wall in the negotiations, none of us can really know the full story. It may be that RMT are totally incompetent at PR and TFL have the best spin doctor in the business. But based on what I’ve seen, I’m more than happy to take a position.

Fuck off RMT.


Nostalgia is a wonderful experience. Visiting an old city, seeing old friends, visiting old bars, shops, and reliving the moments is an experience to be treasured. With Christchurch, we have been deprived.

I visited a full 3 years after the most devastating quake (February 22nd, 2011). In that time, much of the rubble has been cleared, and the city is starting to rebuild. But it was shocking just how much of the condemned old city remains, so long after the event.

I owe more than half my adult life to Christchurch, and I have many friends and family still residing there. It’s difficult to describe what it felt like to see it in this state.

Hopefully these pictures tell at least some of the story.


One thousand three hundred and thirty days.

That’s how long I’d been away from New Zealand, and how long since I’d seen my family in person.  But really, it didn’t feel that long.  Regular Skype contact and Facebook updates mean that keeping in touch with friends and family on the opposite side of the world is easier than it used to be.

Still, it’s a long time between drinks, and it’s surprising what’s changed.

A city has been levelled.  Fast food and beer are about a dollar more expensive.  An overweight German geek, whose name sounds like it was invented during a bubble in Y2K, is championing liberal tech policy.  State highway one is slightly less of an embarrassment.  Bars and shops I used to frequent have gone.  My parents have started winding down the old family home in Wairoa.  Brothers and cousins have grown up.  Friends have gotten married, brought houses, had kids.

But Auckland transport is still shit.

Experiences change your perspective and I’ve certainly had a few of those over the past 4 years.  It did feel as though I was looking at things through a different set of eyes.  Ironically it’s not until you go elsewhere that you realise what you took for granted, and the opportunities you missed.

What follows is a set of pictures from a very short 3-week trip back “home” to New Zealand.  In addition to catching up with great friends, my family and getting plenty of sunshine, this holiday also included a wedding in Wanaka, a 30th birthday on Waiheke Island,  Milford Sound and an emotional tour through the destroyed remnants of a city I once called home.  But that’s another blog post.

13″ Retina Macbook Pro (late 2013) – Buyer Review

As with all my reviews, this is a totally subjective personal view and not an in-depth technical analysis. For more mainstream reviews, check out Engadet, Pocket Lint, Expert Reviews, and Casey Johnston’s Air vs Pro comparison on Arstechnica if you’re also considering an Air.

Retina vs Dell

My old faithful Dell E4300 has done its dash. Actually it still works; it runs Ubuntu well, it has an SSD and 4GB of ram which makes it pretty nippy for web browsing and lightweight tasks, but what sealed its fate was my work laptop - a 15″ Retina Macbook Pro. After getting used to that gorgeous 2880×1800 screen, I found I just couldn’t go back to the Dell any more with its 1280×800 TN LCD (ugh), horrible touchpad and 2009-era performance. Continue reading

It’s nice to be right some times

Five short years ago I wrote an article about my desire for a Nokia N900. I was extremely enthusiastic about the device, which I saw as the future of computing and a sign of things to come. I also said:

Personally I think Linux usage overtaking Windows on personal computing devices is inevitable, and this is how it’s going to happen (although the capabilities of the N900 will have to move down to a much lower price point first). We’ll see if I’m right in 5-10 years time.

It’s now 4 years and 4 months later. I was right about Linux overtaking windows on personal computing devices, but I was wrong about how, and it happened far more quickly than I could have imagined. Continue reading

Which laptop to buy, 2014 edition

In what could only fall firmly into the first-world problems category, I’m currently suffering a dilemma as to what laptop I should buy. My requirements are common – a good balance of power, performance and portability. I’ve decided the specification I should go for is:

  • Intel Core i5 (4th generation, Haswell)
  • 8Gb ram
  • 256Gb SSD
  • 13″ display, resolution at least 1920×1080

I think these specs make for the best price / performance balance on most of the laptops I’ve priced up.

Continue reading

Fixing Puppet 3.2 symlinks on OSX Mavericks

Received the following error when running puppet after upgrading to Mavericks:

/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:45:in `require': cannot load such file -- puppet/util/command_line (LoadError)
	from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rubygems/core_ext/kernel_require.rb:45:in `require'
	from /usr/bin/puppet:3:in `<main>'

Solution is to symlink the packages to the new ruby 2.0.0 directory:


sudo ln -s /usr/lib/ruby/site_ruby/1.8/puppet /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/site_ruby/2.0.0/puppet
sudo ln -s /usr/lib/ruby/site_ruby/1.8/puppet.rb /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/site_ruby/2.0.0/puppet.rb
sudo ln -s /usr/lib/ruby/site_ruby/1.8/semver.rb /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/site_ruby/2.0.0/semver.rb
sudo ln -s /usr/lib/ruby/site_ruby/1.8/facter /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/site_ruby/2.0.0/facter
sudo ln -s /usr/lib/ruby/site_ruby/1.8/facter.rb /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/site_ruby/2.0.0/facter.rb
sudo ln -s /usr/lib/ruby/site_ruby/1.8/hiera /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/site_ruby/2.0.0/hiera
sudo ln -s /usr/lib/ruby/site_ruby/1.8/hiera.rb /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/site_ruby/2.0.0/hiera.rb

Should be fixed in the next major version.


Pausing Spotify and playing a random video in Python – A party trick for Halloween

For a Halloween party last weekend I wrote a python script to pause Spotify, play a random video and start music playback again. The videos were basic ogg files I cobbled together which showed a scary image and evil laughs or screaming with OpenShot. I can’t really share them, as I don’t have rights to the media, but it’s pretty simple to recreate them yourself.

The code for this script is on Github, and I’ve reproduced the latest snapshot below. Feel free to fork and improve if you want to scare your guests, or add support for other OS’s. Presently it only supports Linux because I used dbus to perform the play/pause actions.


This is a Halloween party script which pauses Spotify and plays a video
at random intervals.

import random
import subprocess
from subprocess import call
from time import sleep
import os
import datetime

start_time = datetime.time(21, 0, 0)
stop_time = datetime.time(23, 0, 0)

video_dir = '/home/alex/Videos/scream/'
videos = { 'scream1_nofade.ogg': 30,
'happy.ogg': 1,
'evil_laugh.ogg': 5,

def time_in_range(start, end, x):
"""Return true if x is in the range [start, end]"""
if start <= end:
return start <= x <= end
return start <= x or x <= end

def weighted_choice(weights):
total = sum(weights[video] for video in weights)
r = random.uniform(0, total)
upto = 0
print("total: %s\nrandom: %s" % (total, r))

for video in weights:
w = weights[video]
if upto + w > r:
return video
upto += w
assert False, "shouldn't get here"

def spotifyPause():
command = "dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Pause"
print("pausing spotify")

def spotifyPlay():
print("playing spotify")
command = "dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause"

def play_video(video_file):
print("Playing %s" % video_file)
#call(['/usr/bin/mplayer', '-fs', video_file], stdout=None, stderr=None)
#result = subprocess.Popen(['/usr/bin/mplayer', '-really-quiet', '-fs', video_file])
result = subprocess.check_call(['/usr/bin/mplayer', '-really-quiet', '-fs', video_file], stdout=None, stderr=None)
return result

def playBuzz(buzzfile):
result = subprocess.check_call(['/usr/bin/mplayer', '-really-quiet', '-ss', '18', buzzfile], stdout=None, stderr=None)
return result

def infiniteLoop():
while 1:
current_time =
#if current_time > stop_time or current_time < midday:

choice = weighted_choice(videos)

random_time = random.randrange(1200,2400)
random_time = 3

video_file = video_dir + choice
print("Chose video %s after %s seconds" % (video_file, random_time))

# Whether to play buzz
buzz = False
if random.randrange(0,100) > 90:
buzz = True

# Continue if outside time range
if not time_in_range(start_time, stop_time, current_time):
print("Not playing video, outside time range")

# Do it
if buzz:

if __name__ == "__main__":