Author Archives: tarka

Haltcondition: Now in SPDY (where available)

SPDY is the next big thing in web technology. Nominally it is intended to speed up websites by multiplexing multiple site requests over a single connection; however there is some question about how effective it is at this. But personally I see it’s advantages in the datacenter; by reducing the number of TCP connections required to serve up a page to 1, the resources required for file-descriptors and firewall entries is massively reduced for high-volume sites. I suspect this is why sites such as Twitter and Facebook are adopting it before its usefulness for the end user has been proven.

Always one to jump on a passing bandwagon, Haltcondition is now being served via SPDY if your browser supports it. This is possible via the recently-released Nginx patches. Prior to this I had been testing the official Google Apache module, however this proved unstable as it is incompatible with mod_php; running WordPress under FCGI proved flaky. Adding Nginx as a caching/SPDY/SSL frontend allowed me to continue using Apache as an application container for WordPress.

To enable SPDY on Haltcondtion I took the following strategy:

  • Download the Nginx patches and follow the instructions to build an SSL/SPDY-enabled instance. Personally I installed it under /opt/nginx…
  • Modify the existing Apache/Wordpress vhost to bind to a different port; 8080 is traditional.
  • Configure Nginx to serve HTTP and HTTPS, and forward requests to 8080.
  • On the HTTP vhost configure Nginx to send the ‘Alternate-Protocol “443:npn-spdy/2″‘ header; this tells the browser that SPDY is available on the HTTPS port.
  • Configure your system to start Nginx; personally I use daemontools with Nginx is foreground mode.

One gotcha is that WordPress doesn’t handle this sort of proxy-chaining very well and will tend to go into redirect loops. The workaround for this is to disable the ‘redirect_canonical’ filter; there’s no official way to do this but the ‘Fix Multiple Redirects’ plugin will do this for you.

IPv6 is stalking you (and what you can do about it)

Imagine a not-too-distant future where IPv6 is starting to see widespread adoption. On sunday evening you login to Amazon.com on your laptop and purchase some sex-toys for you and your wife for your upcoming anniversary; good for you for keeping it interesting. Naturally you enable privacy mode in Firefox so it won’t show up in your history, society being what it is.

On Monday you head into your job at a large daycare center where you’re a manager in HR. There’s an upcoming restructure and you want to make sure the employees are reassured that its a good thing; in between meetings you flick through some change-management books on Amazon on your laptop, but can’t see anything useful.

Congratulations! Amazon.com (and anyone they feel free to share with) now know that you have sex-toys and access to young children. No logins, no cookies, all they need to do is look in their logs for laptop’s unique identifier and then match your work’s network block to your purchases at Amazon.

How does this work? First a bit of background (the following skips a few details but is basically true for most people)…

Every piece of network hardware in every computer, phone, etc. in the world has a unique identifier: the Media Access Control address, or MAC. This address is 48 bits long, and different from the IP address you use on the internet; it is used purely for finding machines on your local network.

Although it was never a deliberate design decision, the IPv4 internet has a few privacy mechanisms built into it, almost as a side-effect of its limitations. IPv4 addresses are 32 bits long, far too small to contain any significant portion of the MAC address or any other identifier; the MAC address is quietly dropped the moment your traffic enters the wider internet. And although the IP assigned to you or your employer by your ISP is globally unique, in practice its tracking potential is limited: your home IP is regularly reused by your ISP for other customers, and at work the public address is shared by dozens or even hundreds of employees due to NAT.

With IPv6 it’s a different story. A 128-bit IPv6 address consists of two components; a network address that identifies your whole network (usually 64 bits) and a local component that identifies your machine on your network. This local component is based on your MAC address, and by default is included in all communication with the wider internet. Because it’s bound to your physical hardware the local part always stays the same, regardless of which network you’re connected to; it is in essence a global tracking code, and can be used by remote sites to infer some interesting information about you. The example above is the simplest I could come up with; advertising providers operating across multiple sites are going to be able to do some truly stunning pattern matching. And hardware vendors will already have massive database mapping MAC addresses to users and credit-cards; some of them (e.g. Apple) have deep ties with organisations such as the RIAA, who would dearly love to be able to match an IP address to a name and mailing address without any of that inconvenient subpoena stuff.

