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

<channel>
	<title>Graceful Exits &#187; diagnostics</title>
	<atom:link href="http://www.jpstacey.info/blog/category/diagnostics/www.jpstacey.info/blog/category/diagnostics/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jpstacey.info/blog</link>
	<description>Garbage collection, in a very real sense</description>
	<pubDate>Thu, 14 Aug 2008 09:05:55 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>Trailing commas and unfeasibly high line numbers</title>
		<link>http://www.jpstacey.info/blog/2008/07/08/trailing-commas-and-unfeasibly-high-line-numbers/</link>
		<comments>http://www.jpstacey.info/blog/2008/07/08/trailing-commas-and-unfeasibly-high-line-numbers/#comments</comments>
		<pubDate>Tue, 08 Jul 2008 13:04:12 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/?p=179</guid>
		<description><![CDATA[Bursting IE's Javascript parser, or: generating bizarre error messages through subprocess apoptosis]]></description>
			<content:encoded><![CDATA[<p>In Javascript, trailing commas are to be considered harmful. Strictly speaking, they&#8217;re not allowed by the syntax, but this wouldn&#8217;t be such a problem were it not for the fact that some browsers (including Firefox) will quietly ignore them, pretending briefly that Javascript&#8217;s syntax is Pythonic or, um, Rubric. The safest route to take is to avoid trailing commas wherever possible. <a href="http://www.jpstacey.info/blog/2006/10/03/how-to-write-a-javascript-file/" >I&#8217;ve mentioned the general problem before</a>, and the hard core among you would probably go so far as to <a href="http://www.bofh.org.uk/articles/2008/04/16/a-quick-javascript-formatting-tip" >change their formatting to highlight trailing commas</a>.</p>
<p>But what makes it all far, far worse is that IE6 and IE7 can sometimes produce error messages which, as is usual for those browsers, contain no useful information whatsoever.</p>
<p>Here&#8217;s a recent example:</p>
<blockquote><p>
 Line: 64432871<br />
 Char: 2<br />
 Error: Expected identifier, string or number
</p></blockquote>
<p>See that impossibly high line number? That&#8217;s a result of the parser being struck soundly on the head by the syntax error, and consequently dribbling its way past the end of the Javascript file. IE&#8217;s incomprehensible &#8220;English&#8221; error message conspires with circumstance to make the whole report of no help at all.</p>
<p>Something like <a href="http://www.jslint.com/" >JSLint</a>, on the other hand, is of tremendous help, and we&#8217;ll be running as much Javascript through it as possible in future. JSLint is just as unforgiving, but as it&#8217;s reliably unforgiving and incredibly communicative with it then that&#8217;s a bonus rather than a detriment. </p>
<p>It&#8217;s sometimes a little too strict to be useful, complaining about implicit global variables (even when that variable is called <code>window</code>). My suggestion is to ignore those reports, though; but <em>watch those commas!</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/07/08/trailing-commas-and-unfeasibly-high-line-numbers/feed/</wfw:commentRss>
		</item>
		<item>
		<title>User loading and saving in Drupal 5.x</title>
		<link>http://www.jpstacey.info/blog/2008/06/09/user-loading-and-saving-in-drupal-5x/</link>
		<comments>http://www.jpstacey.info/blog/2008/06/09/user-loading-and-saving-in-drupal-5x/#comments</comments>
		<pubDate>Mon, 09 Jun 2008 15:48:48 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

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

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

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

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

		<category><![CDATA[5.x]]></category>

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/06/09/user-loading-and-saving-in-drupal-5x/</guid>
		<description><![CDATA[Workflows of Drupal's user load and save functionality: spot the hooks and win a programmatical prize.]]></description>
			<content:encoded><![CDATA[<p>Recently at <a href="http://torchbox.com/" >Torchbox</a> we&#8217;ve been looking into how to build extra functionality on top of Drupal users. The standard Drupal user object is a combination of the contents from the users table, plus any properties provided by the core <code>profile</code> module. This means that the Drupal user is a combination of rows (and admittedly deserialized, structured data) from a couple of tables in a relational database. </p>
<div style="float: right;"><a title="flowcharts of user_load and user_save" href="#user-flowcharts"><img src="/blog/files/drupal/core/drupal_user_teaser.gif" alt="flowcharts of user_load and user_save" width="145" height="184" /></a></div>
<p>That works just fine for most purposes, but we may have to bring in content from not just outside the core Drupal tables but outside the core database, and even on a remote server through webservices. To this end we&#8217;ve decomposed the core <code>user</code> module&#8217;s <code>user_load()</code> and <code>user_save()</code> functions. This helps us understand better both the workflow and at what points in it our own code can motor into life, query all those extra resources (or set those queries in motion), assemble the rest of the user++ object, and then hand control back over to Drupal.</p>
<p>For those who don&#8217;t know much about Drupal, its core has a <em>hook-based</em> API structure. At certain points in its workflow, it checks all the modules for functions following certain naming conventions (typically the module name followed by the hook name e.g. <code>mymodule_init</code> on response startup, or <code>mymodule_block</code> to return details about the module&#8217;s support for Drupal page furniture). Any matching hook functions are called in the order defined by module weightings, and then page processing will generally continue: you can crowbar a grind-to-a-halt <code>exit()</code> in your hook, but it&#8217;d be unwise, as you can never be sure what tidying up Drupal might need to do after your hook. Outside these hooks, your code has little control over Drupal&#8217;s core functioning, unless you stub out entirely the bits of core you need yourself, and get your request to use those bits instead.z</p>
<p>Because of the way they let your code tag along with Drupal&#8217;s powerful core, hooks are essential to developing modules in the most <em>Drupalish</em> way. With that in mind, <a name="user-flowcharts"></a>here are flow diagrams of the three basic aspects of user functionality&#8212;create new, load, save existing&#8212;lifted straight from examination of the code:</p>
<ul>
<li><a href="/blog/files/drupal/core/drupal_user_load.gif">Loading an existing user with user_load</a></li>
<li><a href="/blog/files/drupal/core/drupal_user_create.gif">Creating a user: saving a new user with user_save</a></li>
<li><a href="/blog/files/drupal/core/drupal_user_update.gif">Updating a user: saving an existing user with user_save</a></li>
</ul>
<p>Although you have to save a user before you can load them, I&#8217;ve put this functionality first in the above (admittedly unordered) list. There are two main reasons for this:</p>
<ol>
<li><code>user_save</code> actually calls <code>user_load</code> a number of times, once or twice, to &#8220;refresh&#8221; the user object</li>
<li><code>user_load</code> is a more primitive function and so bears examination first</li>
</ol>
<p>Stripped down, <code>user_load</code> consists of: querying the database for a core user record matching the search criteria; returning this and the extended profile data; unserializing a free-data field and inserting it into the user object; discovering user roles; <strong>triggering <code>hook_user('load')</code></strong> and returning the object (or boolean false, if no user found).</p>
<p>What this reveals (which I didn&#8217;t realise before) is that <em>the anonymous user is in the Drupal users table</em>, with ID=0. Otherwise, searching for this user would return no records, and the anonymous user object could not be instantiated. You could therefore attach rich data to the anonymous user, if you were in a hacky mood.</p>
<p>The two <code>user_save</code> workflows are fairly similar. Creating a user means obtaining an ID from the database: because some MySQL providers have poorer feature sets than others, referential integrity is ensured at the application level rather than the database level. In place of obtaining an ID, user update <strong>calls <code>hook_user('update')</code> to pre-process</strong> the user. Both workflows then set aside special fields, such as the user&#8217;s password, user roles and any profile fields managed by that module (determined from <code>user_fields()</code>). Then they save this data into the database in slightly different orders, with user creation <code>calling </code><code>hook_user('insert')</code> early on, and the update procedure <code>calling </code><code>hook_user('after_update')</code> much later in the process, just before determining the external authentication mappings (e.g. OpenID) and returning the user object.</p>
<p>What does this mean for us? Well, we&#8217;ll want varying amounts of data to piggyback on the core user object, so we have somewhere to cache it. Ideally this data won&#8217;t be summoned&#8212;brought out of the distributed data &#8216;cloud&#8217;&#8212;on every request/response cycle, so we&#8217;ll need to do some local cacheing, but not so much that we&#8217;ll get out of synch with the cloud (or that we&#8217;ll duplicate sensitive data). We think that, given the pair of hooks in <code>user_save</code> for existing users, we&#8217;ll have just enough leverage to do this: the first hook will effectively &#8220;tear down&#8221; our extra data, so we can do what we want with it, and store it somewhere temporarily; the second hook will &#8220;set up&#8221; the user for the rest of the request, by putting all that data back in. The existence of <code>user_load</code> within <code>user_save</code> complicates things somewhat, but at the same time it gives us some more wiggle room, because each call to that function fires another hook.</p>
<p>A Drupal hook is worth a thousand lines of module code, but they&#8217;re still a bit few and far between for some workflows. Hopefully the accompanying images will help anyone reading to find them, and ditch those thousand lines before they&#8217;re even written.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/06/09/user-loading-and-saving-in-drupal-5x/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Subversion log messages need not be set in stone</title>
		<link>http://www.jpstacey.info/blog/2008/01/14/subversion-log-messages-need-not-be-set-in-stone/</link>
		<comments>http://www.jpstacey.info/blog/2008/01/14/subversion-log-messages-need-not-be-set-in-stone/#comments</comments>
		<pubDate>Mon, 14 Jan 2008 12:17:23 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/01/14/subversion-log-messages-need-not-be-set-in-stone/</guid>
		<description><![CDATA[Simon Willison mentioned a while back a link to help on how to undo a svn commit in subversion (more a kind of internal branching than an actual undo, of course: but that&#8217;s subversion). That&#8217;s all very well, but how about undoing the log message for a particular commit?
Say you have a codebase that only [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://simonwillison.net/">Simon Willison</a> mentioned a while back a link to help on <a href="http://noehr.org/2007/12/undo_commit_in_subversion_svn_1.html">how to undo a svn commit</a> in subversion (more a kind of internal branching than an actual undo, of course: but that&#8217;s subversion). That&#8217;s all very well, but how about undoing the log message for a particular commit?</p>
<p>Say you have a codebase that only you&#8217;ve worked on, and the log messages are (to say the least) idiosyncratic. Worse, they might contain swear words like &#8220;p*mh*le,&#8221; &#8220;cl*ff-pr*nker&#8221; or &#8220;Gr**nsp*n.&#8221; How can you, for example, get rid of a bit of bitching between programmers like:</p>
<blockquote class="code"><p>
$ svn log -r 200<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
r200 | jps | 2007-05-30 14:50:56 +0100 (Wed, 30 May 2007) | 2 lines</p>
<p>oh for heaven&#8217;s sake - cacheing at view layer broke CSS!<br />
Which buffoon wrote l51-78, ***Malcolm***?<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;
</p>
</blockquote>
<p>The <code>svn propset</code> command in principle <a href="http://svnbook.red-bean.com/en/1.4/svn.ref.svn.c.propset.html" title="svn propset and logs">lets you change log messages</a>. However, most archives are set up to prevent this by default with &#8220;hooks.&#8221; You <em>can</em> alter the configuration of the archive to permit this, if you&#8217;ve got administrator&#8217;s access to the physical files of the archive. But if you&#8217;ve got that, then you can <a href="http://svnbook.red-bean.com/en/1.4/svn.reposadmin.maint.html#svn.reposadmin.maint.setlog" title="svnadmin setlog and logs">change the log message directly</a> with the <code>svnadmin setlog</code> command and the <code>-<!-- -->-bypass-hooks</code> option:</p>
<blockquote class="code"><p>
% echo &#8220;Fixed&#8221; &gt; /tmp/newlog.txt<br />
% svnadmin setlog -<!-- -->-bypass-hooks /home/svn/repositories/bluefish /tmp/newlog.txt -r 200
</p>
</blockquote>
<p>The advantage of this is that all hooks remain in place afterwards, so you don&#8217;t have to worry about re-securing the archive. As the link to the Redbean book up there states, though, be warned that <code>-<!-- -->-bypass-hooks</code> bypasses <em>all</em> hooks: if you have email alerts set up to report each submission, then they too will fail to fire. Another reason not to do it permanently, I suppose.</p>
<p>(And I don&#8217;t work with anyone called Malcolm.)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/01/14/subversion-log-messages-need-not-be-set-in-stone/feed/</wfw:commentRss>
		</item>
		<item>
		<title>&#8220;You have to have something bad happen to you&#8221;</title>
		<link>http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/</link>
		<comments>http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/#comments</comments>
		<pubDate>Mon, 07 Jan 2008 12:05:11 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/</guid>
		<description><![CDATA[Steve Yegge on code&#8217;s worst enemy:
&#8230; This brings us to the second obviously-bad thing that can go wrong with code bases: copy and paste. It doesn&#8217;t take very long for programmers to learn this lesson the hard way. It&#8217;s not so much a rule you have to memorize as a scar you&#8217;re going to get [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://steve-yegge.blogspot.com/">Steve Yegge</a> on <a href="http://steve-yegge.blogspot.com/2007/12/codes-worst-enemy.html">code&#8217;s worst enemy</a>:</p>
<blockquote><p>&#8230; This brings us to the second obviously-bad thing that can go wrong with code bases: copy and paste. It doesn&#8217;t take very long for programmers to learn this lesson the hard way. It&#8217;s not so much a rule you have to memorize as a scar you&#8217;re going to get whether you like it or not. Computers make copy-and-paste really easy, so every programmer falls into the trap once in a while. The lesson you eventually learn is that code always changes, always always always, and as soon as you have to change the same thing in N places, where N is more than 1, you&#8217;ll have earned your scar&#8230;.</p>
</blockquote>
<p>Code reuse is great, although some languages punish you for it: Coldfusion takes a performance hit on behalf of debug logging whenever it crosses a component boundary, even if debugging is turned off. And a lot of includes scattered across the place can make it difficult to track what&#8217;s going on (unless you use those very IDEs that Steve suggests treat code like heaps of dirt to be rearranged). I suppose ultimately it&#8217;s about developing an instinct for balancing short-term performance, ongoing maintainability and long-term scalability, and you only learn that by dint of many, many scars.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Checking the changes for many svn versions, one version at a time</title>
		<link>http://www.jpstacey.info/blog/2007/10/30/checking-the-changes-for-many-svn-versions-one-version-at-a-time/</link>
		<comments>http://www.jpstacey.info/blog/2007/10/30/checking-the-changes-for-many-svn-versions-one-version-at-a-time/#comments</comments>
		<pubDate>Tue, 30 Oct 2007 14:39:49 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/10/30/checking-the-changes-for-many-svn-versions-one-version-at-a-time/</guid>
		<description><![CDATA[Say you want to see both the log and diff of a given svn version, just the differences between it and the previous version, plus log message (i.e. what was committed, and why, for version NUM) The following will work at a bash command prompt:
$ r=NUM; rr=-r`expr $r - 1`:$r; svn log -r$r; svn diff [...]]]></description>
			<content:encoded><![CDATA[<p>Say you want to see both the log and diff of a given svn version, just the differences between it and the previous version, plus log message (i.e. what was committed, and why, for version NUM) The following will work at a bash command prompt:</p>
<blockquote class="code"><p>$ r=NUM; rr=-r`expr $r - 1`:$r; svn log -r$r; svn diff $rr</p>
</blockquote>
<p>It looks a bit unwieldy, but you can keep pressing the up arrow and home key, and re-editing NUM, multiple times to look at multiple changes:</p>
<blockquote class="code"><p>$ r=320; rr=-r`expr $r - 1`:$r; svn log -r$r; svn diff $rr<br />
 . . .<br />
 $ r=321; rr=-r`expr $r - 1`:$r; svn log -r$r; svn diff $rr<br />
 . . .<br />
 $ r=322; rr=-r`expr $r - 1`:$r; svn log -r$r; svn diff $rr
</p>
</blockquote>
<p>Also, you can automate your checking to loop gradually over a range of changes:</p>
<blockquote class="code"><p>$ for ((r=310;r&lt; =336;r+=1))<br />
 &gt; do rr=-r`expr $r - 1`:$r; svn log -r$r; svn diff $rr<br />
 &gt; cat -<br />
 &gt; done
</p>
</blockquote>
<p>Press CTRL-D whenever you&#8217;re finished looking at a given change, and the next change will come up. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/10/30/checking-the-changes-for-many-svn-versions-one-version-at-a-time/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Visualizing an application&#8217;s entire call stack</title>
		<link>http://www.jpstacey.info/blog/2007/09/05/visualizing-an-applications-entire-call-stack/</link>
		<comments>http://www.jpstacey.info/blog/2007/09/05/visualizing-an-applications-entire-call-stack/#comments</comments>
		<pubDate>Wed, 05 Sep 2007 10:34:43 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/09/05/visualizing-an-applications-entire-call-stack/</guid>
		<description><![CDATA[KentBye, Flickr user, has been playing with GraphViz. He&#8217;s used it to turn an XDebug output into a pretty visualization of Drupal&#8217;s call stack, or what functions call what functions during a typical Drupal request.
]]></description>
			<content:encoded><![CDATA[<p><a href="http://flickr.com/photos/kentbye/">KentBye</a>, Flickr user, has been playing with <a href="http://www.graphviz.org/">GraphViz</a>. He&#8217;s used it to turn an <a href="http://xdebug.org/">XDebug</a> output into <a href="http://flickr.com/photos/kentbye/1143104488/">a pretty visualization of Drupal&#8217;s call stack</a>, or what functions call what functions during a typical Drupal request.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/09/05/visualizing-an-applications-entire-call-stack/feed/</wfw:commentRss>
		</item>
		<item>
		<title>OpenSSH, Ubuntu popups and IPv6</title>
		<link>http://www.jpstacey.info/blog/2007/07/16/openssh-ubuntu-popups-and-ipv6/</link>
		<comments>http://www.jpstacey.info/blog/2007/07/16/openssh-ubuntu-popups-and-ipv6/#comments</comments>
		<pubDate>Mon, 16 Jul 2007 10:06:14 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[configuration]]></category>

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/07/16/openssh-ubuntu-popups-and-ipv6/</guid>
		<description><![CDATA[I have a couple of on-login tasks doing various distributed office jobs for me: one brought in all the networked drives from machines in this and the other office; the other backed up my locally stored email to the office server. Because my work rarely spans offices I don&#8217;t pay much attention to the former; [...]]]></description>
			<content:encoded><![CDATA[<p>I have a couple of on-login tasks doing various distributed office jobs for me: one brought in all the networked drives from machines in this and the other office; the other backed up my locally stored email to the office server. Because my work rarely spans offices I don&#8217;t pay much attention to the former; I pay even less to the latter. For various reasons I&#8217;m using ssh to make these connections&#8212;sshfs and duplicity over ssh, respectively&#8212;and I&#8217;ve found it easy enough to set up using keys on the two servers in <code>~/.ssh/authorized_keys</code> .</p>
<p>Until very recently all seemed to be going well with these two jobs, until I suddenly found a rash of OpenSSH popups appearing as Ubuntu struggled in the face of them to start. Often enough of them would appear that GNOME would panic and warn me that my keyboard might have been taken over by, I don&#8217;t know, aliens, or lolcats.</p>
<p>It turned out that my machine was presenting itself as IPv6-addressed to one server, on which the authorised key was only set up with the domain name and IPv4 expected values. This was quick to fix: I added the IPv6 address to the entry in authorized_keys and hey! presto, the automated tasks are now running with nary a whisper.</p>
<p>What&#8217;s more worrying is that, from the looks of my mail backups, they haven&#8217;t run since March. Presumably it&#8217;s only been a recent update to ssh on Ubuntu that has directed these password requests to the screen: until now they were probably being lost to /dev/null . So a change that I initially thought was a pain and had reconfigured what ssh was declaring was my machine&#8217;s IP address, could actually just have been a tightening-up of the error reporting; in the end I was very glad ssh had annoyed me so much, as the annoyance has potentially saved my email backups.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/07/16/openssh-ubuntu-popups-and-ipv6/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Taking Drupal to pieces</title>
		<link>http://www.jpstacey.info/blog/2007/04/17/taking-drupal-to-pieces/</link>
		<comments>http://www.jpstacey.info/blog/2007/04/17/taking-drupal-to-pieces/#comments</comments>
		<pubDate>Tue, 17 Apr 2007 15:36:36 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

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

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

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

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

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

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

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

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

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

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

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

		<category><![CDATA[open-source]]></category>

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2007/04/17/taking-drupal-to-pieces/</guid>
		<description><![CDATA[Since listening to Garrett Coakley speak at the first Geek Night on the topic of Drupal, I&#8217;ve been sniffing round that open-source CMS. He kindly came to speak to us again, and very inspiring it was too. We&#8217;re now having a deeper look at it, seeing what it can do, what are its strengths and [...]]]></description>
			<content:encoded><![CDATA[<p>Since listening to <a href="http://polytechnic.co.uk/">Garrett Coakley</a> speak at the first <a href="http://oxford.geeknights.net/">Geek Night</a> on the topic of <a href="http://drupal.org">Drupal</a>, I&#8217;ve been sniffing round that open-source CMS. He kindly came to speak to us again, and very inspiring it was too. We&#8217;re now having a deeper look at it, seeing what it can do, what are its strengths and weaknesses; that sort of thing.</p>
<p>Drupal is certainly very interesting. Its notion of presentation is remarkable in that, at a certain level, all content consists of homogeneous nodes, whether that consists of uploaded files, images, blog posts, taxonomy categories, or embedded YouTube videos. In addition its API for templating, both as a library of functions and as a workflow that one can hook into, probably rivals WordPress in its scope and power. At the same time, though, the implicit homogeneity makes it hard to structure fundamentally heterogeneous sites; and the API hooks are very difficult to unravel: frequently you&#8217;ll want to get at a function some ten levels deep, and probably three of those levels can be overridden by your own code, but which, and how?</p>
<p>I want to mention more at a later date, to do Drupal justice, but suffice it to say for now that the complex hierarchy of the hook-in workflow is almost entirely opaque in PHP, a language that provides rather terse error reporting, without the function <a href="http://uk.php.net/manual/en/function.debug-print-backtrace.php"><span class="code">debug_print_backtrace()</span></a>. Well worth a look if you&#8217;re debugging spaghetti-code, especially when all you can see is the <a href="http://drupal.org/node/135637">White Screen of Death</a>. Sprinkle it around as the gentle British rain from heaven: lightly, but often.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2007/04/17/taking-drupal-to-pieces/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Throw it all away!</title>
		<link>http://www.jpstacey.info/blog/2006/11/27/throw-it-all-away/</link>
		<comments>http://www.jpstacey.info/blog/2006/11/27/throw-it-all-away/#comments</comments>
		<pubDate>Mon, 27 Nov 2006 13:31:48 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2006/11/27/throw-it-all-away/</guid>
		<description><![CDATA[I&#8217;ve recently been experimenting with calling external commands (mplayer and lame, so you might be able to guess what I&#8217;ve been doing) from within a scripting language (Python, although it needn&#8217;t have been as it turns out). Bizarrely, the external commands&#x2014;argumentae intactae&#x2014;worked absolutely fine on their own, chained together by me, by hand. However, when [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently been experimenting with calling external commands (mplayer and lame, so you might be able to guess what I&#8217;ve been doing) from within a scripting language (Python, although it needn&#8217;t have been as it turns out). Bizarrely, the external commands&#x2014;argumentae intactae&#x2014;worked absolutely fine on their own, chained together by me, by hand. However, when executed in the scripted environment the command that produced large volumes of output was stalling at &#x2013;86.somethingMB, whereas the other command stalling at 7.737MB of output.</p>
<p>Very odd, I thought. Odder still that the higher-volume command was being permitted to write much bigger files before it stopped. So&#8230; it can&#8217;t be a limit imposed by Python on files creating runaway outputs. Unless it&#8217;s a bandwidth limit, so the second command was having its input stream throttled&#8230;. No documentation, though, and very few reports of the error on the web. So what could it be?</p>
<p>The external commands are opened with the <code>subprocess.Popen</code> method in Python, which lets you specify destinations for the three standard I/O streams: input, output and error. I tried setting the latter two to <code>None</code>. All the output from the child processes was splatted onto the screen, and lo! the Python script ran to its natural conclusion.</p>
<p>It turned out that both commands were producing an on-screen counter or ticker to denote progress, and as this was writing to standard output, the buffers provided by Python to collect output and errors were filling up. Once a command is told by the shell that it can no longer write into its output buffer then <a href="https://savannah.cern.ch/bugs/?func=detailitem&#38;item_id=17483" title="Obscure software development portal">it can end up stalling indefinitely</a> until the buffer is cleared!</p>
<p>When I added command-line parameters to turn the ticker off, and piped the output into files rather than into any temporary storage, the whole system ran very nicely indeed. I hope to publish it here soon.</p>
<p><b>Exit gracefully:</b> it&#8217;s not always possible to run external commands in ultra-quiet mode. The diagnostics they produce might be handy, so you can&#8217;t suppress them. However, unless you have a good reason to hang onto the output within your program&#x2014;post-processing, say, to extract meaningful error messages&#x2014;then you should be directing them to files. Also, look out for progress counters that don&#8217;t seem to cause very much output: just because the screen isn&#8217;t scrolling past doesn&#8217;t mean that the command-line program isn&#8217;t generating reams and reams of diagnostics onto the standard output and error streams. And if you direct them into a file then you could end up with a log of gibberish. Try to think in a single dimension and a single direction, like a stream of text: there&#8217;s no support for such cute rewind-and-rewrite diagnostics in logfiles.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2006/11/27/throw-it-all-away/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Testing across the CF/Java boundary</title>
		<link>http://www.jpstacey.info/blog/2006/11/23/testing-across-the-cfjava-boundary/</link>
		<comments>http://www.jpstacey.info/blog/2006/11/23/testing-across-the-cfjava-boundary/#comments</comments>
		<pubDate>Thu, 23 Nov 2006 15:54:16 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

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

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

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

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

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

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

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

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

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

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

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

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2006/11/23/testing-across-the-cfjava-boundary/</guid>
		<description><![CDATA[For reasons of speed I&#8217;m currently embedding Java in Coldfusion code. Given Coldfusion is built on Java, and can instantiate Java objects through createObject("java", class_name), you&#8217;d think that&#8217;d be reasonably easy. But the boundary between Coldfusion and Java is like the gap between two halves of a broken bone: jagged, bleeding-edged and painful when coerced [...]]]></description>
			<content:encoded><![CDATA[<p>For reasons of speed I&#8217;m currently embedding Java in Coldfusion code. Given Coldfusion is built on Java, and can instantiate Java objects through <code>createObject("java", class_name)</code>, you&#8217;d think that&#8217;d be reasonably easy. But the boundary between Coldfusion and Java is like the gap between two halves of a broken bone: jagged, bleeding-edged and painful when coerced into heavy lifting.</p>
<h3>Java nulls in Coldfusion</h3>
<p>The first problem is the Great Coldfusion Error, which is that Coldfusion has no concept of null. At least, it can&#8217;t differentiate natively between null and an empty string. So while you can&#8217;t explicitly tell if a Java method has returned null, and indeed there&#8217;s very little warning of a null appearing in your program&#8217;s collection of function pointers, the second line in the below will explode if there&#8217;s no associated helper for this object:</p>
<blockquote class="code"><p>
&lt;cfset java_object.getAssociatedHelper()&gt;<br />
&lt;cfset java_object.getAssociatedHelper().callHelperMethod()&gt;
</p>
</blockquote>
<p>If this threw a sensible error in a unit-testing environment I&#8217;d have solved the problem quickly, but more of that later. The way round this is to work <em>with</em> Coldfusion&#8217;s prediliction for (a) converting nulls to &#8220;&#8221; and (b) doing all sorts of type-casting on Java objects to integrate Java and CF at the scripting level. Therefore, a check of <code>Len(java_object.getAssociatedHelper())</code> before you proceed does what you might expect for nulls, yet is also happy when the Java method returns a non-null object.</p>
<h3>Errors from errors reporting on errors</h3>
<p>The second major problem is that of Coldfusion&#8217;s introspection. Coldfusion attempts to latch its metadata introspection methods onto Java objects&#x2014;including thrown Java exceptions&#x2014;wherever it thinks is possible. Sadly, that&#8217;s far more times than it actually is possible to provide introspection. This is made worse in a unit-testing environment, where introspection is used for reporting purposes. I&#8217;m using CFCUnit, which is fairly thorough, but would frequently fail with a generic error that I couldn&#8217;t trace at all:</p>
<blockquote class="code"><p>
coldfusion.runtime.java.MethodSelectionException: The selected method getDetail was not found.<br />
<i>Stack trace: all from files within CFCUnit</i>
</p>
</blockquote>
<p>I eventually worked out that Java&#8217;s XSLT engine wasn&#8217;t happy with an instance of the XSLT/XPath function <code>concat()</code> having only one argument; an error, moreover, that <code>xsltproc</code> failed to catch. The detail isn&#8217;t important, though, because you could see a getDetail error anywhere.</p>
<p>When you get this error, don&#8217;t bother with <code>cfdump</code>. That tag itself attempts introspection and throws the same generic error. Instead, use <code>cftry/cfcatch</code> to trap the error, and then dump that and quickly abort:</p>
<blockquote class="code"><p>
&lt;cftry&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;cfset java_object.thisThrowsAGetDetailException()&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;cfcatch&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cfdump var=&#8221;#CFCATCH#&#8221;&gt;&lt;cfabort&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/cfcatch&gt;<br />
&lt;/cftry&gt;
</p>
</blockquote>
<p>In a struct of structs of structs, of exceptions within exceptions within exceptions, I found it: <code>CFCATCH.Cause.Exception.Exception.LocationAsString</code> carried the precise location of the XSLT error in the file. Easy, when you know where to look.</p>
<p><b>Exit gracefully:</b> when Coldfusion calls up the underlying Java, often you don&#8217;t have all of the usual Coldfusion debugging toolkit at your disposal. This means that any introspection of obscure Java exceptions to see what&#8217;s going on will often lead to errors itself, masking the original problem. Let the system throw the error, because the thrown error will eventually bubble up as a Coldfusion struct, with everything else on the way reduced to &#8220;safe&#8221; Coldfusion data-types, suitable for introspection by <code>cfdump</code>. Although Coldfusion is built on Java, its knowledge of its own foundations is not innate: someone has had to build the CF/Java interface. Don&#8217;t expect it to be any stricter or more OO-robust than the rest of Coldfusion.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2006/11/23/testing-across-the-cfjava-boundary/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
