elliot's blog

Zombie Haiku

I noticed this Zombie Haiku book yesterday: http://www.amazon.co.uk/dp/1600610706

Which reminded me of this zombie haiku I wrote when I was about 12 (27 years ago - ouch):

A noxious zombie
eats a mouldy, worm-filled leg
in a rancid cave.

Which isn't very good (though vivid enough for me to remember and obviously ahead of its time); and not strictly haiku (it has no "kireji", or its closest equivalent in English, i.e. "a dignified ending, concluding the verse with a heightened sense of closure" - http://en.wikipedia.org/wiki/Kireji). So I rewrote it while in the bath last night (probably too much information there...):

An ashen zombie
gnaws a muddy, worm-filled leg:
tears run over bones.

Hopefully, this will enable you to see how much I've progressed as an artist.

Update: After having written this, I read this surprisingly relevant blog entry about how we see our artwork when we're young (by way of Rotating Corpse), how our perceptions of it change, and even how art comes to have value.

An unpleasant experience

A few years ago, I wrote a Rails (1.0.0) application for Nicola (my wife), to help her with her PhD research. It ran on her Linux laptop, happily, for those few years.

However, once the new laptop has arrived, I knew I'd have to migrate the application from Linux to Windows; I also wanted to avoid having to update the application for a newer version of Rails. How painful could it be? Fairly.

First I needed an old MySQL server (in case the API has changed), 5.0.15 to be precise. It is practically impossible to find archived downloads on the MySQL website, but I got there eventually.

Next I needed to get an old Ruby (1.8.4) for Windows. Again, virtually impossible to find old versions of Ruby with an installer. When I first did this, there was a Ruby 1.8.4 One-Click Installer for Windows, which seems to have disappeared. I finally tracked it down to some website run off some bloke's back somewhere out East.

Then, I needed Rails 1.0.0. For whatever reason, the Ruby I installed couldn't get Rails off the official gems repository (probably because the gem repo format changed). So I installed rails 1.0.0 on a different machine, created a new Rails project, then froze the 1.0.0 gems into it; then copied the frozen gems over to my app on the new machine. Phew.

Finally, I'd used RedCloth in the app. However, after a couple of attempts, I decided it was easier to rip it out than try to install it on Windows. So I did some surgery.

Add to that the fact that Nicola had forgotten her password (Firefox had been saving it), so I had to manually edit the db to add one; plus no decent text editor on Windows 7; plus MySQL not removing its service properly when I installed the wrong version then uninstalled it (sc delete MySQL removes errant services, by the way); plus Windows 7 making it difficult to get an administrator command prompt; etc. etc..

So overall a frustrating experience, but I did finally get there.

(On top of that, I also migrated several thousand POP-ped emails from Thunderbird 2 on Linux to Thunderbird 3 on Windows: I thought there would be an import wizard which would know what to do, but I saw no sign of it. And moved all her data over and installed OpenOffice. Entertainment all round.)

Once I've got over my trauma, I will provide links to where to find ancient versions of apps and libraries. Perhaps I should be an archaeologist.

Books read 2009, and to read in 2010

Last year I only managed to read 18 books. Pretty poor going. They were:

Microserfs - Douglas Coupland
Magnetism and other stories - F. Scott Fitzgerald
Everything Is Miscellaneous
The Eternal Champion - Michael Moorcock
Phoenix in Obsidian - Michael Moorcock
The Sailor on the Seas of Fate - Michael Moorcock
Dying Inside - Robert Silverberg
Breakthrough - Richard Cowper
Brontomek! - Michael Coney
To Your Scattered Bodies Go - Philip Jose Farmer
Childhood's End - Arthur C. Clarke
400 Billion Stars - Paul J. McAuley
The Road - Cormac McCarthy
Tactics of Conquest - Barry Malzberg
Secret Harmonies - Paul J. McAuley
Inside Intel - Tim Jackson
Imperial Earth - Arthur C. Clarke
A Canticle for Leibowitz - Walter M. Miller Jr.

Of those, The Road was easily the best. I dread to think what a shambles the film will turn it into.

I've also updated my list of important books to include one or two I read last year, and some others I remembered. Plus I created a separate section for my favourite sf books.

This year I'm planning to read some sf classics. Here's the list I'm starting from (as I already have copies of all these):