Luckily this problem was anticipated during the IPv6 specification process and a solution added; RFC3041 privacy extensions. The gist of this is that your operating system can generate a random, short-lived fake local-address that is used for outgoing connections. In the example above, assuming the temporary address is set to a short enough timeout, by the time you’re at work the next day the address you used from home will have been replaced by a new one.

There’s only one problem; it’s not enabled by default in all operating systems. Here’s how to enable it in some of the common ones:

Linux desktop/server distributions

Most Linux distributions seem to have temporary addresses disabled by default. Enabling them is simple enough though:

sudo sysctl -w net.ipv6.conf.all.use_tempaddr=2
sudo sysctl -w net.ipv6.conf.default.use_tempaddr=2
echo net.ipv6.conf.all.use_tempaddr=2 | sudo tee -a /etc/sysctl.conf
echo net.ipv6.conf.default.use_tempaddr=2 | sudo tee -a /etc/sysctl.conf

Android

Temporary addresses seem to be disabled by default in Android. However if you have rooted your phone then you can use the Linux method. Either use an Android terminal app or ‘adb’ from the SDK to get a root shell:

mount -o remount,rw /system
cd /system/etc/
echo net.ipv6.conf.all.use_tempaddr=2 >> sysctl.conf
echo net.ipv6.conf.default.use_tempaddr=2 >> sysctl.conf

Then reboot your phone.

Mac OS X

As of 10.6.7 temporary addresses are disabled. Enabling them is similar to the Linux method:

sudo sysctl -w net.inet6.ip6.use_tempaddr=1
echo net.inet6.ip6.use_tempaddr=1 | sudo tee -a /etc/sysctl.conf

iPhone/iPad

This security advisory implies that iOS 4.3 has this enabled by default. For older releases you’re probably out of luck though.

Window XP/Vista/7

IPv6 temporary addresses seem to been enabled by default; if you can confirm please comment.

Haltcondition: Now in IPv6 (where available)

Well, as of Friday the 4th of February 2011 IANA is officially out of IPv4 addresses. It’s now up to the regional registries to dole out the remaining addresses as they see fit, which will be increasingly sparingly.

To celebrate the beginning of the end of IP as we know it, Haltcondition.net is now available over IPv6:

I’ve also added an IPv6 detection widget on the right, courtesy of Patux. The IPv6 connectivity is provided by a Hurricane Electric tunnel to my Linode box; the fact that I even need to use a tunnel at a professional hosting site is sign of how painful the next couple of years are going to be.

Luckily my ISP are currently trialling consumer-level IPv6, so I can at least test the site. However at this point setting up IPv6 in the home is far from simple; I had to convert from DD-WRT to OpenWRT on my router and do a lot of manual configuration to get an end-to-end connection. It’s going to be a painful transition.

Update: Linode have announced provisional support for IPv6, so this blog is now native end-to-end if your ISP has support. The Linode setup is a bit odd (they only provide a single IP rather than the usual /64) but appears to work.

One of the more intriguing speculations doing the rounds is that Linode rolled this out early as Slicehost are gearing up for IPv6 as they transition into Rackspace’s cloud. If so this is promising, as I hadn’t expected IPv6 to be product differentiator for some time.

XBMC on the Giada N20

We finally updated our old CRT TV to a shiny new 1080p LCD/LED TV. Unfortunately this meant the end-of-life of my trusty hacked v1 XBox, which served as our HTPC via XBMC. The XBox won’t do 1080p though, and realtime decoding of HD x264 requires dedicated hardware such as the NVidia ION chipset.

I originally planned on getting a Boxee Box, but initial reviews were disappointing. I considered building my own rig; there are some nice fanless Intel Atom mini-itx boards out there, but then I saw mention of the Giada N20 on Whirlpool. The N20 is an Atom D525 with an GT218-ION chipset, 2GB of RAM, a 320GB HDD, Gigabit LAN, 802.11N, and the clincher; a built-in IR remote. In short, it’s a near-perfect HTPC; the only thing missing is a blu-ray drive, but as the TV came with a free PS3 I didn’t need or want one.

