<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>talkingCode</title>
	<atom:link href="http://talkingcode.co.uk/feed/" rel="self" type="application/rss+xml" />
	<link>http://talkingcode.co.uk</link>
	<description>Linux, Software Development, Technology</description>
	<pubDate>Mon, 07 Jul 2008 22:07:00 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>Open Rights Group</title>
		<link>http://talkingcode.co.uk/2008/07/07/open-rights-group/</link>
		<comments>http://talkingcode.co.uk/2008/07/07/open-rights-group/#comments</comments>
		<pubDate>Mon, 07 Jul 2008 22:07:00 +0000</pubDate>
		<dc:creator>codders</dc:creator>
		
		<category><![CDATA[rant]]></category>

		<guid isPermaLink="false">http://talkingcode.co.uk/?p=43</guid>
		<description><![CDATA[Dear reader&#8230; (maybe it&#8217;s readers plural),
This weekend I was at Open Tech 2008, which was fun. I got to hear about how cool OpenStreetMap is, about the inspiring work that the Open Knowledge Foundation are doing, and finally got to see Roo give a talk.
I won&#8217;t pretend that the talk from the Open Rights Group [...]]]></description>
			<content:encoded><![CDATA[<p>Dear reader&#8230; (maybe it&#8217;s readers plural),</p>
<p>This weekend I was at <a href="http://www.ukuug.org/events/opentech2008/">Open Tech 2008</a>, which was fun. I got to hear about how cool <a href="http://www.openstreetmap.org/">OpenStreetMap</a> is, about the inspiring work that the <a href="http://www.okfn.org/">Open Knowledge Foundation</a> are doing, and finally got to see <a href="http://rooreynolds.com/">Roo</a> give a <a href="http://rooreynolds.com/2008/07/06/current-cost-presentation-at-open-tech-2008/">talk</a>.</p>
<p>I won&#8217;t pretend that the talk from the <a href="http://www.openrightsgroup.org/">Open Rights Group</a> was the coolest talk I saw all day, but it might have been the most important. I&#8217;ve been following their work for a while but had resisted becoming a member on account of their not being a registered UK charity. On Saturday, I discovered that at least part of the reason they&#8217;re not is that becoming a charity would reduce the extent to which they can act as a political pressure group, which would in many ways defeat the object.</p>
<p>So here&#8217;s the deal. I&#8217;m breaking the unwritten rule of talkingCode and writing about something political that I believe in. If you live in the UK you should be supporting the work of the Open Rights Group however you can. They are a small, bright, committed bunch and are thoroughly deserving of your donations.</p>
<p>Go here to find out about more about them:<br />
<a href="http://www.openrightsgroup.org/2008/07/07/growing-the-org-community-and-having-fun-doing-it/">http://www.openrightsgroup.org/2008/07/07/growing-the-org-community-and-having-fun-doing-it/</a></p>
<p>Then donate some money.</p>
<p>Do this now.</p>
<p>They&#8217;re busy fighting some really important battles on our behalf. It&#8217;s difficult to convince people that these battles are worth fighting or that the issues are really that important when people are having trouble affording petrol or food, but it&#8217;ll be too late to unmake the laws in 20 years time when we realise what we&#8217;ve lost. By then, the very tools with which we would have fought the battle will have been taken from us.</p>
]]></content:encoded>
			<wfw:commentRss>http://talkingcode.co.uk/2008/07/07/open-rights-group/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Java, SSL, and the Keystore of Doom</title>
		<link>http://talkingcode.co.uk/2008/07/04/java-ssl-and-the-keystore-of-doom/</link>
		<comments>http://talkingcode.co.uk/2008/07/04/java-ssl-and-the-keystore-of-doom/#comments</comments>
		<pubDate>Fri, 04 Jul 2008 13:03:38 +0000</pubDate>
		<dc:creator>codders</dc:creator>
		
		<category><![CDATA[code]]></category>

		<category><![CDATA[debian]]></category>

		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://talkingcode.co.uk/?p=42</guid>
		<description><![CDATA[In a break from our Haskell programming&#8230;
I used to be a staunch defender of Java as a language. I still think it&#8217;s relatively good (though mostly for the tool support), but there are things about it that make me want to scream.
Imagine, for example, you&#8217;d like to make an SSL authenticated fetch from a webserver. [...]]]></description>
			<content:encoded><![CDATA[<p>In a break from our Haskell programming&#8230;</p>
<p>I used to be a staunch defender of Java as a language. I still think it&#8217;s relatively good (though mostly for the tool support), but there are things about it that make me want to scream.</p>
<p>Imagine, for example, you&#8217;d like to make an SSL authenticated fetch from a webserver. You have a client certificate to authenticate your client, and a server certificate to authenticate the server, and you&#8217;ve generated them both from your own CA. Shouldn&#8217;t be that hard, right? Wrong <img src='http://talkingcode.co.uk/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> Everything SSL has to be configured via the key stores, so you need to import your private certificate and the server&#8217;s public certificate in to your key store in order to make anything go.</p>
<p>There are two stores - the Trust Store and the Key Store. The Trust store contains the certificates you trust (CAs, etc.). The Key Store contains certificates for which you have the private key and against which you&#8217;ll encrypt challenges to verify your identity. All you have to do is populate them&#8230;</p>
<p><b>Step 1: Don&#8217;t use GCJ</b><br />
There are a lot of great things to be said for the Open Source outlook on life. GCJ isn&#8217;t one of them. It works quite like Java, except when you try and run anything. Unfortunately it works sufficiently like Java that you don&#8217;t necessarily know you&#8217;re using it, and it&#8217;s installed as the default on a lot of Debian machines.</p>
<pre>
keytool error: java.lang.IllegalStateException: masked envelope
</pre>
<p>That was the first cryptic clue that I was using GCJ. Other clues are random GC messages on the console. Here&#8217;s a quick way to tell if you&#8217;re infected:</p>
<pre>
$ ls -l /etc/alternatives/ | grep -c java-gcj
24
</pre>
<p>The number you&#8217;re looking for is &#8216;0&#8242; on a correctly configured system. Specifically you want to see:</p>
<pre>
$ chase `which keytool`
/usr/lib/jvm/java-1.5.0-sun-1.5.0.15/jre/bin/keytool
$ chase `which java`
/usr/lib/jvm/java-1.5.0-sun-1.5.0.15/jre/bin/java
</pre>
<p>If you&#8217;re not getting that, reconfigure the alternative:</p>
<pre>
# update-alternatives --config java

There are 7 alternatives which provide `java'.

  Selection    Alternative
-----------------------------------------------
          1    /etc/alternatives/kaffe-system/bin/java
          2    /usr/bin/gij-wrapper-4.0
*         3    /usr/lib/jvm/java-1.5.0-sun/jre/bin/java
          4    /usr/bin/gij-4.1
          5    /usr/bin/gij-4.3
 +        6    /usr/lib/jvm/java-gcj/jre/bin/java
          7    /usr/bin/gij-4.2
</pre>
<p><b>Step 2: Import the CA</b><br />
Now we&#8217;re running the right JVM, it should be a simple matter of:</p>
<pre>
$ #Create a trust store with a CA Cert in it (teststore.jks doesn't yet exist)
$ keytool -import -v -trustcacerts -alias myalias -file cacert.pem -keystore teststore.jks
Enter keystore password:
keytool error: java.lang.NullPointerException
</pre>
<p>Oh. There may be a way to use blank passwords on keystores, but keytool ain&#8217;t it. Let&#8217;s try again with a password:</p>
<pre>
$ keytool -import -v -trustcacerts -alias myalias -file cacert.pem -keystore teststore.jks
Enter keystore password: password
</pre>
<p>Smashing. That&#8217;ll mean we can at least connect to the remote host. But the SSL handshake will still fail when the host sees our lack of client certificate.</p>
<pre>
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
</pre>
<p><b>Step 3: Import the Client certificate</b><br />
My client certificate comes as two files - a certificate PEM file (the public part) and a key PEM file (the private part). Naïvely, I tried just installing the PEM part:</p>
<pre>
$ keytool -import -v -alias myalias2 -file signup1-cert.pem -keystore teststore.jks
Enter keystore password:  password
keytool error: java.lang.Exception: Input not an X.509 certificate
</pre>
<p>*sigh*. That&#8217;ll happen. Fortunately, we can convert from PEM to &#8216;DER&#8217;, which is something that keytool understands, using &#8216;openssl&#8217;:</p>
<pre>
$ openssl x509 -in signup1-cert.pem -inform PEM -out signup1-cert.der -outform DER
$ keytool -import -v -alias myalias2 -file signup1-cert.der -keystore teststore.jks
Enter keystore password:  password
Certificate was added to keystore
[Storing teststore.jks]
</pre>
<p>It&#8217;s stored, but unfortunately a) it doesn&#8217;t work and b) keytool thinks this is a &#8216;trustedCertEntry&#8217; rather than a &#8216;keyEntry&#8217;:</p>
<pre>
$ keytool -v -list -keystore teststore.jks
...
Entry type: trustedCertEntry
...
</pre>
<p>Now, we can use &#8216;openssl&#8217; to convert our certificate and key into a PKCS#12 combined key file: </p>
<pre>
$ openssl pkcs12 -export -in signup1-cert.pem -inkey signup1-key.pem -out signup1.p12
</pre>
<p>Even better, according to the <a href="http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#KeystoreFormats">documentation</a>, PKCS#12 format files are valid key stores&#8230; unless you try and use them:</p>
<pre>
default context init failed: java.io.IOException: Invalid keystore format
</pre>
<p>Right. Let&#8217;s try that as a combined PEM format file then:</p>
<pre>
$ openssl pkcs12 -in mykey.p12 -out keystore.pem -nodes
$ keytool -import -v -alias clientcert -file keystore.pem -keystore keystore.jks
Enter keystore password:  password
keytool error: java.lang.Exception: Input not an X.509 certificate
</pre>
<p>True. (Incidentally, that&#8217;s No DES, not &#8216;nodes&#8217;) But we can convert PEM files to DER files</p>
<pre>
$ openssl x509 -in keystore.pem -inform PEM -out keystore.der -outform DER
$ keytool -import -v -alias clientcert -file keystore.der -keystore keystore.jks
Enter keystore password:  password
</pre>
<p><b>Step 4: Using the keystore in your program</b><br />
You can configure the keystore at runtime as follows:</p>
<pre>
    System.setProperty("javax.net.ssl.keyStore", context.getRealPath(KEYSTORE));
    System.setProperty("javax.net.ssl.keyStorePassword", "password");
    System.setProperty("javax.net.ssl.trustStore", context.getRealPath(TRUSTSTORE));
    System.setProperty("javax.net.debug", "ssl");
    HttpClient httpClient = new HttpClient();
    GetMethod httpGet = new GetMethod("https://something.com");
    httpClient.executeMethod(httpGet);
    return new String(httpGet.getResponseBody());
</pre>
<p>javax.net.debug=ssl truly is a magic rune. I don&#8217;t know if you can get a list of such runes, but commit that one to memory. The debug output is pretty handy, if I little hard to follow.</p>
<p><b>Step 5: Become frustrated</b><br />
What I didn&#8217;t mention, and perhaps should have mentioned above, is that I still hadn&#8217;t managed to import my key as a keyEntry, so this code still didn&#8217;t work. I downloaded the source code to the JDK and tried single-stepping KeyTool, but that also didn&#8217;t help. [Aside: People who create compressed archives without a top-level folder should be shot].</p>
<p><b>Step 6: Use KeyMan</b><br />
KeyMan can be downloaded from IBM Alphaworks at time of writing:<br />
<a href="http://www.alphaworks.ibm.com/tech/keyman/download">http://www.alphaworks.ibm.com/tech/keyman/download</a><br />
It &#8216;just works&#8217;. It lets you import your certificate and create a valid key store. Thanks IBM! (Source code plz).</p>
]]></content:encoded>
			<wfw:commentRss>http://talkingcode.co.uk/2008/07/04/java-ssl-and-the-keystore-of-doom/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Coding style, Haskell</title>
		<link>http://talkingcode.co.uk/2008/06/30/coding-style-haskell/</link>
		<comments>http://talkingcode.co.uk/2008/06/30/coding-style-haskell/#comments</comments>
		<pubDate>Mon, 30 Jun 2008 06:02:48 +0000</pubDate>
		<dc:creator>codders</dc:creator>
		
		<category><![CDATA[haskell]]></category>

		<category><![CDATA[rant]]></category>

		<guid isPermaLink="false">http://talkingcode.co.uk/?p=41</guid>
		<description><![CDATA[I finished chapter five of the Haskell book I&#8217;m reading last night, and the bits of it are starting to make sense. I was doing some of the exercises and managing to write functions that compiled first time - I&#8217;m all about the small victories.
What I&#8217;m enjoying most about the book, though, is that as [...]]]></description>
			<content:encoded><![CDATA[<p>I finished chapter five of the Haskell book I&#8217;m reading last night, and the bits of it are starting to make sense. I was doing some of the exercises and managing to write functions that compiled first time - I&#8217;m all about the small victories.</p>
<p>What I&#8217;m enjoying most about the book, though, is that as well as teaching the language it does a good job of teaching some of the culture. A lot of writing good software is about making the most effective use of the tools a language provides and that usually only comes with time and experience. The book helps, though, providing gentle prods in the right direction:</p>
<blockquote><p>
Many tail recursive functions are better expressed using list manipulation functions like map, take, and filter. Without a doubt, it takes some practice to get used to using these. What we get in return for our initial investment in learning to use these functions is the ability to skim more easily over code that uses them.</p>
<p>The reason for this is simple. A tail recursive function definition has the same problem as a loop in an imperative language: it&#8217;s completely general, so we have to look at the exact details of every loop, and every tail recursive function, to see what it&#8217;s really doing. In contrast, map and most other list manipulation functions do only one thing; we can take for granted what these simple building blocks do, and focus on the idea the code is trying to express, not the minute details of how it&#8217;s manipulating its inputs.</p>
<p>In the middle ground between tail recursive functions (with complete generality) and our toolbox of list manipulation functions (each of which does one thing) lie the folds. A fold takes more effort to understand than, say, a composition of map and filter that does the same thing, but at the same time it behaves more regularly and predictably than a tail recursive function. As a general rule, don&#8217;t use a fold if you don&#8217;t need one, but think about using one instead of a tail recursive loop if you can.</p>
<p>As for anonymous functions, they tend to interrupt the “flow” of reading a piece of code. It is very often as easy to write a local function definition in a let or where clause, and use that, as it is to put an anonymous function into place. The relative advantages of a named function are twofold: we&#8217;re not confronted with the need to understand the function&#8217;s definition when we&#8217;re reading the code that uses it; and a well chosen function name acts as a tiny piece of local documentation.
</p></blockquote>
<p>&#8230; and they&#8217;ve not once suggested I write any comments yet. Woot <img src='http://talkingcode.co.uk/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>The Book:<br />
http://book.realworldhaskell.org/beta/</p>
<p>Chapter 5:<br />
http://book.realworldhaskell.org/beta/fp.html</p>
]]></content:encoded>
			<wfw:commentRss>http://talkingcode.co.uk/2008/06/30/coding-style-haskell/feed/</wfw:commentRss>
		</item>
		<item>
		<title>More Haskell fun</title>
		<link>http://talkingcode.co.uk/2008/06/28/more-haskell-fun/</link>
		<comments>http://talkingcode.co.uk/2008/06/28/more-haskell-fun/#comments</comments>
		<pubDate>Sat, 28 Jun 2008 08:38:13 +0000</pubDate>
		<dc:creator>codders</dc:creator>
		
		<category><![CDATA[code]]></category>

		<category><![CDATA[haskell]]></category>

		<guid isPermaLink="false">http://talkingcode.co.uk/?p=40</guid>
		<description><![CDATA[&#8220;Define a tree type that has only one constructor, like our Java example. Instead of the Empty constructor, use the Maybe type to refer to a node&#8217;s children.&#8221;
Fair enough. How bout this?

data MaybeTree a = MaybeNode (Maybe (a (MaybeTree a) (MaybeTree a)))

It&#8217;s a real type. I can even make real values in the type:

maybeTree = [...]]]></description>
			<content:encoded><![CDATA[<p>&#8220;<em>Define a tree type that has only one constructor, like our Java example. Instead of the Empty constructor, use the Maybe type to refer to a node&#8217;s children.</em>&#8221;</p>
<p>Fair enough. How bout this?</p>
<pre>
data MaybeTree a = MaybeNode (Maybe (a (MaybeTree a) (MaybeTree a)))
</pre>
<p>It&#8217;s a real type. I can even make real values in the type:</p>
<pre>
maybeTree = MaybeNode (Just ("fish",
             (MaybeNode (Just ("left",
                               (MaybeNode Nothing),
                               (MaybeNode Nothing)))),
             (MaybeNode (Just ("right",
                               (MaybeNode Nothing),
                               (MaybeNode Nothing))))))
</pre>
<p>Buuut I can&#8217;t print them. Because I don&#8217;t derive Show. If I try to derive Show:</p>
<pre>
    No instance for (Show (a (MaybeTree a) (MaybeTree a)))
      arising from the 'deriving' clause of a data type declaration
                   at working.hs:(51,0)-(52,30)
    Possible fix:
      add an instance declaration for
      (Show (a (MaybeTree a) (MaybeTree a)))
    When deriving the instance for (Show (MaybeTree a))
</pre>
<p>That&#8217;s fair enough. And GHC&#8217;s even provided me with a hint. So I just&#8230; err&#8230; instance Show something, right? Wrong <img src='http://talkingcode.co.uk/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> </p>
<p>Let&#8217;s write the show function for my tree type:</p>
<pre>
showTree (MaybeNode Nothing) = "empty"
showTree (MaybeNode (Just (a, b, c))) = "Node: " ++ (show a) ++
              ", Left: " ++ (showTree b) ++
              ", Right: " ++ (showTree c)
</pre>
<p>s&#8217;all good. But the type of that function?</p>
<pre>
showTree :: (Show t) => MaybeTree ((,,) t) -> [Char]
</pre>
<p>See that ((,,) t)? That&#8217;s the badness.</p>
<pre>
*Main> :kind (,,)
(,,) :: * -> * -> * -> *
</pre>
<p>Yeah. So it&#8217;s a tuple that has three type variables. Fun. Now I&#8217;m pretty sure that I ought to be able to define an instance of Show for my type, but I can&#8217;t for the life of me work out what the syntax is going to be</p>
<pre>
instance (Show a) => Show (MaybeTree ((,,) a)) where
       show t = showTree t

working.hs:58:0:
    Illegal instance declaration for `Show (MaybeTree ((,,) a))'
        (All instance types must be of the form (T a1 ... an)
         where a1 ... an are distinct type *variables*
         Use -XFlexibleInstances if you want to disable this.)
    In the instance declaration for `Show (MaybeTree ((,,) a))'
</pre>
<p>??? How about</p>
<pre>
instance (Show a) => Show (a, MaybeTree a, MaybeTree a) where
        show t = showTree t

working.hs:61:40:
    Kind mis-match
    Expected kind `* -> * -> *', but `a' has kind `*'
    In the type `MaybeTree a'
    In the type `(a, MaybeTree a, MaybeTree a)'
    In the type `(Show a) => Show (a, MaybeTree a, MaybeTree a)'
</pre>
<p>Any answers much appreciated, glorious lazyweb. I&#8217;m adding this to the list of exercises in the book that you can&#8217;t answer at the point you&#8217;ve reached in the book (this is chapter 4). Even after reading around about types and kinds and other peoples&#8217; use of <em>instance</em>, I&#8217;m clueless.</p>
<p>And changing my type to be something sane doesn&#8217;t count. If it&#8217;s not possible to <em>Show</em> my type, I&#8217;d like to know why <img src='http://talkingcode.co.uk/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><b>Update:</b><br />
After much discussion with <em>sffubs</em> and <em>sos</em>, it seems the only reasonable thing to do is to </p>
<pre>
{-# LANGUAGE FlexibleInstances #-}
instance (Show t) => Show (MaybeTree ((,,) t)) where
  show = showTree
</pre>
<p>We&#8217;re not quite sure what <a href="http://hackage.haskell.org/trac/haskell-prime/wiki/FlexibleInstances">Flexible Instances</a> are, but it seems that&#8217;s what&#8217;s needed to make this datatype work. The real answer is obviously not to use a crazy datatype:</p>
<pre>
data FooTree a = Maybe a ((FooTree a), (FooTree a)) deriving (Show)
</pre>
<p>Thanks both.</p>
]]></content:encoded>
			<wfw:commentRss>http://talkingcode.co.uk/2008/06/28/more-haskell-fun/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Getting started with Haskell&#8230; still</title>
		<link>http://talkingcode.co.uk/2008/06/27/getting-started-with-haskell-still/</link>
		<comments>http://talkingcode.co.uk/2008/06/27/getting-started-with-haskell-still/#comments</comments>
		<pubDate>Fri, 27 Jun 2008 06:46:47 +0000</pubDate>
		<dc:creator>codders</dc:creator>
		
		<category><![CDATA[code]]></category>

		<category><![CDATA[haskell]]></category>

		<guid isPermaLink="false">http://talkingcode.co.uk/?p=39</guid>
		<description><![CDATA[I can’t help but think there’s a bit of a gap in the market for introductory texts on Haskell. I say this in part because, at time of writing, if you google (hah! I’m using it as a verb! Trademark that!) “Getting Started Haskell”, you might end up here =/
I’d resolved to try getting started [...]]]></description>
			<content:encoded><![CDATA[<p>I can’t help but think there’s a bit of a gap in the market for introductory texts on Haskell. I say this in part because, at time of writing, if you google (hah! I’m using it as a verb! Trademark that!) “Getting Started Haskell”, you might end up here =/</p>
<p>I’d resolved to try getting started again on account of continuing to hear people rave about the language, so last night I did what I always do when learning something new - I googled “Getting Started X”. I found this awesome e-book / blog:</p>
<p><a href="http://book.realworldhaskell.org/beta/index.html">http://book.realworldhaskell.org/beta/index.html</a></p>
<p>It’s very well written (if a little rough round the edges - beta is the word), but I still think the learning curve presented is a _little_ steep for simpletons like myself. Bear with me while I expose my ignorance.</p>
<p>We’re using GHC. GHC is recommended by the book, it’s recommended by Don (who is indescribably leet: <a href="http://cgi.cse.unsw.edu.au/~dons/blog/">http://cgi.cse.unsw.edu.au/~dons/blog/</a>), and it’s recommended by my n-sim colleagues (who mostly are, except for me: <a href="http://www.n-sim.com">http://www.n-sim.com</a>).</p>
<pre>
# apt-get install ghc6
# ghci
GHCi, version 6.8.2: http://www.haskell.org/ghc/  : ? for help
Loading package base ... linking ... done.
Prelude>
</pre>
<p>aaah. Prelude. Don’t I feel at home. In fact I don’t - this is all pretty weird, but working through the first couple of chapters of the book was fun. Walk with me a while…</p>
<p><b>Type Porn</b><br />
If types don’t excite you, this probably isn’t the language for you. But they should; they’re awesome.</p>
<pre>
Prelude> :set +t
Prelude> 1337
1337
it :: Integer
</pre>
<p>In GHCI (interactive GHC interpreter), setting “+t” makes the interpreter print the type of whatever you’ve just evaluated. Technically, it prints the type of “it” - the special value in to which your last evaluated expression is loaded (there is no spoon, there are no variables). I know what “1337″ is, I know what “it” is, but what’s “Integer”?</p>
<pre>
Prelude> :info Integer
data Integer
  = GHC.Num.S# GHC.Prim.Int#
  | GHC.Num.J# GHC.Prim.Int# GHC.Prim.ByteArray#
        -- Defined in GHC.Num
instance Enum Integer -- Defined in GHC.Num
instance Eq Integer -- Defined in GHC.Num
instance Integral Integer -- Defined in GHC.Real
instance Num Integer -- Defined in GHC.Num
instance Ord Integer -- Defined in GHC.Num
instance Read Integer -- Defined in GHC.Read
instance Real Integer -- Defined in GHC.Real
instance Show Integer -- Defined in GHC.Num
</pre>
<p>ooo… fancy. What does that all mean? Well, I&#8217;m only on chapter 3, but in my simplistic Object Oriented view of the world, we&#8217;re effectively saying that Integer implements the interfaces Enum, Eq, Integral, Num, Org, Read, Real and Show (but the truth is a little more involved).</p>
<pre>
Prelude> :info Enum
class Enum a where
  succ :: a -> a
  pred :: a -> a
  toEnum :: Int -> a
  fromEnum :: a -> Int
  enumFrom :: a -> [a]
  enumFromThen :: a -> a -> [a]
  enumFromTo :: a -> a -> [a]
  enumFromThenTo :: a -> a -> a -> [a]
        &#8212; Defined in GHC.Enum
instance Enum Integer &#8212; Defined in GHC.Num
instance Enum Float &#8212; Defined in GHC.Float
instance Enum Double &#8212; Defined in GHC.Float
instance Enum Bool &#8212; Defined in GHC.Enum
instance Enum Ordering &#8212; Defined in GHC.Enum
instance Enum Char &#8212; Defined in GHC.Enum
instance Enum () &#8212; Defined in GHC.Enum
instance Enum Int &#8212; Defined in GHC.Enum
</pre>
<p>You kind of have to be comfortable with looking at types of the form:</p>
<pre>
a -> a -> a -> [a]
</pre>
<p>&#8220;enumFromThenTo&#8221; obviously takes three values and returns a list of values. (The joy of types, right? You know what it does by what its type is.) Moreover, we can see that it&#8217;s defined for the instances Integer, Float, Double, Bool, Ordering, Char, () and Int.</p>
<pre>
Prelude> enumFromThenTo 1 2 8
[1,2,3,4,5,6,7,8]
Prelude> enumFromThenTo () () ()
[(),(),(),(),(),()^CInterrupted.
</pre>
<p>and we can type functions too:</p>
<pre>
Prelude> :type fst
fst :: (a, b) -> a
</pre>
<p>What does that one do? There's only one thing it can do! Yes, I know, that's practically pornographic.</p>
<p><b>The exercise</b><br />
<em>"Write a function lastButOne, that returns the element before the last."</em></p>
<p>Trivial, right? A five year old could do it. Well, excuse me while I have a quick flashback to ML ticks (<a href="http://www.cl.cam.ac.uk/teaching/1998/FoundsCS/ticks.pdf">PDF</a>) and rock gently back and forth in the corner. You have to bear in mind that, at this point in the book, we don't know there's a 'length' function in Prelude, we've not been taught pattern matching or case statements, and we're still simplistically minded imperative programmers. So naïvely, the best we might be able to do is:</p>
<pre>
-- in add.hs
count n [] = n
count n xs = count (n+1) (drop 1 xs)

myLastButOne xs = head (drop ((count 0 xs) - 2) xs)

Prelude> :load add.hs
[1 of 1] Compiling Main             ( add.hs, interpreted )
Ok, modules loaded: Main.
*Main> myLastButOne [1,2..10]
9
</pre>
<p>Repeat after me&#8230; &#8220;ewww&#8221;. And even to do that, I&#8217;ve had to use mysterious pattern matching which hasn&#8217;t been explained at that point in the book. Now, we could assume that a resourceful reader might find the &#8216;length&#8217; function:</p>
<pre>
myLastButOne xs = head (drop ((length xs) - 2) xs)
</pre>
<p>But that&#8217;s still pretty unsatisfactory. For all I know, <em>length</em> is O(n) in the length of the list, so I&#8217;ll be going down the list twice. I daren&#8217;t imagine what Don would say. Even if it&#8217;s O(1), it doesn&#8217;t feel right. After a bit of head scratching and syntax guessing, I came to:</p>
<pre>
lastButOne (h:t) = case t of
                       (a:[]) -> h
                       (a:b) -> lastButOne t
</pre>
<p>which, for me at least, feels a little better. But I don&#8217;t know it&#8217;s right. I&#8217;m welcoming any pointers here. Now obviously for the <em>&#8220;Find the last but nth item&#8221;</em>, going down the list twice is looking less unattractive:</p>
<pre>
myLastButN n xs = head (drop ((length xs) - (n+1)) xs)
</pre>
<p>It&#8217;s still not great though. Would that I could <em>list[-n]</em>. But that&#8217;s not the point.</p>
<p><b>Summary</b><br />
I&#8217;m determined to learn more Haskell and continue to expose my ignorance on this blog. Any pointers to good docs are welcome - &#8220;Haskell for simpletons&#8221;, that sort of thing. Meantimes I&#8217;ll continue to read the book. My stretch goal is to understand the things written on Don&#8217;s blog and on the following:</p>
<p>Conal Elliott:<br />
<a href="http://conal.net/blog/">http://conal.net/blog/</a></p>
<p>Kenn Knowles:<br />
<a href="http://www.kennknowles.com/blog/">http://www.kennknowles.com/blog/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://talkingcode.co.uk/2008/06/27/getting-started-with-haskell-still/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Removing bytes from a file</title>
		<link>http://talkingcode.co.uk/2008/06/25/removing-bytes-from-a-file/</link>
		<comments>http://talkingcode.co.uk/2008/06/25/removing-bytes-from-a-file/#comments</comments>
		<pubDate>Wed, 25 Jun 2008 09:45:29 +0000</pubDate>
		<dc:creator>codders</dc:creator>
		
		<category><![CDATA[c]]></category>

		<category><![CDATA[code]]></category>

		<guid isPermaLink="false">http://talkingcode.co.uk/?p=37</guid>
		<description><![CDATA[Morning,
I copied and pasted a (Ruby) script from a PDF this morning, and on executing it I got a whole pile of:

webservice.rb:33: Invalid char `\240' in expression
webservice.rb:33: Invalid char `\302' in expression

which was annoying. For reasons best known to KPDF (or oowriter, or my window manager&#8217;s cut-and-paste buffer), the spaces in the script (&#8221; &#8220;) [...]]]></description>
			<content:encoded><![CDATA[<p>Morning,</p>
<p>I copied and pasted a (Ruby) script from a PDF this morning, and on executing it I got a whole pile of:</p>
<pre>
webservice.rb:33: Invalid char `\240' in expression
webservice.rb:33: Invalid char `\302' in expression
</pre>
<p>which was annoying. For reasons best known to KPDF (or oowriter, or my window manager&#8217;s cut-and-paste buffer), the spaces in the script (&#8221; &#8220;) had been encoded as 0xc2 0xa0, which is sort of UTF16 if you look at it sideways, but essentially useless to me.</p>
<p>So how do you remove 200 instances of a 2-byte sequence from a file? I didn&#8217;t have a good way, but this bad way sufficed:</p>
<pre>
cat &gt; rm.c &lt;&lt; EOF
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;

int main(int arcg, char *argv[])
{
  unsigned char c;

  while (read(0, &#038;c, 1)==1)
  {
    if (c != 0xc2 &#038;&#038; c != 0xa0)
    {
      write(1, &#038;c, 1);
    }
    else if (c == 0xc2)
    {
      write(1, &#8221; &#8220;, 1);
    }
  }
}
EOF
make rm
cat webservice.rb | ./rm > output.rb
</pre>
<p>So, my dearest lazyweb&#8230; better answers?</p>
]]></content:encoded>
			<wfw:commentRss>http://talkingcode.co.uk/2008/06/25/removing-bytes-from-a-file/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Awesome D-Bus</title>
		<link>http://talkingcode.co.uk/2008/06/10/awesome-d-bus/</link>
		<comments>http://talkingcode.co.uk/2008/06/10/awesome-d-bus/#comments</comments>
		<pubDate>Tue, 10 Jun 2008 18:50:02 +0000</pubDate>
		<dc:creator>codders</dc:creator>
		
		<category><![CDATA[code]]></category>

		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://talkingcode.co.uk/2008/06/10/awesome-d-bus/</guid>
		<description><![CDATA[I&#8217;ve been using a new window manager - Awesome WM. It&#8217;s pretty fine. At version 2.3, it doesn&#8217;t currently support window tabbing in the way Ion does, but I&#8217;m assured that that feature is on its way. Everything else works pretty swishly, and the desktop tagging features are particularly nice.
It doesn&#8217;t come with a system [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using a new window manager - Awesome WM. It&#8217;s pretty fine. At version 2.3, it doesn&#8217;t currently support window tabbing in the way Ion does, but I&#8217;m assured that that feature is on its way. Everything else works pretty swishly, and the desktop tagging features are particularly nice.</p>
<p>It doesn&#8217;t come with a system tray out of the box, so I&#8217;d managed to miss some incoming instant messages. Fortunately you can write your own widgets for Awesome - you just pipe your widget updates into &#8216;awesome-client&#8217;.</p>
<p>So all I needed was a way to get the new message notification out of Pidgin&#8230;</p>
<pre>
#!/usr/bin/env python

from BeautifulSoup import BeautifulSoup
import os
import dbus.glib
import gobject
import sys

class CheckedObject:
    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, attr):
        return CheckedAttribute(self, attr)

class CheckedAttribute:
    def __init__(self, cobj, attr):
        self.cobj = cobj
        self.attr = attr

    def __call__(self, *args):
        result = self.cobj.obj.__getattr__(self.attr)(*args)
        if result == 0:
            raise "Error: " + self.attr + " " +
               str(args) + " returned " +
               str(result)
        return result

def awesome_write(string):
    awesome = os.popen("awesome-client", "w")
    widget_message = "0 widget_tell widgetbar im text %s\n" % string
    awesome.write(widget_message)
    awesome.close()

def message_received(account, sender, message, conversation, flags):
    html = BeautifulSoup(message)
    try:
      message = html.font.font.string
    except Exception, e:
      pass
    awesome_write("%s &lt;%s&gt;" % (message, sender))

def message_sent(account, receiver, message):
    awesome_write("")

bus = dbus.SessionBus()

obj = None
try:
    obj = bus.get_object(
        "im.pidgin.purple.PurpleService",
        "/im/pidgin/purple/PurpleObject")
except:
    print "Couldn't find Pidgin on the Bus"
    sys.exit(1)

purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")

cpurple = CheckedObject(purple)

bus.add_signal_receiver(message_received, dbus_interface="im.pidgin.purple.PurpleInterface", signal_name="ReceivedImMsg")
bus.add_signal_receiver(message_sent, dbus_interface="im.pidgin.purple.PurpleInterface", signal_name="SentImMsg")

gobject.MainLoop().run()
</pre>
<p>D-Bus really seems to be coming along quite nicely. dbus-inspector shows that there are a bunch of applications enabled for it (including Pidgin and XChat), and the language support seems to be fairly polished. Can&#8217;t wait to see what else ends up on the bus.</p>
<p>Ars run-through (with code):<br />
<a href="http://arstechnica.com/reviews/apps/pidgin-2-0.ars/4">http://arstechnica.com/reviews/apps/pidgin-2-0.ars/4</a></p>
<p>Pidgin list of conversation signals:<br />
<a href="http://developer.pidgin.im/doxygen/dev/html/conversation-signals.html#sent-im-msg">http://developer.pidgin.im/doxygen/dev/html/conversation-signals.html#sent-im-msg</a></p>
<p>D-Bus Inspector:<br />
<a href="http://www.vitavonni.de/projekte/dbus-inspector.html.en">http://www.vitavonni.de/projekte/dbus-inspector.html.en</a></p>
<p>Awesome WM:<br />
<a href="http://awesome.naquadah.org/">http://awesome.naquadah.org/</a></p>
<p>Ion WM:<br />
<a href="http://modeemi.fi/~tuomov/ion/">http://modeemi.fi/~tuomov/ion/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://talkingcode.co.uk/2008/06/10/awesome-d-bus/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Normalising MP3s</title>
		<link>http://talkingcode.co.uk/2008/06/08/normalising-mp3s/</link>
		<comments>http://talkingcode.co.uk/2008/06/08/normalising-mp3s/#comments</comments>
		<pubDate>Sun, 08 Jun 2008 12:09:07 +0000</pubDate>
		<dc:creator>codders</dc:creator>
		
		<category><![CDATA[debian]]></category>

		<guid isPermaLink="false">http://talkingcode.co.uk/2008/06/08/normalising-mp3s/</guid>
		<description><![CDATA[I&#8217;m changing the way I blog, and possibly starting to do it again. But I digress&#8230;
The OpenRightsGroup blog linked a recording of an interesting talk with Jonathan Zittrain (whose new book is getting some press and whose e-book PDF is available for free download), but the recording was a bit quiet and I wanted to [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m changing the way I blog, and possibly starting to do it again. But I digress&#8230;</p>
<p>The OpenRightsGroup blog linked a recording of an interesting talk with Jonathan Zittrain (whose new book is getting some press and whose e-book PDF is available for free download), but the recording was a bit quiet and I wanted to listen to it while cooking my lunch&#8230;</p>
<blockquote><p>
# sudo apt-get install mp3gain<br />
# mp3gain /tmp/org.mp3</p>
<p>/tmp/org.mp3<br />
Recommended &#8220;Track&#8221; dB change: 25.760000<br />
Recommended &#8220;Track&#8221; mp3 gain change: 17<br />
WARNING: some clipping may occur with this gain change!<br />
Max PCM sample at current gain: 21450.428803<br />
Max mp3 global gain field: 190<br />
Min mp3 global gain field: 129</p>
<p>Recommended &#8220;Album&#8221; dB change for all files: 25.760000<br />
Recommended &#8220;Album&#8221; mp3 gain change for all files: 17<br />
WARNING: with this global gain change, some clipping may occur in file /tmp/org.mp3</p>
<p># mp3gain -g 17 /tmp/org.mp3<br />
Applying gain change of 17 to /tmp/org.mp3&#8230;</p>
<p>done
</p></blockquote>
<p>&#8230;which was nice.</p>
<p>Talk:<br />
<a href="http://www.openrightsgroup.org/2008/06/06/the-future-of-the-internet-in-focus/">http://www.openrightsgroup.org/2008/06/06/the-future-of-the-internet-in-focus/</a></p>
<p>Book:<br />
<a href="http://futureoftheinternet.org/">http://futureoftheinternet.org/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://talkingcode.co.uk/2008/06/08/normalising-mp3s/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Buzzword Bingo - Tomcat, Jetty, Cactus, Derby, Velocity, Maven</title>
		<link>http://talkingcode.co.uk/2008/01/23/buzzword-bingo-tomcat-jetty-cactus-derby-velocity-maven/</link>
		<comments>http://talkingcode.co.uk/2008/01/23/buzzword-bingo-tomcat-jetty-cactus-derby-velocity-maven/#comments</comments>
		<pubDate>Wed, 23 Jan 2008 21:16:04 +0000</pubDate>
		<dc:creator>codders</dc:creator>
		
		<category><![CDATA[code]]></category>

		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://talkingcode.co.uk/2008/01/23/buzzword-bingo-tomcat-jetty-cactus-derby-velocity-maven/</guid>
		<description><![CDATA[I&#8217;ve been writing a webapp at work recently. Because I&#8217;m writing it in Java, the scope for me to post interesting articles about what I&#8217;m doing has been pretty limited - I don&#8217;t know that much about enterprisey Java, and I spend most of my time bashing my head against a Java-shaped wall. A quick [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been writing a <a href="http://en.wikipedia.org/wiki/Web_application" rel="nofollow">webapp</a> at work recently. Because I&#8217;m writing it in Java, the scope for me to post interesting articles about what I&#8217;m doing has been pretty limited - I don&#8217;t know that much about enterprisey Java, and I spend most of my time bashing my head against a Java-shaped wall. A quick overview is probably worth doing though.</p>
<p><b>Apache</b><br />
If you&#8217;ve not heard of the <a href="http://www.apache.org/" rel="nofollow">Apache Foundation</a> (outside the context of their fine <a href="http://httpd.apache.org/" rel="nofollow">webserver</a>), go visit their site now. Amongst other things, Apache are creating an incredible resource on that site in the form of a huge code commons. If you&#8217;re not sure what a commons is, a) shame on you and b) read <a href="http://www.the-future-of-ideas.com/" rel="nofollow">this fine book</a> (in fact, read it even if you are sure). The majority of the code on the Apache site is Java, so if you&#8217;re developing an application in Java it&#8217;s well worth checking the links on the left-hand side of the main page to see if they&#8217;ve already written what you&#8217;re writing, or something that will help you. The code is all <a href="http://www.apache.org/licenses/LICENSE-2.0" rel="nofollow">Apache-licensed</a> - a <a href="http://www.opensource.org/licenses/bsd-license.php" rel="nofollow">BSD-style</a> license that is amenable to reuse in commercial projects as well as Free Software projects. It&#8217;s also very high quality code. You basically can&#8217;t lose.</p>
<p><b>strace is your friend</b><br />
One of the biggest irritations, I&#8217;ve found, in using the Apache Java projects (and this is more of a function of Java than Apache) is trying to make Java find the appropriate config files. It&#8217;s pretty difficult to tell which config files Java is seeing, if any. You can download the source to the component you&#8217;re using and single step it in Eclipse, but this tends to get tedious at about the point you hit the <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ClassLoader.html" rel="nofollow">class loader</a>, which is exactly the point at which it&#8217;ll do any resource location. What you can do, though, is:</p>
<pre>
strace -f -p[YOUR_PID] 2&gt;&amp;1 | grep &#8220;your_config_file.xml&#8221;
</pre>
<p>You&#8217;re looking for things like calls to &#8217;stat&#8217; or results of &#8216;ENOENT&#8217;. This will generally tell you what Java&#8217;s looking for and where. That is, I grant you, a sledgehammer-nut solution, but I&#8217;ve found it quicker than anything else. If you know a better way to work out where I should be putting my Velocity toolbox.xml in my Maven tree for the Webapp to run in Jetty under Cactus please let me know. It&#8217;s not in the FAQ.</p>
<p><b>My environment</b><br />
What am I doing with all these projects?</p>
<ul>
<li><a href="http://maven.apache.org/" rel="nofollow">Maven</a> - Your lifecycle management tool (build and dependency management). Maven2 is much improved over Maven for having the package repositories work 99% of the time rather than the 50% that was more common in the original. The whole <a href="http://maven.apache.org/guides/introduction/introduction-to-the-pom.html" rel="nofollow">POM</a> thing is&#8230; errr&#8230; a little obtuse, I grant you, but you can use Maven in a dumb way without too much trouble. The <a href="http://maven.apache.org/eclipse-plugin.html" rel="nofollow">Eclipse plugin</a> is a great way to find the packages you need too.</li>
<li><a href="http://tomcat.apache.org/" rel="nofollow">Tomcat</a> - The application server. Can&#8217;t really do a Webapp without one of those. Tomcat isn&#8217;t the only server out there, but it&#8217;s pretty well used and, as at 5.5-ish, not too difficult to make go.</li>
<li><a href="http://velocity.apache.org/" rel="nofollow">Velocity</a> - The templating engine. The web is awash with webapp &#8216;frameworks&#8217;; Apache have about four of them for starters. Sometimes, though, you&#8217;re not writing for web browsers. Sometimes, you just want a way to turn your <a href="http://en.wikipedia.org/wiki/Plain_Old_Java_Object" rel="nofollow">POJOs</a> into arbitrary <a href="http://en.wikipedia.org/wiki/Markup_language" rel="nofollow">markup</a>. Velocity is fast, uncomplicated and fully featured.</li>
<li><a href="http://jakarta.apache.org/cactus/" rel="nofollow">Cactus</a> - The Servlet test framework. I&#8217;ve still not completely wrapped my head around Cactus, but basically for each of your unit tests you have <em>setUp</em> and <em>tearDown</em> to manipulate state on the server, and <em>begin</em> and <em>end</em> to manipulate state on the client, and Cactus will run web requests inside a test harness for you. Trés handy.</li>
<li><a href="http://www.mortbay.org/" rel="nofollow">Jetty</a> - A lightweight servlet container. Controversially not an Apache project, Jetty is really quite handy for running your Cactus tests. Instead of pushing the <a href="http://en.wikipedia.org/wiki/WAR_%28file_format%29" rel="nofollow">WAR</a> all the way to Tomcat, you can new up a Jetty server inside the Maven test task and run your functional tests there.</li>
<li><a href="http://db.apache.org/derby/" rel="nofollow">Derby</a> - The lightweight database. To avoid having to have a real database available in order to run your unit tests, I find it convenient to put some test fixtures in a Derby DB and run the servlet off the back of that. This plays really nicely with the Cactus / Jetty setup and has the added advantage that (unlike MySQL) if you try and create a <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/sql/PreparedStatement.html" rel="nofollow">prepared statement</a> that your schema can&#8217;t possibly run, Derby will warn you about that at preparation time rather than execution time. With a bit of tweaking, then, you can statically check your statements against the schema.</li>
</ul>
<p>Making all that play together has been nightmarish, either because of my relative inexperience or because it&#8217;s genuinely difficult. I&#8217;ve embarrassingly failed to write down all the errors I encountered and how to fix them, but I may cover some of the more tricky parts of the setup in future articles. For all the setup work, though, being able to type <em>mvn install</em> and feel confident that your latest refactoring hasn&#8217;t broken the complex application you&#8217;ve written is worth almost any amount of blood, sweat and tears.</p>
]]></content:encoded>
			<wfw:commentRss>http://talkingcode.co.uk/2008/01/23/buzzword-bingo-tomcat-jetty-cactus-derby-velocity-maven/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Simple webservice client, Ruby</title>
		<link>http://talkingcode.co.uk/2008/01/14/simple-webservice-client-ruby/</link>
		<comments>http://talkingcode.co.uk/2008/01/14/simple-webservice-client-ruby/#comments</comments>
		<pubDate>Mon, 14 Jan 2008 21:44:27 +0000</pubDate>
		<dc:creator>codders</dc:creator>
		
		<category><![CDATA[code]]></category>

		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://talkingcode.co.uk/2008/01/14/simple-webservice-client-ruby/</guid>
		<description><![CDATA[Haven&#8217;t really got anything useful to write about, so here&#8217;s a simple bit of code to make XML requests to a webservice. It&#8217;s useful for me as a reference because it covers things I want to do fairly regularly - MD5-summing, Base64 encoding, fetching a page over HTTP and parsing and dumping an XML document.
For [...]]]></description>
			<content:encoded><![CDATA[<p>Haven&#8217;t really got anything useful to write about, so here&#8217;s a simple bit of code to make XML requests to a webservice. It&#8217;s useful for me as a reference because it covers things I want to do fairly regularly - MD5-summing, Base64 encoding, fetching a page over HTTP and parsing and dumping an XML document.</p>
<p>For the sake of a complete example, the service we&#8217;re looking at here is a relatively <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a>ful directory service, exposing nested resources by extending the request URL:</p>
<pre>
# Root of service
http://some.service.com/api_root/

# List of locations
http://some.service.com/api_root/locations

# List of categories for location ID 4
http://some.service.com/api_root/categories/location/4
</pre>
<p>Requests can also have query arguments appended to specify, for example, numbers of results to return and sort order. Additionally, an authentication token and username are sent as query parameters, so that a complete request might look like:</p>
<pre>
http://some.service.com/api_root/categories/location/4?
    count=20&#038;sort=name&#038;uid=someuser&#038;hash=5ju5eVirhXRqjdobToZiGA%3D%3D
</pre>
<p>The code, then, for our simple client is:</p>
<pre>
#!/usr/bin/ruby

require 'digest/md5'
require 'base64'
require 'cgi'
require 'net/http'
require 'uri'
require 'rexml/document'
require 'rexml/xpath'

BASE="http://some.service.com/api_root/"
UID="username"
PASS="suitable_password"

# Generates a valid authentication token based on 'PASS' and the
# current timestamp
def token
  plaintext = Time.now().to_i.to_s + '.' + PASS
  md5 = Digest::MD5.digest(plaintext)
  return Base64.encode64(md5).strip
end

# Returns a valid service URL, including authentication tokens
def url_for(method, args, queryargs = Hash.new)
  queryargs['uid'] = UID
  queryargs['hash'] = token
  escaped_query_parts = queryargs.collect do |entry|
    entry.collect { |e| CGI.escape(e) }.join(&#8221;=&#8221;)
  end
  escaped_args = args.unshift(method).collect { |a| CGI.escape(a) }
  path = escaped_args.join(&#8221;/&#8221;) + &#8220;?&#8221; + escaped_query_parts.join(&#8217;&#038;')
  return BASE + path
end

# Fetches an XML document from the supplied URL
def fetch_xml(url)
  xml_string = Net::HTTP.get(URI.parse(url))
  if !xml_string
    puts &#8220;Request failed&#8221;
    exit
  end
  doc = REXML::Document.new xml_string
end

# Dumps out the &#8216;name&#8217; and &#8216;url&#8217; attributes for a nodelist
def dump_name_attributes(doc, path)
  REXML::XPath.each(doc, path) do |node|
    puts attribute_value(node, &#8216;@name&#8217;) +&#8221; (&#8221;+ attribute_value(node, &#8216;@url&#8217;) +&#8221;)&#8221;
  end
end

# Fetches the value of the attribute with the supplied name, or nil
def attribute_value(node, path)
  attribute = REXML::XPath.first(node, path)
  if !attribute
    return nil
  end
  return attribute.value
end
</pre>
<p>&#8230; and we might make a request as follows:</p>
<pre>
puts "Category List:"
xml = fetch_xml(url_for("categories", ["location","4"],
               { &#8220;count&#8221; => &#8220;20&#8243;,
                  &#8220;sort&#8221; => &#8220;name&#8221; }
        ))
dump_name_attributes(xml, &#8216;xmlservice/categories/category&#8217;)
</pre>
<p>assuming that the returned XML looks a little like this:</p>
<pre>
&lt;xmlservice&gt;
  &lt;categories&gt;
    &lt;category name="Food" url="/api_root/category/food"/&gt;
    &lt;category name="Drink" url="/api_root/category/drink"/&gt;
    &lt;category name="Art" url="/api_root/category/art"/&gt;
  &lt;/categories&gt;
&lt;/xmlservice&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://talkingcode.co.uk/2008/01/14/simple-webservice-client-ruby/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