A Case of Conscience - James Blish
Downward to the Earth - Robert Silverberg
Man Plus - Frederik Pohl
Venus Plus X - Theodore Sturgeon
Davy - Edgar Pangborn
The Space Merchants - Frederik Pohl & C.M. Kornbluth
The Diamond Age - Neal Stephenson
Blood Music - Greg Bear
Stand on Zanzibar - John Brunner
Time Out of Joint - Philip K. Dick
The Embedding - Ian Watson
The Fifth Head of Cerberus - Gene Wolfe
I Am Legend - Richard Matheson
On Wings of Song - Thomas M. Disch
Ringworld - Larry Niven
The Child Garden - Geoff Ryman

Let's see how I get on.

A script for parsing work log files

Attached is my Ruby script for parsing log files I keep at work. I have to complete a weekly report, and this forms the basis of that; as I don't keep regular office hours (I flexi-work around child care), it also helps me keep track of the hours I've worked.

The basic principle of operation is as follows:

  1. I create a file for each working week, called something like week45.log
  2. During the week, I record bits of activity I do (see below); I also note down stuff I plan to do next (again, see below)
  3. At the end of the week, I run parse_work_log <file name> > summary.out on the file to produce a log of what I've done
  4. If anything goes wrong, I tend to edit the work log and regenerate, so I can just keep the log (not the summary)
  5. I cut and paste from the summary.out file into an email I send round

The format of the file is deliberately simple to make it easy to maintain; there are a handful of formatting rules. An example is shown below.


09:30-12:00    Researching this and that #research
12:00-13:00    -Lunch
13:00-14:00    More research
14:00-18:00    Writing some application #coding


09:30-10:00    Admin #Admin
10:00-10:15    -Break
10:00-12:00    Found out something rather marvellous #Very important research
12:00-12:45    -Lunch
12:45-18:00    Writing another application #coding

+NEXT Have lots of fun banging my head on a brick wall
+NEXT Reinstall my operating system

Which, when parsed, produces this on stderr:


Worked 15.25 hours

And this on stdout:

This week:


  * Admin

Very important research:

  * Found out something rather marvellous


  * Writing some application
  * Writing another application


  * Researching this and that


  * Have lots of fun banging my head on a brick wall
  * Reinstall my operating system

Notes on formatting:

  • The asterisks and dates are just there to make it more readable - they're basically ignored
  • An entry is a single line with the format HH:MM-HH:MM <...whitespace...> <text> <#optional tag>\n
  • The time span for an entry is added to the total time, unless the entry text contains -Lunch or -Break
  • # creates a tagged entry which gets included in the report; it appears as a bullet point with the tag as its heading; any entries with the same tag get aggregated under a single heading; tags and entries appear in the order they occur in the file
  • Any line starting with +NEXT gets listed in the Next section at the end; tags don't work on this (could, but don't at the moment)

It is pretty primitive, but it does the job for me.

Installation: there isn't any, really. It works from the command line and needs Ruby. The licence? BSD, I guess.

An introduction (of sorts) to JavaScript desktop application development with Gjs and Clutter

This turned into a pretty long blog entry. To help you decide whether you want to stick it out, it's about:

  • My experience with C development for Moblin
  • JavaScript for desktop applications
  • Gjs, GObject introspection, and GIR repository installation
  • Running JavaScript Clutter applications using gjs
  • Interesting movements in the JavaScript world


I started work at Intel's Open Source Technology Centre 6 weeks ago (just realised I haven't written about that here yet), working on the Moblin SDK. Moblin is a Linux-based platform for mobile devices (netbooks, UMPCs, that sort of thing); my role in the project is working as part of the SDK team - basically trying to help third-party developers outside Intel develop software which runs on Moblin. So far, this has involved learning as much about the Moblin stack and ecosystem as possible, as well as helping organise and add to the content on Moblin-related websites. (It's challenging, exciting work and I'm thoroughly enjoying it so far.)

Currently, software development on Moblin is comparable to generic Linux development: languages like Python, Ruby, C++, Perl, Java, C# (via Mono) etc. are all available. However, if you want to make use of the full range of Moblin libraries (like our stuff for managing media metadata or interacting with social networking sites), and combine them with Clutter (our GUI toolkit), the best approach (at the moment) is to program in C. While many of the Moblin libraries have bindings to other languages (like Python and Perl), C gives you the best, most consistent access to all of them (as they're all written in C). You'll also find Moblin development easier if you're familiar with GNOME and glib, both of which are fairly C-centric.