Out of the box the N20 comes installed with Ubuntu and XBMC; however it’s a very grab-bag install; there’s a lot of additional cruft on the system, whereas a HTPC should be cut-down to boot fast and ‘just work’. I was going to roll my own Ubuntu-based install, but after quick trial of the XBMC-Live distribution I was so impressed I went with that as-is. XBMC-Live is Ubuntu-based anyway (10.04/Lucid LTS) so is highly customisable, but has some nice polish such as an XBMC boot-splash. Despite the name it installs straight to the HD. It mostly works out of the box but requires a few tweaks to get the most out of it, so here’s a step-by-step run-through.

Installing XBMC-Live

To do the install you’ll need the following:

  • A USB drive; a 2GB thumb-drive should be plenty
  • The XBMC-Live image from here
  • UNetbootin
  • A live internet connection
  • A wired ethernet connection (as wireless doesn’t work during the install)
  • A USB keyboard for the install phase

To do the install, back-up anything you want from the original distribution and then:

  1. Burn the XBMC-Live image to the USB drive using UNetbootin (Ubuntu’s USB drive creator doesn’t appear to like the image).
  2. Plug in the ethernet, keyboard and USB drive, then start the N20.
  3. When the splash screen shows press Delete to bounce to the BIOS
  4. Change the boot order to boot the USB drive first, save the config and reboot; XBMC-Live should now start
  5. If you wish you can now boot into the Live XBMC and play-around
  6. To do a full install, reboot and select install during the startup
  7. The installer is the Ubuntu text-based one; instructions for using it are on the Ubuntu wiki but the defaults are fine for most users

On completion you will have a mostly-working XBMC installation, including traditional problem areas such as power-on by remote. Suspend/hibernate work out of the box, but with a ~1 minute boot-up from power-on to a responding system I haven’t found them necessary.

But a few tweaks are needed to get the most out of the system …

HDMI Audio

To get XBMC fully working over HDMI the following tweaks are required:

In System Config->System Settings->Audio Setting change the following:

  • Set Audio Output to HDMI
  • Unset “Device is DTS Capable”
  • Set Audio Output Device to “HDA NVidia HDMI”
  • Set Audio Passthrough Device to “HDA NVidia HDMI”

This will get audio working for playback. However the menu feedback sounds do not work; this is because the analog output is the default and XBMC doesn’t appear to use the audio device setting above for UI sounds. This can be worked-around by changing the default in ALSA; simply create the file /etc/asound.conf (or ~/.asoundrc) and add the following:

pcm.!default {
		type plug
		slave {
			pcm "hw:1,3" 
		}
}

(“hw:1,3″ is the HDMI device, found by getting the device list with ‘aplay -L’; see the ALSA docs for details.)

Enabling more keys on the remote

The IR receiver is interesting, in that it doesn’t interact with IRDA, but appears to the system as a keyboard/mouse combo. By default XBMC expect IRDA/Lirc events; it’s technically possible to turn these keypresses into events, but it’s easer to just tell XBMC to use it as a keyboard:

  • Go to System Config->System Settings->Input
  • Enable “Remote Control sends keyboard presses”
  • Disable “Enable Mouse”

This gets the core buttons working, including power on/off. One unsolved problem is that some of the more specialised buttons don’t work. This is more than a case of mapping buttons; as far as I can tell many of them don’t even register as events in the Linux subsystem. I’ll need to look into this some more.

Configuring wireless

The N20 has an Atheros AR9285 chip; this is fully supported with the ath9k driver out of the box. Ubuntu normally controls networking via NetworkManager but that is not installed with XBMC-Live. However we can fall-back to the powerful but less user-friendly Debian interfaces method:

  • Edit /etc/network/interfaces
  • Add the following lines:
    auto wlan0
    iface wlan0 inet dhcp
      wpa-ssid YOURNETWORKSSID
      wpa-psk YOURNETWORKPASSWORD
    
  • Do ‘sudo ifup wlan0′ to bring the wireless network up

Extra tweaks

Adding Add-Ons

The latest version of XBMC supports ‘add-ons’, which enable extra functionality. While there are only a few official add-ons, there are a number of unofficial repositories that supply 3rd-party modules. For Australian users the ‘Catchup TV’ repository adds support for the various online channel streaming TV services, including ABC’s iView.

