<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'><id>tag:blogger.com,1999:blog-8309163</id><updated>2007-12-28T18:08:49.423Z</updated><title type='text'>delete.me.uk</title><link rel='alternate' type='text/html' href='http://delete.me.uk/blog.html'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://delete.me.uk/blog.atom'/><author><name>Paul Sowden</name></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>23</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8309163.post-116228123493064665</id><published>2006-10-31T07:00:00.000Z</published><updated>2006-10-31T07:53:54.943Z</updated><title type='text'>Mozilla's Context Menus</title><content type='html'>&lt;h1&gt;Mozilla's Context Menus&lt;/h1&gt;

&lt;p&gt;Several years back I followed Mozilla's (the product now known as &lt;a href="http://www.mozilla.org/projects/seamonkey/"&gt;SeaMonkey&lt;/a&gt;) progress pretty closely and one person who's blog I followed was &lt;a href="http://mpt.net.nz/"&gt;Matthew Thomas&lt;/a&gt;, or as everyone seems to know him, MPT.  The guy pushed usuability and user interface design on bugzilla and God knows Mozilla needed it, the interface was quite simply horrible.

&lt;p&gt;I wasn't directly involved in any Mozilla development, past the odd bug report, so my perspective is very much as an outsider, but I gather that as Mozilla was open sourced most of the developers were those on the payroll of Netscape (which was now a division of AOL Time Warner).  The idea of open sourcing a project and instantly attracting developers who sacrafice their free time is flawed, however MPT was a guy who wasn't employed by Netscape but devoted time to helping with usability and triaging in bugzilla.

&lt;p&gt;Mozilla was an open source project but the original goal of the project was to drive the Netscape browser.  With all the contributors to Mozilla being employees of Netscape several desicions that went into the codebase, and notably the UI, were driven by Netscape without heedence of the community.

&lt;p&gt;One example of this, which has always stuck in my mind, is the context menus.  I'm not entirely sure of the story behind the context menus but &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=75338"&gt;bug 75338&lt;/a&gt; follows MPT's spec and related discussion.  After an extended period of time and several iterations a pretty darn beautifull &lt;a href="http://www.mozilla.org/projects/ui/menus/shortcut/"&gt;context menu specification&lt;/a&gt; is created (complete with classic mozilla.org banner) which is miles more elegant than the context menus which existed in Mozilla at the time.  I find these context menus amazingly well thought out and designed and I still think this spec is really something.

&lt;p&gt;This story doesn't have a happy ending, ultimately a Netscape engineer created a &lt;a href="http://www.mozilla.org/projects/ui/communicator/framework/contextmenus/cmrev2a.html"&gt;massively inferior spec&lt;/a&gt; which didn't change the menus too much (they still had the oh-so-useful "Set as Wallpaper" option) so the diehard faithful users wouldn't get too confused (what users?).  The Netscape spec was implemented and MPT got fed up of being ignored and jumped ship.

&lt;p&gt;The reason I am posting this is because I don't want to lose the link to MPT's context menu specification.  It made a real impression on me and I can only hope that when I come to create a UI it is as well planned and designed as this.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2006/10/mozillas-context-menus' title='Mozilla&apos;s Context Menus'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=116228123493064665' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/116228123493064665'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/116228123493064665'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-114609036312039018</id><published>2006-04-26T23:18:00.000+01:00</published><updated>2006-04-26T23:26:03.173+01:00</updated><title type='text'>rbNarcissus v0.2</title><content type='html'>&lt;h1&gt;rbNarcissus v0.2&lt;/h1&gt;

&lt;p&gt;I updated &lt;a href="http://idontsmoke.co.uk/2005/rbnarcissus/"&gt;rbNarcissus&lt;/a&gt; to a second version with a lot of jiggling so that it actually works when parsing anything that I tried to throw at it now.  I also stuck up an example script which shows how you can extract information by walking the parse tree.&lt;/p&gt;

&lt;p&gt;Running the Ruby parser over the Narcissus parser takes a second or two, so I don't think it's stunning performance wise.  Next I'd really love to have the time to look at creating a run time.  I'd also like to know enough Ruby to make it a module, but the reference seemed rather brief on the topic so I didn't really know where to run.&lt;/p&gt;</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2006/04/rbnarcissus-v02' title='rbNarcissus v0.2'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=114609036312039018' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114609036312039018'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114609036312039018'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-114540479554097276</id><published>2006-04-19T00:51:00.000+01:00</published><updated>2006-04-19T00:59:55.556+01:00</updated><title type='text'>Scope of Variables in JavaScript</title><content type='html'>&lt;h1&gt;Scope of Variables in JavaScript&lt;/h1&gt;

&lt;p&gt;A little piece of JavaScript trivia;  the scope of JavaScript variables is decided at parse time, not at run time, just like named functions.  An example:

&lt;pre&gt;&lt;span class="keyword"&gt;function&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;()&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt; foo &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;'bar'&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; foo&lt;/span&gt;
&lt;span class="cbracket"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The scope of the variable &lt;code&gt;foo&lt;/code&gt; is the function body, even though the variable is declared in the statement after an assigment to the variable.  It works in my the same way that this runs without error:

&lt;pre&gt;&lt;span class="keyword"&gt;function&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;()&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; bar &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;foo&lt;/span&gt;&lt;span class="symbol"&gt;();&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;function&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;foo &lt;/span&gt;&lt;span class="symbol"&gt;()&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;return&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;'baz'&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="cbracket"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Even though the function &lt;code&gt;foo&lt;/code&gt; is not defined in the code until after it is called, the parser picks up the name of the function so that the run time knows what to do.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2006/04/scope-of-variables-in-javascript' title='Scope of Variables in JavaScript'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=114540479554097276' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114540479554097276'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114540479554097276'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-114497722746658863</id><published>2006-04-14T01:57:00.000+01:00</published><updated>2006-04-14T02:18:04.436+01:00</updated><title type='text'>Variable Names vs. Argument Names in Spidermonkey</title><content type='html'>&lt;h1&gt;Variable Names vs. Argument Names in Spidermonkey&lt;/h1&gt;

&lt;p&gt;Spidermonkey, the JavaScript engine at the heart of Firefox and other Gecko browsers, treats  variables declared inline and those declared in the argument list differently.  I noticed this quirk a little while ago, and stumbled upon it again recently.  To demonstrate, first an example.&lt;/p&gt;

&lt;pre&gt;&lt;span class="keyword"&gt;function&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;foo &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;arg1&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;alert&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;arguments&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;]);&lt;/span&gt;
&lt;span class="normal"&gt; arg1 &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;'bar'&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;alert&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;arguments&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;]);&lt;/span&gt;
&lt;span class="cbracket"&gt;}&lt;/span&gt;

&lt;span class="function"&gt;foo&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="string"&gt;'test'&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;In this example the first alert box says 'test', however the second alert box says 'bar'.  This might not be what you expect and certainly isn't what I expected.  The variable &lt;code&gt;arg1&lt;/code&gt; is not just a reference to the object that was passed in.  Using the assigment operator doesn't just change the reference contained in the variable &lt;code&gt;arg1&lt;/code&gt; to point to another object, it also changes the &lt;code&gt;arguments&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;What I expected to happen, and what happens in other browsers would be more like this:&lt;/p&gt;

&lt;pre&gt;&lt;span class="keyword"&gt;function&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;foo &lt;/span&gt;&lt;span class="symbol"&gt;()&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; arg1 &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; arguments&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;];&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;alert&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;arguments&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;]);&lt;/span&gt;
&lt;span class="normal"&gt; arg1 &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;'bar'&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;alert&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;arguments&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;]);&lt;/span&gt;
&lt;span class="cbracket"&gt;}&lt;/span&gt;

&lt;span class="function"&gt;foo&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="string"&gt;'test'&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;With both the first and second alert boxes reading 'test' and the variable simply being a reference, independant of the reference in the &lt;code&gt;arguments&lt;/code&gt; array.&lt;/p&gt;

&lt;p&gt;Odd.&lt;/p&gt;</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2006/04/variable-names-vs-argument-names-in' title='Variable Names vs. Argument Names in Spidermonkey'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=114497722746658863' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114497722746658863'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114497722746658863'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-114467578263250576</id><published>2006-04-10T14:13:00.000+01:00</published><updated>2006-04-10T14:29:57.356+01:00</updated><title type='text'>innerHTML using a Pythonesque Template Object</title><content type='html'>&lt;h1&gt;innerHTML using a Pythonesque Template Object&lt;/h1&gt;

&lt;p&gt;There are becoming some increasingly prettier ways to hide away the verbosity of using the W3C's DOM to create anything more complicated than a single element, for example &lt;a href="http://www.vivabit.com/bollocks/2006/04/06/introducing-dom-builder"&gt;Vivabit's DOM Builder&lt;/a&gt;.  The other option, generously donated by Microsoft, is to just throw a HTML string at the &lt;code&gt;innerHTML&lt;/code&gt; attribute of any &lt;code&gt;Element&lt;/code&gt; object.

&lt;p&gt;As part of its standard library Python provides a &lt;a href="http://docs.python.org/lib/node109.html"&gt;Template&lt;/a&gt; class contained in the string module. This class makes it easy to construct templates which can be used over for several substitution operations, or just one.  Recently I've been using a JavaScript implementation to generate HTML strings for use with &lt;code&gt;innerHTML&lt;/code&gt;, letting me avoid the DOM.

&lt;p&gt;The object definition is given below.  It processes the string in the constructor, providing improved performance for multiple substitutions.

&lt;pre&gt;&lt;span class="keyword"&gt;function&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;Template &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;template&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;template &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; template&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;

&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; idpattern &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;new&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;RegExp&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="string"&gt;"^({("&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;+&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;idpattern &lt;/span&gt;&lt;span class="symbol"&gt;+&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;")})|("&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;+&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;idpattern &lt;/span&gt;&lt;span class="symbol"&gt;+&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;")"&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; parts &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;[];&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; i &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; j &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;while&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;((&lt;/span&gt;&lt;span class="normal"&gt;j &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;template&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;indexOf&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;delimiter&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; i&lt;/span&gt;&lt;span class="symbol"&gt;))&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;!=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;if&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;i &lt;/span&gt;&lt;span class="symbol"&gt;!=&lt;/span&gt;&lt;span class="normal"&gt; j&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;&lt;span class="normal"&gt; parts&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;push&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;template&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;substring&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;i&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; j&lt;/span&gt;&lt;span class="symbol"&gt;++));&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;

&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="comment"&gt;// check for an escaped delimiter, doubled up&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;if&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;template&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;charAt&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;j&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;==&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;delimiter&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="keyword"&gt;if&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;typeof&lt;/span&gt;&lt;span class="normal"&gt; parts&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;parts&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;length &lt;/span&gt;&lt;span class="symbol"&gt;-&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="symbol"&gt;]&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;==&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"string"&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;    parts&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;parts&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;length &lt;/span&gt;&lt;span class="symbol"&gt;-&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="symbol"&gt;]&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;+=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;delimiter&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;else&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;    parts&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;push&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;delimiter&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt;   i &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;++&lt;/span&gt;&lt;span class="normal"&gt;j&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;continue&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;

&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; result &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;template&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;substring&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;j&lt;/span&gt;&lt;span class="symbol"&gt;).&lt;/span&gt;&lt;span class="function"&gt;match&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;idpattern&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;if&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;result &lt;/span&gt;&lt;span class="symbol"&gt;==&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;null&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;throw&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;new&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;Error&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="string"&gt;"Invalid placeholder in string: index "&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;+&lt;/span&gt;&lt;span class="normal"&gt; i&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; key &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; result&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="symbol"&gt;]&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;||&lt;/span&gt;&lt;span class="normal"&gt; result&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="symbol"&gt;];&lt;/span&gt;
&lt;span class="normal"&gt;  parts&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;push&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;key&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;split&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="string"&gt;"."&lt;/span&gt;&lt;span class="symbol"&gt;));&lt;/span&gt;
&lt;span class="normal"&gt;  i &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; j &lt;/span&gt;&lt;span class="symbol"&gt;+&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;result&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="symbol"&gt;]&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;?&lt;/span&gt;&lt;span class="normal"&gt; result&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="symbol"&gt;].&lt;/span&gt;&lt;span class="normal"&gt;length &lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt; key&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;length&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;if&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;i &lt;/span&gt;&lt;span class="symbol"&gt;!=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;template&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;length&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;&lt;span class="normal"&gt; parts&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;push&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;template&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;substring&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;i&lt;/span&gt;&lt;span class="symbol"&gt;));&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;

