Console gaming on a remote X display

I have recently ended up in a situation where creating something like this (see diagram) would allow me to play my Game Cube on my laptop display before I finalise my purchase of a nice new LCD display for my desktop system.
Game Cube -> Tv Card -> Linux Box (no display) -> 100Base-t Network -> Laptop (with display)

gamecube-to-laptop

Playing a console game over a remote X display is slightly more challenging than simply watching TV. With TV you can capture your video and audio input, compress it, send it over the network in a nice format and decompress it at the other end. Sure, you’ll be watching TV that is maybe one second to a minute behind whats actually being broadcast but its in sync and it looks good. If you’re attempting to play a game in a similar fashion even 500ms (1/2 a second) delay would make most console games totally un-playable, with this in mind I set about console gaming over remote X with ssh.
It should be noted that:

  1. While attempting this I had no access to the internet, just to whatever documentation came with my debian / ubuntu installs
  2. My desktop runs debian testing and my laptop runs ubuntu edgy eft
  3. If you just want the solution, skip down to Attempt 4.

Attempt 1 - tvtime

Usually when playing Game Cube on a local display attached to my desktop I use a fantastic application called tvtime, To run this I SSH’ed from my laptop to my desktop with X display forwarding and compression enabled:

iain@laptop ~> ssh -X -C -o CompressionLevel=9 desktop

iain@desktop ~> tvtime

Unfortunately for me tvtime does not appear to work via X display forwarding, it appears to be looking for an xvideo port to connect to and fails upon startup, most likely tvtime was not designed for this.

Attempt 2 - xawtv

Xawtv is a tried and tested linux tv viewing tool, its almost guaranteed to work and it did:

iain@laptop ~> ssh -X -C -o CompressionLevel=9 desktop

iain@desktop ~> xawtv -remote