It’s also worth reiterating that this is a dual-hyperthreaded machine, equivalent to a high-end workstation just a few years ago, and has access to the full Ubuntu software repositories. As such it is more than capable of running the full suite of P2P and download apps in the background with no effect on playback performance. Personally I use a Sabnzbd/Sickbeard combo to automatically download US current-affairs programs that are otherwise unavailable in Australia.

Removing the stand

The N20 is designed to be used upright on a (surprisingly sturdy) stand. This didn’t fit into my TV cabinet, but just laying it down didn’t seem like a good idea as it would partially block the air intake. However I found some small stick-on ~1cm feet at Jaycar that gave it sufficient height for decent airflow.

To-dos and other possibilities

As mentioned above, there are a number of buttons on the remote that would be useful to have but don’t show-up in XBMC. This may be a Linux or Xorg driver-level question, but I need to investigate further.

As well as supporting power-on via the remote, the Giada BIOS has support for Wake-on-LAN; this would be useful for remote administration but I haven’t played with it yet. It turns out I was wrong about this; the N20 doesn’t have WOL.

While I’m happy with the system as-is, it would be nice to have the option to modify the system at a later date (such as adding an SSD for even faster boot-times). But case looks well-sealed, but it should be possible to get it open some-how. Update: See the comment by Rich below about opening the case and replacing the drive.

Anode, an Internode usage widget for Android

anode-0.1-widgetSo recently I took a break from fighting with a Cheney garbage collector to do a bit of Android hacking. I recently bought a Nexus One for a trip to the UK; now I’m back on my home internet connection and while there’s already an Internode usage app on the Android market it doesn’t have a widget, and I wanted something that showed usage ‘at a glance’. In the spirit of scratching your own itch I’ve built my own and it’s now available on the Market.

Unfortunately, at this point I haven’t yet managed to get permission from Internode to use their logo in the widget so I’ve just used a place-holder ‘i’ for the time being.

As usual, this is all open-source; the code is available on Github.

Further discussion over at the Whirlpool forums.

Update: If you need a full-app rather than Anode’s summary-widget then you may want to look at NodeDroid.

Cheating at puzzles for fun and … well, just fun actually

As mentioned elsewhere, I recently moved to the internal-systems team at Atlassian. The team there are puzzle obsessed; each day works stops in the afternoon to engage in bout of competitive puzzle solving. One particular favorite is Daily Set, which involves finding matching sets of three tiles based on some simple rules. This is diligently solved each day by the team members and the times recorded for comparison. An amusing little diversion and team-building ritual. With one problem: I fucking suck at it.

Really, I’m appalling. While everyone else’s scores are recorded in a spreadsheet to be pored over and analysed, I can’t even complete the bloody puzzle. Each day I end up repeatedly finding the same couple of sequences over and over again, stuck in some sort of sisyphean nightmare.

I joked that I’d have better luck writing a program to do image analysis and pattern-recognition to solve the puzzle than actually doing it myself. After being humiliated by the bloody thing one time too many I realised this probably really is the case. After all, I’m a tool-user at heart, and the idea of beating it into submission was starting to look quite attractive. It turns out this is perfectly feasible and not that hard if you know a few tricks; what follows is an explanation of how I got a working Set cheater.

The full Python sourcecode is available at Github. The code itself was hacked together with much experimentation in a day; it’s inconsistent, frequently redundant and shouldn’t be considered best, or even sane, practice. However it does have reasonably complete unit-tests and contains a few tricks that novice Pythonistas may find useful.

The Rules

Set consists of 12 tiles. Each tile has 4 properties that with 3 possible values:

  • Number of shapes (1-3)
  • Type of shapes (diamond, oval or squiggle)
  • Colour of shapes (red, green or purple)
  • Shape pattern (empty, solid or lines)

28 17 78

Each ‘set’ consists of 3 tiles where each attribute is either all the same or all different. There are 6 sets. That’s it.

Getting the images

Fetching the images is simple; we use urllib2 to fetch the main page, use a simple regular expression to extract the puzzle-image paths, then urllib2 to download them.

Once downloaded we need to convert them into something we can process easily. GIF is a palette-based format which is a pain for this sort of work; we’d prefer an array of RGB values. I toyed with implementing a GIF decoder but it turns out the Python Imaging Library will do the conversion for us so I ran with this in the end. The result is an RGB image representation that can be addressed either with getpixel(x,y) or as a 2D array.