My background isn't in low-level system programming. I have been learning C since starting at Intel, and have enjoyed it thoroughly, but there are several aspects of it I could live without:

  • Memory management is my main bugbear. I really don't want to have to care about allocating memory for data structures, then cleaning up when I'm finished with them. Learning how to (still learning...) has definitely enhanced my understanding of how programs actually work under the bonnet, but dealing with memory directly is not, in general, fun. I'd rather the runtime dealt with it.
  • autotools (aka the GNU Build System) are not straightforward, especially if you're used to build tools like Ant and Rake (or even Maven). I know they are extremely powerful and flexible, and ubiquitous for open source projects, but I defy anyone to tell me they are simple, easy to learn, or well documented. In fact, the autotools (automake, autoconf) actually wrap other tools (make) which are even more complicated. This is partly a consequence of the job they do (making it possible to compile software across different platforms), but means they are not approachable. See the diagram on the autools Wikipedia page to get an idea of how complicated they are.
  • Pseudo object oriented programming (in C) isn't really as pleasant as full OOP (in a language like Ruby). GObject for C (part of GLib) gives you some of the facilities of full OOP, but (as far as I understand it) it's not possible to encapsulate data with the methods which act upon it. It also seems tremendously complicated. Even with GObject, you are still basically doing imperative programming, so encapsulation relies on namespacing and (kind of) casting objects to the right class before passing them to a function (as classes don't seem to know about their parent class, as such). Having said all this, one smart feature GObject does support is introspection, which makes it possible to automate binding other languages to a C library.

So, with my background, and with the goal of making Moblin development easy and attractive, I am keen to find alternatives to having to program in C all the time. Dynamic, interpreted languages (like Ruby or JavaScript) seem to me to be better suited to exploratory, iterative programming: the kind of programming most people do most of the time. This is a goal shared by the GObject Introspection project:

C is good for graphics, multimedia, and lower level systems work. However, writing complex software is difficult and error-prone without garbage collection. A managed runtime such as JavaScript, Python, Java, Lua, .NET, Scheme etc. makes a lot of sense for non-fast-path application logic such as configuration, layout, dialogs, etc. ... Thus, one of the major goals of the GObject introspection project is to be a convenient bridge between these two worlds, and allow you to choose the right tool for the job, rather than being limited inside one or the other. (from http://live.gnome.org/GObjectIntrospection)

GObject Introspection is already being used in GNOME development, to generate JavaScript bindings for the GNOME libraries: the next version of the GNOME desktop (in GNOME 3), GnomeShell, uses JavaScript extensively (calling Clutter, the Moblin graphics library, incidentally). Gjs is the name of the project producing the bindings, as well as being the home of the JavaScript engine itself (also called gjs, and based on Mozilla's implementation of JavaScript in C, SpiderMonkey).

JavaScript is an interesting language. I've used it in web applications for quite a long time (since about 2000), but never entertained the idea of using it for anything other than client-side web programming. Occasionally I'd come across server-side JavaScript (persevere), JavaScript implementations like Rhino, and even wrote some ASP code in JScript (as Microsoft called it) a few years ago. Frameworks like jQuery and the thorough integration of JavaScript with Rails meant that I've done more of it in recent months, but I never thought of using it as a general purpose language, or one for desktop development.

Looking for an alternative to C, and hearing from my colleagues about JavaScript, made me decide to get a feel for Gjs et al, as well as write something to run on Moblin. I decided to write a JavaScript application which made use of the Moblin graphics library, Clutter. Eventually, I ended up successfully writing a JavaScript implementation of tic-tac-toe, using Clutter for the user interface, and even including some simple animation. As an application, it is a bit scrappy (the code is attached), but as a learning aid, doing the project was very useful. It wasn't an easy journey, but it was an eventually satisfying one.

Using JavaScript for the not-web

I did my development work on a Fedora Core 11 laptop, with an Intel chipset.

I tried a variety of ways to install all the pieces I needed for JavaScript development with Gjs, GObject Introspection, GNOME libraries, and Moblin libraries. Even getting an idea of what all the pieces do is painful, and the documentation is pretty woeful. I ended up doing lots of source code grep-ing and googling.

In the end, it turns out that the following packages are available for Fedora Core:

  • gobject-introspection: This provides tools and APIs for working with GIR XML files and typelib (binary versions of the GIR files): these are two formats for storing introspection data about GObject classes (basically, mapping the API of a C library into language-neutral descriptions of the APIs). The metadata for several common libraries (like GLib) is part of this package.
  • gir-repository: This provides more introspection metadata about other common libraries (like GTK+ and DBus-GLib)
  • gjs: This enables you to use the gobject-introspection data to access C libraries from JavaScript (i.e. it's the JavaScript bindings for GNOME libraries).

Now, unfortunately, the versions in the repositories for Fedora 11 are out of date: generating the Clutter bindings requires gobject-introspection-1.0, which isn't available. Plus, this code is so new that it's changing very rapidly, and you probably need the latest version from the source repository to get stuff to work.

To compile all these bits, you're going to need the basic build tools. On Fedora, that means this lot:

$ sudo yum install git flex bison gnome-common libgnome-devel libffi-devel \
    python-devel libtool automake autoconf make gtk-doc xulrunner-devel

(And maybe others: I lost track. But if you're trying to do this yourself, you'll probably know what to do if something's missing. Anyway, Josh is going to sort some packages out before long, hopefully. If you know a better way, let me know.)

Once you've got those installed, though, you should be able to build everything from source fairly easily.

As we're installing into /usr/local, first thing to do is make sure the compiler/linker can find your custom-compiled packages. In your ~/.bashrc file, add this line:

export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig

This tells the pkg-config tool (used by autotools to locate libraries and headers) where your custom installations are. Then reload your bash settings with:

$ source ~/.bashrc

to make sure they're picked up. Any future bash sessions will use this setting. Now you're ready to build.


$ git clone git://git.gnome.org/gobject-introspection
$ cd gobject-introspection
$ ./autogen.sh --prefix=/usr/local
$ make
$ sudo make install


$ git clone git://git.gnome.org/gir-repository
$ cd gir-repository
$ ./autogen.sh --prefix=/usr/local
$ make
$ sudo make install


$ git clone git://git.gnome.org/gjs
$ cd gjs
$ ./autogen.sh --prefix=/usr/local
$ make
$ sudo make install

You can check gjs is working by doing:

$ /usr/local/bin/gjs
gjs> 1+1

It's a good idea to add /usr/local/bin to your path, again in ~/.bashrc:

export PATH=$PATH:/usr/local/bin

(and source ~/.bashrc to pick it up if necessary)

To compile Clutter itself, you'll also need these library headers:

$ sudo yum install glib2-devel mesa-libGL-devel libXext-devel \
    libXfixes-devel libXdamage-devel pango-devel cairo-devel

(Again, maybe others too.)

Once you've got those too, you can checkout Clutter using git, and build it with introspection turned on:

$ git clone git://git.clutter-project.org/clutter
$ cd clutter
$ ./autogen.sh --prefix=/usr/local --enable-introspection
$ make
$ sudo make install

The final step is one which doesn't appear to be documented anywhere, but which is utterly vital: without it, gjs can't find any of the introspection metadata, and won't be able to call any of the C libraries through their JavaScript bindings. Add this line to your ~/.bashrc file:

export GI_TYPELIB_PATH=$GI_TYPELIB_PATH:/usr/local/share/gir-1.0/

(Again, use source if necessary.)

Testing gjs with Clutter

To test the install, and make sure the Clutter JavaScript bindings are working, put this code into a file test.js:

const Clutter = imports.gi.Clutter;
Clutter.init (0, null);
let stage = Clutter.Stage.get_default ();
stage.title = "Test";
stage.set_color(new Clutter.Color( {red:150, blue:0, green:0, alpha:255} ));
stage.show ();
Clutter.main ();
stage.destroy ();

Run it from a command line with:

$ gjs test.js

You should see something like this:

If this works, you should be able to run my tic-tac-toe (semi-)implementation, linked at the end of this blog entry. To run it, copy the two files into a directory, remove the .txt suffixes, then get a command line in that directory and run:

$ gjs ox.js

There's no AI (so you'll have to play both sides), but notice the use of a scale animation as each move is written to the board. Also interesting is how you can use anonymous JavaScript functions to define callbacks for signals.

I've not experimented extensively, beyond calling a few bits of the Clutter and Netbook Toolkit APIs. If you want more examples, have a look at the GnomeShell tests and UI code. The mx tests are another source of sample code I used.

Another tip: if you're trying to work out what's available in the JavaScript bindings, there's unfortunately no nice way to do it at the moment. Your only recourse is to grep the XML GIR files, which are located in:


Reading these is a bit of a chore, and I also found it difficult to figure out what was in the API. For example, if you're trying to use a Clutter constant like CLUTTER_X_AXIS, the GIR file has this entry:

<namespace name="Clutter"

... loads of cruft ...

  <enumeration name="RotateAxis"
                  doc="Axis of a rotation."

    <member name="x_axis"


... loads more cruft ...


So, to reference the CLUTTER_X_AXIS constant, my first thought was look up the member element with a c:identifier corresponding to the constant I want; then use the path from the namespace, through the enumeration name, to the member name, i.e.:


But in fact it's:


(the name attribute, capitalised).

I also found that some methods and classes in the GIR for GLib didn't work (like GLib.printf). I'm sure there's a good reason why, it's just I couldn't work it out.

What's missing?

I spent quite a few hours figuring this stuff out, and stumbled a lot along the way. Partly because I'm not a C programmer, partly because I'm new to GNOME, I'm sure. But I think there are a few things which would have improved my experience:

  • Decent documentation, particularly of the JavaScript APIs generated for C libraries like GLib - at the moment, working out what's going to be available in the JavaScript bindings is very tedious
  • An easy installation process (see above) - largely though because I'm using libraries which are too bleeding edge, just because they're the only ones which worked well
  • An intelligible module system, for modularising code - at the moment my application will only run from the directory where the files are, as I've yet to work out how to get the path to the directory containing the script programmatically; I'm not sure how you'd organise large groups of files spread over lots of directories
  • A decent packaging system with dependency tracking, so that you can distribute JS apps and know they'll work
  • Functions to make developers' lives easier, like a decent REPL (gjs doesn't even have a print function - there is a patch to gjs which will give you that - see here: http://bugzilla-attachments.gnome.org/attachment.cgi?id=135898 - but you'll have to patch manually at the moment to get it)

And finally, it might be worth taking a look at Seed, which is an alternative JavaScript implementation, but one which still understands GObject introspection. Seed is interesting in that it seems to provide more niceties, like a better REPL environment, more documentation, and a fuller standard library (filesystem and environment interfaces in particular).

What's next for JavaScript?

It looks as if the JavaScript world is hotting up at the moment. This is a recent news report on the state of JavaScript:


It mentions the CommonJS standardisation effort, which is attempting to resolve some of the shortcomings of JavaScript as a general purpose language.

Reading through the CommonJS wiki, I was particularly interested in Narwhal, which resolves some of the issues I mentioned in the last section: it includes a package manager, module system, and standard library. It also provides support for different JavaScript engine back-ends: currently this includes a SpiderMonkey adapter. Given that Gjs is broadly based on SpiderMonkey, it seems likely that creating a Gjs back-end for Narwhal wouldn't be too onerous.

One other thing which could potentially be useful in Narwhal is the availability of separate Narwhal environments (called "seas") with their own set of packages. This could help isolate applications from each other in an environment like Moblin, where you want third parties to be able to develop applications without trampling on each other's libraries.

Another tool of interest is jake, a port of Ruby rake to JavaScript, which seems to be optimised to work with Narwhal. This could provide a reasonable alternative to autotools for the simpler build requirements of a JavaScript application (where there's no need for a compile step or library linking).

A combination of Narwhal (packaging/modules), with the power of Gjs binding to pretty much any C library, would make an attractive environment to develop in.

I should also mention node.js, server-side JavaScript primarily designed for building network programs, but which incorporates a CommonJS module system. It's built on Google's V8 JavaScript engine. It's also interesting because it is designed to be highly performant and memory-efficient, and has an interesting event-driven I/O model, like EventMachine or Twisted.

I'm definitely looking forward to seeing what happens next.

Back on Fedora

A few years ago, I used to work on RedHat Linux, then Fedora: my first Linux machine ran RedHat Linux. Then I got sick of things breaking every time I upgraded (on one traumatic occasion, my audio stopped working after a Fedora upgrade) and switched to Ubuntu.

But in my new job, I need Linux, but also need to encrypt my laptop's hard drive. I had a go at doing this with Ubuntu, with disastrous results. Didn't really know what I was doing (I did manage to encrypt the hard drive, but couldn't figure out how to mount it during boot). Fedora makes this simple, though. So I moved across, and have to say I'm pretty glad I did. It's very similar to Ubuntu in many ways, and I don't feel like I'm missing anything. My main annoyance was SELinux, which just wanted to stop me having any kind of fun with my computer; so I switched it off.

So, if you need to PGP encrypt your hard drive, but currently use Ubuntu, have a look at Fedora instead.

Playing mp3s on Moblin (2.1)

I have an EeePC with Moblin 2.1 (release candidate) installed on it (via the packages in http://repo.moblin.org/moblin/releases/2.1/ia32/os/). By default, you don't get an mp3 decoder with this distribution. It wasn't obvious (when I googled for it) how to install the right GStreamer plugins: several blog entries suggested a variety of pretty hacky methods and work-arounds.

Then I chanced on a blog entry which mentioned that Fluendo have a free legally-downloadable RPM of their own mp3 encoder; I remember someone at work mentioning it too. I downloaded and installed this onto my netbook with no difficulties. You have to register for an account and go through a faux shopping basket to get it, but it is fairly painless. Here's the product page URL:


My favourite blog

I was going to put "probably", but then decided that, no, this is my favourite:


I love the way this chap writes. Mainly about second-hand books he's found and/or read, but often about their cover art, the ephemera he finds inside them, brilliant expositions about small towns he's visited, and other bits and pieces. There's a certain gentle Englishness, quiet pathos, and calm reflection about his work which strikes just the right balance for me.

xtranormal and making movies

Above is the first movie I've made with xtranormal, called Ex-super villain first date. Not sure how I've never come across this site before, but it is a fantastic piece of web engineering: an in-browser (Flash), animated movie creation application. Basic accounts are free, and give you a pretty good range of stuff you can do. The interface is very simple and intuitive. It seems best suited to the sort of stilted absurdist style I attempted above, which took me maybe an hour to put together. Much fun.

Memory leaks and JQuery and htmlunit and...

(Just a quick note about JQuery and rdfquery and memory leaks and htmlunit and such like for lost souls googling desperately for clues.)

I was having issues with some Webdriver tests, running under the htmlunit driver: they worked locally, but ran into Java "out of memory: heap space exhaustion" issues when running as part of a Hudson build on our Linux build server. The build also worked on another virtual machine with the Internet Explorer driver, so it seemed to be something specific to the htmlunit driver (maybe). After upgrading Java, upgrading Hudson (the continuous integration server), and tweaking the Java heap size, and still no joy, I found a few mentions of memory leaks in relation to htmlunit and JQuery (the Javascript library we're using), which I decided were worth investigating.

One comment in particular seemed plausible: that the Javascript on the pages under test was causing memory leaks in the Javascript engine in htmlunit (Rhino, I think?). It seemed possible that how we were using JQuery was causing Javascript to leak memory, but only in the context of the htmlunit driver. I trawled around the various bug trackers for htmlunit and webdriver, and got a few ideas (though couldn't pin the issue down enough to raise a bug myself).

One suggested fix (in the general context of JQuery, rather than specifically with regard to htmlunit) was to ensure that any event handlers bound to DOM elements via JQuery should explicitly be removed when the page unloads. This was easy to implement: I just added a final event binding to each page which looked like this (inside a <script> tag, obviously):

$(document).unload(function() {$('*').unbind(); });

I was also using the short-hand JQuery event binding syntax in my code, i.e. things like this:

$('#save').click(function() {
   // ...

I changed these to the long-hand form (as this issue only started appearing when I started using the short-hand version):

$('#save').bind('click', function() {
   // ...

One last thing I did was ensure that I called the quit() method on any Webdriver driver instances after I'd finished with them; and closeAllWindows() on any htmlunit WebClient instances when finished with them.

Unfortunately, I didn't do this very scientifically, and made all these changes at once. But the end result was that the build started running again. So if you're having out of memory errors with Webdriver/htmlunit/Hudson/JQuery/rdfquery, you at least have somewhere to start from :)

Syndicate content