<?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>My Diversions</title>
	<atom:link href="http://diversions.nfshost.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://diversions.nfshost.com/blog</link>
	<description>Notes on things I'm thinking and doing</description>
	<pubDate>Sun, 03 Aug 2008 10:28:16 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>Laptop design stupidity</title>
		<link>http://diversions.nfshost.com/blog/2008/08/03/laptop-design-stupidity/</link>
		<comments>http://diversions.nfshost.com/blog/2008/08/03/laptop-design-stupidity/#comments</comments>
		<pubDate>Sun, 03 Aug 2008 10:28:16 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
		
		<category><![CDATA[Computer Science]]></category>

		<category><![CDATA[General Interest]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/?p=47</guid>
		<description><![CDATA[A relative of mine has a recent HP Pavillion laptop. (I suggested that she get a Mac, but she was concerned about MS Office compatibility).

I was doing some telephone support trying to reattach it to her wireless network tonight. I was ultimately unsuccessful, but I did learn two reasons why HP laptops suck.


HP has their [...]]]></description>
			<content:encoded><![CDATA[<p>A relative of mine has a recent HP Pavillion laptop. (I suggested that she get a Mac, but she was concerned about MS Office compatibility).</p>

<p>I was doing some telephone support trying to reattach it to her wireless network tonight. I was ultimately unsuccessful, but I did learn two reasons why HP laptops suck.</p>

<ol>
<li>HP has their own &#8216;wireless assistant&#8217; wizard, with a plethora of confusing options, so even my limited knowledge of Windows network configuration was useless.</li>
<li>The laptop has a wireless on/off switch on its front. This switch was in the off position, but the software couldn&#8217;t tell that. All it could say was &#8216;please check the network switch&#8217; &#8212; and it didn&#8217;t show a picture giving the switch&#8217;s location. I had to Google and then describe the location over the phone. It&#8217;s a hardware switch when it should be a software switch, and to add insult to injury, its state isn&#8217;t even visible to the software!</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://diversions.nfshost.com/blog/2008/08/03/laptop-design-stupidity/feed/</wfw:commentRss>
		</item>
		<item>
		<title>I am on the front page of cuil!</title>
		<link>http://diversions.nfshost.com/blog/2008/07/29/i-am-on-the-front-page-of-cuil/</link>
		<comments>http://diversions.nfshost.com/blog/2008/07/29/i-am-on-the-front-page-of-cuil/#comments</comments>
		<pubDate>Tue, 29 Jul 2008 04:35:13 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/2008/07/29/i-am-on-the-front-page-of-cuil/</guid>
		<description><![CDATA[Well at least my picture is:



Perhaps the Sudbury, Ontario municipal sculptor will use that photo as a reference when they erect a statue honoring Tom Davies&#8230;
]]></description>
			<content:encoded><![CDATA[<p>Well at least my picture is:</p>

<p><img src="http://diversions.nfshost.com/skitch/tom_davies_-_Cuil-20080729-115008.jpg" /></p>

<p>Perhaps the Sudbury, Ontario municipal sculptor will use that photo as a reference when they erect a statue honoring Tom Davies&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://diversions.nfshost.com/blog/2008/07/29/i-am-on-the-front-page-of-cuil/feed/</wfw:commentRss>
		</item>
		<item>
		<title>How to increase your Ycombinator Karma without really trying</title>
		<link>http://diversions.nfshost.com/blog/2008/07/28/how-to-increase-your-ycombinator-karma-without-really-trying/</link>
		<comments>http://diversions.nfshost.com/blog/2008/07/28/how-to-increase-your-ycombinator-karma-without-really-trying/#comments</comments>
		<pubDate>Mon, 28 Jul 2008 11:06:59 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
		
		<category><![CDATA[General Interest]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/?p=45</guid>
		<description><![CDATA[
]]></description>
			<content:encoded><![CDATA[<p><img src="http://diversions.nfshost.com/skitch/Hacker_News_|_The_Hydrogen_Hoax-20080728-211502.jpg"/></p>
]]></content:encoded>
			<wfw:commentRss>http://diversions.nfshost.com/blog/2008/07/28/how-to-increase-your-ycombinator-karma-without-really-trying/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A New Blog</title>
		<link>http://diversions.nfshost.com/blog/2008/07/26/a-new-blog/</link>
		<comments>http://diversions.nfshost.com/blog/2008/07/26/a-new-blog/#comments</comments>
		<pubDate>Sat, 26 Jul 2008 06:17:08 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/?p=44</guid>
		<description><![CDATA[I&#8217;ve recently found myself not blogging because I didn&#8217;t wish to inflict the posts on Planet Atlassian. So now anything non-technical which I don&#8217;t think is of interest to subscribers to this blog (Hi to both of you!) appears here.
]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently found myself not blogging because I didn&#8217;t wish to inflict the posts on <a href="http://planet.atlassian.com/">Planet Atlassian</a>. So now anything non-technical which I don&#8217;t think is of interest to subscribers to this blog (Hi to both of you!) appears <a href="http://diversions.nfshost.com/blog2/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://diversions.nfshost.com/blog/2008/07/26/a-new-blog/feed/</wfw:commentRss>
		</item>
		<item>
		<title>ICFP2008 Programming Contest</title>
		<link>http://diversions.nfshost.com/blog/2008/07/16/icfp2008-programming-contest/</link>
		<comments>http://diversions.nfshost.com/blog/2008/07/16/icfp2008-programming-contest/#comments</comments>
		<pubDate>Wed, 16 Jul 2008 05:31:39 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
		
		<category><![CDATA[Computer Science]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/?p=43</guid>
		<description><![CDATA[Along with some colleagues I entered the ICFP programming contest this year.

You can read some more about our experience at Matt&#8217;s blog.

I thought the problem &#8212; guiding a Mars rover to a goal amongst obstacles &#8212; was very well chosen. It was possible to navigate the example maps with very simple software, so everyone could [...]]]></description>
			<content:encoded><![CDATA[<p>Along with some colleagues I entered the <a href="http://icfpcontest.org/">ICFP programming contest</a> this year.</p>

<p>You can read some more about our experience at <a href="http://www.mattryall.net/blog/2008/07/icfp-programming-contest-2008">Matt&#8217;s blog</a>.</p>

<p>I thought the problem &#8212; guiding a Mars rover to a goal amongst obstacles &#8212; was very well chosen. It was possible to navigate the example maps with very simple software, so everyone could get the satisfaction of seeing their rover succeed. If you had the time and skills, there were a vast number of directions to go in to improve your rover&#8217;s performance. This compares favourably with last year&#8217;s problem. <a href="http://save-endo.cs.uu.nl/">That problem</a> was very clever, and I had a lot of fun playing with it, but I never got close to having a worthwhile submission because the threshold for even partial success was quite high. So kudos to the ICFP2008 team for creating a problem which has a low barrier to entry while still having the &#8216;dynamic range&#8217; needed to challenge the top teams.</p>

<p>I&#8217;ll definitely participate next year. Among the lessons we learnt:</p>

<ul>
<li>Have all the team on the same premises, especially for the first few hours. When you are writing software this quickly you need to all be on the same page all the time.</li>
<li>For developing geometry based heuristics visualisation is very important. You need to be able to see what your code is trying to do &#8212; where it is trying to go, what it thinks is blocking it, when it starts to turn and so on.</li>
</ul>

<p>We wrote our entry in Java, but over the next few weeks I plan to produce something just as sophisticated in <a href="http://openquark.org">CAL</a>. It is a <em>functional</em> programming contest after all <img src='http://diversions.nfshost.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://diversions.nfshost.com/blog/2008/07/16/icfp2008-programming-contest/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Take Two</title>
		<link>http://diversions.nfshost.com/blog/2008/07/09/take-two/</link>
		<comments>http://diversions.nfshost.com/blog/2008/07/09/take-two/#comments</comments>
		<pubDate>Wed, 09 Jul 2008 03:32:52 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
		
		<category><![CDATA[CAL and Open Quark]]></category>

		<category><![CDATA[Computer Science]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/2008/07/09/take-two/</guid>
		<description><![CDATA[I&#8217;m much happier with the second version:

out3 a =
    let
        renderGroup g =
            let 
                char = head g;
 [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m much happier with the second version:</p>

<pre><code>out3 a =
    let
        renderGroup g =
            let 
                char = head g;
                count = length g;
                renderChars :: Int -&gt; String;
                renderChars n =
                    (fromChar char) ++
                    (if n &gt;1 then  " " ++ (renderChars $ n-1) else "");
            in
                if count &gt; 2 then
                    (renderChars 2) ++ 
                    " &lt;span&gt;" ++ (renderChars (count - 2)) ++ "&lt;/span&gt;"
                else
                    renderChars count;
        concatWithSep list = (head list) ++ concatMap (\s -&gt; " " ++ s) (tail list);
    in
        concatWithSep $ map renderGroup (group a);
</code></pre>

<p>This only uses one &#8216;exotic&#8217; list function, group:</p>

<pre><code>group :: Eq a =&gt; [a] -&gt; [[a]]
    Splits the specified list into a list of lists of equal, adjacent elements.
</code></pre>

<p>My program is longer than Matt&#8217;s &#8212; roughly twice as long &#8212; but I think this version is easier to understand.</p>

<p>Matt&#8217;s Javascript for loop has some complicated state, contained in some loop variables which are modified in the body of the loop as well as in the for statement itself. I think that&#8217;s a recipe for confusion.</p>
]]></content:encoded>
			<wfw:commentRss>http://diversions.nfshost.com/blog/2008/07/09/take-two/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Dustin&#8217;s Programming Problem Take One</title>
		<link>http://diversions.nfshost.com/blog/2008/07/09/dustins-programming-problem-take-one-2/</link>
		<comments>http://diversions.nfshost.com/blog/2008/07/09/dustins-programming-problem-take-one-2/#comments</comments>
		<pubDate>Tue, 08 Jul 2008 22:07:14 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
		
		<category><![CDATA[CAL and Open Quark]]></category>

		<category><![CDATA[Computer Science]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/2008/07/09/dustins-programming-problem-take-one-2/</guid>
		<description><![CDATA[My colleague Matt Ryall wrote about this simple algorithm for marking up a series of letters &#8212; which is complex enough to be interesting.

I wrote a version in CAL:

arr = ['a', 'b', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e',
          'f', 'e', 'f', 'e', 'f', 'a', [...]]]></description>
			<content:encoded><![CDATA[<p>My colleague Matt Ryall <a href="http://mattryall.net/blog/2008/07/dustins-programming-problem">wrote about this simple algorithm</a> for marking up a series of letters &#8212; which is complex enough to be interesting.</p>

<p>I wrote a version in <a href="http://openquark.org">CAL</a>:</p>

<pre><code>arr = ['a', 'b', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e',
          'f', 'e', 'f', 'e', 'f', 'a', 'a', 'a', 'f', 'f', 'f'];

data State = State string :: String current :: (Maybe Char) count :: Int;

out =
    let
        initial = State &#8220;&#8221; Nothing 0;
        f :: State -&gt; Char -&gt; State;
        f state char =
            let
                State s current count = state;
                charStr = fromChar char;
                appendSameChar = 
                    if count == 2 then
                        s ++ &#8221; &lt;span&gt;&#8221; ++ charStr
                    else
                        s ++ &#8221; &#8221; ++ charStr;
                appendDiffChar =
                    if count &gt; 2 then
                        s ++ &#8220;&lt;/span&gt; &#8221; ++ charStr
                    else
                        s ++ &#8221; &#8221; ++ charStr;
            in
                case current of
                    Nothing -&gt; State (fromChar char) (Just char) (1 :: Int);
                    Just c -&gt;
                        if c == char then
                            State appendSameChar (Just char) (count+1)
                        else
                            State appendDiffChar (Just char) 1;
            ;
        finalState = foldLeftStrict f initial arr;
    in
        finalState.State.string ++(if finalState.State.count &gt; 2 then
            &#8220;&lt;/span&gt;&#8221;
        else
            &#8220;&#8221;);
</code></pre>

<p>Positive proof that you can write verbose, confusing code in any language &#8212; but at least this code had no bugs &#8212; once it compiled it worked correctly first time.</p>

<p>As a follow up to this I will try to do better!</p>
]]></content:encoded>
			<wfw:commentRss>http://diversions.nfshost.com/blog/2008/07/09/dustins-programming-problem-take-one-2/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Project Euler for non-mathematicians?</title>
		<link>http://diversions.nfshost.com/blog/2008/04/26/project-euler-for-non-mathematicians/</link>
		<comments>http://diversions.nfshost.com/blog/2008/04/26/project-euler-for-non-mathematicians/#comments</comments>
		<pubDate>Fri, 25 Apr 2008 22:23:39 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
		
		<category><![CDATA[Computer Science]]></category>

		<category><![CDATA[General Interest]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/?p=36</guid>
		<description><![CDATA[This site has potential to be quite interesting, depending on the quality of the instructions.

It may also self select an interesting group of people &#8212; I wonder what a version of Slashdot which only those people knew about would be like?
]]></description>
			<content:encoded><![CDATA[<p><a href="http://instructionset.org/about/?">This site</a> has potential to be quite interesting, depending on the quality of the instructions.</p>

<p>It may also self select an interesting group of people &#8212; I wonder what a version of Slashdot which only those people knew about would be like?</p>
]]></content:encoded>
			<wfw:commentRss>http://diversions.nfshost.com/blog/2008/04/26/project-euler-for-non-mathematicians/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Crowd Authentication for Google&#8217;s AppEngine</title>
		<link>http://diversions.nfshost.com/blog/2008/04/14/crowd-authentication-for-googles-appengine/</link>
		<comments>http://diversions.nfshost.com/blog/2008/04/14/crowd-authentication-for-googles-appengine/#comments</comments>
		<pubDate>Mon, 14 Apr 2008 12:05:35 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
		
		<category><![CDATA[AppEngine]]></category>

		<category><![CDATA[Computer Science]]></category>

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

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

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/2008/04/14/crowd-authentication-for-googles-appengine/</guid>
		<description><![CDATA[The launch of Google&#8217;s AppEngine has given me the obligation to find out what it&#8217;s all about, and the opportunity to learn a bit more about one of our products, Crowd &#8212; and, of course, pick up some Python along the way.

I began by working through Google&#8217;s Guestbook example, and then replaced its use of [...]]]></description>
			<content:encoded><![CDATA[<p>The launch of Google&#8217;s AppEngine has given me the obligation to find out what it&#8217;s all about, and the opportunity to learn a bit more about one of <a href="http://www.atlassian.com">our</a> products, <a href="http://www.atlassian.com/software/crowd">Crowd</a> &#8212; and, of course, pick up some Python along the way.</p>

<p>I began by working through Google&#8217;s Guestbook example, and then replaced its use of Google&#8217;s Users API with single sign on via Crowd.</p>

<h2>Crowd Single Sign On</h2>

<p>A Crowd client application authenticates via SOAP calls to a Crowd server. The sequence looks like this:</p>

<p><a href='http://diversions.nfshost.com/blog/wp-content/uploads/crowd-seq.png' title='crowd-seq.png'><img src='http://diversions.nfshost.com/blog/wp-content/uploads/crowd-seq.png' alt='Crowd authentication sequence diagram' width=500 /></a></p>

<h2>Duck Punching httplib for SOAP</h2>

<p>I used the <a href="http://trac.optio.webfactional.com/wiki/soaplib">soaplib Python SOAP library</a> to talk to Crowd. This library uses <a href="http://docs.python.org/lib/module-httplib.html">httplib</a> to talk to the SOAP server, which is a problem as AppEngine only allows applications to use Google&#8217;s HTTP request mechanism.</p>

<p>I adapted soaplib to use Google&#8217;s <a href="tp://code.google.com/appengine/docs/urlfetch/fetchfunction.html">fetch</a> function by &#8216;Duck Punching&#8217;, also known as &#8216;Monkey Patching&#8217;. This globally overrides a library class with a class of your own:</p>

<pre><code>import httplib

class AppEngineHTTPConnection(object):
... delegate the functions called by soaplib to Google's fetch ...

class Crowd(object):
def __init__(self, path, applicationName, applicationPassword):
    # do some monkeypatching
    httplib.HTTPConnection = AppEngineHTTPConnection
</code></pre>

<p>Simple, and safe in this case, as we want any client of httplib to use our replacement.</p>

<p>By default, soaplib puts an empty namespace on strings and arrays, so I cut, pasted and renamed these classes, changing them to explicitly set the correct namespace. A Pythonista could probably duck-punch their way out of that with less duplication</p>

<p>My modified Guestbook application adds login and logout URLs which authenticate with Crowd and create the appropriate cookie.</p>

<h2>Caveats and Conclusions</h2>

<p>AppEngine doesn&#8217;t support SSL, so your username and password are transmitted unencrypted to the application. To avoid this you could write a small authentication application to be hosted with your Crowd server under SSL.</p>

<p>Your Crowd server and your Google AppEngine application need to be on the same domain, in order to share the Crowd SSO cookie. This should be possible by assigning your domain to a Google Apps account, but I haven&#8217;t managed to add my Google Apps domain to my Google AppEngine application yet.</p>

<h2>Python</h2>

<p>I strongly dislike weakly typed languages such as Python. IDEs can&#8217;t sensibly provide code completion, and I found that I made many errors which were only caught at runtime. Most of these were in code which could easily have been type checked at compile time.</p>

<p>The sooner <a href="http://www.python.org/workshops/2000-01/proceedings/papers/aycock/aycock.html">type inference is added to Python</a> or AppEngine supports JVM languages, the happier I&#8217;ll be. I expect the latter to happen first.</p>

<h2>Code</h2>

<p>The code for this AppEngine app can be found in my <a href="http://diversions.nfshost.com/cgi-bin/gitweb.cgi?p=crowd-appengine;a=summary">crowd-appengine Git repository</a>. As usual, get a <a href="http://diversions.nfshost.com/cgi-bin/gitweb.cgi?p=crowd-appengine;a=snapshot;h=61dfb63b65904910cfa2ef513f4ee04e3067f2c8;sf=tgz">snapshot</a> if you don&#8217;t have a git client installed.</p>
]]></content:encoded>
			<wfw:commentRss>http://diversions.nfshost.com/blog/2008/04/14/crowd-authentication-for-googles-appengine/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A CAL webapp with persistent data using GWT, STM and BDB</title>
		<link>http://diversions.nfshost.com/blog/2008/03/27/a-cal-webapp-with-persistent-data-using-gwt-stm-and-bdb/</link>
		<comments>http://diversions.nfshost.com/blog/2008/03/27/a-cal-webapp-with-persistent-data-using-gwt-stm-and-bdb/#comments</comments>
		<pubDate>Thu, 27 Mar 2008 12:24:26 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
		
		<category><![CDATA[CAL and Open Quark]]></category>

		<category><![CDATA[Computer Science]]></category>

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

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/2008/03/27/a-cal-webapp-with-persistent-data-using-gwt-stm-and-bdb/</guid>
		<description><![CDATA[aka, attack of the TLAs.

This webapp&#8217;s architecture is depicted below:




The browser runs a Javascript thick client compiled from Java by GWT. Some of the classes have CAL annotations. These don&#8217;t affect the client, but allow the server side of the GWT RPC protocol to call CAL functions.
The CAL functions store persistent data using Software Transactional [...]]]></description>
			<content:encoded><![CDATA[<p>aka, attack of the TLAs.</p>

<p>This webapp&#8217;s architecture is depicted below:</p>

<p><a href='http://diversions.nfshost.com/blog/wp-content/uploads/calgwt2.png' title='Webapp Architecture'><img src='http://diversions.nfshost.com/blog/wp-content/uploads/calgwt2.png' alt='Webapp Architecture' /></a></p>

<ul>
<li>The browser runs a Javascript thick client compiled from Java by GWT. Some of the classes have <a href="http://diversions.nfshost.com/blog/2008/03/15/gwt-as-a-cal-client/">CAL annotations</a>. These don&#8217;t affect the client, but allow the server side of the GWT RPC protocol to call CAL functions.</li>
<li>The CAL functions store persistent data using <a href="http://en.wikipedia.org/wiki/Software_transactional_memory">Software Transactional Memory</a>. This is a simple Java implementation based on the description in <a href="http://research.microsoft.com/~simonpj/papers/stm/stm.pdf">Composable memory transactions</a>. It is given a CAL interface similar to a subset of <a href="http://haskell.org/ghc/docs/latest/html/libraries/stm/Control-Concurrent-STM.html">Haskell&#8217;s Control.Concurrent.STM</a>.</li>
<li>Each STM TVar stores its value as a key-value pair in a <a href="http://www.oracle.com/database/berkeley-db/je/index.html">Berkeley DB Java Edition</a> database.</li>
</ul>

<p>Any data structure can be built on top of TVars &#8212; and each TVar is a mutable reference, these are <em>not</em> functional data structures.</p>

<p>In this application a simple hashmap is used. Skiplists and relaxed balance btrees are other data structures which might allow reasonable concurrency too, while also providing features like in-order traversal.</p>

<p>This illustrates the relationship between the CAL objects in the <a href="http://openquark.org/Documents/javadoc/org/openquark/cal/runtime/ExecutionContext.html">CAL ExecutionContext</a> and key-value pairs in the BDB:</p>

<p><a href='http://diversions.nfshost.com/blog/wp-content/uploads/cal-gwt-stm-persistence.png' title='cal-gwt-stm-persistence.png'><img src='http://diversions.nfshost.com/blog/wp-content/uploads/cal-gwt-stm-persistence.png' alt='cal-gwt-stm-persistence.png' width=500 /></a></p>

<p>The root of the persistent data structure is a TVar with a &#8216;well-known&#8217; id &#8212; 1 in the example, which is created by a <a href="http://www.haskell.org/haskellwiki/Constant_applicative_form">constant applicative form function</a>. This TVar will retrieve its value from the BDB when it is created, or if no value exists for its id, it will be initialised with a default value, which in the case of a hashmap is an array of TVars, each containing an empty list of key-value pairs. A value stored in a TVar is persisted to the BDB by serialising it using CAL&#8217;s default <code>output</code> function and <a href="http://xstream.codehaus.org/">Xstream</a>, which can serialize and deserialize instances which are not serializable and do not have accessible constructors.</p>

<p>TVars themselves have <code>transient</code> values, so only the id is persisted &#8212; the value is lazily loaded when required, using the id. So even though a TVar may persist a complicated tree of CAL algebraic values, this stops at the first TVar. (The root TVar is never persisted itself &#8212; only its value is stored).</p>

<p>You can get a <a href="http://diversions.nfshost.com/cgi-bin/gitweb.cgi?p=calex;a=snapshot;h=62165fb0519d5a4bcf692c615500bcdae9be669f;sf=tgz">snapshot here</a> &#8212; just unpack it and run <code>ant run</code>, then point your browser at <code>http://localhost:8080/caltest.html</code>. Or <a href="http://diversions.nfshost.com/cgi-bin/gitweb.cgi?p=calex;a=summary">browse the source</a>.</p>

<p>The <code>ant</code> build script includes a target <code>run-tests</code> which runs some <a href="http://selenium.openqa.org/">Selenium</a> tests. Stop the server before running that target.</p>

<p>Note that the source code includes various bits of half-baked rubbish, in addition to that described above!</p>
]]></content:encoded>
			<wfw:commentRss>http://diversions.nfshost.com/blog/2008/03/27/a-cal-webapp-with-persistent-data-using-gwt-stm-and-bdb/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