Finding The Shape’s Colour

The seemingly simplest parameter to fetch is the colour. On the surface it seems to just be a case of dropping all the white pixels then just selecting the most common pixel colour. We then just apply some tolerance values to roughly catagorise the colours into red, green and purple. However in practice this fails on images with low surface-area due to antialiasing:

73-close-up2

All those greys and low-intensity reds are actually more common than the base color, confusing the matching.

For colour categorisation and manipulation RGB isn’t always the most useful representation. In particular in this case we’re not actually all that interested in the actual colour as much as the intensity of the colour. HSV gives a better ‘human-oriented’ view of colour, so to strip out the antialiased pixels we convert into the HSV colourspace and drop anything below an appropriate saturation value:

  ...
  p = self.img.getpixel((x,y))
  (hue,sat,val) = rgb_to_hsv(*pxtofloat(p))
  if sat > 0.5:  # Ignore greyscale colors
      ...

The ‘rgb_to_hsv’ routine is built into Python. Unfortunately it expects values in the 0.0-1.0 range, and the imaging library uses 0-255 values (this mismatch is unfortunately rather common in graphics libraries). So a some quick conversion routines are needed:

def pxtofloat(px):
    return tuple(map(lambda x: float(x)/255, px))

def pxtoint(px):
    return tuple(map(lambda x: int(x*255), px))

HSV also makes sense when categorising the colours as we can work with a single ‘hue’ value rather than three colour components:

  if hue < 0.1:
      self._colour = Colour.RED
  elif hue > 0.3 and hue < 0.35:
      self._colour = Colour.GREEN
  elif hue > 0.77 and hue < 0.81:
      self._colour = Colour.PURPLE
  else:
      raise RuntimeError("Couldn't work out the color")

Finding The Number Of Shapes

Counting the images is also presents issues with colour. While the horizontal alignment of the shapes should reduce the problem to drawing a line through the middle and counting the transitions, in practice the patterns and antialiasing confuse the issue so we need to get rid of these. The first step is to drop the colour; once again HSV helps us out here: if we zero out the hue and saturation and make the value an average of the RGB values we get a greyscale representation of the source image:

# Convert to greyscale by removing saturation and hue, and averaging
# RGB to be V
def toGreyscale(px):
    fpx = pxToFloat(px)
    rgb = hsv_to_rgb(0,0, reduce(lambda a,b: a+b, fpx)/3.0)
    return pxToInt(rgb)

...

bwimg = pxfilter(img, toGreyscale)

(‘pxfilter’ is a routine that returns a copy of an image with a function applied to each pixel.)

79-color 79-gs

However, the antialiasing is still visible and could potentially cause problems later so we want to get rid of it. So we apply a threshold filter:

# All px above val == white, all below == black
def threshold(th, px):
    v = rgb_to_hsv(*pxtofloat(px))[2]
    if v < th:
        return (0,0,0)
    else:
        return (255,255,255)
...
bwimg = pxfilter(bwimg, partial(threshold, 0.6))