&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;_compiled &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; parts&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="cbracket"&gt;}&lt;/span&gt;

&lt;span class="normal"&gt;Template&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="keyword"&gt;prototype&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;delimiter &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"$"&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt;Template&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="keyword"&gt;prototype&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;idpattern &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"[_A-z][._A-z0-9]*"&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;

&lt;span class="normal"&gt;Template&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="keyword"&gt;prototype&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;substitute &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;function&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;keys&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; str &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;""&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;

&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; i &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; part&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;while&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;part &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;_compiled&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;i&lt;/span&gt;&lt;span class="symbol"&gt;++])&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;if&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;typeof&lt;/span&gt;&lt;span class="normal"&gt; part &lt;/span&gt;&lt;span class="symbol"&gt;==&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"string"&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;&lt;span class="normal"&gt; str &lt;/span&gt;&lt;span class="symbol"&gt;+=&lt;/span&gt;&lt;span class="normal"&gt; part&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;else&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="keyword"&gt;for&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; j &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; value &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; keys&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;&lt;span class="normal"&gt; j &lt;/span&gt;&lt;span class="symbol"&gt;&amp;lt;&lt;/span&gt;&lt;span class="normal"&gt; part&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;length&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;&lt;span class="normal"&gt; j&lt;/span&gt;&lt;span class="symbol"&gt;++)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;    value &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; value&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;part&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;j&lt;/span&gt;&lt;span class="symbol"&gt;]];&lt;/span&gt;
&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt;   str &lt;/span&gt;&lt;span class="symbol"&gt;+=&lt;/span&gt;&lt;span class="normal"&gt; value&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;

&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;return&lt;/span&gt;&lt;span class="normal"&gt; str&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;This object is great to use with a response from one of Yahoo's API calls, formatting the JSON object.  An example implementation of the &lt;code&gt;showUrls&lt;/code&gt; from my &lt;a href="http://delete.me.uk/2006/04/yahoo-apis.html"&gt;previous post&lt;/a&gt; would like this:

&lt;pre&gt;&lt;span class="keyword"&gt;function&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;showUrls &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;result&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; link &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;new&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="function"&gt;Template&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="string"&gt;'\&lt;/span&gt;
&lt;span class="string"&gt;  &amp;lt;p&amp;gt;&amp;lt;a href="$ClickUrl" target="blank"&amp;gt;$Title&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;\&lt;/span&gt;
&lt;span class="string"&gt;    &amp;lt;span style="color: gray;"&amp;gt;$Note&amp;lt;/span&amp;gt;'&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; links &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"&amp;lt;div&amp;gt;"&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; results &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; result&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;ResultSet&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;Result&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; i &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; url&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;while&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;url &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; results&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;i&lt;/span&gt;&lt;span class="symbol"&gt;++])&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;&lt;span class="normal"&gt; links &lt;/span&gt;&lt;span class="symbol"&gt;+=&lt;/span&gt;&lt;span class="normal"&gt; link&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;substitute&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;url&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt; links &lt;/span&gt;&lt;span class="symbol"&gt;+=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"&amp;lt;/div&amp;gt;"&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;
&lt;span class="normal"&gt; $&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="string"&gt;"url_container"&lt;/span&gt;&lt;span class="symbol"&gt;).&lt;/span&gt;&lt;span class="normal"&gt;innerHTML &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; links&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="cbracket"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;One thing to be careful about here however is escaping the HTML and attributes correctly.  This is a poor man's E4X.

&lt;p&gt;I really need to get around to setting up a code repository so that it's easier for me to maintain my snippets online, rather than just posting them to my blog and letting them stale.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2006/04/innerhtml-using-pythonesque-template' title='innerHTML using a Pythonesque Template Object'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=114467578263250576' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114467578263250576'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114467578263250576'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-114435302014289580</id><published>2006-04-06T19:05:00.000+01:00</published><updated>2006-04-14T02:19:27.876+01:00</updated><title type='text'>Source Code Highlighting from the Clipboard on OS X</title><content type='html'>&lt;h1&gt;Source Code Highlighting from the Clipboard on OS X&lt;/h1&gt;

&lt;p&gt;So it doesn't get lost here is a command you can use to highlight source code on OS X:

&lt;pre&gt;$ pbpaste | \&lt;!-- a bug in blogger --&gt;
  tr '\r' '\n' | \&lt;!-- would cause the lines and slashes to be stripped --&gt;
  source-highlight --no-doc --css foo.css --src-lang js | \&lt;!-- if these comments weren't here! --&gt;
  pbcopy&lt;/pre&gt;

&lt;p&gt;First, &lt;code&gt;pbpaste&lt;/code&gt; pastes the contents of the clipboard (or pasteboard in Mac lingo) onto standard out.  We then pipe it to &lt;code&gt;tr&lt;/code&gt; which is a simple substitution command to replace the Mac line breaks with UNIX line breaks that &lt;code&gt;source-highlight&lt;/code&gt;, a GNU program, understands.  This is then piped through to &lt;a href="http://www.gnu.org/software/src-highlite/"&gt;&lt;code&gt;source-highlight&lt;/code&gt;&lt;/a&gt;, with options to format using CSS and a flag specifying the language (the CSS file name can be anything, it makes no difference with the &lt;code&gt;--no-doc&lt;/code&gt; flag).  Finally it's piped to &lt;code&gt;pbcopy&lt;/code&gt; which sticks it back onto the clipboard.  Easy!

&lt;p&gt;I had to install &lt;code&gt;source-highlight&lt;/code&gt; from source, the version on Fink was too old and didn't have the JS language definition (and what good is it without JavaScript!).  The only dependancy is &lt;a href="http://www.boost.org/"&gt;the Boost C++ RegExp library&lt;/a&gt;.  This isn't too hard to install; first you have to download the &lt;code&gt;bjam&lt;/code&gt; binary, a make tool, and use it to compile and install the Boost libraries.

&lt;p&gt;Lo and behold, highlighted source code.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2006/04/source-code-highlighting-from' title='Source Code Highlighting from the Clipboard on OS X'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=114435302014289580' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114435302014289580'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114435302014289580'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-114434596376906625</id><published>2006-04-06T18:29:00.000+01:00</published><updated>2006-04-06T19:01:47.136+01:00</updated><title type='text'>Yahoo! APIs</title><content type='html'>&lt;h1&gt;Yahoo! APIs&lt;/h1&gt;

&lt;p&gt;Yahoo! have recently been populating their &lt;a href="http://developer.yahoo.com/"&gt;developer page&lt;/a&gt; with an impressive array of APIs for folks to access the raw data from their various services, as well as their recent acquisitions.  The services are super easy to use too.

&lt;p&gt;When Google first announced their SOAP API to their search engine, while the data was there to be had, there was a large barrier to getting to it.  Yahoo's APIs can all be accessed using REST, which means simple &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; requests and as well as offering language neutral XML they also offer JSON and PHP formatted results.  For a Web developer constrained to a Web browser it doesn't get better than this, the APIs can be queried accross domains.

&lt;p&gt;Below is a simple object that I've been using to fire off requests to the Yahoo APIs.

&lt;pre&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; yApi &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt; IMAGE&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"http://api.search.yahoo.com/ImageSearchService/V1/imageSearch"&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;
&lt;span class="normal"&gt; RELATED&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"http://api.search.yahoo.com/WebSearchService/V1/relatedSuggestion"&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;
&lt;span class="normal"&gt; MYWEB_URL&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"http://api.search.yahoo.com/MyWebService/V1/urlSearch"&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;
&lt;span class="normal"&gt; MYWEB_TAG&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"http://api.search.yahoo.com/MyWebService/V1/tagSearch"&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;

&lt;span class="normal"&gt; defaults&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;  appid&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"idontsmoke"&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;
&lt;span class="normal"&gt; get&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;function&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;url&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; parameters&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="comment"&gt;// add in the defaults&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;for&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; key &lt;/span&gt;&lt;span class="keyword"&gt;in&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;defaults&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="keyword"&gt;if&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;parameters&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;key&lt;/span&gt;&lt;span class="symbol"&gt;]&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;==&lt;/span&gt;&lt;span class="normal"&gt; undefined&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;    parameters&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;key&lt;/span&gt;&lt;span class="symbol"&gt;]&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;defaults&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;key&lt;/span&gt;&lt;span class="symbol"&gt;];&lt;/span&gt;
&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt;  url &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;this&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;encode_url&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;url&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; parameters&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; script &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; document&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;createElement&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="string"&gt;"script"&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;span class="normal"&gt;  script&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;src &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; url&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt;  script&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;type &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"text/javascript"&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;
&lt;span class="normal"&gt;  document&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;getElementsByTagName&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="string"&gt;"head"&lt;/span&gt;&lt;span class="symbol"&gt;)[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;].&lt;/span&gt;&lt;span class="function"&gt;appendChild&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;script&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;
&lt;span class="normal"&gt; encode_url&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="keyword"&gt;function&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;url&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; parameters&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;  components &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;[];&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;for&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; key &lt;/span&gt;&lt;span class="keyword"&gt;in&lt;/span&gt;&lt;span class="normal"&gt; parameters&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;   values &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; parameters&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;key&lt;/span&gt;&lt;span class="symbol"&gt;];&lt;/span&gt;
&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="keyword"&gt;if&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;typeof&lt;/span&gt;&lt;span class="normal"&gt; parameters&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;key&lt;/span&gt;&lt;span class="symbol"&gt;]&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;!=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"array"&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;&lt;span class="normal"&gt; values &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;values&lt;/span&gt;&lt;span class="symbol"&gt;];&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="keyword"&gt;for&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;var&lt;/span&gt;&lt;span class="normal"&gt; i &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; len &lt;/span&gt;&lt;span class="symbol"&gt;=&lt;/span&gt;&lt;span class="normal"&gt; values&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;length&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;&lt;span class="normal"&gt; i &lt;/span&gt;&lt;span class="symbol"&gt;&amp;lt;&lt;/span&gt;&lt;span class="normal"&gt; len&lt;/span&gt;&lt;span class="symbol"&gt;;&lt;/span&gt;&lt;span class="normal"&gt; i&lt;/span&gt;&lt;span class="symbol"&gt;++)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt;    components&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;push&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;
&lt;span class="normal"&gt;     &lt;/span&gt;&lt;span class="function"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;key&lt;/span&gt;&lt;span class="symbol"&gt;)&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;+&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"="&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;+&lt;/span&gt;
&lt;span class="normal"&gt;     &lt;/span&gt;&lt;span class="function"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;values&lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="normal"&gt;i&lt;/span&gt;&lt;span class="symbol"&gt;]));&lt;/span&gt;
&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="keyword"&gt;return&lt;/span&gt;&lt;span class="normal"&gt; url &lt;/span&gt;&lt;span class="symbol"&gt;+&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"?"&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="symbol"&gt;+&lt;/span&gt;&lt;span class="normal"&gt; components&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;join&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="string"&gt;"&amp;amp;"&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;
&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;}&lt;/span&gt;

&lt;span class="cbracket"&gt;}&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Which can then be called using something like:

&lt;pre&gt;&lt;span class="normal"&gt;yApi&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="function"&gt;get&lt;/span&gt;&lt;span class="symbol"&gt;(&lt;/span&gt;&lt;span class="normal"&gt;yApi&lt;/span&gt;&lt;span class="symbol"&gt;.&lt;/span&gt;&lt;span class="normal"&gt;MYWEB_TAG&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="cbracket"&gt;{&lt;/span&gt;
&lt;span class="normal"&gt; yahooid&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt;  &lt;/span&gt;&lt;span class="string"&gt;"ashleysowden"&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;
&lt;span class="normal"&gt; tag&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt;      &lt;/span&gt;&lt;span class="symbol"&gt;[&lt;/span&gt;&lt;span class="string"&gt;"javascript"&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"awesome"&lt;/span&gt;&lt;span class="symbol"&gt;],&lt;/span&gt;
&lt;span class="normal"&gt; output&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt;   &lt;/span&gt;&lt;span class="string"&gt;"json"&lt;/span&gt;&lt;span class="symbol"&gt;,&lt;/span&gt;
&lt;span class="normal"&gt; callback&lt;/span&gt;&lt;span class="symbol"&gt;:&lt;/span&gt;&lt;span class="normal"&gt; &lt;/span&gt;&lt;span class="string"&gt;"showUrls"&lt;/span&gt;
&lt;span class="cbracket"&gt;}&lt;/span&gt;&lt;span class="symbol"&gt;);&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The only problem is I can't get the damn thing to respond with a list constrained to my Yahoo ID and the support channels for the APIs seem questionable at best.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2006/04/yahoo-apis' title='Yahoo! APIs'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=114434596376906625' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114434596376906625'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/114434596376906625'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-113529297769219778</id><published>2005-12-22T22:55:00.000Z</published><updated>2005-12-22T23:12:22.396Z</updated><title type='text'>JsBot, Jot and another Year</title><content type='html'>&lt;h1&gt;JsBot, Jot and another Year&lt;/h1&gt;

&lt;p&gt;So another year is coming to a close, and this one was pretty.  This summer saw me interning at &lt;a href="http://jot.com/"&gt;JotSpot&lt;/a&gt;, the premier Wiki company.  I got the opportunity to work out in San Francisco, California alongside some DHTML guys I've pseudo-known for 5 years; &lt;a href="http://alex.dojotoolkit.org/"&gt;Alex&lt;/a&gt; and &lt;a href="http://stilleye.com/"&gt;Dave "Schnotz"&lt;/a&gt;.  I also got the chance to meet some &lt;a href="http://youngpup.net/"&gt;other&lt;/a&gt; &lt;a href="http://troutgirl.com/blog/"&gt;cool&lt;/a&gt; &lt;a href="http://www.dylanschiemann.com/"&gt;people&lt;/a&gt; and drink lots of tequila, notably at the &lt;a href="http://renkoo.com/"&gt;Renkoo&lt;/a&gt; launch party.

&lt;p&gt;While at Jot I had the chance to work on the &lt;a href="http://dojotoolkit.org/"&gt;Dojo JavaScript toolkit&lt;/a&gt;, and helped to push its first release out of the door.  I ended up pouring hours and hours into it and my biggest contribution was the Jot sponsored RichText component which attempts to wrap up the WYSIWYG editing capabilities of the browsers in a lightweight way, without trying to push them where they don't want to go.  A horrible and thankless job, but what I feel turned out to be a rather reasonable output.  I also think its best moment is yet to come, we'll have to wait and see where.

&lt;p&gt;More recently I've wrapped up &lt;a href="http://www.jibble.org/pircbot.php"&gt;PircBot&lt;/a&gt; so as to allow IRC bots written in JavaScript, a fantastically flexible scripting language, dubbed &lt;a href="http://idontsmoke.co.uk/2005/jsbot/"&gt;JsBot&lt;/a&gt;.  It's another small project that I unfortuantly don't have the time to take anywhere as my final year at &lt;a href="http://www.soton.ac.uk/"&gt;university&lt;/a&gt; sucks up all my time.

&lt;p&gt;Moving onto next year, I finally pop out of my formal education and into the job market, we'll have to wait and see where that does take me.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2005/12/jsbot-jot-and-another-year' title='JsBot, Jot and another Year'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=113529297769219778' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/113529297769219778'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/113529297769219778'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-112321616941842773</id><published>2005-08-05T05:12:00.000+01:00</published><updated>2005-08-05T05:29:29.426+01:00</updated><title type='text'>rbnarcissus</title><content type='html'>&lt;h1&gt;rbNarcissus - JavaScript parsing in Ruby&lt;/h1&gt;

&lt;p&gt;So this weekend gone I decided it was about time for me to turn back to the server for a little action, having spent my life on the client for as long as I can remember now. I thought maybe I'd throw together a bit of &lt;abbr&gt;PHP&lt;/abbr&gt; and revel in the luxery of a &lt;code&gt;foreach&lt;/code&gt; statement. But I'm young and trendy, I script in Python, I've known JavaScript since &lt;abbr&gt;DHTML&lt;/abbr&gt; was teh sux0r. &lt;a href="http://troutgirl.com/blog/"&gt;Joyce&lt;/a&gt; mocked my plans for some &lt;abbr&gt;PHP&lt;/abbr&gt; loving, and suggested all the cool kids use Ruby, and Ruby on Rails. She then proceeded to ridicule me, and I caved; I'm not strong.

&lt;p&gt;So for the past couple of days I devoted my long long commute, sitting on the public transport system of San Francisco Bay Area, to learning a little Ruby and working on a script that lets me stay in reach of the familier and friendly world of JavaScript, a JavaScript parser. The result, a port of the Mozilla Foundation's &lt;a href="http://lxr.mozilla.org/mozilla/source/js/narcissus/jsparse.js"&gt;Narcissus JavaScript parser&lt;/a&gt; written in Ruby: &lt;a href="http://idontsmoke.co.uk/2005/rbnarcissus/"&gt;rbNarcissus&lt;/a&gt;.

&lt;p&gt;Currently only a parser with nary an interpreter in sight it has questionable use. It's also my first Ruby script and so probably doesn't follow the conventions amazingly well; I've still very much got my JavaScript hat on, waving the flag and singing the anthem (and plugging &lt;a href="http://dojotoolkit.org/"&gt;Dojo&lt;/a&gt;).</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2005/08/rbnarcissus' title='rbnarcissus'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=112321616941842773' title='2 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/112321616941842773'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/112321616941842773'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-111368172417104545</id><published>2005-04-16T19:19:00.000+01:00</published><updated>2005-04-17T01:16:21.986+01:00</updated><title type='text'>e4x</title><content type='html'>&lt;h1&gt;ECMAScript for &lt;abbr title="Extensible Markup Language"&gt;XML&lt;/abbr&gt; (&lt;abbr title="ECMAScript for XML"&gt;E4X&lt;/abbr&gt;): Debunking an example&lt;/h1&gt;

&lt;p&gt;I'd never heard of &lt;a href="http://www.ecma-international.org/publications/standards/Ecma-357.htm"&gt;&lt;abbr title="ECMAScript for XML"&gt;E4X&lt;/abbr&gt; (ECMAScript for &lt;abbr title="Extensible Markup Language"&gt;XML&lt;/abbr&gt;)&lt;/a&gt;, an extension to ECMAScript (JavaScript) specifically for handling data encumbered by &lt;abbr&gt;XML&lt;/abbr&gt;, before today. It was developed several years ago, has been adopted by &lt;a href="http://www.ecma-international.org/"&gt;Ecma&lt;/a&gt; and published in June 2004, and is apparently now implemented in Mozilla's products.

&lt;p&gt;The article I stumbled across is titled &lt;a href="http://dev2dev.bea.com/pub/a/2002/09/JSchneider_XML.html"&gt;Native XML Scripting in BEA WebLogic Workshop&lt;/a&gt; and offers an argument for the extension over using the standard JavaScript &lt;abbr title="Document Object Model"&gt;DOM&lt;/abbr&gt; bindings.

&lt;p&gt;Looking at the example scripts the article presents it's clear the &lt;abbr&gt;E4X&lt;/abbr&gt; notation is much cleaner and easier to work with; the &lt;abbr&gt;DOM&lt;/abbr&gt; oriented function is horrible and full of tree maneuvering (why didn't they use a &lt;a href="http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/traversal.html#Traversal-TreeWalker"&gt;&lt;code&gt;TreeWalker&lt;/code&gt;&lt;/a&gt; then?). Below is the short and sweet E4X function which completes the job outlined in the article.

&lt;pre class="code javascript"&gt;// the E4X function
function toHTML (srcDoc) {
    var destDoc = &amp;lt;html/&amp;gt;;

    for (var atom in srcDoc..ATOM) {
        var ptext = "";
        for(var item in atom.children()) {
            ptext += item + "\n";
        }
        destDoc[destDoc.length] = &amp;lt;P&amp;gt;{ptext}&amp;lt;/P&amp;gt;;
    }
    return destDoc;
}&lt;/pre&gt;

&lt;p&gt;The same job can apparently be accomplished using the function below, this time using DOM API calls to crawl the trees and create a document.

&lt;pre class="code java"&gt;// the original DOM function
public Document toHTML(Document srcDoc) throws Exception {
    Document destDoc = srcDoc.getImplementation().createDocument("","HTML",null);
    Node root = destDoc.getFirstChild();

    Node node = srcDoc.getFirstChild().getFirstChild();

    while (node != null) {
        if (node.getNodeName().equals("ATOM")) {
            Node pNode = destDoc.createElement("P");
            root.appendChild(pNode);

            Node tempNode = node.getFirstChild();
            while (tempNode != null) {
                if (tempNode.getNodeType() == Node.ELEMENT_NODE) {
                    Node n = tempNode.getFirstChild();
                    while (n != null) {
                        if (n.getNodeType() == Node.TEXT_NODE) {
                            Node tValue = destDoc.createTextNode(n.getNodeValue() + "\n");
                            pNode.appendChild(tValue);
                        }

                        n = n.getNextSibling();
                    }
                }

                tempNode = tempNode.getNextSibling();
            }
        }

        node = node.getNextSibling();
    }

    return destDoc;
 }&lt;/pre&gt;

&lt;p&gt;This code isn't JavaScript 1.5 (ECMAScript 3) and from the looks of it it's Java. Right away, this isn't comparing like with like, Java is much more verbose. Next the author has this to say about the example:

&lt;blockquote cite="http://dev2dev.bea.com/pub/a/2002/09/JSchneider_XML.html"&gt;
&lt;p&gt;[T]he logic of the program is almost completely overwhelmed and obscured by tree navigation logic and &lt;abbr&gt;DOM&lt;/abbr&gt; &lt;abbr&gt;API&lt;/abbr&gt; calls. Consequently, creating, reading, and maintaining the code is tedious, time consuming and error prone. In addition, the &lt;abbr&gt;DOM&lt;/abbr&gt; requires the programmer to learn and adopt a tree-based object model and a relatively extensive &lt;abbr&gt;API&lt;/abbr&gt; for performing operations on this object model.
&lt;/blockquote&gt;

&lt;p&gt;This is just plain unfair! The &lt;abbr&gt;DOM&lt;/abbr&gt; example is very poorly written. Rewriting the function, using JavaScript so as to align the goal posts, I came out with this:

&lt;pre class="code javascript"&gt;// my re-written DOM function
function toHtml(srcDoc) {
    var destDoc = srcDoc.implementation.createDocument(null,"html",null);

    var atoms = srcDoc.getElementsByTagName("ATOM"), atom;
    for (var i = 0; (atom = atoms[i]); i++) {
        var p = destDoc.createElement("p");
        destDoc.documentElement.appendChild(p);
    
        for (var j = 0, item; (item = atom.childNodes[j]); j++) {
            if (item.nodeType == Node.ELEMENT_NODE)
                p.textContent += item.textContent + "\n";
        }
    }
    return destDoc;
}&lt;/pre&gt;

&lt;p&gt;Now this is almost the same as the &lt;abbr&gt;E4X&lt;/abbr&gt; example. It only requires a tiny bit more work to mould it into a form using only the fragments of the &lt;abbr&gt;DOM&lt;/abbr&gt; current browsers support. The function is only 3 lines longer and to someone who knows the syntax for both languages, equally as readable. The biggest advantage the &lt;abbr&gt;DOM&lt;/abbr&gt; code holds, however, is that it will probably also be familiar to those who have used the &lt;abbr&gt;DOM&lt;/abbr&gt; in other languages (say, Java!).

