<?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>Jason R Briggs &#187; internet</title>
	<atom:link href="http://www.briggs.net.nz/log/category/internet/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.briggs.net.nz/log</link>
	<description>by Jason R Briggs</description>
	<pubDate>Tue, 18 Nov 2008 23:48:32 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.3</generator>
	<language>en</language>
			<item>
		<title>RESTful resources</title>
		<link>http://www.briggs.net.nz/log/2007/12/16/restful-resources/</link>
		<comments>http://www.briggs.net.nz/log/2007/12/16/restful-resources/#comments</comments>
		<pubDate>Sun, 16 Dec 2007 01:31:32 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[development]]></category>

		<category><![CDATA[do-my-invoice]]></category>

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2007/12/16/restful-resources/</guid>
		<description><![CDATA[A recent release of Do My Invoice was a minor update to add more documentation for the various resources used in the application.  DMI is a REST application &#8212; well, at the very least, that was the initial design goal &#8212; so there are some basic access points for most system resources.
For example, you [...]]]></description>
			<content:encoded><![CDATA[<p>A recent release of <a href="http://www.domyinvoice.com">Do My Invoice</a> was a minor update to add more documentation for the various resources used in the application.  DMI is a <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm">REST</a> application &#8212; well, at the very least, that was the initial design goal &#8212; so there are some basic access points for most system resources.</p>
<p>For example, you may call GET to request your user profile:</p>
<pre>
<code>    http://www.domyinvoice.com/resources/[username]/profile</code>
</pre>
<p>Using <a href="http://curl.haxx.se/">CURL</a> the request:</p>
<pre>
<code>curl -X GET -u joebloggs:password http://www.domyinvoice.com/resources/joebloggs/profile</code>
</pre>
<p>&#8230;will return something like&#8230;</p>
<pre>
<code>&lt;profile&gt;
    &lt;username&gt;joebloggs&lt;/username&gt;
	&lt;email_address&gt;joe@bloggs.com&lt;/email_address&gt;
	&lt;first_name&gt;Joe&lt;/first_name&gt;
	&lt;last_name&gt;Bloggs&lt;/last_name&gt;
&lt;/profile&gt;</code>
</pre>
<p>Resources in DMI are self-describing, thus with the addition of a single parameter, you can view the documentation for that resource.  Thus the url&#8230;</p>
<pre>
<code>http://www.domyinvoice.com/resources/joebloggs/profile?help</code>
</pre>
<p>&#8230;returns a list of the HTTP verbs accepted by the resource, basic description and more detailed information about each verb.  If you don&#8217;t have an account (it&#8217;s free for the first month, by the way), you can see a static version of this help information <a href="http://www.domyinvoice.com/resource-profile.html">here</a>.</p>
<p>Another example, is the <strong>clients</strong> resource.  You can GET a list of clients:</p>
<pre>
<code>curl -X GET -u joebloggs:password http://www.domyinvoice.com/resources/joebloggs/clients</code>
</pre>
<pre>
<code>&lt;clients&gt;
	&lt;client id="76"&gt;
		&lt;client-name&gt;test company&lt;/client-name&gt;
		&lt;address1&gt;address line 1&lt;/address1&gt;
		&lt;address2&gt;address line 2&lt;/address2&gt;
		&lt;city&gt;London&lt;/city&gt;
		&lt;postcode&gt;sa1 sa2&lt;/postcode&gt;
		&lt;country&gt;United Kingdom&lt;/country&gt;
	&lt;/client&gt;
&lt;/clients&gt;</code>
</pre>
<p>A client can be added with the use of an HTTP PUT:</p>
<pre>
<code>curl -X PUT -u joebloggs:password http://www.domyinvoice.com/resources/joebloggs/clients/test+company+2 -d @-

address_1=23+Wrights+Lane&amp;address_2=Kensington&amp;city=London&amp;postcode=W8+6TA&amp;country=GB&amp;currency_symbol=£&amp;currency_format=1&amp;sales_tax_label=VAT&amp;sales_tax=0.175</code>
</pre>
<p>Which also returns the created client (assuming nothing went wrong):</p>
<pre>
<code>&lt;clients&gt;
	&lt;client id="80"&gt;
		&lt;client-name&gt;test+company+2&lt;/client-name&gt;
		&lt;address1&gt;23 Wrights Lane&lt;/address1&gt;
		&lt;address2&gt;Kensington&lt;/address2&gt;
		&lt;city&gt;London&lt;/city&gt;
		&lt;postcode&gt;W8 6TA&lt;/postcode&gt;
		&lt;country&gt;United Kingdom&lt;/country&gt;
	&lt;/client&gt;
&lt;/clients&gt;</code>
</pre>
<p>Said client could then be deleted with the use of the DELETE verb:</p>
<pre>
<code>curl -X DELETE -u joebloggs:password http://www.domyinvoice.com/resources/joebloggs/clients/test+company+2</code>
</pre>
<p>The obvious advantage of using RESTful resources internally is that I&#8217;m effectively providing an external API for free &#8212; in other words, without requiring any additional development effort.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2007/12/16/restful-resources/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Dodgy ISPs</title>
		<link>http://www.briggs.net.nz/log/2007/09/24/dodgy-isps/</link>
		<comments>http://www.briggs.net.nz/log/2007/09/24/dodgy-isps/#comments</comments>
		<pubDate>Mon, 24 Sep 2007 10:02:06 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[commentary]]></category>

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2007/09/24/dodgy-isps/</guid>
		<description><![CDATA[Is it just me, or do ISPs in New Zealand tend to operate on the south-side of the &#8220;moral tracks&#8221;?  At the moment, I&#8217;m trying to decide whether it&#8217;s worth having an argument with Orcon over the advertising for their &#8220;Zero Shock&#8221; plan (see &#8220;The Yogurt Container Broadband Plan&#8220;) &#8212; supposedly, this plan is [...]]]></description>
			<content:encoded><![CDATA[<p>Is it just me, or do ISPs in New Zealand tend to operate on the south-side of the &#8220;moral tracks&#8221;?  At the moment, I&#8217;m trying to decide whether it&#8217;s worth having an argument with Orcon over the advertising for their &#8220;Zero Shock&#8221; plan (see &#8220;<a href="http://www.briggs.net.nz/log/2007/09/20/the-yogurt-container-broadband-plan/">The Yogurt Container Broadband Plan</a>&#8220;) &#8212; supposedly, this plan is &#8220;traffic managed&#8221; to keep email and web access fast, and the speed of P2P applications are reduced as a consequence (by accepting this, you get the piece of mind that if you go over your datacap, you won&#8217;t get charged extra&#8230; as long as you don&#8217;t keep going over every month).  For me, traffic management actually meant I had the average speed of a 28K modem most evenings for any site out of the country.  Of course, if you look at their Terms &#038; Conditions, there&#8217;s just enough caveats there to make them liable for nothing.  Legally they&#8217;re fine.  I quibble, however, on the dubious morals that allow a company to sell a &#8220;broadband&#8221; plan that they know barely meets the definition at the best of times.</p>
<p>To be honest, I really have no argument with Orcon otherwise.  It just seems like false advertising to call something &#8220;Zero Shock&#8221;, when I find myself damn shocked at how slow it is.</p>
<p>The other ISP I have experience with is IHUG, who, if they reduce their prices for some reason, will keep quiet about it&#8230; &#8220;it&#8217;s your responsibility to check our website&#8221;.  I&#8217;ve experienced this and so, more recently, has my father.  Seems you should focus on keeping your current customers happy, rather than just attracting new ones.</p>
<p>That&#8217;s two of NZ&#8217;s larger ISPs, and I know the largest (Xtra) has had problems in the <a href="http://www.geekzone.co.nz/darrylb/1779">past</a>.  </p>
<p>I wonder if the issue is industry wide?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2007/09/24/dodgy-isps/feed/</wfw:commentRss>
		</item>
		<item>
		<title>The Yogurt Container Broadband Plan</title>
		<link>http://www.briggs.net.nz/log/2007/09/20/the-yogurt-container-broadband-plan/</link>
		<comments>http://www.briggs.net.nz/log/2007/09/20/the-yogurt-container-broadband-plan/#comments</comments>
		<pubDate>Thu, 20 Sep 2007 09:49:11 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[commentary]]></category>

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2007/09/20/the-yogurt-container-broadband-plan/</guid>
		<description><![CDATA[It&#8217;s an impressive feat.
When my daughter was about 2 and a half years old, we got a long piece of string, poked it through holes in a pair of yogurt containers, pulled the string tight and used it as a telephone.  It was difficult to get the concept across to a 2 year old; [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s an impressive feat.</p>
<p>When my daughter was about 2 and a half years old, we got a long piece of string, poked it through holes in a pair of yogurt containers, pulled the string tight and used it as a telephone.  It was difficult to get the concept across to a 2 year old; of talking into the container, then listening for the response.  It was also difficult keep the string taut enough, so that sound waves were transmitted properly.</p>
<p>Somehow, <a href="http://www.orcon.net.nz">Orcon</a> have managed not only to keep a piece of string tight over thousands of kilometres, they have also managed to connect the yogurt container to the local internet loop.  An extremely impressive piece of engineering.  Even if it does mean my international traffic is slower than a 28K modem.  Just think of the science!</p>
<p><center>* * *</center></p>
<p>So it&#8217;s now almost a month since I first noticed the <a href="http://www.briggs.net.nz/log/2007/08/29/radioactive-relief/">problem</a>, and over 3 weeks since I reported it &#8212; and there is still no resolution in sight.  At least a couple of emails have gone unanswered in the last few weeks, although the initial response from their support department (instructions on how to provide all the data their technicians would need) was positive.  Last night I finally gave up waiting and decided to sit on hold for 10 minutes or so.  Their helpdesk, while nice enough (and local), were unable to shed any light and would need to pass on the details to technicians.  But&#8230;</p>
<p><em>&#8220;&#8230;we have had reports from other customers of similar problems&#8230; it may have something to do with the traffic shaping&#8230;&#8221;</em></p>
<p>Yes.  I&#8217;m blimmin&#8217; well aware that it&#8217;s traffic shaping.  I could&#8217;ve told you that a month ago.</p>
<p><em>&#8220;&#8230;a quick fix might be to upgrade your plan&#8230;&#8221;</em></p>
<p>Where&#8217;s the sound of screeching tyres when you want it?  </p>
<p>Upgrade my plan?</p>
<p>I must remember that if I ever get a complaint about software I&#8217;ve developed&#8230;</p>
<p><em>&#8220;I&#8217;m sorry you&#8217;re having problems sir.  Other people have also experienced problems with that version of our software.  I invite you to upgrade to a more expensive version, in which we have fixed that issue.&#8221;</em></p>
<p>PS.  Unsurprisingly, still no response from technical support.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2007/09/20/the-yogurt-container-broadband-plan/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Painful IE6 event handling</title>
		<link>http://www.briggs.net.nz/log/2007/07/02/painful-ie6-event-handling/</link>
		<comments>http://www.briggs.net.nz/log/2007/07/02/painful-ie6-event-handling/#comments</comments>
		<pubDate>Mon, 02 Jul 2007 06:49:55 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[development]]></category>

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2007/07/02/painful-ie6-event-handling/</guid>
		<description><![CDATA[If you want to preload images before displaying them in the browser, a convenient way to do so is to use image.onload.
For example, the following code shows the onload in action:

img = new Image();

var onloadFunc = function() {
    alert("got here... you really should do something now");
};

img.onload = onloadFunc;
img.src = url;
if (img.complete) {
 [...]]]></description>
			<content:encoded><![CDATA[<p>If you want to preload images before displaying them in the browser, a convenient way to do so is to use image.onload.</p>
<p>For example, the following code shows the onload in action:</p>
<pre>
<code>img = new Image();

var onloadFunc = function() {
    alert("got here... you really should do something now");
};

img.onload = onloadFunc;
img.src = url;
if (img.complete) {
    onloadFunc();
}</code>
</pre>
<p>That works in most situations, but I&#8217;ve just discovered IE6 is seriously buggy (so what&#8217;s new?) in its onload event handling.  The specific problem is preloading an image from the body&#8217;s onload event (or any other method that fires after the page has loaded, such as a script at the bottom of the page, etc).</p>
<p>A morning of googling failed to find a solution, so for <em>future-me</em>&#8217;s reference, basically the best way to ensure images are preloaded at the end of a pageload is something like the following:</p>
<pre>
<code>var timer = null;
var images = new Array(); 

// trigger this from the body's onload
function onPageLoad() {
	images[0] = new Image();
	images[0].src = 'url to some image';
	images[1] = new Image();
	images[1].src = 'url to another image';
	timer = window.setInterval("onPageCheck()", 250);
} 

function onPageCheck() {
	for(var i = 0; i &amp;lt; images.length; i++) {
		if (!images[i].complete) {
			return;
		}
	}

	window.clearInterval(timer);
	images = null;

	// now use the images
	...
}</code>
</pre>
<p>Basically, create an array of images (where the .src property triggers the preload), then use a timeout to check if the load is completed.</p>
<p>This appears to get around the problem.  Note that the onload seems to work fine when triggered outside of the page onload (a button click and so on).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2007/07/02/painful-ie6-event-handling/feed/</wfw:commentRss>
		</item>
		<item>
		<title>logproxy project</title>
		<link>http://www.briggs.net.nz/log/2007/06/11/logproxy-project/</link>
		<comments>http://www.briggs.net.nz/log/2007/06/11/logproxy-project/#comments</comments>
		<pubDate>Mon, 11 Jun 2007 08:12:31 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[development]]></category>

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

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2007/06/11/logproxy-project/</guid>
		<description><![CDATA[One of my earliest posts (back when I was using blogger.com), was regarding a reverse logging proxy &#8212; a simple Python script to transparently log requests between a client and a server.  Very useful for debugging web service calls, to see what exactly what is being sent back and forth.
I&#8217;ve just added logproxy.py to [...]]]></description>
			<content:encoded><![CDATA[<p>One of my earliest <a href="http://www.briggs.net.nz/log/2005/08/02/reverse-logging-proxy/">posts</a> (back when I was using blogger.com), was regarding a reverse logging proxy &#8212; a simple Python script to transparently log requests between a client and a server.  Very useful for debugging web service calls, to see what exactly what is being sent back and forth.</p>
<p>I&#8217;ve just added <a href="http://www.briggs.net.nz/log/projects/logproxypy/">logproxy.py</a> to my <a href="http://www.briggs.net.nz/log/projects/">projects</a> page, after updating it to handle virtual hosts (in other words, when using Apache to serve more than one domain).</p>
<p>This is not quite as impressive a change as it might sound.  It basically means correctly setting the Host HTTP header, rather than defaulting to localhost&#8230;</p>
<p>Anyway, a few people appear to have found it useful, judging from my access logs, so this update might help someone else (it certainly helped me figure out why my wsgi app was failing to properly handle multipart form content).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2007/06/11/logproxy-project/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Digest, basic&#8230;. IE7?</title>
		<link>http://www.briggs.net.nz/log/2007/05/12/digest-basic-ie7/</link>
		<comments>http://www.briggs.net.nz/log/2007/05/12/digest-basic-ie7/#comments</comments>
		<pubDate>Sat, 12 May 2007 04:55:37 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[development]]></category>

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2007/05/12/digest-basic-ie7/</guid>
		<description><![CDATA[I&#8217;ve just discovered that my implementation of a Digest Authentication middleware for WSGI, which had been working perfectly with Firefox, fails miserably when I try it with IE.
A bit of googling finds the following&#8230;
http://www.eweek.com/article2/0%2C1895%2C1500432%2C00.asp
http://www.extremetech.com/article2/0,1697,20373,00.asp
&#8230;making me think that I&#8217;m basically stuffed, despite the fact that I followed the RFC. Excellent work Microsoft! (Sarcasm alert!)
Should&#8217;ve done some [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just discovered that my implementation of a Digest Authentication middleware for WSGI, which had been working perfectly with Firefox, fails miserably when I try it with IE.</p>
<p>A bit of googling finds the following&#8230;</p>
<p><a href="http://www.eweek.com/article2/0%2C1895%2C1500432%2C00.asp">http://www.eweek.com/article2/0%2C1895%2C1500432%2C00.asp</a><br />
<a href="http://www.extremetech.com/article2/0,1697,20373,00.asp">http://www.extremetech.com/article2/0,1697,20373,00.asp</a></p>
<p>&#8230;making me think that I&#8217;m basically stuffed, despite the fact that I followed the RFC. Excellent work Microsoft! (Sarcasm alert!)</p>
<p>Should&#8217;ve done some reading first I think.</p>
<p>So now a decision.  Persevere with digest auth and upgrade (irreversibly?) to IE7 in the vain hope that it works, or roll back to Basic auth which will obviously support more browsers.</p>
<p>Much as I&#8217;d like to stick with digest (and see if my implementation works in IE7), I think Basic auth is the safer option (at least coupled with SSL), particularly when you look at browser <a href="http://www.w3schools.com/browsers/browsers_stats.asp">market share</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2007/05/12/digest-basic-ie7/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Basic CSS Popups</title>
		<link>http://www.briggs.net.nz/log/2007/04/06/basic-css-popups/</link>
		<comments>http://www.briggs.net.nz/log/2007/04/06/basic-css-popups/#comments</comments>
		<pubDate>Fri, 06 Apr 2007 03:11:52 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[css]]></category>

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

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2007/04/06/basic-css-popups/</guid>
		<description><![CDATA[Every time I have a requirement for a basic CSS popup box of some kind, I end up going through the same process.  Hunt through old code looking for straightforward examples, then trawl through the googleweb trying to find something that isn&#8217;t an example of a CSS popup menu.
I&#8217;m sure pure CSS popup menus [...]]]></description>
			<content:encoded><![CDATA[<p>Every time I have a requirement for a basic CSS popup box of some kind, I end up going through the same process.  Hunt through old code looking for straightforward examples, then trawl through the googleweb trying to find something that <b>isn&#8217;t</b> an example of a CSS popup menu.</p>
<p>I&#8217;m sure pure CSS popup menus are all well and good, but it&#8217;s painful picking out the useful bits.</p>
<p>So, more for my own future reference, a simple CSS popup can be accomplished using the following CSS:</p>
<pre>
<code>a span {
	display: none;
	text-decoration: none;
}

a:hover {
/** fix for IE6 popup bug.  nice one Microsoft! */
	overflow: hidden;
	text-decoration: none;
}

a:hover span {
	display: inline;
	border: 1px solid black;
	position: absolute;
	background-color: white;
	padding: 5px;
	margin-left: 5px;
	overflow: hidden;
}</code>
</pre>
<p>The first reference hides the popup, the second redisplays, using margin-left to move the popup a little to the right of the href it&#8217;s linked from.</p>
<p>Then create HTML as follows:</p>
<pre>
<code>&lt;p&gt;this is a test this is a test this is a test this is a test this is a test this is a test this is a test
this is a test this is a test this is a test this is a test this is a test this is a test this is a test
&lt;a href="#"&gt;popup&lt;span&gt;test message 1&lt;br /&gt;test message 2&lt;/span&gt;&lt;/a&gt;
this is a test this is a test this is a test this is a test this is a test this is a test this is a test this is a test
this is a test this is a test this is a test this is a test this is a test this is a test this is a test this is a test
this is a test this is a test this is a test this is a test this is a test this is a test &lt;/p&gt;</code>
</pre>
<p>Check this <a href='http://www.briggs.net.nz/log/wp-content/uploads/2007/04/popup.html' title='popup'>link</a> for an example.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2007/04/06/basic-css-popups/feed/</wfw:commentRss>
		</item>
		<item>
		<title>mod_python and wsgi</title>
		<link>http://www.briggs.net.nz/log/2006/07/11/mod_python-and-wsgi/</link>
		<comments>http://www.briggs.net.nz/log/2006/07/11/mod_python-and-wsgi/#comments</comments>
		<pubDate>Tue, 11 Jul 2006 10:59:23 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[internet]]></category>

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2006/07/11/mod_python-and-wsgi/</guid>
		<description><![CDATA[Every time I sit down to do something with mod_python, I have problems.  Usually they can be traced to forgetting to RTFM.
It doesn&#8217;t help that I tend to put experimental code in my apache www dir on occasion &#8212; and forget to back it up &#8212; so that after a system reinstall, I then [...]]]></description>
			<content:encoded><![CDATA[<p>Every time I sit down to do something with mod_python, I have problems.  Usually they can be traced to forgetting to RTFM.</p>
<p>It doesn&#8217;t help that I tend to put experimental code in my apache www dir on occasion &#8212; and forget to back it up &#8212; so that after a system reinstall, I then have to dredge the dim, dark recesses of my memory to remember how to do simple stuff.</p>
<p>So for my own future reference&#8230;</p>
<ol>
<li>a WSGI handler (wsgi_handler.py) for mod_python can be found <a href="http://trac.gerf.org/pse/wiki/WSGIHandler">here</a></li>
<li>the handler needs to be accessible on the python path, so copying it to /usr/lib/python2.4/site-packages means it&#8217;s accessible (there&#8217;s a better way, but it momentarily escapes me)</li>
<li>the apache config required is:
<pre>
<code>&lt;Directory /var/www/test&gt;
PythonHandler wsgi_handler
PythonOption WSGI.Application hello::simple_app
AddHandler python-program .py
&lt;/Directory&gt;</code>
</pre>
<p>Where:</p>
<ul>
<li>/var/www/test is an absolute path to a directory I&#8217;m serving on the web</li>
<li>hello is a python script (hello.py &#8212; see below)</li>
<li>simple_app is a function in the script</li>
</ul>
<p>In the case of my kubuntu laptop, I just created a mod_python.conf file containing the above in /etc/apache2/mods-enabled</li>
<li>hello.py, a simple WSGI app, looks like this (snaffled from the python PEP for WSGI):
<pre>
<code>def simple_app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type','text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']</code>
</pre>
</li>
<li>restart apache, and hopefully we&#8217;re away&#8230;</li>
</ol>
<p>I&#8217;ve also added an extension to make wsgi_handler slightly more useful for my purposes; the ability to serve more than one &#8216;app&#8217; from the same script.  The extended version can be found <a href="http://http://www.briggs.net.nz/sup/2006/07/11/wsgi_handler.py">here</a>.</p>
<p>The apache configuration can then be modified to:</p>
<pre>
<code>&lt;Directory /var/www/test&gt;
PythonHandler wsgi_handler
PythonOption WSGI.Application hello
AddHandler python-program .py
&lt;/Directory&gt;</code>
</pre>
<p>And hello.py now looks like this:</p>
<pre>
<code>def simple_app(environ, start_response):
    status = '200 OK'
    print str(environ)
    response_headers = [('Content-type','text/plain')]
    start_response(status, response_headers)
    return ['Hello WSGI world!\n']

def test(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-Type','text/plain')]
    start_response(status, response_headers)
    return ['test test test\n']</code>
</pre>
<p>Meaning that you can now point your browser to:</p>
<p>http://localhost/test/test.py/simple_app</p>
<p>or:</p>
<p>http://localhost/test/test.py/test</p>
<p>Which is useful for experimentation.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2006/07/11/mod_python-and-wsgi/feed/</wfw:commentRss>
		</item>
		<item>
		<title>templating continued</title>
		<link>http://www.briggs.net.nz/log/2006/05/30/templating-continued/</link>
		<comments>http://www.briggs.net.nz/log/2006/05/30/templating-continued/#comments</comments>
		<pubDate>Tue, 30 May 2006 01:15:14 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[development]]></category>

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

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2006/05/30/templating-continued/</guid>
		<description><![CDATA[I&#8217;ve done a little more work on &#8216;my&#8217; approach to templating.  One thing I&#8217;ve only mentioned in passing, is that there are other templating engines out there that work in this fashion &#8212; both in Python and Java.  HTMLTemplate, is a python module I&#8217;ve already mentioned previously.  Tapestry is a Java framework, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve done a little more work on &#8216;my&#8217; approach to templating.  One thing I&#8217;ve only mentioned in passing, is that there are other templating engines out there that work in this fashion &#8212; both in Python and Java.  HTMLTemplate, is a python module I&#8217;ve already mentioned previously.  Tapestry is a Java framework, which I haven&#8217;t personally used, but seem to recall uses an attribute language for its templates.  And there are others, so what I&#8217;m experimenting with is hardly anything new.  But I have yet to see one that I think goes far enough with the removal of markup from view components.  Not to harp on about it too much (not half).</p>
<p><span id="more-80"></span><br />
Continuing from the code started <a href="http://www.briggs.net.nz/log/2006/05/29/templating-revisited">here</a>, I&#8217;ve added data for the central section of the page; which uses the dom from an imported template.  The engine has been changed slightly to re-calculate the ID attributes of imports so that they remain unique in the page.  This is something that the user/developer would need to be aware of, but not necessarily the template designer.</p>
<pre>
<code>template[<span class="pystring">'main:top-content'</span>] = engine.<span class="pyname">load</span>(<span class="pystring">'multi-col-content.html'</span>)
template[<span class="pystring">'main:top-content:heading'</span>] = <span class="pystring">'Treat Yourself'</span></span>

template[<span class="pystring">'main:top-content:img'</span>] = [ template2.<span class="pyname">get</span>(None, src='amazon_fp_files/1887521003.<span class="pyname">jpg'</span>, alt='some title text'),
                                     template2.<span class="pyname">get</span>(None, src='amazon_fp_files/1887521003.<span class="pyname">jpg'</span>, alt='some other title text'),
                                     template2.<span class="pyname">get</span>(None, src='amazon_fp_files/0316015849.<span class="pyname">jpg'</span>, alt='some title text') ]

template[<span class="pystring">'main:top-content:title'</span>]  = [ <span class="pystring">'Some title text'</span>, <span class="pystring">'Some other title text'</span>, <span class="pystring">'More title text'</span> ]
template[<span class="pystring">'main:top-content:author'</span>] = [ <span class="pystring">'by Someone'</span>, <span class="pystring">'by Another Person'</span>, <span class="pystring">'by Yet Another Person'</span> ]
template[<span class="pystring">'main:top-content:price'</span>]  = [ ' ', <span class="pystring">'$10.99'</span>, <span class="pystring">'$15.25'</span> ]
template[<span class="pystring">'main:top-content:link'</span>]   = template2.<span class="pyname">hidden</span>()

template[<span class="pystring">'main:repeated-content'</span>] = [ engine.<span class="pyname">load</span>(<span class="pystring">'multi-col-content.html'</span>),
                                      engine.<span class="pyname">load</span>(<span class="pystring">'multi-col-content.html'</span>) ]

template[<span class="pystring">'main:repeated-content:1:heading'</span>] = <span class="pystring">'Up to 50% Off Bostonian Shoes'</span>
template[<span class="pystring">'main:repeated-content:1:img'</span>]     = [ template2.<span class="pyname">get</span>(None, src='amazon_fp_files/B0007MCQCQ.<span class="pyname">jpg'</span>, alt='shoe1'),
                                                template2.<span class="pyname">get</span>(None, src='amazon_fp_files/B0007MCQR6.<span class="pyname">jpg'</span>, alt='shoe2'),
                                                template2.<span class="pyname">get</span>(None, src='amazon_fp_files/B000BYIBA6.<span class="pyname">jpg'</span>, alt='shoe3') ]
template[<span class="pystring">'main:repeated-content:1:title'</span>]   = template2.<span class="pyname">hidden</span>()
template[<span class="pystring">'main:repeated-content:1:author'</span>]  = template2.<span class="pyname">hidden</span>()
template[<span class="pystring">'main:repeated-content:1:price'</span>]   = template2.<span class="pyname">hidden</span>()
template[<span class="pystring">'main:repeated-content:1:link'</span>]    = [ template2.<span class="pyname">get</span>(<span class="pystring">'link1 text'</span>, href='http://localhost/amazon/somelink1'),
                                               template2.<span class="pyname">get</span>(<span class="pystring">'link2 text'</span>, href='http://localhost/amazon/somelink2'),
                                               template2.<span class="pyname">get</span>(<span class="pystring">'link3 text'</span>, href='http://localhost/amazon/somelink3') ]

template[<span class="pystring">'main:repeated-content:2:heading'</span>] = <span class="pystring">'Free Shipping on the New Samsung DLP HDTVs'</span>
template[<span class="pystring">'main:repeated-content:2:img'</span>]     = [ template2.<span class="pyname">get</span>(None, src='amazon_fp_files/B000F2N7D0.<span class="pyname">jpg'</span>, alt='tv1'),
                                                template2.<span class="pyname">get</span>(None, src='amazon_fp_files/B000F2P300.<span class="pyname">jpg'</span>, alt='tv2'),
                                                template2.<span class="pyname">get</span>(None, src='amazon_fp_files/B000F2PHDI.<span class="pyname">jpg'</span>, alt='tv3') ]
template[<span class="pystring">'main:repeated-content:2:title'</span>]   = template2.<span class="pyname">hidden</span>()
template[<span class="pystring">'main:repeated-content:2:author'</span>]  = template2.<span class="pyname">hidden</span>()
template[<span class="pystring">'main:repeated-content:2:price'</span>]   = template2.<span class="pyname">hidden</span>()
template[<span class="pystring">'main:repeated-content:2:link'</span>]    = [ template2.<span class="pyname">get</span>(<span class="pystring">'link1 text'</span>, href='http://localhost/amazon/somelink1'),
                                                template2.<span class="pyname">get</span>(<span class="pystring">'link2 text'</span>, href='http://localhost/amazon/somelink2'),
                                                template2.<span class="pyname">get</span>(<span class="pystring">'link3 text'</span>, href='http://localhost/amazon/somelink3') ]</code>
</pre>
<p>The template itself, at this point is remarkably uncomplicated, meaning that most of the complexity stays in the code (something I don&#8217;t personally have a problem with):</p>
<pre>
<code>&lt;div id="main"&gt;
    &lt;div&gt;
        &lt;h2&gt;Main Column&lt;/h2&gt;
        &lt;span id="main:top-content"&gt;
        top content pane here
        &lt;/span&gt;
    &lt;/div&gt;

    &lt;div&gt;
        todo: replace this with 'specials' section
    &lt;/div&gt;    

    &lt;div id="main:repeated-content"&gt;
        repeated content here
    &lt;/div&gt;
&lt;/div&gt;</code>
</pre>
<p>The imported template is also simple.  The cell contents are defined once, then repeated in code using a list of imported templates (<code>engine.load(...)</code> statements), and finally content is applied to those imported elements; and in some cases removed, using the <code>template2.hidden()</code> statement.</p>
<pre>
<code>&lt;div&gt;
    &lt;h4 id="heading"&gt;heading here&lt;/h4&gt;
    &lt;table class="multicol"&gt;
        &lt;tr&gt;
            &lt;td id="img"&gt;&lt;img src="" alt="" /&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td id="title"&gt;title text here&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td id="author"&gt;author text here&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td id="price"&gt;$0.00&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td id="link"&gt;&lt;a href=""&gt;link text&lt;/a&gt;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/table&gt;
&lt;/div&gt;</code>
</pre>
<p><strong>Resources:</strong></p>
<ul>
<li><a href="http://bluebear.co.nz/sup/2006/05/30/templating-continued/amazon_template.html">Main template</a></li>
<li><a href="http://bluebear.co.nz/sup/2006/05/30/templating-continued/multi-col-content.html">Imported template</a></li>
<li><a href="http://bluebear.co.nz/sup/2006/05/30/templating-continued/template2.py">Template engine</a></li>
<li><a href="http://bluebear.co.nz/sup/2006/05/30/templating-continued/amazon.py">Script to create amazon html</a></li>
<li><a href="http://bluebear.co.nz/sup/2006/05/30/templating-continued/test.html">Current output</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2006/05/30/templating-continued/feed/</wfw:commentRss>
		</item>
		<item>
		<title>templating revisited</title>
		<link>http://www.briggs.net.nz/log/2006/05/29/templating-revisited/</link>
		<comments>http://www.briggs.net.nz/log/2006/05/29/templating-revisited/#comments</comments>
		<pubDate>Mon, 29 May 2006 01:04:31 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[development]]></category>

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

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2006/05/29/templating-revisited/</guid>
		<description><![CDATA[I finally took an hour to revisit the templating code mentioned back here, using minidom instead of rparsexml.  As expected, refactoring produces better code, but &#8216;better&#8217; is a relative term &#8212; it&#8217;s still a major hack-job.  However, in this case, I&#8217;m not bothered as long as it proves a point with as little [...]]]></description>
			<content:encoded><![CDATA[<p>I finally took an hour to revisit the templating code mentioned back <a href="http://www.briggs.net.nz/log/2006/05/16/fugly-templating/">here</a>, using minidom instead of rparsexml.  As expected, refactoring produces better code, but &#8216;better&#8217; is a relative term &#8212; it&#8217;s still a major hack-job.  However, in this case, I&#8217;m not bothered as long as it proves a point with as little effort as possible.</p>
<p>So, to recap my prior thoughts:</p>
<ol>
<li>I don&#8217;t like the complexity, and general inelegance, of the templates required to produce dynamic content with facelets &#038; JSF.  Faces on its own is bad enough; facelets (while admittedly helping to fix a lot of the nastiness inherent in JSF) adds its own ugliness factor.</li>
<li>I don&#8217;t think it would be hard to design something better.  Actually, let me rephrase that:
<p><em>An electric charge applied to a few single-celled organisms contained in a small bucket of slime could design something better.</em></li>
</ol>
<p>My intention is, therefore, to hack together a quick prototype &#8212; hopefully coming up with something a little more elegant in the process.  And since (I hope) I have a few brain cells to rub together, I might just provide reasonable competition to the bucket of slime.</p>
<p><span id="more-77"></span><br />
For demo purposes, I&#8217;ve come up with a basic template copying the main sections of the <a href="http://www.amazon.com">Amazon</a> front page:</p>
<p><a href="http://www.briggs.net.nz/log/wp-content/uploads/2006/09/amazon_screenshot.thumbnail.gif"><img id="image106" src="http://www.briggs.net.nz/log/wp-content/uploads/2006/09/amazon_screenshot.thumbnail.gif" alt="Amazon Screenshot" /></a></p>
<p>I&#8217;m gradually adding dynamic elements and enhancing the templating as I go.  At the moment, the template looks like <a href="http://www.briggs.net.nz/sup/2006/05/29/templating-revisited/amazon_template.html">this</a>.  Note I&#8217;m not bothering to include style and images from the Amazon site &#8212; focussing, rather, on the content and basic layout.</p>
<p>Below you can see an example of the code used to inject dynamic content.  Basically, I&#8217;ve defined 2 classes: Localiser - a component to localise the text in an element, and ValueLocaliser - a preset value that will be localised and replace the text in an element.  The dummy &#8216;localise&#8217; function merely converts the text to upper case; just to prove it has processed the text.  Once the template is loaded, dynamic content is added using the xhtml element <a href="http://www.w3.org/TR/REC-xml/#id">ID</a> as the reference.<br />
For example a template with:</p>
<p><code>&lt;p id="someid"&gt;default value&lt;/p&gt;</code></p>
<p>would be injected with dynamic content using the code:</p>
<p><code>template['someid'] = 'somevalue'</code></p>
<p>Similarly, a template with:</p>
<p><code>&lt;a id="myanchor" href=""&gt;link text&lt;/p&gt;</code> </p>
<p>Could be repeated in the output by applying:</p>
<p><code>template["myanchor"] = [ template2.get('Amazon', href='http://www.amazon.com'),<br />
                              template2.get('Google', value='http://www.google.com') ]</code></p>
<p>It&#8217;s worth emphasising that all I&#8217;m talking about here is templating; not lifecycle, event handling and other guff that goes into your average web &#8216;framework&#8217;.  Thus the code below is all about applying the content of a model (albeit just dummy data) to a view.  The advantage of this approaching to templating xhtml content is that you can view the template in-browser &#8212; what-you-see-is-what-you-get (well almost).</p>
<p>The (unfinished) result of running the code against the aforementioned template can be found <a href="http://www.briggs.net.nz/sup/2006/05/29/templating-revisited/test.html">here</a>.  You can hopefully see that the &#8216;localiser&#8217; has converted text to uppercase where specified.  The template &#8216;engine&#8217;, as it currently stands, is <a href="http://www.briggs.net.nz/sup/2006/05/29/templating-revisited/template2.py">here</a>.</p>
<p>More to come&#8230;</p>
<pre>
<code><span class="pycomment">#! /usr/bin/python</span>

<span class="pykeyword">import</span> template2

<span class="pycomment"># dummy localiser function</span>
<span class="pycomment"># just returns upper value of string to prove it has</span>
<span class="pycomment"># processed</span>
<span class="pykeyword">def</span> <span class="pyname">localise</span>(val):
    return val.<span class="pyname">upper</span>()

<span class="pykeyword">class</span> <span class="pyname">Localiser</span>(template2.<span class="pyname">PluginAttributes</span>):
    <span class="pymlcomment">'''
    a subclass of a template plugin that 'localises' the content
    of an element (nodeValue) and any children.  Note that the
    localise is just a dummy function that capitalises the value
    '''</span>

    <span class="pykeyword">def</span> <span class="pyname">process</span>(self, dom, node):
        template2.<span class="pyname">PluginAttributes</span>.<span class="pyname">process</span>(self, dom, node)

        <span class="pykeyword">if</span> node.<span class="pyname">nodeValue</span>:
            node.<span class="pyname">nodeValue</span> = localise(node.<span class="pyname">nodeValue</span>)

        <span class="pykeyword">if</span> node.<span class="pyname">hasChildNodes</span>():
            <span class="pykeyword">for</span> n <span class="pykeyword">in</span> node.<span class="pyname">childNodes</span>:
                self.<span class="pyname">process</span>(dom, n)

<span class="pykeyword">class</span> <span class="pyname">ValueLocaliser</span>(template2.<span class="pyname">PluginAttributes</span>):
    <span class="pymlcomment">'''
    a subclass of a template plugin which 'localises' a preset
    value
    '''</span>

    <span class="pykeyword">def</span> <span class="pyname">__init__</span>(self, content, **kwargs):
        template2.<span class="pyname">PluginAttributes</span>.<span class="pyname">__init__</span>(self, **kwargs)
        self.<span class="pyname">content</span> = content

    <span class="pykeyword">def</span> <span class="pyname">process</span>(self, dom, node):
        template2.<span class="pyname">PluginAttributes</span>.<span class="pyname">process</span>(self, dom, node)
        <span class="pykeyword">if</span> node.<span class="pyname">firstChild</span>:
            node.<span class="pyname">firstChild</span>.<span class="pyname">nodeValue</span> = localise(self.<span class="pyname">content</span>)
        <span class="pykeyword">else</span>:
            node.<span class="pyname">nodeValue</span> = localise(self.<span class="pyname">content</span>)

<span class="pycomment"># create an instance of the template engine, then load</span>
<span class="pycomment"># a template</span>
engine = template2.<span class="pyname">Engine</span>()
template = engine.<span class="pyname">load</span>(<span class="pystring">'amazon_template.html'</span>)

<span class="pycomment"># create a localiser</span>
localiser = Localiser()

<span class="pycomment"># inject banner1 content</span>
template[<span class="pystring">'b1:home'</span>] = template2.<span class="pyname">get</span>(href='http://www.<span class="pyname">amazon</span>.<span class="pyname">com'</span>)
template[<span class="pystring">'b1:user-store'</span>] = template2.<span class="pyname">get</span>(<span class="pystring">'Jason\'s Store'</span>, href='http://localhost/amazon/store/jason')
template[<span class="pystring">'b1:categories'</span>] = template2.<span class="pyname">get</span>(href='http://localhost/amazon/categories')
template[<span class="pystring">'b1:account'</span>] = template2.<span class="pyname">get</span>(href='http://localhost/amazon/account/jason')
template[<span class="pystring">'b1:cart'</span>] = template2.<span class="pyname">get</span>(href='http://localhost/amazon/cart/jason')
template[<span class="pystring">'b1:help'</span>] = Localiser(href='http://localhost/amazon/help')
template[<span class="pystring">'b1:wish-list'</span>] = template2.<span class="pyname">get</span>(href='http://localhost/amazon/wish-list/jason')

<span class="pycomment"># inject banner 2 content</span>
template[<span class="pystring">'b2:specials'</span>] = [ ValueLocaliser(<span class="pystring">'Gift Ideas'</span>, href='http://localhost/amazon/gifts'),
                            ValueLocaliser(<span class="pystring">'International'</span>, href='http://localhost/amazon/international'),
                            ValueLocaliser(<span class="pystring">'New Releases'</span>, href='http://localhost/amazon/new-releases'),
                            ValueLocaliser(<span class="pystring">'Top Sellers'</span>, href='http://localhost/amazon/top-sellers'),
                            ValueLocaliser(<span class="pystring">'Today\'s Deals'</span>, href='http://localhost/amazon/todays-deals'),
                            ValueLocaliser(<span class="pystring">'Sell your stuff'</span>, href='http://localhost/amazon/sell') ]

template[<span class="pystring">'b2:searchlabel'</span>] = Localiser()
template[<span class="pystring">'b2:searchwhat'</span>] = [ template2.<span class="pyname">get</span>(<span class="pystring">'Amazon.com'</span>, value='amazon'),
                              template2.<span class="pyname">get</span>(<span class="pystring">'Books'</span>, value='books'),
                              template2.<span class="pyname">get</span>(<span class="pystring">'Popular Music'</span>, value='popular-music'),
                              template2.<span class="pyname">get</span>(<span class="pystring">'Music Downloads'</span>, value='music-downloads') ]
template[<span class="pystring">'b2:searchtext'</span>] = template2.<span class="pyname">get</span>(None, value='some search term I entered last')

<span class="pycomment"># inject banner 3 content</span>
template[<span class="pystring">'b3:welcome1'</span>] = localiser
template[<span class="pystring">'b3:user'</span>] = <span class="pystring">'Jason R Briggs'</span></span>
template[<span class="pystring">'b3:welcome2'</span>] = localiser
template[<span class="pystring">'b3:recommendations'</span>] = template2.<span class="pyname">get</span>(None, href='http://localhost/amazon/recommendations/jason')

<span class="pycomment"># inject subnav content</span>
template[<span class="pystring">'subnav:browse-heading'</span>] = localiser
template[<span class="pystring">'subnav:favourites-heading'</span>] = localiser
template[<span class="pystring">'subnav:favourites'</span>] = [ ValueLocaliser(<span class="pystring">'Books'</span>, href='http://localhost/amazon/favourites/books/jason'),
                                  ValueLocaliser(<span class="pystring">'Music'</span>, href='http://localhost/amazon/favourites/music/jason') ]

template[<span class="pystring">'subnav:stores-heading'</span>] = localiser
template[<span class="pystring">'subnav:stores'</span>] = [ ValueLocaliser(<span class="pystring">'Apparel &amp;amp; Accessories'</span>, href='http://localhost/amazon/stores/apparel'),
                              ValueLocaliser(<span class="pystring">'Beauty'</span>, href='http://localhost/amazon/stores/beauty'),
                              ValueLocaliser(<span class="pystring">'DVD\'s TV Central'</span>, href='http://localhost/amazon/stores/dvd'),
                              ValueLocaliser(<span class="pystring">'Electronics'</span>, href='http://localhost/amazon/stores/electronics'),
                              ValueLocaliser(<span class="pystring">'Gourmet Food'</span>, href='http://localhost/amazon/stores/food') ]

<span class="pycomment"># inject content for the books/music/dvd subsection</span>
template[<span class="pystring">'subnav:bmd'</span>] = [ ValueLocaliser(<span class="pystring">'Books'</span>, href=<span class="pystring">'http://localhost/amazon/bmd/books'</span>),
                           ValueLocaliser(<span class="pystring">'DVD'</span>, href='http://localhost/amazon/bmd/dvd'),
                           ValueLocaliser(<span class="pystring">'Magazine Subscriptions'</span>, href='http://localhost/amazon/bmd/subscriptions'),
                           ValueLocaliser(<span class="pystring">'Music'</span>, href='http://localhost/amazon/bmd/music'),
                           ValueLocaliser(<span class="pystring">'Video'</span>, href='http://localhost/amazon/bmd/video'),
                           ValueLocaliser(<span class="pystring">'Amazon Shorts'</span>, href='http://localhost/amazon/bmd/shorts'),
                           ValueLocaliser(<span class="pystring">'Textbooks'</span>, href='http://localhost/amazon/bmd/textbooks') ]

<span class="pycomment"># print out the result</span>
print <span class="pyname">str</span>(template)</code>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2006/05/29/templating-revisited/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Murphy&#8217;s Law example</title>
		<link>http://www.briggs.net.nz/log/2006/05/25/murphys-law-example/</link>
		<comments>http://www.briggs.net.nz/log/2006/05/25/murphys-law-example/#comments</comments>
		<pubDate>Thu, 25 May 2006 10:51:13 +0000</pubDate>
		<dc:creator>jrbriggs</dc:creator>
		
		<category><![CDATA[development]]></category>

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

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

		<guid isPermaLink="false">http://www.briggs.net.nz/log/2006/05/25/murphys-law-example/</guid>
		<description><![CDATA[No sooner have I set up a brand-spanking new site, than I am suddenly too busy to do anything with it.  Not only that, but I also gave myself a challenge to come up with an example of something better than the butt-ugly facelets/JSF templating, and I&#8217;ve had no time to do anything much [...]]]></description>
			<content:encoded><![CDATA[<p>No sooner have I set up a brand-spanking new site, than I am suddenly too busy to do anything with it.  Not only that, but I also gave myself a <a href="http://www.briggs.net.nz/log/2006/05/16/fugly-templating/">challenge</a> to come up with an example of something better than the butt-ugly facelets/JSF templating, and I&#8217;ve had no time to do anything much about that either.  I have, however, decided that trying to hack together Amazon page would be a good test of the layout concepts, especially taking into consideration how busy the Amazon front page is.  So I&#8217;ll document the process as I go&#8230; thinking aloud, so to speak.</p>
<p>I have hit one minor snag already.  I&#8217;ve used rparsexml.py in my hacked together template engine (a piece of python code that will admittedly never win any code-elegance competitions), only to discover (RTFM) it dumps html comment blocks &#8212; which is perhaps only a pain if you happen to wrap your embedded styles in comments.  So I haven&#8217;t entirely convinced myself that it&#8217;s not worth going back and revisiting the code with a better xml parser, motivation being in general short supply at the moment&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.briggs.net.nz/log/2006/05/25/murphys-law-example/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