(‘partial’ is Python’s currying implementation; for more information see the functools documentation.

79-color 79-gs 79-bw

We now have a ‘clean’ image to work with. However the shape patterns still confuse the counting. My solution to this is use flood-fill to set all the area outside the image borders to a known colour (e.g. red) and then treat anything else as shape contents. There are probably Python libraries out there to do this for us but flood-filling is so simple it’s easier to just implement our own:

# Return new copy of image that has been flooded
def flooded(img, target, replacement):    
    i2 = img.copy()

    # Recursive flood routing, based on version in wikipedia.
    #
    #     http://en.wikipedia.org/wiki/Flood_fill
    #
    # This requires bumping Python's recursion limit up, and should
    # probably be coverted to a queue-based version ...
    sys.setrecursionlimit(10000)
    def flood(img, target, replacement, sx, sy, x=0, y=0):
        if img[x,y] != target: return
        if img[x,y] == replacement: return
        img[x,y] = replacement
        if x-1 >= 0: flood(img, target, replacement, sx, sy, x-1, y)
        if x+1 < sx: flood(img, target, replacement, sx, sy, x+1, y)
        if y-1 >= 0: flood(img, target, replacement, sx, sy, x, y-1)
        if y+1 < sy: flood(img, target, replacement, sx, sy, x, y+1)

    flood(i2.load(), target, replacement, *i2.size)
    return i2

fcol = (255,0,0)
fimg = flooded(self.bwimg, (255,255,255), fcol)

79-flooded

Now we can just use simple 2D raycasting to count the red->other transitions. We also save the shape edge-locations (‘spans’) for later use:

  y = fimg.size[1]/2  # Half-way down
  for x in range(fimg.size[0]):
      p = fimg.getpixel((x,y))
      if p != fcol and prev == fcol:
	  # This is a rising edge; count
	  trans += 1
	  span = [x,None]
      elif p == fcol and prev != fcol:
	  # Falling edge, save span
	  span[1] = x
	  self._spans.append(span)
      prev = p

Finding The Pattern

We use a similar technique to find the pattern; we use the spans we saved in the previous step to find the center of one shape. Then we raycast vertically through it, counting the transitions. The count tells us the pattern:

  span = self.spans[0]
  x = span[0] + ((span[1]-span[0]) / 2)

  white = (255,255,255)
  prev = white
  trans = 0
  for y in range(self.bwimg.size[1]):
      p = self.bwimg.getpixel((x,y))
      if prev == white and p != white:
	  # White->Black edge
	  trans += 1
      prev = p

  if trans == 1:
      self._pattern = Pattern.SOLID
  elif trans == 2:
      self._pattern = Pattern.BLANK
  elif trans > 5:  # Lines should be between 6-10 transitions
      self._pattern = Pattern.LINES
  else:
      raise RuntimeError("Not enough transitions in shape: %s"%trans)

Finding The Shape

The shapes are the trickiest part to work out. The images are rather small, so techniques such as converting to polygons or vectors are not going to be very consistent. This is compounded by the fact that two of the images (the diamond and the oval) are, topologically-speaking, quite similar. In the end, after pondering a few techniques I came up with a hybrid system.

The first step is to get some data about one edge of a shape. To do this we use the span-and-raycast technique:

  # Scan to find top/bottom edge
  span = self.spans[0]
  def findtop(sy, ey, step):
      for y in range(sy, ey, step):
	  for x in range(span[0],span[1]+1):
	      if self.bwimg.getpixel((x,y)) != (255,255,255):
		  return y

  top = findtop(0,self.bwimg.size[1], 1)
  bottom = findtop(self.bwimg.size[1]-1, 0, -1)

  # Scan left side, recording values
  def findleft(y):
      #for x in range(span[0],span[1]+1):
      for x in range(0,self.bwimg.size[0]):
	  if self.bwimg.getpixel((x,y)) != (255,255,255):
	      return x

  left = []
  for y in range(top, bottom+1):
      left.append(findleft(y))

And with this we can calculate the variance in the edge:

  prev = None
  diff = []
  for x in left:
      if prev != None:
	  d = x-prev
	  diff.append(d)
      prev = x

However the number of values varies slightly between the same shape in different configurations. For that reason we want to remove duplicate variances and flat areas to get a distilled view of the edge:

  # Calculate the overall variance trend by reducing contiguous
  # trends to single values
  vdiff=[]
  prev = 0
  for d in diff:
      if d < 0 and not prev < 0:
	  vdiff.append(-1)
	  prev = -1
      elif d > 0 and not prev > 0:
	  vdiff.append(1)
	  prev = 1

This give us a surprisingly concise view of the shapes; the squiggle is [-1, 1, -1, 1] and the oval and diamond are [-1, 1]. To differentiate between the last two we can count the overall ratio of flatness to changes:

  # Calc zero to non-zero variation 
  zcount = 0.0
  nzcount = 0.0
  for d in diff:
      if d == 0: 
	  zcount += 1
      else:
	  nzcount +=1 
  zratio = nzcount / zcount

With these statistics we can categorise the shapes appropriately:

  if vdiff == [-1, 1, -1, 1]:
      # Wavy == squiggle:
      self._shape = Shape.SQUIGGLE
  elif vdiff == [-1, 1] and zratio < 0.5:
      # Up then down, but has large contiguous area == oval
      self._shape = Shape.OVAL
  elif vdiff == [-1, 1] and zratio > 0.70:
      # Up then down, but not especially flat == diamond            
      self._shape = Shape.DIAMOND
  else:
      raise RuntimeError("Couldn't work out the shape of %s" % self.pos)

Calculating The Sets

This part is actually pretty simple; I won’t post the code here. Basically we just brute-force iterate over every combination of images and compare them, discarding any group that is not either all the same or all different. The surviving groups are placed into a set container to remove duplicates. Once done these are then printed out as x/y positions in the original webpage to be entered manually.

One obvious improvement would be to have the program enter the values for us. The webpage uses javascript to record the selections so this would either be a case of working out what calls are being made back to the server or using Selenium to control a browser.

The programming language for this year is my own

Generally I try and learn a programming language a year; it’s useful to constantly test your assumptions and your ability to reason in new ways. However, as I started to learn Javascript earlier this year I also started to wonder about exactly what I’m trying to achieve with this practice.

Where am I going here?

Learning other programming languages is useful because is causes you to question, and hopefully expand, the practices you use in the programs write day-to-day. But expansion can be in more than one dimension; Erlang may force me to think about the trade-offs of concurrency and immutability but I am still none-the-wiser about how Erlang achieves its blindingly-fast context switching. I’ve learned the power of Common Lisp’s conditions/restarts but don’t really grok why they’re faster than Java’s exceptions.

There are also some questions no programming language by itself is going to answer; what are the benefits of converting code to CPS during compilation? Everyone seems to be building JIT compilers on LLVM; how much work is that? Could we eliminate NullPointerExceptions by just removing the concept of null and telling programmers to suck it up?

Some things can only be learned by doing. Time to implement a language rather than just learning one.

Implementing Lisp

I didn’t want to get bogged down in language syntax design and parser details (not yet anyway), so I decided that the first run should be to implement a Lisp system. The core of Lisp is simple to parse, flexible enough to implement any concepts that interest me and famously easy to bootstrap. The initial plan was to implement a basic Scheme-like interpreter in Python, implement compilation to LLVM, then re-implement the compiler in my minimal language in the classic compiler bootstrap pattern. I figured the Python/Scheme implementation shouldn’t take me long as I knew Lisp pretty well.

About 200 lines of Python in I realised I didn’t know shit.

Back to basics

One of the insight that learning lisp brings is realising that virtually all programming data-structures and operations can be implemented via lambdas, but I quickly realised that I didn’t actually know how to do much of this in practice. Oh well, back to the books; SICP and in particular Lisp in Small Pieces.

Having revised the fundamentals, I initially went on to implement a metacircular interpreter in Chicken Scheme. However this rapidly became confusing; you have to constantly keep track of which version of lisp you’re currently working with; the implementer or the implementee. And if your implementation of lambda is just a call to the implementation language’s lambda then how much have you really learned? So once I had something equivalent to LiSP’s basic evaluator I ported the resulting code to Python, building up from cons cells and the fundamental first-class objects (functions, integers, strings and symbols).

Where I’m at

At this point I have a core Lisp-1 interpreter with a handful of primitives defined. The next step is to implement CL-style macros, and then start looking at compiling this down to LLVM. Once I have a working executable I will then re-implement the compiler in the new language. This then will become the test-bed for adding whatever aspects interest me; immutability, monads, unnullable references, etc.

I’m not planning on rushing this; this is not intended to be a production language but a vehicle for learning. If I need to wander off on a tangent of digging into Oz or OCaml for inspiration then I will. But even at this early stage I’ve learned a lot about the theory and practice of language implementation and the limits of my own (assumed) knowledge.

Reading queues asynchronously in Python’s multiprocessing module

Python 2.6 will add a multiprocessing module that supports fork/join semantics and management of process pools. However even in this multiprocess environment it is still necessary to do some asynchronous processing of communication updates. The main way that processes communicate in this environment are through shared queues (implemented as socket-pairs or unix pipes under the hood), but we need a method for the UI to be notified about updates to any queues it is listening on without blocking (for example in the main event loop). Luckily it is possible to get at underlying file-descriptor, which can then be managed with select() or some abstraction thereof. Unfortunately there’s no official support for this but we can still poke around inside the implementation class to get at the details. The code below shows how to do this with GTK. This just spawns off a sub-process that counts up and sends the current number to the UI via a queue, which then displays the number:

from __future__ import print_function
import gtk, gobject, time, multiprocessing, Queue


class UI:

    def destroy(self, widget, data=None):
        self.outq.put("quit")
        gtk.main_quit()

    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.connect("destroy", self.destroy)
        self.window.set_border_width(10)
    
        self.label = gtk.Label("Not Set!")
        self.window.add(self.label)
    
        self.label.show()
        self.window.show()

    def update(self, fd, cond):
        val = self.inq.get()
        self.label.set_text("Value is %s" % val)
        return True

    def main(self, outq, inq):
        self.outq = outq
        self.inq = inq

        # This is the tricky bit, we get the socket FD of the
        # underlying pipe from the queue object.  We hope that the
        # internal reader variable doesn't change.
        fd = inq._reader.fileno()

        # This tells GTK to watch this FD and notify us when data is
        # available.  We use newer API, gdk_input_read is deprecated
        gobject.io_add_watch(fd, gobject.IO_IN, self.update)
        gtk.main()


def counter(inq, outq, interval):
    count = 1
    again = True
    while again:
        print("Putting %s on queue" % count)
        outq.put(count)
        count += 1

        try:
            print("Reading from queue...")
            ret = inq.get(True, interval)
            if ret == "quit":
                print("Got quit message")
                again = False
        except Queue.Empty:
            # Timed-out, carry on
            pass


if __name__ == "__main__":
    q1 = multiprocessing.Queue()
    q2 = multiprocessing.Queue()

    proc = multiprocessing.Process(target=counter, args=(q1, q2, 1,))
    proc.start()

    ui = UI()
    ui.main(q1, q2)

    proc.join()

Obviously if the underlying implementation variables change this will break; hopefully a more standard way of getting at this information will be added to the API.

Current affairs programs suck

I’ve been importing my old mail into Gmail and discovering some interesting snippets I’d all but forgotten. The following is from a mail I sent a friend when I was the lead programmer for a startup in 2000 doing mortgage brokering online:

One interesting event was that we appeared (for free) on a current-affairs program in various cities one night. [Note: It was "Today Tonight".] That was mental. They saw one of our press-releases about the “true cost of your mortgage”, and thought it would make a good piece. We basically wrote the thing for them and supplied all the people that told their ‘story’ on it. Lesson: when you see an ‘expose’, ask who stands to benefit from it. Worked for us though. After it aired somewhere between 4000-8000 people logged onto the site *at the same time*.

Caveat Spectator.

The Economist on boomers and bubbles

My old team-leader Scott “Satan” MacGibbon pointed out a couple of Economist articles that touch on some of the things I’ve been thinking about…

The first article is on the migration to less centralised and specialised workplaces. Most of it is another variation on the “Starbucks is the new cubicle” theme that seems to be discovered by journalists every couple of months, but I found the discussion on the revival of “Third Places” interesting, not least because I hadn’t actually encountered the term before.

The other is a short and (for the Economist) to-the-point article on the further damage that the boomer retirement wave of housing sales may do to the already seriously-wounded US property market. Most of it is along the line of the points I made below, in that the same logic applies in the Australian market, maybe even more so given that the investment property has been the preferred method of salting something away for the future for some time now. However his paragraph caught my eye:

Suburbs, which swelled with the baby-boomers, may begin to decline. If the building industry contracts, home prices may remain more stable. Or developers may switch to serving the old, building more compact housing near amenities. Towns may make new efforts to attract immigrants, who already accounted for 40% of the growth in homeownership between 2000 and 2006.

Unfortunately what the article fails to address is how this will interact with the rising cost of private transportation caused by peak-oil (or the less hysterical “plateau-oil“, as John Quiggin terms it). My first thought is that there are two ways this can play out; rising costs will further speed the collapse of the suburban lifestyle, or they will force the accommodation of more flexible work conditions. But there is another factor; the most remarkable effect of the changes in the oil market is likely to be in food production. There is already a recognition that most of the food we eat travels are ridiculous distance to our plates (supposedly ~2,500Km on average, although I can’t find a source for that). This may cause a fundamental change in the way we live as it becomes more economical to move closer to the centres of food production. This in turn may revitalise the currently bland and homogeneous environment of the suburban tracts; it’s possible that in the end the suburbs may become the country villages of the 21st century.