<meta content="StarOffice 7 (Solaris Sparc)" name="GENERATOR" /><meta content="20061124;15040900" name="CREATED" /><meta content="16010101;0" name="CHANGED" />After re-sizing xawtv to a fairly tiny window of roughly 320×240px the output was in real time, with practically no<style>!– @page { size: 8.27in 11.69in; margin: 0.79in } P { margin-bottom: 0.08in } –></style><span lang="en-GB"> perceivable</span> delay. Next I attempted to set xawtv to full screen, a big mistake. It upped the resolution of the tv window to 1024×768 (the resolution of my laptop display) and attempted to pipe all 786432 pixels per frame uncompressed across the network in real time, nice. The end result being a slide-show about 5 seconds behind real time, completely unplayable.</p> <p><strong>Attempt 3 - ffmpeg, mplayer, pipes & a network (madness)<br /> </strong></p> <p>After the failure of xawtv I had determined that the bottleneck was the network. I could see from my network / cpu utilisation graphs that the cpu was hardly getting used and the network was pegged at 100% usage. This made me think of compressing the video “on the fly” and then sending it over the network to my laptop - due to the latency involved in encoding this was not my greatest idea but getting it to work was an interesting experiment.</p> <p>It was obvious that I needed to keep the latency as low as possible, this meant getting as few components in my encoding -> network -> decoding chain as possible. After the reading of some man pages I realised that <a href="http://ffmpeg.mplayerhq.hu/">ffmpeg</a> and <a href="http://www.mplayerhq.hu/">mplayer</a> could encode and play from standard input / output, this sent the unix geek in me a little bit crazy. Even though the sane voice in my head was saying “this is stupid, its never going to work as you want it” but the unix geek in me simply retorted with “but wouldn’t it be cool if it worked!”. In the end unix geek won, it was a sad moment for my sanity.</p> <p>Some time and many many command line arguments later, it was working. By using ssh keys to avoid any input on my part I had managed to redirect the standard output of a remote ffmpeg command over ssh and into the standard input of mplayer, the command looks something like this…</p> <blockquote><p>iain@laptop ~> ssh desktop “/home/iain/src/ffmpeg-0.4.9-pre1/ffmpeg -vd /dev/video0 -an -f mpeg1video -aspect 4:3 -tvstd pal - 2> /dev/null” | mplayer -</p></blockquote> <p><meta content="text/html; charset=utf-8" http-equiv="CONTENT-TYPE" /><title /><meta content="StarOffice 7 (Solaris Sparc)" name="GENERATOR" /><meta content="20061124;15040900" name="CREATED" /><meta content="16010101;0" name="CHANGED" />Now, be warned this does actually work (as it should, of course) infact for standard tv this works really well, although its probably easier for one to use the ffserver tool which is bundled with ffmpeg (I did’nt for a number of reasons which I wont go into now). For playing games, it still does’nt work, there’s a constant 1/2 second or so delay. I assume this is how much ffmpeg needs in its buffer to encode the stream before sending it. I attempted a number of different codecs and resolutions; an mpeg2 transport stream at a dvd like resolution looks <style> <!-- @page { size: 8.27in 11.69in; margin: 0.79in } P { margin-bottom: 0.08in } --</style>particularly lovely but still suffers from the same delay.</p> <p><strong>Attempt 4 - mplayer, or what should really have been Attempt 3</strong></p> <p>After reading the <a href="http://www.mplayerhq.hu/">mplayer</a> manual (the parts useful to me anyway) I noticed that mplayer could play from <a href="http://www.linuxtv.org/">v4l2 (video for linux)</a> devices. Hoping that it would employ a more intelligent technique than xawtv when displaying in full screen mode I set about configuring mplayer. It is fairly easy to configure and work with once you’ve found the relevant options, I opted to put the options in a config file (usually located in ~/.mplayer/config) instead of typing them each time I wanted to use a v4l device. The entry in the config file looks something like this:</p> <blockquote><p>tv=driver=v4l2:input=2:width=256:height=192:device=/dev/video0:normid=1:noaudio=1:fps=30</p></blockquote> <p>As you can see, that’s going to play at a fairly small resolution (256×192) and limit the fps to 30 with no audio. The steps to run this are fairly similar to xawtv:</p> <blockquote><p>iain@laptop ~> ssh -X -C -o CompressionLevel=9 desktop</p> <p>iain@desktop ~> mplayer tv://</p></blockquote> <p>After mplayer had started and expecting the worst I tapped ‘f’ to put mplayer into full screen mode. Shockingly it worked, some how mplayer appears to get the remote x server to stretch the image to full screen size, keeping the source resolution fixed. This method works really well, I played about with some higher resolutions but the delay increased too much, 256×192 appears to be a happy medium. After several hours of gaming I’m happy to say that it is possible to play console games on a remote X display </p> <!-- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"> <rdf:Description rdf:about="http://blog.buttermountain.co.uk/2006/11/24/console-gaming-on-a-remote-x-display/" dc:identifier="http://blog.buttermountain.co.uk/2006/11/24/console-gaming-on-a-remote-x-display/" dc:title="Console gaming on a remote X display" trackback:ping="http://blog.buttermountain.co.uk/2006/11/24/console-gaming-on-a-remote-x-display/trackback/" /> </rdf:RDF> --> </div><!-- END POST-ENTRY --> </div><!-- END POST-CONTENT --> </div><!-- END-CONTAINER --> <div class="post-header"> <h3 class="post-date">2006 11 24</h3> <p class="post-categories"><a href="http://blog.buttermountain.co.uk/category/linux/" title="View all posts in Linux" rel="category tag">Linux</a><br/> <a href="http://blog.buttermountain.co.uk/category/v4l/" title="View all posts in v4l" rel="category tag">v4l</a><br/> <a href="http://blog.buttermountain.co.uk/category/hacks/" title="View all posts in hacks" rel="category tag">hacks</a></p> <p class="post-comments"><a href="http://blog.buttermountain.co.uk/2006/11/24/console-gaming-on-a-remote-x-display/#comments" title="Comment on Console gaming on a remote X display">Comments (1)</a></p> <p class="post-permalink"><a href="http://blog.buttermountain.co.uk/2006/11/24/console-gaming-on-a-remote-x-display/" title="Permalink to Console gaming on a remote X display" rel="permalink">Permalink</a></p> </div><!-- END POST-FOOTER --> </div><!-- END POST --> <div id="post-10" class="post"> <div class="post-container"> <div class="post-content"> <h2 class="post-title"><a href="http://blog.buttermountain.co.uk/2006/11/13/disabled-parking/" title="Permalink to Disabled Parking" rel="bookmark">Disabled Parking</a></h2> <div class="post-entry"> <p>In France it is wise not to break the law and park in spaces which are reserved for the disabled. Unlike in England where someone may simply park in the disabled parking space and hope that they will not get fined.</p> <p>These clever people appear to have avoided breaking the law but some how missed the point.</p> <p>Note: all the cars in this picture have been parked in the same position overnight, the picture was taken at about 2pm</p> <p><a class="imagelink" title="disabled-parking.jpg" href="http://blog.buttermountain.co.uk/wp-content/uploads/2006/11/disabled_parking.jpg"> </a> <a class="imagelink" title="disabled-parking.jpg" href="http://blog.buttermountain.co.uk/wp-content/uploads/2006/11/disabled_parking.jpg" /></p> <div style="text-align: center"><a class="imagelink" title="disabled-parking.jpg" href="http://blog.buttermountain.co.uk/wp-content/uploads/2006/11/disabled_parking.jpg"><img width="449" height="560" id="image9" alt="disabled-parking.jpg" src="http://blog.buttermountain.co.uk/wp-content/uploads/2006/11/disabled_parking.jpg" /></a></div> <!-- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"> <rdf:Description rdf:about="http://blog.buttermountain.co.uk/2006/11/13/disabled-parking/" dc:identifier="http://blog.buttermountain.co.uk/2006/11/13/disabled-parking/" dc:title="Disabled Parking" trackback:ping="http://blog.buttermountain.co.uk/2006/11/13/disabled-parking/trackback/" /> </rdf:RDF> --> </div><!-- END POST-ENTRY --> </div><!-- END POST-CONTENT --> </div><!-- END-CONTAINER --> <div class="post-header"> <h3 class="post-date">2006 11 13</h3> <p class="post-categories"><a href="http://blog.buttermountain.co.uk/category/france/" title="View all posts in France" rel="category tag">France</a><br/> <a href="http://blog.buttermountain.co.uk/category/nontech/" title="View all posts in nontech" rel="category tag">nontech</a></p> <p class="post-comments"><a href="http://blog.buttermountain.co.uk/2006/11/13/disabled-parking/#respond" title="Comment on Disabled Parking">Comments (0)</a></p> <p class="post-permalink"><a href="http://blog.buttermountain.co.uk/2006/11/13/disabled-parking/" title="Permalink to Disabled Parking" rel="permalink">Permalink</a></p> </div><!-- END POST-FOOTER --> </div><!-- END POST --> <div id="post-8" class="post"> <div class="post-container"> <div class="post-content"> <h2 class="post-title"><a href="http://blog.buttermountain.co.uk/2006/11/06/accessing-persistent-objects-with-apache-ws-xmlrpc-30-a-documented-example/" title="Permalink to Accessing Persistent Objects with Apache ws-xmlrpc 3.0 - A Documented Example" rel="bookmark">Accessing Persistent Objects with Apache ws-xmlrpc 3.0 - A Documented Example</a></h2> <div class="post-entry"> <p><strong>Introduction</strong></p> <p>A common use case for an xml-rpc based application server would be one which involves the use of one or more persistent objects. Without any kind of persistence a server handling xml-rpc requests will either be ineffective or inefficient.</p> <p>Accessing Persistent objects in an exposed method/user handler with Apache xml-rpc 3.0 is a process involving several layers of redirection. This can be difficult for anyone who is not familiar with the ws-xmlrpc 3.0 code base. The purpose of this document is to provide a working example using the standalone servlet server which can assist people new to ws-xmlrpc 3.0.</p> <p><strong>Before We Begin</strong></p> <p>For those of you who are just interested in the source code to this example, that can be found here: <a id="p7" href="http://blog.buttermountain.co.uk/wp-content/uploads/2006/11/ws-xmlrpc-30-buttermountain-example.zip">ws-xmlrpc-3.0-buttermountain-example.zip</a></p> <p>This document and the code has been created with the help of the ws-xmlrpc FAQ examples and the help of the Apache ws-xmlrpc mailing list.</p> <p>It is assume that you have read the examples on the Apache ws-xmlrpc website and are familiar with the Java programming language.</p> <p>Finally, I recommend that you open up the source code and read through the sample code with this document.</p> <p><strong>In The Beginning There Was Nothing</strong></p> <p>Before you even begin starting to write your handler methods (the methods which will be exposed via xml-rpc), you must first collect the required libraries and setup the correct directory structure. The directory structure I have opted for looks something like this:</p> <p>org/buttermountain/xmlrpc/server<br /> org/buttermountain/xmlrpc/client<br /> org/buttermountain/pobject<br /> javax<br /> lib</p> <p>The javax directory contains all of the Sun servlet classes and the lib directory contains all of the Apache ws-xmlrpc 3.0 jar’s and the Apache ws jar’s that they depend upon.</p> <p>As for the other directories, xmlrpc/server contains all of our server files, xmlrpc/client contains a sample java ws-xmlrpc client. Finally, the pobject directory contains our very simple persistent object class.</p> <p><strong>User Handler Methods</strong></p> <p>When creating an xml-rpc server you will need to create a class which has its methods exposed via xml-rpc. With Apache ws-xmlrpc 3.0 this is done by creating two classes, one which is your interface (ExposedMethodsInterface.java) and one which is the implementation of this interface (ExposedMethodsImplementation.java).</p> <p>The interface will merely define the methods, their inputs and return data types. For a method to be exposed via xml-rpc it must be public and have a return type that is not void, here is the example interface code</p> <p>public interface ExposedMethodsInterface {<br /> public void init(Pobject pobject);<br /> public boolean setString(String string);<br /> public String getString();<br /> }</p> <p>Three methods have been defined, firstly the init() method is a non exposed method which we will call from one of our extended classes to pass our persistent object in (much more on this later). The ‘get and set’ methods are public and will be exposed via xml-rpc, hopefully you can imagine what is going on in the underlying implementation, if not take a look at the ‘ExposedMethodsImplementation.java’<br /> file provided in the example code.</p> <p><strong>A Sample Persistent Object</strong></p> <p>The persistent object for this example is incredibly simple, it exists solely to keep this example simple. The code is so short that I will include it here:</p> <p>public class Pobject {<br /> private String storedString = “”;<br /> public synchronized void setString(String string){<br /> storedString = string;<br /> }<br /> public synchronized String getString(){<br /> return storedString;<br /> }<br /> }</p> <p>As you can see, all it does is store a string and then allows the programmer the ability to ‘get and set’ the string.</p> <p><strong>Here lies the problem</strong></p> <p>Someone who is not familiar with the ws-xmlrpc 3.0 tool-kit may be thinking:</p> <blockquote><p>“Why do I even need an object like this? surely something as simple as a string could be stored in my handler class?”</p></blockquote> <p>This is where the problem begins, the user handler classes are completely stateless, up-to the point that a new instance of the handler class is created to handle each individual xml-rpc request. After the request is completed the handler instance is disposed of - never to be used again.</p> <p><strong>A solution to the problem</strong></p> <p>To get around this problem, one can call methods of the handler class after it has been initialised and just before it handles an xml-rpc request. Once one has the required knowledge this is a relatively simple task. However, judging by my experience and messages on the Apache xml-rpc mailing list, there is some confusion regarding how one can do this.</p> <p>To access methods of the handler class in this way, three of the ws-xmlrpc classes must be extended and the correct methods within them must be overridden / extended. In the sample code there is another class which has been extended (AuthenticationHandler by BmAuthHandler.java) This includes another example from the ws-xmlrpc FAQ which explains how to enable basic HTTP authentication. I have left this in to provide a more complete example.</p> <p>The classes call each other in the following Hierarchy:</p> <p>ServletServer</p> <p>|____> XmlRpcServlet<br /> |____> RequestSpecificProcessorFactoryFactory<br /> |____> Can make calls to user handler methods.\</p> <p>We will be extending the XmlRpcServlet class and the RequestSpecificProcessorFactoryFactory class. It is within the XmlRpcServlet that your persistent objects will be initialised, it is within the RequestSpecificProcessorFactoryFactory class that you will make calls to your handler methods.</p> <p><strong>Your very own ‘ServletServer’</strong></p> <p>Making use of the ServletWebServer class is very simple and is the starting point of your standalone Apache ws-xmlrpc 3.0 server. The ServeletServer class merely initialises your servlet (in this case one that we have extended ourselves) and then starts up the servlet web server on the specified port. See the file:<br /> ‘org/buttermountain/xmlrpc/server/ServletServer.java’ for details.</p> <p><strong>Extending the XmlRpcServlet</strong></p> <p>The XmlRpcServlet is persistent, it is only initialised once (when using ServletServer, I have not tested this with anything else (such as TomCat)). This class is extended within ‘org/buttermountain/xmlrpc/server/BmXmlRpcServlet.java’. It is here that the example persistent<br /> object (Pobject) class is initialised:</p> <p>private Pobject pobject = new Pobject();</p> <p>Within BmXmlRpcServlet The methods ‘isAuthenticated’ and ‘XmlRpcHandlerMapping’ are used to handle basic HTML authentication, you may ignore those for the purposes of this example. The method that we are interested in is the newPropertyHandlerMapping method. Is is<br /> within this method that we initialise our next (and final) extended class the BmProcessorFactory which extends the RequestSpecificProcessorFactoryFactory class.</p> <p><strong>Extending the RequestSpecificProcessorFactoryFactory</strong></p> <p>The RequestSpecificProcessorFactoryFactory is an incredibly long variable name, my extended version of this class uses a much shortened name ‘BmProcessorFactory’ it can be found here ‘org/buttermountain/xmlrpc/server/BmProcessorFactory.java’. It is within this class<br /> that you can actually call methods on your handler class.</p> <p>I have implemented the ProcessorFactory in the following way, the initialisation method for this class takes in our persistent object from the XmlRpcServlet. The getRequestProcessor() method is then overridden, it is in this method that we make calls to our handler methods.</p> <p>If you remember the ExposedMethodsInterface class had a method called ‘init()’ which took an object of type Pobject. The implementation for this method looks like this:</p> <p>public void init(Pobject pobject){<br /> this.pobject = pobject;<br /> }</p> <p>The variable ‘pobject’ is declared in the main body of the class allowing it to be accessible from all of the methods. This method is called from the BmProcessorFactory in the following way:<br /> ExposedMethodsInterface proc = (ExposedMethodsInterface)<br /> super.getRequestProcessor(pClass, pRequest);<br /> proc.init(pobject);<br /> return proc;</p> <p>Finally in that one line ‘proc.init(pobject)’ you can pass the persistent object to your handler class. It would be here that you could call any other methods you may want to on your handler method, one thing you must make sure is that all of your handler classes implement an init() method in the same way. Any handler classes which do not will throw an XmlRpcException and refuse to work.</p> <p><strong>Pulling it all together</strong></p> <p>Before the xml-rpc server can be run you must create a mapping file, this file creates a mapping between exposed method names and method names local to java. The included file to handle this is called ‘XmlRpcServlet.properties’ and looks like this:</p> <p>ExposedMethodsInterface=org.buttermountain.xmlrpc.server.ExposedMethodsImplementation<br /> org.buttermountain.xmlrpc.server.ExposedMethodsInterface=org.buttermountain.xmlrpc.server.ExposedMethodsImplementation</p> <p>The default location of this file is ‘org/apache/xmlrpc/webserver/XmlRpcServlet.properties’, However, I have overridden this location in the newXmlRpcHandlerMapping method of our BmXmlRpcServlet class.</p> <p><strong>Starting the xmlrpc server</strong></p> <p>The source I’ve included has a file listing the relative classpath (./classpath) and another file listing all of the source files (./sourcefiles).</p> <p>Under Linux the following steps can be taken to compile and execute the code (assuming that java/javac are in your $PATH)</p> <p>user@host $ ~/xmlrpc-example> export CLASSPATH=`cat classpath`<br /> user@host $ ~/xmlrpc-example> javac @sourcefiles<br /> user@host $ ~/xmlrpc-example> java org/buttermountain/xmlrpc/server/ServletServer<br /> 04-Nov-2006 21:16:06 org.apache.xmlrpc.webserver.XmlRpcServlet log<br /> INFO: init</p> <p>If you’ve not changed anything the Apache ws-xmlrpc server should now be running on localhost port 5555</p> <p><strong>Testing the example server</strong></p> <p>To make things even easier I’ve included two clients, one written in Java (ProxyClient.java) which is code taken from the Apache ws-xmlrpc client FAQ and one written in Python. Both clients perform the same operations but set a different string. These two clients should prove to you that the xml-rpc server is working as intended.</p> <p>Under Linux (again) make sure you have started the server (as mentioned above), now in another terminal:</p> <p>user@host $ ~/xmlrpc-example> export CLASSPATH=`cat classpath`<br /> user@host $ ~/xmlrpc-example> python python_client/client.py<br /> The oldstring was: <<< note: the default string is ""<br /> setting string to: python xmlrpc client<br /> The string is now: python xmlrpc client</p> <p>user@host $ ~/xmlrpc-example> java org/buttermountain/xmlrpc/client/ProxyClient<br /> The oldstring was: python xmlrpc client<br /> setting string to: java xmlrpc client<br /> The string is now: java xmlrpc client</p> <p>Take a look at the source code of both those examples if you wish to see how they work in more detail, the output should look something like the above.</p> <p>Note: The client and server code should work under any operating system where Java & Apache ws-xmlrpc 3.0 are supported. The Python client should work under any operating system which supports Python.<br /> i.e the code should run on systems other than Linux.</p> <p><strong>Conclusion</strong></p> <p>I hope that this example will be useful to people attempting to use the Apache ws-xmlrpc 3.0 tools. If you have any questions / comments etc, please drop me an email.</p> <p>Thank you to the kind people of the Apache ws-xmlrpc mailing list who helped me get to a working solution and to the Apache ws-xmlrpc developers who have created a fantastic (although sometimes complicated) tool kit. </p> <!-- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"> <rdf:Description rdf:about="http://blog.buttermountain.co.uk/2006/11/06/accessing-persistent-objects-with-apache-ws-xmlrpc-30-a-documented-example/" dc:identifier="http://blog.buttermountain.co.uk/2006/11/06/accessing-persistent-objects-with-apache-ws-xmlrpc-30-a-documented-example/" dc:title="Accessing Persistent Objects with Apache ws-xmlrpc 3.0 - A Documented Example" trackback:ping="http://blog.buttermountain.co.uk/2006/11/06/accessing-persistent-objects-with-apache-ws-xmlrpc-30-a-documented-example/trackback/" /> </rdf:RDF> --> </div><!-- END POST-ENTRY --> </div><!-- END POST-CONTENT --> </div><!-- END-CONTAINER --> <div class="post-header"> <h3 class="post-date">2006 11 06</h3> <p class="post-categories"><a href="http://blog.buttermountain.co.uk/category/code/" title="View all posts in code" rel="category tag">code</a><br/> <a href="http://blog.buttermountain.co.uk/category/xml-rpc/" title="View all posts in xml-rpc" rel="category tag">xml-rpc</a><br/> <a href="http://blog.buttermountain.co.uk/category/apache/" title="View all posts in Apache" rel="category tag">Apache</a></p> <p class="post-comments"><a href="http://blog.buttermountain.co.uk/2006/11/06/accessing-persistent-objects-with-apache-ws-xmlrpc-30-a-documented-example/#comments" title="Comment on Accessing Persistent Objects with Apache ws-xmlrpc 3.0 - A Documented Example">Comments (4)</a></p> <p class="post-permalink"><a href="http://blog.buttermountain.co.uk/2006/11/06/accessing-persistent-objects-with-apache-ws-xmlrpc-30-a-documented-example/" title="Permalink to Accessing Persistent Objects with Apache ws-xmlrpc 3.0 - A Documented Example" rel="permalink">Permalink</a></p> </div><!-- END POST-FOOTER --> </div><!-- END POST --> <div class="navigation"> <div class="alignleft"></div> <div class="alignright"></div> </div><!-- END NAVIGATION --> </div><!-- END CONTENT --> </div><!-- END CONTAINER --> <div id="sidebar"> <ul> <li id="home-link"> <h2><a href="http://blog.buttermountain.co.uk/" title="Butter Mountain">Home</a></h2> </li> <li class="pagenav"><h2>Pages</h2><ul><li class="page_item"><a href="http://blog.buttermountain.co.uk/about/" title="About">About</a></li> </ul></li> <li id="category-links"> <h2>Categories</h2> <ul> <li><a href="http://blog.buttermountain.co.uk/category/apache/" title="View all posts filed under Apache">Apache</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/code/" title="View all posts filed under code">code</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/cooking/" title="View all posts filed under Cooking">Cooking</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/debug/" title="View all posts filed under debug">debug</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/django/" title="View all posts filed under Django">Django</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/entropy/" title="View all posts filed under entropy">entropy</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/france/" title="View all posts filed under France">France</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/gtk/" title="View all posts filed under gtk">gtk</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/hacks/" title="View all posts filed under hacks">hacks</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/hardware/" title="View all posts filed under hardware">hardware</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/junk/" title="View all posts filed under junk">junk</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/jython/" title="View all posts filed under jython">jython</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/linux/" title="View all posts filed under Linux">Linux</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/mysql/" title="View all posts filed under MySQL">MySQL</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/net-boot/" title="View all posts filed under Net Boot">Net Boot</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/networking/" title="View all posts filed under networking">networking</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/nontech/" title="View all posts filed under nontech">nontech</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/open-solaris/" title="View all posts filed under Open Solaris">Open Solaris</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/pxe/" title="View all posts filed under PXE">PXE</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/python/" title="View all posts filed under python">python</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/solaris/" title="View all posts filed under Solaris">Solaris</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/v4l/" title="View all posts filed under v4l">v4l</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/xml-rpc/" title="View all posts filed under xml-rpc">xml-rpc</a> </li> <li><a href="http://blog.buttermountain.co.uk/category/zfs/" title="View all posts filed under ZFS">ZFS</a> </li> </ul> </li> <li id="search"> <h2><label for="s">Search</label></h2> <form id="searchform" method="get" action="http://blog.buttermountain.co.uk/"> <div> <input id="s" name="s" type="text" value="" tabindex="1" size="10" /> <br/> <input id="searchsubmit" name="searchsubmit" type="submit" value="Find" tabindex="2" /> </div> </form> </li> </ul> </div> <div id="footer"> <p> © 2008 iain | Thanks, <a href="http://wordpress.org/" title="WordPress">WordPress</a> | <a href="http://www.plaintxt.org/themes/barthelme/" title="Barthelme for WordPress" rel="follow">Barthelme</a> theme by <a href="http://scottwallick.com/" title="scottwallick.com" rel="follow">Scott</a> | <!-- The following is a link to the theme author's sponsor. Please consider its smallness and that Scott was nice enough to make this theme publically available. --> Sponsor: <a href="http://www.active-sandals.com/womreefsan.html" title="Support: Reef Sandals">Reef Sandals</a> | Valid <a href="http://validator.w3.org/check?uri=http://blog.buttermountain.co.uk&outline=1&verbose=1" title="Valid XHTML 1.0 Strict" rel="nofollow">XHTML</a> & <a href="http://jigsaw.w3.org/css-validator/validator?uri=http://blog.buttermountain.co.uk/wp-content/themes/Barthelme/style.css&profile=css2&warning=no" title="Valid CSS" rel="nofollow">CSS</a> | RSS: <a href="http://blog.buttermountain.co.uk/feed/" title="Butter Mountain RSS 2.0 (XML) Feed" rel="alternate" type="application/rss+xml">Posts</a> & <a href="http://blog.buttermountain.co.uk/comments/feed/" title="Butter Mountain Comments RSS 2.0 (XML) Feed" rel="alternate" type="application/rss+xml">Comments</a> </p> </div> </div><!-- END WRAPPER --> <!-- Somehow 14 queries occured in 0.715 seconds. Magic! --> <!-- The "Barthelme" theme copyright (c) 2006 Scott Allan Wallick - http://www.plaintxt.org/themes/ --> <script src="http://www.google-analytics.com/urchin.js" type="text/javascript"> </script> <script type="text/javascript"> _uacct = "UA-2761551-1"; urchinTracker(); </script> </body> </html>