&lt;p&gt;The &lt;abbr&gt;E4X&lt;/abbr&gt; example also appears to use an abbreviated version of the for statement which allows iteration of an array with unpacking of each element in the statement (&amp;#xE0; la Python). If we were able to use this then my function would look like this:

&lt;pre class="code javascript"&gt;function toHtml(srcDoc) {
    var destDoc = srcDoc.implementation.createDocument(null,"html",null);

    for (var atom in srcDoc.getElementsByTagName("ATOM")) {
        var p = destDoc.createElement("p");
        destDoc.documentElement.appendChild(p);
    
        for (var item in atom.childNodes) {
            if (item.nodeType == Node.ELEMENT_NODE)
                p.textContent += item.textContent + "\n";
        }
    }
    return destDoc;
}&lt;/pre&gt;

&lt;p&gt;So in terms of real difference, this function is really not any from that written using &lt;abbr&gt;E4X&lt;/abbr&gt;. The harshly worded statement in the article is founded on false claims and really just serves to stengthen the case for the author's baby.

&lt;p&gt;I'm not judging &lt;abbr&gt;E4X&lt;/abbr&gt; here, this is a very simplistic use case, and I don't know much about the syntax, but to argue for it's adoption by producing a shoddy example for the opposition is not really fair. The &lt;abbr&gt;DOM&lt;/abbr&gt; is not beautiful but neither is it ugly&amp;#x2014;at least give credit where credit is due.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2005/04/e4x' title='e4x'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=111368172417104545' title='2 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/111368172417104545'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/111368172417104545'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-111186674822198474</id><published>2005-03-26T19:40:00.000Z</published><updated>2005-03-28T20:28:01.920+01:00</updated><title type='text'>iso8601</title><content type='html'>&lt;h1&gt;Parsing &lt;abbr title="World Wide Web Consortium"&gt;W3C&lt;/abbr&gt;'s &lt;abbr title="International Standards Organisation"&gt;ISO&lt;/abbr&gt; 8601 Date/Times in JavaScript&lt;/h1&gt;

&lt;p&gt;Many standards all over the place use &lt;a href="http://www.w3.org/TR/NOTE-datetime"&gt;the &lt;abbr&gt;W3C&lt;/abbr&gt;'s subset of the &lt;abbr&gt;ISO&lt;/abbr&gt; 8601 standard&lt;/a&gt; to specify a date and time unambiguously. After a very brief search I couldn't find a simple JavaScript function to parse a string in this form, so here's one I wrote for the job. It should be bullet-proof and accept any correctly formatted date/time in the correct style.

&lt;pre class="javascript code"&gt;Date.prototype.setISO8601 = function (string) {
    var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
        "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
        "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
    var d = string.match(new RegExp(regexp));

    var offset = 0;
    var date = new Date(d[1], 0, 1);

    if (d[3]) { date.setMonth(d[3] - 1); }
    if (d[5]) { date.setDate(d[5]); }
    if (d[7]) { date.setHours(d[7]); }
    if (d[8]) { date.setMinutes(d[8]); }
    if (d[10]) { date.setSeconds(d[10]); }
    if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
    if (d[14]) {
        offset = (Number(d[16]) * 60) + Number(d[17]);
        offset *= ((d[15] == '-') ? 1 : -1);
    }

    offset -= date.getTimezoneOffset();
    time = (Number(date) + (offset * 60 * 1000));
    this.setTime(Number(time));
}&lt;/pre&gt;

&lt;p&gt;To use it you'll first have to create a &lt;code&gt;Date&lt;/code&gt; object and then invoke the method. The usage mirrors the &lt;code&gt;setTime&lt;/code&gt; method provided by the standard JavaScript &lt;code&gt;Date&lt;/code&gt; object.

&lt;pre class="javascript code"&gt;var date = new Date();
date.setISO8601("2005-03-26T19:51:34Z");&lt;/pre&gt;

&lt;p&gt;Simple. I guess this would fit nicely into a "standard hack" catagory, if there were such a thing.

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Having just tripped onto &lt;abbr title="British Summertime"&gt;BST&lt;/abbr&gt; I noticed the timezones weren't coming out correctly so I've fixed up the function and it should be right now. Working with timeshifts when your system is set to &lt;abbr&gt;UTC&lt;/abbr&gt; can make it all too easy to miss something.

&lt;p&gt;While I was at it I needed to go back again so here is the reverse function, &lt;code&gt;toISO8601String&lt;/code&gt;.

&lt;pre class="javascript code"&gt;Date.prototype.toISO8601String = function (format, offset) {
    /* accepted values for the format [1-6]:
     1 Year:
       YYYY (eg 1997)
     2 Year and month:
       YYYY-MM (eg 1997-07)
     3 Complete date:
       YYYY-MM-DD (eg 1997-07-16)
     4 Complete date plus hours and minutes:
       YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
     5 Complete date plus hours, minutes and seconds:
       YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
     6 Complete date plus hours, minutes, seconds and a decimal
       fraction of a second
       YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
    */
    if (!format) { var format = 6; }
    if (!offset) {
        var offset = 'Z';
        var date = this;
    } else {
        var d = offset.match(/([-+])([0-9]{2}):([0-9]{2})/);
        var offsetnum = (Number(d[2]) * 60) + Number(d[3]);
        offsetnum *= ((d[1] == '-') ? -1 : 1);
        var date = new Date(Number(Number(this) + (offsetnum * 60000)));
    }

    var zeropad = function (num) { return ((num &lt; 10) ? '0' : '') + num; }

    var str = "";
    str += date.getUTCFullYear();
    if (format &gt; 1) { str += "-" + zeropad(date.getUTCMonth() + 1); }
    if (format &gt; 2) { str += "-" + zeropad(date.getUTCDate()); }
    if (format &gt; 3) {
        str += "T" + zeropad(date.getUTCHours()) +
               ":" + zeropad(date.getUTCMinutes());
    }
    if (format &gt; 5) {
        var secs = Number(date.getUTCSeconds() + "." +
                   ((date.getUTCMilliseconds() &lt; 100) ? '0' : '') +
                   zeropad(date.getUTCMilliseconds()));
        str += ":" + zeropad(secs);
    } else if (format &gt; 4) { str += ":" + zeropad(date.getUTCSeconds()); }

    if (format &gt; 3) { str += offset; }
    return str;
}&lt;/pre&gt;

&lt;p&gt;This function takes two arguments, both optional. The first describes the format the resulting string should take, ie. how many components to include. This is an integer between 1 and 6, with the meanings listed above in the comment block. The second argument is an optional timezone offset. If it is not specified the timezone is set to &lt;abbr&gt;UTC&lt;/abbr&gt; using the &lt;code&gt;Z&lt;/code&gt; character. It takes the form &lt;code&gt;+HH:MM&lt;/code&gt; or &lt;code&gt;-HH:MM&lt;/code&gt;.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2005/03/iso8601' title='iso8601'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=111186674822198474' title='19 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/111186674822198474'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/111186674822198474'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-111082340618120183</id><published>2005-03-14T15:11:00.000Z</published><updated>2005-03-14T18:25:45.536Z</updated><title type='text'>xbox</title><content type='html'>&lt;h1&gt;Microsoft Gen '05 at Southampton&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://www.microsoft.com/uk/academia/gen05/"&gt;&lt;img src="/2005/03/gen05.jpeg" alt="Microsoft Gen'05 &amp;#187;"&gt;&lt;/a&gt;

&lt;p&gt;Last Wednesday the Microsoft propaganda machine &lt;a href="http://www.ecs.soton.ac.uk/news/693"&gt;descended upon our campus at the University of Southampton&lt;/a&gt; to pimp their latest products to us. As part of their &lt;a href="http://www.microsoft.com/uk/academia/"&gt;Academic Alliance&lt;/a&gt; they're pretty keen on getting us using everything Microsoft. The event was dubbed "Gen'05" although I'm not entirely sure what that's meant to mean. The banners read "creation generation events" which I guess is trying to be snazzy and cool. Inside there were a couple of stands showcasing the latest and greatest from everyone's favourite software company.

&lt;p&gt;I found it a little interesting, although probably not in the way Microsoft was intending. There seemed to be a focus on moving away from the PC, with Xboxen set up, some media centre thing and some portable devices running Windows Embedded (or what have you) among a few other stands. All the products were running on no-name hardware, it didn't look like Microsoft had a single big or reputable named supporter for any of it's "visions". We didn't stay very long and only really had a little play with the handheld PCs; the handwriting recognition was absolutely atrocious. All in all I wasn't overly impressed but neither was I surprised, I don't really expect much from Microsoft.

&lt;p&gt;Just before we left we had a quick chat with one of the recruiters who told us they were looking for marketing, sales and technical people, so we should be in with a chance! Lucky us. I can't say that the event or the marketing behind it has inspired me to work at Microsoft at all, so unfortuantly they're going to have to join the queue at the back. Sorry Microsoft!

&lt;p&gt;&lt;img src="/2005/03/tshirt.png" alt="" class="float"&gt;Anyway, the only reason we went in to the event at all was to pick up one the free T-shirts they were handing out. We were told we would get one if we handed in a quick questionnaire on our way out, having looked around. So, we went in and walked around as we were told and handed over our details in exchange for our "reserved 4 gr8ness" t-shirts (very nice, don't you think?). Apparently handing over our details also entered us to &lt;a href="http://www.microsoft.com/uk/academia/gen05/prizedraw/"&gt;a competition to win an Xbox&lt;/a&gt;. This morning, lo and behold, I got a call from Microsoft and it turns out I won the Xbox. yay me! These past couple of weeks are turning out to be pretty good and I'll soon be the owner of &lt;a href="http://www.xbox.com/en-GB/hardware/crystalconsole.htm"&gt;one ugly (but much appreciated) console&lt;/a&gt;.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2005/03/xbox' title='xbox'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=111082340618120183' title='1 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/111082340618120183'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/111082340618120183'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-110847384699986135</id><published>2005-02-12T14:37:00.000Z</published><updated>2005-02-21T21:55:19.933Z</updated><title type='text'>validation</title><content type='html'>&lt;h1&gt;&lt;abbr title="Hypertext Markup Language"&gt;HTML&lt;/abbr&gt; Validation&lt;/h1&gt;

&lt;p&gt;Over a week ago now &lt;a href="http://www.quirksmode.org/"&gt;&lt;abbr title="Peter-Paul Koch"&gt;PPK&lt;/abbr&gt;&lt;/a&gt; wrote an article for &lt;a href="http://alistapart.com/"&gt;A List Apart&lt;/a&gt; magazine entitled &lt;a href="http://www.alistapart.com/articles/scripttriggers/"&gt;JavaScript Triggers&lt;/a&gt; in which he described a method of providing additional information for a scripting layer to use. Basically, this information is whacked into attributes on your standard &lt;abbr&gt;HTML&lt;/abbr&gt; elements and become the &lt;q&gt;triggers&lt;/q&gt;. There is a warning included at the top of his article indicating that the subject may be controversial, as I can tell A List Apart has built itself around some pretty &lt;span title="read: anal"&gt;pedantic&lt;/span&gt; people :-). Alongside &lt;abbr&gt;PPK&lt;/abbr&gt;'s article was another, entitled &lt;a href="http://www.alistapart.com/articles/customdtd/"&gt;Validating a Custom &lt;abbr title="Document Type Definition"&gt;DTD&lt;/abbr&gt;&lt;/a&gt; from &lt;a href="http://catcode.com/index.html"&gt;J. David Eisenberg&lt;/a&gt;. It almost seemed to be hinting at saving grace on the part of &lt;abbr title="A List Apart"&gt;ALA&lt;/abbr&gt;; we did a bad but looky here.

&lt;h2&gt;Was &lt;abbr&gt;PPK&lt;/abbr&gt; right?&lt;/h2&gt;

&lt;p&gt;A few days after the article was published &lt;abbr&gt;PPK&lt;/abbr&gt; wrote an entry in &lt;a href="http://www.quirksmode.org/blog/"&gt;his blog&lt;/a&gt; to &lt;a href="http://www.quirksmode.org/blog/archives/2005/02/javascript_trig_1.html"&gt;wrap up the feedback&lt;/a&gt; he got on the subject of validation. There were a couple of points raised, some valid, some moot. In my opinion the correct solution is namespacing in the world of &lt;abbr title="Extensible Markup Language"&gt;XML&lt;/abbr&gt;, however this is not a real world solution, &lt;a href="http://www.microsoft.com/ie/" title="Internet Explorer"&gt;the 10lb gorilla&lt;/a&gt; doesn't support it so it isn't going to stick. The solution that seemed to hold the most weight is the use of custom &lt;abbr&gt;DTD&lt;/abbr&gt;s, these make your document validate and it works, best of both worlds! Well, actually, not.

&lt;h2&gt;Conformance with the &lt;abbr&gt;HTML&lt;/abbr&gt; specification&lt;/h2&gt;

&lt;p&gt;Most people's gold standard of validation is either the &lt;a href="http://validator.w3.org/"&gt;&lt;abbr title="World Wide Web Consortium"&gt;W3C&lt;/abbr&gt;'s validator&lt;/a&gt; or one of the other similar online services. It gives you a nice, official looking report with a clear message at the top of the document which tells you whether you got it right or wrong. All these validators sit atop of &lt;a href="http://openjade.sourceforge.net/" title="OpenSP"&gt;a newer version&lt;/a&gt; of &lt;a href="http://www.jclark.com/"&gt;James Clark&lt;/a&gt;'s &lt;a href="http://www.jclark.com/sp/"&gt;SP&lt;/a&gt;, pretty much the  defacto validating &lt;abbr title="Standard Generalised Markup Language"&gt;SGML&lt;/abbr&gt; parser. The fact that no one in the real world uses this parser almost makes them and the issue of validation entirely academic, but I'll come onto this later. My point right now is that these only check a document against it's &lt;abbr&gt;DTD&lt;/abbr&gt; to ensure validity.

&lt;p&gt;The &lt;a href="http://www.w3.org/TR/html4/"&gt;&lt;abbr&gt;HTML&lt;/abbr&gt; specification&lt;/a&gt; says:

&lt;blockquote cite="http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.1"&gt;
&lt;p&gt;Each markup language defined in &lt;abbr&gt;SGML&lt;/abbr&gt; is called an &lt;dfn&gt;&lt;abbr&gt;SGML&lt;/abbr&gt; application&lt;/dfn&gt;. An &lt;abbr&gt;SGML&lt;/abbr&gt; application is generally characterized by:

&lt;ol&gt;
&lt;li&gt;&lt;a href="http://www.w3.org/TR/html4/sgml/sgmldecl.html"&gt;An &lt;abbr&gt;SGML&lt;/abbr&gt; declaration&lt;/a&gt;. The &lt;dfn&gt;&lt;abbr&gt;SGML&lt;/abbr&gt; declaration&lt;/dfn&gt; specifies which characters and delimiters may appear in the application.
&lt;li&gt;&lt;a href="http://www.w3.org/TR/html4/sgml/dtd.html"&gt;A &lt;dfn&gt;document type definition&lt;/dfn&gt; (&lt;abbr&gt;DTD&lt;/abbr&gt;)&lt;/a&gt;. The &lt;abbr&gt;DTD&lt;/abbr&gt; defines the syntax of markup constructs. The &lt;abbr&gt;DTD&lt;/abbr&gt; may include additional definitions such as character entity references.
&lt;li&gt;A specification that describes the semantics to be ascribed to the markup. This specification also imposes syntax restrictions that cannot be expressed within the &lt;abbr&gt;DTD&lt;/abbr&gt;.
&lt;li&gt;Document instances containing data (content) and markup. Each instance contains a reference to the &lt;abbr&gt;DTD&lt;/abbr&gt; to be used to interpret it.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first two requirements are checked by the validator, however the third isn't. This third point is where strict conformance dies and your document essentially ceases to be an &lt;abbr&gt;HTML&lt;/abbr&gt; document.

&lt;p&gt;The &lt;abbr&gt;HTML&lt;/abbr&gt; specification includes a few appendices including &lt;a href="http://www.w3.org/TR/html4/appendix/notes.html#notes-invalid-docs"&gt;notes on invalid documents&lt;/a&gt; which outline what happens if your document isn't valid. It recommends (to &lt;abbr title="User Agents"&gt;UA&lt;/abbr&gt;s, not authors) that &lt;q&gt;if a user agent encounters an attribute it does not recognize, it should ignore the entire attribute specification (i.e., the attribute and its value)&lt;/q&gt;. This bodes well for our use case, however in a note to authors, directly underneath, it also states that &lt;q&gt;since user agents may vary in how they handle error conditions, authors and users &lt;a href="http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2119.html#sec-2"&gt;must not&lt;/a&gt; rely on specific error recovery behavior&lt;/q&gt; (where the definition of &lt;q&gt;must not&lt;/q&gt; is given by &lt;a href="http://www.ietf.org/rfc/rfc2119.txt" title="Key words for use in RFCs to Indicate Requirement Levels"&gt;&lt;abbr title="Request for Comments"&gt;RFC&lt;/abbr&gt; 2119&lt;/a&gt; and means &lt;q&gt;absolute prohibition&lt;/q&gt;, which is pretty final). So this method is definite no-no according to the specification.

&lt;p&gt;The same section also says that &lt;q&gt;for reasons of interoperability, authors &lt;a href="http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2119.html#sec-2"&gt;must not&lt;/a&gt; "extend" &lt;abbr&gt;HTML&lt;/abbr&gt; through the available &lt;abbr&gt;SGML&lt;/abbr&gt; mechanisms (e.g., extending the &lt;abbr&gt;DTD&lt;/abbr&gt;, adding a new set of entity definitions, etc.)&lt;/q&gt;. Again, this pretty clearly and cleanly cuts out J. David Eisenberg's method. If you do use his method to force &lt;abbr&gt;SGML&lt;/abbr&gt; validity you sacrifice your status as an &lt;abbr&gt;HTML&lt;/abbr&gt; document.

&lt;h2&gt;Is validation moot?&lt;/h2&gt;

&lt;p&gt;With all this heartache to fight for strict conformance to the &lt;abbr&gt;HTML&lt;/abbr&gt; specification, is it worth it? The other day I noticed &lt;a href="http://web-graphics.com/"&gt;Nate&lt;/a&gt; mention that validation is &lt;q cite="http://web-graphics.com/mtarchive/001493.php"&gt;a tool, not a label&lt;/q&gt;. I'm not entirely sure what that means, but I think the general meme is that if your document is parsed correctly in the major browsers, the final hurdle kind of becomes moot, it's just not worth the effort.

&lt;p&gt;From my standpoint I see the that purpose of strict validation is that all documents will become universally easy to parse and &lt;abbr&gt;UA&lt;/abbr&gt;s can simply use drop in parsers. It's the dream. At the moment we have to put a fantastic amount of work into producing &lt;a href="http://www.mozilla.org/"&gt;a really good parser&lt;/a&gt; that is up to the task of tackling the Web. This is not a good place to be. However, most people will tell you that this is &lt;em&gt;only&lt;/em&gt; a dream, it's not going to happen. The mindshare you would have to win to get there is awesome (not like the hotdogs). In my opinion the best we can do is to ensure content we produce is known good and accept the rest of the world just isn't going to get there.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2005/02/validation' title='validation'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=110847384699986135' title='2 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110847384699986135'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110847384699986135'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-110671408039562434</id><published>2005-01-26T02:59:00.000Z</published><updated>2005-02-21T22:06:03.463Z</updated><title type='text'>proxyicon</title><content type='html'>&lt;h1&gt;A Proxy File Widget&lt;/h1&gt;

&lt;p&gt;I seem to be becoming rather opinionated and very critical of my user interfaces. I'm not sure whether this is a good or a bad thing. The more opinionated I get about a subject the more I seek information with a slant and I tend to close my mind somewhat, which has got to be bad, although there's nothing like the ramblings of zealot to set me back on the straight. My experience with &lt;abbr title="Human Computer Interaction"&gt;HCI&lt;/abbr&gt; is a little limited, I only know what I've read on the Internet so I may be way out with some of my assumptions. Taking that onboard; I've been playing around with a proxy file widget.

&lt;p&gt;Both &lt;a href="http://developer.gnome.org/projects/gup/hig/2.0/"&gt;Gnome's &lt;abbr title="Human Interface Guidelines"&gt;HIG&lt;/abbr&gt;&lt;/a&gt; and &lt;a href="http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGIntro/chapter_1_section_1.html"&gt;OS X's &lt;abbr&gt;HIG&lt;/abbr&gt;&lt;/a&gt; recommend using an &lt;abbr title="Single Document Interface"&gt;SDI&lt;/abbr&gt;, where there is a one-to-one mapping between documents and windows. This enforces the desktop metaphor, the window effectively &lt;em&gt;is&lt;/em&gt; the document. Document windows in OS X have a small &lt;a href="http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGWindows/chapter_8_section_3.html#//apple_ref/doc/uid/20000961/TPXREF53"&gt;proxy icon&lt;/a&gt; in the title bar which allows you to directly manipulate the document via drag and drop and also view the document's path and open any folder along the way. The applications in Gnome use a variety of interfaces; one which uses the &lt;abbr&gt;SDI&lt;/abbr&gt; well is Eye of Gnome, the image viewer. My biggest frustration with Gnome's &lt;abbr&gt;SDI&lt;/abbr&gt; however, is that the metaphor stops there, the document is shown in the window, but there is no way of manipulating the document, hell, you can't even tell which document you're looking at once it's open. This is really an aside though, venting a frustration, I wanted to draw attention to OS X's proxy icons. Below is a screen capture with the path pop-up menu.

&lt;p class="figure"&gt;&lt;img src="/2005/01/osxproxyicon.png" alt="The path pop-up menu of OS X's proxy icons shows the path to the current file with each menu item opening a Finder window at that location." title="The pop-up path menu of proxy icons in OS X. It is activated by command-clicking the proxy icon."&gt;

&lt;p&gt;&lt;a href="http://www.gnome.org/projects/nautilus/"&gt;Nautilus&lt;/a&gt;, &lt;a href="http://www.gnome.org/"&gt;Gnome&lt;/a&gt;'s file manager, contains a widget which provides the same functionality as the &lt;q cite="http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGWindows/chapter_8_section_3.html#//apple_ref/doc/uid/20000961/TPXREF53"&gt;path pop-up menu&lt;/q&gt; that the proxy icon provides in OS X, allowing the user to jump up the folder hierarchy. It lives in the bottom left hand corner of every window and allows easy navigation up the filesystem. I don't think it's as good as OS X's&amp;mdash;the icons aren't present and the top level is printed as the forward slash character (urgh). The biggest difference between the two is that OS X's is top-down with the folder is at the top of the hierarchy, whereas Nautilus's is bottom-up, we're at the bottom of the hierarchy. I suspect that these designs came about partly from the position of the menu, being on the top of the window in OS X and the bottom in Gnome, causing both menus to pop-up over the current window. That aside, I think I prefer OS X's top-down view, giving the document the most importance as the current focus.

&lt;p class="figure"&gt;&lt;img src="/2005/01/nautilusmenu.png" alt="A pop-up path menu is provided in the bottom left hand corner of corner of every window in Nautilus, similar to that in OS X." title="The pop-up path menu in the corner of Nautilus windows. Not quite as sexy as OS X's"&gt;

&lt;p&gt;OS X appears to strive to hide the semantics of paths. That is, I can't think of anywhere where a path is printed in the form &lt;var&gt;/path/to/somewhere&lt;/var&gt;. If you didn't know beforehand, then from in everyday use you probably wouldn't be able to discern that the path separator was a forward slash "/". &lt;ins datetime=" 2005-01-26T05:44:00Z"&gt;(&lt;strong&gt;Update&lt;/strong&gt;: The Finder info window displays the path using a colon ":" as the separator, which previous Mac OS's used).&lt;/ins&gt; When the path in to a file is displayed in Finder arrow graphics are used to represent the path and each folder has a proxy icon. I think this is a Good Thing. Gnome's &lt;abbr&gt;HIG&lt;/abbr&gt; has a section which recommends providing &lt;a href="http://developer.gnome.org/projects/gup/hig/2.0/principles-direct-manipulation.html"&gt;direct manipulation&lt;/a&gt; and OS X's &lt;abbr&gt;HIG&lt;/abbr&gt; infers this with its entire &lt;a href="http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/index.html?http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGWindows/chapter_8_section_3.html"&gt;section on drag and drop&lt;/a&gt; (compared to the tiny section in Gnome's &lt;abbr&gt;HIG&lt;/abbr&gt; mentioning &lt;a href="http://developer.gnome.org/projects/gup/hig/2.0/input.html#drag-drop"&gt;drag and drop&lt;/a&gt;, which is pale in comparison). The proxy icons are a fantastic way of doing this, the icon &lt;em&gt;is&lt;/em&gt; &lt;span title="otherwise it wouldn't be a proxy icon!"&gt;(at least an intermediate to)&lt;/span&gt; the document and allows direct manipulation.

&lt;p&gt;All of that was a rather long winded way of saying that I've been toying with the idea of a little proxy file widget using &lt;a href="http://www.pygtk.org/"&gt;PyGTK&lt;/a&gt;. The idea would be to use this instead of the normal &lt;var&gt;/path/to/whereever/&lt;/var&gt; text. I've made a little prototype which is shown below. Currently the code just shows the pop-up, the file is made up. Unlike the widget in Nautilus it's not a button as it's meant to actually represent the file. I'm not sure whether it's taking it too far by adding drag and drop or just to leave it popping up the path menu when clicked. One solution around this wouldd be to use a modifier key or the right mouse button for one or the other, but one thing I've learnt is that this is a complete cop-out solution&amp;mdash;hiding functionality in a non-obvious way (which context menus actively encourage).

&lt;p class="figure"&gt;&lt;img src="/2005/01/filemenu.png" title="A proxy file widget: the icon is displayed next to the filename and a path pop-up is produced when the widget is clicked." alt=""&gt;

&lt;p&gt;As I said at the beginning of this rant, I'm not very experienced at &lt;abbr&gt;HCI&lt;/abbr&gt; design, I have no formal education in the subject, and while my widget may look pretty it could very well be crap from a &lt;abbr&gt;HCI&lt;/abbr&gt; perspective.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2005/01/proxyicon' title='proxyicon'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=110671408039562434' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110671408039562434'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110671408039562434'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-110504624364530315</id><published>2005-01-06T21:01:00.000Z</published><updated>2005-01-06T21:17:23.646Z</updated><title type='text'>wiki</title><content type='html'>&lt;h1&gt;&lt;abbr title="What You See Is What You Get"&gt;WYSIWYG&lt;/abbr&gt; Wiki Markup &amp;rarr; the &lt;abbr title="World Wide Web"&gt;WWW&lt;/abbr&gt;&lt;/h1&gt;

&lt;p&gt;If your Web browser had a previous knowledge of a wiki dialogue, which is entirely possible, they're not complex (by design), and was able to ascertain the &lt;code&gt;POST&lt;/code&gt; &lt;abbr&gt;URL&lt;/abbr&gt; to modify the wiki page by scanning the page for an edit link and taking a peek, then it is feasible that you should be able to modify the page inline and simply &lt;code&gt;POST&lt;/code&gt; it off to the server without ever having to know about the markup.

&lt;p&gt;Bam. Full circle. Well, almost; &lt;code&gt;PUT&lt;/code&gt; will have been shunned in favour of &lt;code&gt;POST&lt;/code&gt;, which all Web browsers actually contain support for. Odd, indeed.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2005/01/wiki' title='wiki'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=110504624364530315' title='3 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110504624364530315'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110504624364530315'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-110489100623310083</id><published>2005-01-05T02:07:00.000Z</published><updated>2005-01-05T02:10:06.233Z</updated><title type='text'>excessivetabs</title><content type='html'>&lt;h1&gt;Tabs, Tabs Everywhere&lt;/h1&gt;

&lt;p&gt;&lt;img src="/2005/01/tabs" alt="Gnome has far too many apps that utilise tabs!"&gt;

&lt;p&gt;Worst. Widget. Ever.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2005/01/excessivetabs' title='excessivetabs'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=110489100623310083' title='3 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110489100623310083'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110489100623310083'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-110433855175764040</id><published>2004-12-29T16:29:00.000Z</published><updated>2005-02-21T22:07:48.410Z</updated><title type='text'>fuzzytimepy</title><content type='html'>&lt;h1&gt;Fuzzy Time Python Function&lt;/h1&gt;

&lt;p&gt;Here is the Python function I've been using to fuzzy up time estimates, loosely inspired from the fuzzying function used in &lt;a href="http://www.mozilla.org/products/camino/"&gt;Camino&lt;/a&gt;.

&lt;pre class="python code"&gt;
&lt;span class="py_keyword"&gt;def&lt;/span&gt; &lt;span class="py_name"&gt;time&lt;/span&gt;&lt;span class="py_operator"&gt;(&lt;/span&gt;&lt;span class="py_name"&gt;seconds&lt;/span&gt;&lt;span class="py_operator"&gt;)&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt;
    &lt;span class="py_comment"&gt;# check for seconds first
&lt;/span&gt;    &lt;span class="py_keyword"&gt;if&lt;/span&gt; &lt;span class="py_name"&gt;seconds&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="py_number"&gt;60&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt;
        &lt;span class="py_keyword"&gt;if&lt;/span&gt; &lt;span class="py_name"&gt;seconds&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="py_number"&gt;13&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt;
            &lt;span class="py_keyword"&gt;if&lt;/span&gt; &lt;span class="py_name"&gt;seconds&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="py_number"&gt;7&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt; &lt;span class="py_name"&gt;seconds&lt;/span&gt; &lt;span class="py_operator"&gt;=&lt;/span&gt; &lt;span class="py_number"&gt;5&lt;/span&gt;
            &lt;span class="py_keyword"&gt;else&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt; &lt;span class="py_name"&gt;seconds&lt;/span&gt; &lt;span class="py_operator"&gt;=&lt;/span&gt; &lt;span class="py_number"&gt;10&lt;/span&gt;
            &lt;span class="py_keyword"&gt;return&lt;/span&gt; &lt;span class="py_string"&gt;"under %d seconds"&lt;/span&gt; &lt;span class="py_operator"&gt;%&lt;/span&gt; &lt;span class="py_name"&gt;seconds&lt;/span&gt;
        &lt;span class="py_keyword"&gt;return&lt;/span&gt; &lt;span class="py_string"&gt;"under a minute"&lt;/span&gt;

    &lt;span class="py_comment"&gt;# seconds becomes minutes and we keep checking
&lt;/span&gt;    &lt;span class="py_name"&gt;minutes&lt;/span&gt; &lt;span class="py_operator"&gt;=&lt;/span&gt; &lt;span class="py_name"&gt;seconds&lt;/span&gt;&lt;span class="py_operator"&gt;/&lt;/span&gt;&lt;span class="py_number"&gt;60.0&lt;/span&gt;
    &lt;span class="py_keyword"&gt;if&lt;/span&gt; &lt;span class="py_name"&gt;minutes&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="py_number"&gt;55&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt;
        &lt;span class="py_keyword"&gt;if&lt;/span&gt; &lt;span class="py_name"&gt;minutes&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="py_number"&gt;2&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt; &lt;span class="py_keyword"&gt;return&lt;/span&gt; &lt;span class="py_string"&gt;"about a minute"&lt;/span&gt;
        &lt;span class="py_keyword"&gt;return&lt;/span&gt; &lt;span class="py_string"&gt;"about %d minutes"&lt;/span&gt; &lt;span class="py_operator"&gt;%&lt;/span&gt; &lt;span class="py_name"&gt;minutes&lt;/span&gt;

    &lt;span class="py_comment"&gt;# this will never seemingly never end. now seconds become hours
&lt;/span&gt;    &lt;span class="py_name"&gt;hours&lt;/span&gt; &lt;span class="py_operator"&gt;=&lt;/span&gt; &lt;span class="py_name"&gt;minutes&lt;/span&gt;&lt;span class="py_operator"&gt;/&lt;/span&gt;&lt;span class="py_number"&gt;60.0&lt;/span&gt;
    &lt;span class="py_keyword"&gt;if&lt;/span&gt; &lt;span class="py_name"&gt;hours&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="py_number"&gt;48&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt;
        &lt;span class="py_keyword"&gt;if&lt;/span&gt; &lt;span class="py_name"&gt;hours&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="py_number"&gt;1.08&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt; &lt;span class="py_keyword"&gt;return&lt;/span&gt; &lt;span class="py_string"&gt;"about an hour"&lt;/span&gt;
        &lt;span class="py_keyword"&gt;elif&lt;/span&gt; &lt;span class="py_name"&gt;hours&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="py_number"&gt;1.92&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt; &lt;span class="py_keyword"&gt;return&lt;/span&gt; &lt;span class="py_string"&gt;"over an hour"&lt;/span&gt;
        &lt;span class="py_keyword"&gt;elif&lt;/span&gt; &lt;span class="py_name"&gt;hours&lt;/span&gt; &lt;span class="py_operator"&gt;%&lt;/span&gt; &lt;span class="py_number"&gt;1&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="py_number"&gt;0.08&lt;/span&gt; &lt;span class="py_keyword"&gt;or&lt;/span&gt; &lt;span class="py_name"&gt;hours&lt;/span&gt; &lt;span class="py_operator"&gt;%&lt;/span&gt; &lt;span class="py_number"&gt;1&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;gt;&lt;/span&gt; &lt;span class="py_number"&gt;0.92&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt;
            &lt;span class="py_keyword"&gt;if&lt;/span&gt; &lt;span class="py_name"&gt;hours&lt;/span&gt; &lt;span class="py_operator"&gt;%&lt;/span&gt; &lt;span class="py_number"&gt;1&lt;/span&gt; &lt;span class="py_operator"&gt;&amp;gt;&lt;/span&gt; &lt;span class="py_number"&gt;0.92&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt; &lt;span class="py_name"&gt;hours&lt;/span&gt; &lt;span class="py_operator"&gt;+=&lt;/span&gt; &lt;span class="py_number"&gt;1&lt;/span&gt;
            &lt;span class="py_keyword"&gt;return&lt;/span&gt; &lt;span class="py_string"&gt;"about %d hours"&lt;/span&gt; &lt;span class="py_operator"&gt;%&lt;/span&gt; &lt;span class="py_name"&gt;hours&lt;/span&gt;
        &lt;span class="py_keyword"&gt;else&lt;/span&gt;&lt;span class="py_operator"&gt;:&lt;/span&gt; &lt;span class="py_keyword"&gt;return&lt;/span&gt; &lt;span class="py_string"&gt;"over %d hours"&lt;/span&gt; &lt;span class="py_operator"&gt;%&lt;/span&gt; &lt;span class="py_name"&gt;hours&lt;/span&gt;

    &lt;span class="py_comment"&gt;# and the beat goes on, hours turn to days
&lt;/span&gt;    &lt;span class="py_keyword"&gt;return&lt;/span&gt; &lt;span class="py_string"&gt;"over %d days"&lt;/span&gt; &lt;span class="py_operator"&gt;%&lt;/span&gt; &lt;span class="py_operator"&gt;(&lt;/span&gt;&lt;span class="py_name"&gt;hours&lt;/span&gt; &lt;span class="py_operator"&gt;/&lt;/span&gt; &lt;span class="py_number"&gt;24&lt;/span&gt;&lt;span class="py_operator"&gt;)&lt;/span&gt;&lt;span class="py_text"&gt;&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;On a related note (and a shameless attempt to register both words with Google), when searching it still differentiates between the British spelling, &lt;a href="http://www.google.co.uk/search?q=humanise"&gt;humanise&lt;/a&gt;, and the American spelling, &lt;a href="http://www.google.co.uk/search?q=humanize"&gt;humanize&lt;/a&gt;. Not sure why you'd want to not get the results from both spellings, unless maybe you were looking for an entirely British opinion on the subject.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2004/12/fuzzytimepy' title='fuzzytimepy'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=110433855175764040' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110433855175764040'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110433855175764040'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-110426899244747462</id><published>2004-12-28T02:20:00.000Z</published><updated>2004-12-28T23:57:34.616Z</updated><title type='text'>fuzzytime</title><content type='html'>&lt;h1&gt;Humanising Date/times: Fuzzy Time&lt;/h1&gt;

&lt;p&gt;&lt;img src="/2004/12/timeremain.png" alt="" class="float"&gt;I first noticed this trend in Mac OS X's progress windows which would give "fuzzy" time estimates until completion, that is time esitmates of the form "about an hour" or "under a minute". My assertions are based only on assumptions, but I see this as good for two reasons. Firstly the time is usually only a fickle estimate with many variables so to give an estimate accurate to the second is misleading. Secondly the time is more human, that is your average human doesn't need to distinguish between, say, 58 minutes until completion and 56 minutes, or 1 minute, 15 seconds and 1 minutes, 11 seconds.
&lt;p&gt;Mac OS X will also give some date/times as relative to the present. That is, if the file was modified yesterday or today the date string will say yesterday or today instead of explicitly listing the day of the month as usual. Again, an assumption I'm making is that date/times are easier for a human to understand if there is some context, the context here being current time and also that small differences in time are usually moot. The only case I can think of off the top of my head where you would need an exact explicit date/time is if you are making a direct comparison with something, maybe another file or a record somewhere.
&lt;p&gt;This trend of using fuzzy and relative date/times seems to be a Good Thing, and it has been completely embraced by the Gnome desktop. (Although I can't see it explicitly stated in their &lt;a href="http://developer.gnome.org/projects/gup/hig/2.0/"&gt;&lt;abbr title="Human Interface Guidelines"&gt;HIG&lt;/abbr&gt;&lt;/a&gt; it is implied in the pictures, for &lt;a href="http://developer.gnome.org/projects/gup/hig/2.0/controls-progress-bars.html#time-remaining"&gt;time-remaining progress indicators&lt;/a&gt; for example, and it is also demonstrated in some applications, notably Nautilus.)
&lt;p&gt;This fuzzy formatting of date/times is also visible in the weblog community. The new thing that I noticed introduced here is demonstrated by &lt;a href="http://www.1976design.com/blog/"&gt;Dunstan Orchard of 1976design fame&lt;/a&gt; of &lt;a href="http://www.1976design.com/blog/archive/2004/07/23/redesign-time-presentation/"&gt;fuzzying relative to the time of day&lt;/a&gt;, introducing phrases like "early morning" and "late evening". This practice again humanises the times as (from my experience) we tend to think of time relative to the things we do or remember, which I would guess includes the environment. So a general timeframe of "late evening" means just as much at a glance as 22:11, but saves us the bother of having to think about it in terms of the time of day.
&lt;p&gt;One project that seems to be experimenting with relative times somewhat is &lt;a href="http://www.gnome.org/projects/beagle/" title="Beagle: A search tool for the Gnome desktop"&gt;Beagle&lt;/a&gt;. In some of &lt;a href="http://www.beaglewiki.org/index.php/BeagleScreenshots" title="Screecaps of Beagle"&gt;the screencaps&lt;/a&gt; you can see times like "4 days ago", which generally I think I'd find more human than a day of the month. I'm sure I've seen more screenshots posted on &lt;a href="http://planet.gnome.org/"&gt;&lt;abbr title="Planet Gnome"&gt;p.g.o&lt;/abbr&gt;&lt;/a&gt; but they seem to have escaped me (on a side note, a &lt;abbr title="Planet Gnome"&gt;p.g.o&lt;/abbr&gt; search engine would be really useful).
&lt;p&gt;I'm curious as to how far this can be extrapolated. Things like times which a minute ago read "today" now all read "yesterday" depending on which side of midnight you are on. For fuzzy times to work, the computer will have to think in fuzzy times, or times that are meaningful to the user. Also, how far can you extrapolate relative dates. Will including key dates help? If a file is marked as being last modified "Christmas Day" or "On Your Birthday", would this help the user to understand with less effort than simply saying "December, 25" or (in my case) "November, 17".
&lt;p&gt;On a related note I noticed a great suggestion, which seems pretty obvious in hindsight, made by &lt;a href="http://www.actsofvolition.com/"&gt;Steven Garrity&lt;/a&gt; that &lt;a href="http://www.actsofvolition.com/archives/2004/december/apluginideafor"&gt;&lt;abbr title="Instant Messenging"&gt;IM&lt;/abbr&gt; clients should display local time for the recipient&lt;/a&gt;. A simple but excellent idea.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2004/12/fuzzytime' title='fuzzytime'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=110426899244747462' title='3 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110426899244747462'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110426899244747462'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-110411647360503447</id><published>2004-12-27T02:42:00.000Z</published><updated>2004-12-27T03:05:23.573Z</updated><title type='text'>avalanche0.1</title><content type='html'>&lt;h1&gt;Avalanche 0.1: A BitTorrent Downloader for Gnome&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://idontsmoke.co.uk/2004/avalanche/"&gt;&lt;img src="http://idontsmoke.co.uk/2004/avalanche/screencap.small.png" alt="Avalanche BitTorrent Downloader for Gnome"&gt;&lt;/a&gt;
&lt;p&gt;In an almost unheard of flurry of activity I've posted another piece of Python I've spent some time on; &lt;a href="http://idontsmoke.co.uk/2004/avalanche/"&gt;Avalanche , A BitTorrent Downloader for Gnome&lt;/a&gt;.
&lt;p&gt;Many people complain about the cryptic names of software and in particular Open Source software is a pretty bad offender, however, when all the obvious names are taken what else are we to do? What I did was search in a thesaurus which produced a word which can be associated with "torrent" but still has seemingly little correlation to the function of the program.
&lt;p&gt;The thing I've tried to get with this application is absolute compliance with the &lt;a href="developer.gnome.org/projects/gup/hig/2.0/"&gt;Gnome &lt;abbr&gt;HIG&lt;/abbr&gt;&lt;/a&gt; along with some (hopefully) well placed information to produce a nice intuitive interface which provides everything you should need to monitor a download. Sounds a little like idealistic bullshit, but there you go. I think the interface has come out fairly well. I have been trying to outdo the already good &lt;a href="http://gnome-bt.sourceforge.net/"&gt;gnome-bt&lt;/a&gt; and a there's a couple of areas I think mine does better in.
&lt;p&gt;Everything you should would want in a glance (based on a use case involving only me, admittidly) is provided in the main window. Everything else is provided in a second informational window. The advantage of this is that all the information can be seen at once and only pertinent information is displayed by default. This is the biggest thing that irks me about tabs, and why I think Apple's Finder Info window is vastly superior to Nautilus's Tabbed Info window.
&lt;p&gt;I'm throwing this out into the world off the back of the open source cornerstone &lt;a href="http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html"&gt;release early, release often&lt;/a&gt; and hence this release has been dubbed "release early, release often". Theoretically this allows users to try it out and get hooked while I continue with development, although I'm not expecting much. While this release is "early", I'm not going to have much time in the immediate future to follow through and release often, so don't expect much for the moment.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2004/12/avalanche01' title='avalanche0.1'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=110411647360503447' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110411647360503447'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110411647360503447'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-110376026639067150</id><published>2004-12-22T23:53:00.000Z</published><updated>2004-12-23T00:11:22.586Z</updated><title type='text'>btpropertypage</title><content type='html'>&lt;h1&gt;BitTorrent Property Page for Nautilus&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://idontsmoke.co.uk/2004/btpropertypage/"&gt;&lt;img src="http://idontsmoke.co.uk/2004/btpropertypage/screencap.small.png" alt=""&gt;&lt;/a&gt;
&lt;p&gt;Hello, does anyone still read this? I'm a really terrible "blogger", but hey.
&lt;p&gt;While I should be busy doing my third year project and revising for my exams coming up in January I've been playing around with GTK programming, BitTorrent and Python. I've made a little script to show the information contained in BitTorrent 'metainfo' files as a Property Page tab in Nautilus. You can grab it over at &lt;a href="http://idontsmoke.co.uk/2004/btpropertypage/"&gt;idontsmoke&lt;/a&gt;.
&lt;p&gt;This was actually only a side track, I've been playing around with the idea of making a client, which sort of works, isn't finished and may never be. I'm slowly getting the hang of GTK, that's the part I spent the most time wrestling with to get this Property Page working. After having used Cocoa and Apple's Interface Builder it is very frustrating at times fighting with spacing and damn &lt;code&gt;GtkBox&lt;/code&gt;es using Glade and progmatically. Interface Builder makes it &lt;em&gt;very&lt;/em&gt; easy to make &lt;abbr&gt;HIG&lt;/abbr&gt; complient applications, whereas with Glade I'm still not sure of the best way  and I just seem to pad everything in &lt;code&gt;Gtk.Alignment&lt;/code&gt;s.
&lt;p&gt;The other thing I dislike about Gnome's &lt;abbr&gt;HIG&lt;/abbr&gt; is it seems to recommend everything is so spaced out, and every interface ends up looking big and clunky.
&lt;p&gt;Anyway, check out the &lt;a href="http://idontsmoke.co.uk/2004/btpropertypage/"&gt;Property Page&lt;/a&gt; and &lt;a href="mailto:paul@idontsmoke.co.uk"&gt;let me know&lt;/a&gt; what you think.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2004/12/btpropertypage' title='btpropertypage'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=110376026639067150' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110376026639067150'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/110376026639067150'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-109545949978641166</id><published>2004-09-17T23:17:00.000+01:00</published><updated>2004-09-17T23:21:29.623+01:00</updated><title type='text'>ieproto</title><content type='html'>&lt;h1&gt;Emulating Prototyping of &lt;abbr title="Document Object Model"&gt;DOM&lt;/abbr&gt; Objects in Internet Explorer&lt;/h1&gt;

&lt;p&gt;In Mozilla all &lt;abbr title="Document Object Model"&gt;DOM&lt;/abbr&gt; objects are native Javascript objects, which means we can easily use &lt;a href="http://www.mozilla.org/docs/dom/mozilla/protodoc.html"&gt;prototypes&lt;/a&gt; to add methods and properties to all instances of a &lt;abbr&gt;DOM&lt;/abbr&gt; class at once. This is very useful as it allows us to easily extend the functionality of &lt;abbr&gt;DOM&lt;/abbr&gt; objects. Unfortuantly there isn't such an easy way to do this in &lt;abbr title="Internet Explorer"&gt;IE&lt;/abbr&gt;, but we can emulate it by using behaviors and extending the &lt;a href="http://w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-2141741547"&gt;&lt;code&gt;document.createElement&lt;/code&gt; method&lt;/a&gt;.

&lt;p&gt;To illustrate my method I've written my own &lt;code&gt;getAttribute&lt;/code&gt; and &lt;code&gt;setAttribute&lt;/code&gt; functions to replace the pair provided in Internet Explorer which fix the problem of having to use &lt;a href="http://www.doxdesk.com/personal/posts/wd/20020617-dom.html"&gt;&lt;var&gt;className&lt;/var&gt; instead of &lt;var&gt;class&lt;/var&gt; and &lt;var&gt;htmlFor&lt;/var&gt; instead of &lt;var&gt;for&lt;/var&gt;&lt;/a&gt;. These need to be applied to every single &lt;abbr&gt;DOM&lt;/abbr&gt; object.

&lt;h2&gt;My methods&lt;/h2&gt;

&lt;p&gt;The two methods I'm implementing are part of the &lt;a href="http://w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-745549614"&gt;&lt;code&gt;Element&lt;/code&gt; interface&lt;/a&gt;, so I've created my own &lt;code&gt;Element&lt;/code&gt; class to contain them. The functions themselves are very simple and are  shown below.

&lt;pre class="code javascript"&gt;Element = function () {};

Element.prototype.getAttribute = function (attribute) {
    if (attribute == "class") attribute = "className";
    if (attribute == "for") attribute = "htmlFor";
    return this[attribute];
}

Element.prototype.setAttribute = function (attribute, value) {
    if (attribute == "class") attribute = "className";
    if (attribute == "for") attribute = "htmlFor";
    this[attribute] = value;
}&lt;/pre&gt;


&lt;h2&gt;How does it work&lt;/h2&gt;

&lt;p&gt;There are two places that &lt;abbr&gt;DOM&lt;/abbr&gt; objects come from:

&lt;ol&gt;
	&lt;li&gt;they're either present in the original document
	&lt;li&gt;or they are created using &lt;code&gt;document.createElement&lt;/code&gt;
&lt;/ol&gt;

&lt;p&gt;Adding methods and properties to elements created using the &lt;code&gt;document.createElement&lt;/code&gt; method is easy; all we have to do is extend this function, do our modifcations and return our new object. Adding methods and properties to the elements in the original document is a little harder, we have to process each one individually, which would involve walking through the whole document. Fortunatly Internet Explorer provides an easy way to extend the functionality of all elements on a page by using &lt;abbr&gt;DHTML&lt;/abbr&gt; behaviours.

&lt;h3&gt;Using Behaviours&lt;/h3&gt;

&lt;p&gt;&lt;abbr&gt;DHTML&lt;/abbr&gt; behaviours, like the &lt;a href="http://www.mozilla.org/"&gt;Mozilla project&lt;/a&gt;'s &lt;a href="http://www.w3.org/TR/xbl/"&gt;&lt;abbr title="XML Binding Language"&gt;XBL&lt;/abbr&gt;&lt;/a&gt;, allow you to bind Javascript (hence behaviours) to the &lt;abbr&gt;DOM&lt;/abbr&gt; elements in a document.

&lt;blockquote cite="http://msdn.microsoft.com/workshop/author/behaviors/behaviors_node_entry.asp" lang="en-us"&gt;
	&lt;p&gt;Dynamic HTML (&lt;abbr&gt;DHTML&lt;/abbr&gt;) behaviors are components that encapsulate specific functionality or behavior on a page. When applied to a standard &lt;abbr title="Hypertext Markup Language"&gt;HTML&lt;/abbr&gt; element on a page, a behavior enhances that element's default behavior.
&lt;/blockquote&gt;

&lt;p&gt;Behaviours can be bound to elements using either &lt;a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/behavior_1.asp" title="behavior CSS property"&gt;a &lt;abbr title="Cascading Style Sheets"&gt;CSS&lt;/abbr&gt; property&lt;/a&gt; or &lt;a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/addbehavior.asp" title="addBehavior method"&gt;progmatically using Javascript&lt;/a&gt;. This allows us to add Javascript methods and variables to all the &lt;abbr&gt;HTML&lt;/abbr&gt; objects in a document using a &lt;abbr&gt;CSS&lt;/abbr&gt; wildcard, &lt;a href="http://www.w3.org/TR/CSS21/selector.html#universal-selector" title="the Universal Selector, an asterisk (*)"&gt;the universal selector&lt;/a&gt;.

&lt;p&gt;The &lt;a href="http://msdn.microsoft.com/workshop/components/htc/reference/htcref.asp"&gt;&lt;abbr title="HTML Component"&gt;HTC&lt;/abbr&gt;&lt;/a&gt; file we need simply adds the two methods, which are just references to the methods we defined above. It would look something like this:

&lt;pre class="code htc"&gt;&amp;lt;PUBLIC:COMPONENT&amp;gt;
    &amp;lt;PUBLIC:METHOD NAME="getAttribute"
           INTERNALNAME="_getAttribute" /&amp;gt;
    &amp;lt;PUBLIC:METHOD NAME="setAttribute"
           INTERNALNAME="_setAttribute" /&amp;gt;

    &amp;lt;script type="text/javascript"&amp;gt;
        var el = new Element;
        _getAttribute = el.getAttribute;
        _setAttribute = el.setAttribute;
    &amp;lt;/script&amp;gt;
&amp;lt;/PUBLIC:COMPONENT&amp;gt;&lt;/pre&gt;

&lt;h3&gt;Extending &lt;code&gt;createElement&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;To extend the &lt;code&gt;createElement&lt;/code&gt; method we first have to store a reference to Internet Explorer's built in method. We then define our own method in place of the default one, calling the built in method to first create the element. After creating the element it's simply a case of adding our &lt;code&gt;Element&lt;/code&gt; interface, which includes the two methods I created above, and returning the new new element with our methods attached.

&lt;p&gt;The code to do this is pretty short and is shown below:

&lt;pre class="code javascript"&gt;var __IEcreateElement = document.createElement;

document.createElement = function (tagName) {
    var element = __IEcreateElement(tagName);

    var interface = new Element;
    for (method in interface)
        element[method] = interface[method];

    return element;
}&lt;/pre&gt;


&lt;h2&gt;Including the Files&lt;/h2&gt;

&lt;p&gt;Adding the required &lt;abbr&gt;CSS&lt;/abbr&gt; and Javascript to your documents is quick and painless, thanks to Internet Explorer's &lt;a href="http://msdn.microsoft.com/workshop/author/dhtml/overview/ccomment_ovw.asp"&gt;conditional comments&lt;/a&gt;, which allow authors to add &lt;abbr&gt;HTML&lt;/abbr&gt; hidden in specially formatted comment blocks. The snippet you'll need will look something like this:

&lt;pre class="code html"&gt;&amp;lt;!--[if IE]&amp;gt;
    &amp;lt;script type="text/javascript" src="attributes.js"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;style type="text/css"&amp;gt;
        * { behavior: url(attributes.htc); }
    &amp;lt;/style&amp;gt;
&amp;lt;![endif]--&amp;gt;&lt;/pre&gt;

&lt;p&gt;Here I've put the Javascript in a file named &lt;var&gt;attributes.js&lt;/var&gt; and the &lt;abbr&gt;HTC&lt;/abbr&gt; is in a file called &lt;var&gt;attributes.htc&lt;/var&gt;. The conditional comment ensures that only Internet Explorer downloads these files. This is should now allow us to access the &lt;code&gt;class&lt;/code&gt; and &lt;code&gt;for&lt;/code&gt; attributes using the &lt;code&gt;getAttribute&lt;/code&gt; and &lt;code&gt;setAttribute&lt;/code&gt; in all the modern browsers, including &lt;abbr&gt;IE&lt;/abbr&gt;.


&lt;h2&gt;Closure&lt;/h2&gt;

&lt;p&gt;Well, that's it, it's a pretty simple method which seems to work fairly well.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2004/09/ieproto' title='ieproto'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=109545949978641166' title='10 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/109545949978641166'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/109545949978641166'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-109534592164515223</id><published>2004-09-16T15:22:00.000+01:00</published><updated>2004-09-16T15:51:02.513+01:00</updated><title type='text'>addbehaviour</title><content type='html'>&lt;h1&gt;&lt;code&gt;addBehavior&lt;/code&gt; is psuedo Asynchronous&lt;/h1&gt;

&lt;p&gt;Microsoft's documentation for the &lt;a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/addbehavior.asp"&gt;&lt;code&gt;addBehavior&lt;/code&gt; method&lt;/a&gt; almost implies that the method is added to elements asynchronously. It says:

&lt;blockquote cite="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/addbehavior.asp" lang="en-us"&gt;&lt;p&gt;Unless the behavior specified in the &lt;code&gt;addBehavior&lt;/code&gt; call is one of the default behaviors built into Internet Explorer, the &lt;code&gt;addBehavior&lt;/code&gt; call causes Internet Explorer to download the behavior asynchronously, before the behavior is attached to the element.&lt;/blockquote&gt;

&lt;p&gt;This sentence is a little ambiguous; it could mean that the behaviour is only downloaded asynchronously and then applied to the element synchronously, or that the entire method is asynchronous, downloading and all. The next paragraph in the documentation starts &lt;q cite="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/addbehavior.asp" lang="en-us"&gt;Due to the asynchronous nature of the &lt;code&gt;addBehavior&lt;/code&gt; method, its return value cannot be relied on [...]&lt;/q&gt;, although all that can be deduced from this is that the method is not blocking, which is quite true.

&lt;p&gt;If we require any of the methods the &lt;a href="http://msdn.microsoft.com/workshop/author/behaviors/overview.asp" title="Introduction to DHTML Behaviours in Internet Explorer"&gt;behaviour&lt;/a&gt; implements then it would be very useful if the &lt;code&gt;addBehavior&lt;/code&gt; method was blocking, or if we could make it blocking. If it was actually asynchronous we could simply wait until the methods we want to use are added, probably by sitting in a while loop. Unfortuantly this doesn't seem to work, Internet Explorer will just sit in a loop forever more.

&lt;p&gt;I'm not sure what this implies about the synchronous nature of the &lt;code&gt;addBehavior&lt;/code&gt; method, but any methods added using behaviours are not exposed during the same execution path the &lt;code&gt;addBehavior&lt;/code&gt; call was made, so as far as I am concerned this method is only pseudo asynchronous.

&lt;p&gt;If you need to wait for a behaviour to be added then one way is to listen for the &lt;a href="http://msdn.microsoft.com/workshop/components/htc/reference/events/oncontentready.asp"&gt;oncontentready event&lt;/a&gt; using the &lt;a href="http://msdn.microsoft.com/workshop/components/htc/reference/elements/attach.asp"&gt;&lt;code&gt;PUBLIC:ATTACH&lt;/code&gt; element&lt;/a&gt; in your &lt;a href="http://msdn.microsoft.com/workshop/components/htc/reference/htcref.asp"&gt;&lt;abbr title="Hypertext Markup Language"&gt;HTML&lt;/abbr&gt; Component file&lt;/a&gt;; when this is called your behaviours should be there and exposed.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2004/09/addbehaviour' title='addbehaviour'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=109534592164515223' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/109534592164515223'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/109534592164515223'/><author><name>Paul Sowden</name></author></entry><entry><id>tag:blogger.com,1999:blog-8309163.post-109510229473384068</id><published>2004-09-13T19:58:00.000+01:00</published><updated>2004-09-13T20:11:50.960+01:00</updated><title type='text'>blogger</title><content type='html'>&lt;h1&gt;Blogger with Comments&lt;/h1&gt;

&lt;p&gt;I've moved back over to using &lt;a href="http://www.blogger.com/"&gt;Blogger&lt;/a&gt; to publish content on this site. This way I can easily allow anyone to comment, although the Blogger interface seems to hold a prejudice against those who don't have a Blogger account, forcing posts labelled as &lt;abbr title="Anonymous Coward"&gt;AC&lt;/abbr&gt;.
&lt;p&gt;I imagine, as always, a sparadic littering of updates administered to this site, however I wanted to get it active again so I can throw the things I'm working on out there for comment. There are a couple of coding enterprises (actually, countless) that I have undertaken, with the probability of any tangible peice of software being produced pretty damn low, but I'd like to share my ideas and see if anything would actually float.</content><link rel='alternate' type='text/html' href='http://delete.me.uk/2004/09/blogger' title='blogger'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8309163&amp;postID=109510229473384068' title='1 Comments'/><link rel='replies' type='application/atom+xml' href='http://delete.me.uk/blog.atom' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/109510229473384068'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8309163/posts/default/109510229473384068'/><author><name>Paul Sowden</name></author></entry></feed>