<?xml version="1.0" encoding="utf-8"?>
<!-- generator="wordpress/2.0.11" -->
<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/"
	>

<channel>
	<title>rephrase</title>
	<link>http://rephrase.net/days</link>
	<description>trees overt</description>
	<pubDate>Tue, 27 May 2008 12:02:33 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.0.11</generator>
	<language>en</language>
			<item>
		<title>Mrs. Gamely&#8217;s Words</title>
		<link>http://rephrase.net/days/08/04/mrs-gamelys-words</link>
		<comments>http://rephrase.net/days/08/04/mrs-gamelys-words#comments</comments>
		<pubDate>Wed, 30 Apr 2008 13:56:08 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
		
		<category>wordplay</category>

		<category>books</category>

		<category>Mark Helprin</category>

		<category>Winter's Tale</category>

		<category>vocabulary</category>

		<guid isPermaLink="false">http://rephrase.net/days/08/04/mrs-gamelys-words</guid>
		<description><![CDATA[Mark Helprin&#8217;s Winter&#8217;s Tale is a delight, even if its apparent themes are little more than an excuse for the wordplay window-dressing. I might not have found perfect justice, but a hall of light and mirrors built from language is quite enough for me.

One thing that needled, not being the sort to read with dictionary [...]]]></description>
			<content:encoded><![CDATA[<p>Mark Helprin&#8217;s <a href="http://www.amazon.com/Winters-Tale-Mark-Helprin/dp/0156031191/">Winter&#8217;s Tale</a> is a delight, even if its apparent themes are little more than an excuse for the wordplay window-dressing. I might not have found perfect justice, but a hall of light and mirrors built from language is quite enough for me.</p>

<p>One thing that needled, not being the sort to read with dictionary in hand, was this:</p>

<blockquote><p>Though Mrs. Gamely was by all measures prescientific and illiterate, she did know words. Where she got them was anyone&#8217;s guess, but she certainly had them. Virginia speculated that the people on the north side of the lake, steeped in variations of English both tender and precise, had made with their language a tool with which to garden a perfect landscape. Those who are isolated in small settlements may not know of the complexities common to great cities, but their hearts are rich, and so words are generated and retained. Mrs. Gamely&#8217;s vocabulary was enormous. She knew words no one had ever heard of, and she used words every day that had been mainly dead or sleeping for hundreds of years. Virginia checked them in the Oxford dictionary, and found that (almost without exception) Mrs. Gamely&#8217;s usage was flawlessly accurate. For instance, she spoke of certain kinds of dogs as Leviners. She called the areas near Quebec march-lands. She referred to diclesiums, liripoops, rapparees, dagswains, bronstrops, caroteels, opuntias, and soughs. She might describe something as patibulary, fremescent, pharisaic, Roxburghe, or glockamoid, and words like mormal, jeropigia, endosmic, mage, palmerin, thos, vituline, Turonian, galingale, comprodor, nox, gaskin, secotine, ogdoad, and pintulary fled from her lips in Pierian saltarellos. Their dictionary looked like a sow&#8217;s ear, because Virginia spent inordinate proportions of her days racing through it, though when Mrs. Gamely was angry a staff of ten could not have kept pace with her, and half a dozen linguaphologists would have collapsed from hypercardia.</p></blockquote>

<p>&mdash; <cite>Winter&#8217;s Tale</cite> (New York: Harvest, 2005), 225-226</p>

<p>For reference (thanks, <cite>Oxford English Dictionary</cite>!):</p>

<dl>

<dt>Leviner</dt>
<dd>? (presumably not from &#8220;levin&#8221;, to emit flashes of lightning)</dd>

<dt>march-land</dt>
<dd>a border territory</dd>

<dt>diclesium</dt>
<dd>botanical term for a kind of dry, seed-retaining fruit</dd>

<dt>liripoop</dt>
<dd>part of a graduate&#8217;s hood in early academic costume; later (presumably by derivation) &#8220;to have [one&#8217;s] liripoop&#8221; was to have learned a lesson or part</dd>

<dt>rapparee</dt>
<dd>a 17th-century Irish pikeman; later an Irish bandit</dd>

<dt>dagswain</dt>
<dd>a kind of rough bed-cover</dd>

<dt>bronstrops (singular)</dt>
<dd>a female procuress [of sexual services]</dd>

<dt>caroteel</dt>
<dd>an old commercial measure of quantity (&#8221;a caroteel of cloves&#8221;)</dd>

<dt>opuntia</dt>
<dd>originally a Greek herb; later an American cactus</dd>

<dt>sough</dt>
<dd>a whisper or murmur or breath; or, a drain or swampy place; or, a ploughshare</dd>

<dt>patibulary</dt>
<dd>of or relating to a gallows (patibulum: fork-shaped gibbet)</dd>

<dt>fremescent</dt>
<dd>growing noisy</dd>

<dt>pharisaic</dt>
<dd>of the Pharisees, hence legalistic, self-righteous, devoted to the letter and not the spirit</dd>

<dt>Roxburghe</dt>
<dd>a style of bookbinding</dd>

<dt>glockamoid</dt>
<dd>shaped like an arrow-head (note: not in OED)</dd>

<dt>mormal</dt>
<dd>a kind of scab or sore</dd>

<dt>jeropigia</dt>
<dd>from Portuguese &#8220;geropiga&#8221;, a mixture of grape juice, brandy and sugar used to adulterate wines</dd>

<dt>endosmic</dt>
<dd>relating to endosmosis, the flow of a fluid from an area of lesser concentration to one of greater</dd>

<dt>mage</dt>
<dd>a magician, or more generally a wise man</dd>

<dt>Palmerin</dt>
<dd>16th Century Spanish romantic hero, hence any knightly champion</dd>

<dt>thos</dt>
<dd>old Greek and Latin name for some kind of canine animal not definitively identified by subsequent historians</dd>

<dt>vituline</dt>
<dd>of or like a calf (vitulus: calf)</dd>

<dt>Turonian</dt>
<dd>part of the Cretaceous period</dd>

<dt>galingale</dt>
<dd>a gingery spice; better known as galangal</dd>

<dt>comprodor</dt>
<dd>possibly a misspelling of &#8220;comprodor&#8221;, a native steward or head servant, intermediary with the locals</dd>

<dt>Nox</dt>
<dd>personification of the night, from nox, night</dd>

<dt>gaskin</dt>
<dd>a kind of breeches; or, formation from &#8220;gasket&#8221;</dd>

<dt>secotine</dt>
<dd>possibly a misspelling of &#8220;Seccotine&#8221;, a brand of glue originating in the 19th century</dd>

<dt>ogdoad</dt>
<dd>the number eight, a set of eight; or specifically the Ogdoad, eight divine beings of ancient Egypt</dd>

<dt>pintulary</dt>
<dd>?</dd>

<dt>Pierian</dt>
<dd>relating to Pieria, home of the Muses; hence, poetic</dd>

<dt>saltarello</dt>
<dd>an animated Italian and Spanish dance</dd>

</dl>

<p>Trawling the book for the rest of Helprin&#8217;s vocabulary I leave for someone else, but special mention is due to &#8220;amphibological&#8221; &#8212; of amphibology/amphiboly, ambiguity of speech, especially deriving from grammatical construction &#8212; for appearing in context in the title <cite>Amphibological Whimsey Dances</cite>. It&#8217;s a better name for wordplay than wordplay.</p>
]]></content:encoded>
			<wfw:commentRss>http://rephrase.net/days/08/04/mrs-gamelys-words/feed/</wfw:commentRss>
		</item>
		<item>
		<title>IntelliType XML</title>
		<link>http://rephrase.net/days/08/02/intellitype-xml</link>
		<comments>http://rephrase.net/days/08/02/intellitype-xml#comments</comments>
		<pubDate>Tue, 05 Feb 2008 00:40:48 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
		
		<category>hacks</category>

		<category>hardware</category>

		<category>intellitype</category>

		<category>keyboard</category>

		<category>windows</category>

		<guid isPermaLink="false">http://rephrase.net/days/08/02/intellitype-xml</guid>
		<description><![CDATA[Microsoft hardware is fabulous, but &#8212; like everyone else ever to buy one &#8212; I was disgruntled to find that the Natural Ergonomic Keyboard 4000&#8217;s centre-keyboard lever is set to control zoom, and only zoom, rather than something like vertical scroll. Worse, IntelliType won&#8217;t let you change it, unlike almost every other special key on [...]]]></description>
			<content:encoded><![CDATA[<p>Microsoft hardware is fabulous, but &#8212; like everyone else ever to buy one &#8212; I was disgruntled to find that the <a href="http://www.microsoft.com/hardware/mouseandkeyboard/ProductDetails.aspx?pid=043">Natural Ergonomic Keyboard 4000</a>&#8217;s centre-keyboard lever is set to control zoom, and only zoom, rather than something like vertical scroll. Worse, IntelliType won&#8217;t let you change it, unlike almost every other special key on the board.</p>

<p>Luckily, it turns out that it&#8217;s a limitation of the interface, not the software; you can get a lot more done with a little registry tweaking and two XML configuration files in the installation directory:</p>

<ul>
<li><code>C:\Program Files\Microsoft IntelliType Pro\commands.xml</code></li>
<li><code>C:\Program Files\Microsoft IntelliType Pro\mscmdkey.xml</code></li>
</ul>

<p>There are two different kinds of customisation possible:</p>

<ol>
<li>Use the registry to map keys to commands specified in <code>mscmdkey.xml</code></li>
<li>Change the behaviour of those commands in specific contexts with <code>commands.xml</code></li>
</ol>

<p>First, we want to look at <code>mscmdkey.xml</code>.</p>

<h3><code>mscmdkey.xml</code></h3>

<p><code>mscmdkey.xml</code> lists commands sent out by the keyboard to IntelliType. It should probably be treated as read-only, but it&#8217;s informative; <code>commands.xml</code> can&#8217;t easily be edited without it. The commands look like this:</p>

<pre><code>&lt;Command name= 'VOLUME_UP_COMMAND' id='700' isUI='false' default='true' &gt;
    &lt;ResourceIDs displayName='3809' description='4009' descriptionPlusAccel='0' osdText='4270'/&gt;
&lt;/Command&gt;
</code></pre>

<p>The magic numbers are inscrutable (a <code>displayName</code> of 3809, an <code>osdText</code> of 4270?), but the <code>name</code> and <code>id</code> are simple enough.</p>

<p>The <code>name</code> is a human-readable label. <code>VOLUME_UP_COMMAND</code> is the default action of the volume-up button. <code>SAVE_COMMAND</code> corresponds to the &#8220;Save&#8221; button above F11. Some of the commands don&#8217;t have buttons on all keyboards: the Natural 4000 has no &#8220;next track&#8221; button (<code>MEDIA_NEXT_TRACK_COMMAND</code>), but the Natural MultiMedia does. Some of the commands <em>never</em> have buttons: <code>BATTERY_LOW_COMMAND</code> is an automatic feature of the battery-powered wireless models.</p>

<p>We&#8217;ll need the <code>id</code> when we get to <code>commands.xml</code>. To change the Zoom lever we want:</p>

<ul>
<li><code>&lt;Command name= 'ZOOM_IN_COMMAND' id='319' default='true' &gt;</code></li>
<li><code>&lt;Command name= 'ZOOM_OUT_COMMAND' id='320' default='true' &gt;</code></li>
</ul>

<p>319 and 320, respectively.</p>

<p>Some commands have an <code>MSReserved</code> sub-element. The <code>appCommand</code> attribute corresponds to a <a href="http://msdn2.microsoft.com/en-us/library/ms646275(VS.85).aspx"><code>WM_APPCOMMAND</code></a> parameter (e.g., for <code>NEW_COMMAND</code> it&#8217;s 29, the defined value of <code>APPCOMMAND_NEW</code>).</p>

<p>I&#8217;ve had no success trying to add my own commands under high, unused <code>id</code>s.</p>

<h3>Remapping keys</h3>

<p>The IntelliType software allows you to remap some, but not all, of the keyboard&#8217;s keys. When you do, the changes are saved to the registry at <code>HKEY_CURRENT_USER\Software\Microsoft\IntelliType Pro\EventMapping</code>.</p>

<p>The easiest way to find the key-code of a key you want to remap is to use IntelliType to assign it, then modify the values. The entry for my second favourites button looks like this:</p>

<pre><code>[HKEY_CURRENT_USER\Software\Microsoft\Intellitype Pro\EventMapping\79]
"ShellExecute"="cmd.exe"
"Friendly"="Python"
"Arguments"="/K python"
"Command"=dword:00000320
</code></pre>

<p>The important one is <code>Command</code>. <code>dword:00000320</code> is 0&#215;320 hex, or 800 in decimal. Search <code>mscmdkey.xml</code> for a command with an <code>id</code> of 800 and you&#8217;ll find <code>SHELL_EXECUTE_COMMAND</code> &#8212; that sounds a lot like what we&#8217;re doing. You can use any of the commands from <code>mscmdkey.xml</code> here, though not all of them work.</p>

<p><code>Friendly</code> is just a human-readable name (this entry displays in the favourites menu as &#8220;start Python&#8221;). <code>ShellExecute</code> and <code>Arguments</code> are specific to <code>SHELL_EXECUTE_COMMAND</code>.</p>

<p>IntelliType can only set the favorites buttons to applications and URLs, but I miss the next and previous track buttons from my Natural MultiMedia. I&#8217;ve put them as faves 4 and 5:</p>

<pre><code>[HKEY_CURRENT_USER\Software\Microsoft\Intellitype Pro\EventMapping\81]
"Command"=dword:000002c0

[HKEY_CURRENT_USER\Software\Microsoft\Intellitype Pro\EventMapping\82]
"Command"=dword:000002bf
</code></pre>

<p><code>0x2c0</code> is 704, <code>MEDIA_PREVIOUS_TRACK_COMMAND</code>; <code>0x2bf</code> is 703, <code>MEDIA_NEXT_TRACK_COMMAND</code>.</p>

<p>Some keys can&#8217;t be remapped. The &#8220;My Favorites&#8221; key, for example, can be disabled with <code>DISABLE_COMMAND</code> (400) but operates as normal with any other value.</p>

<h3>Editing <code>commands.xml</code></h3>

<p><code>commands.xml</code> lets us redefine what those commands actually do in any given context. It makes sense: not all software is alike, so triggering (e.g.) a spell check will require something different in OpenOffice.Org Writer than in Microsoft Word. Many of the mappings are simpler than you might think: <code>SAVE_COMMAND</code> (311), for example, is just a macro that performs the &#8220;Ctrl + s&#8221; keyboard shortcut!</p>

<p><code>commands.xml</code> looks something like this, trimmed for brevity:</p>

<pre><code>&lt;DPGCmd&gt;
    &lt;ENG&gt;
        &lt;Application UniqueName="StandardSupport"&gt;
            &lt;C311 Type="5" KeySeq="ctrl s" /&gt;
            &lt;C401 Type="5" KeySeq="F7" /&gt;
        &lt;/Application&gt;
    &lt;/ENG&gt;
    &lt;ALL&gt;
        &lt;Application UniqueName="Notepad" AppName="Notepad"&gt;
            &lt;C311 Type="1" wParam="0x10001" /&gt;
            &lt;C401 Type="0" /&gt;
            &lt;C309 Type="5" KeySeq="alt F4" /&gt;
        &lt;/Application&gt;
    &lt;/ALL&gt;
&lt;/DPGCmd&gt;
</code></pre>

<p>We&#8217;re not interested in a lot of this. Each installed language has an element under the root <code>DPGCmd</code> node defining the function of a command in that locale. <a href="http://msdn2.microsoft.com/en-us/library/ms903928.aspx"><code>ENG</code> means English</a>. The special element <code>ALL</code> applies to all languages; unless you&#8217;re a hardcore polyglot then it&#8217;s all you&#8217;ll need.</p>

<p>Commands are mapped on a per-application basis, but <code>AppName</code> doesn&#8217;t seem to actually do anything: change &#8220;Notepad&#8221; to &#8220;Potato&#8221; and the keys will work the same.</p>

<p><code>UniqueName</code> is the important one, and refers to the window class name passed to the relevant <a href="http://msdn2.microsoft.com/en-us/library/ms633586(VS.85).aspx">Windows API</a> functions. If you want to do application-specific customisation, there&#8217;s third-party software around (e.g. <a href="http://www.searchlores.org/tools.htm">The Customiser</a>) that can get a class name from any active window. If not, the special <code>UniqueName</code> value &#8220;<code>StandardSupport</code>&#8221; applies to all window classes.</p>

<p>Be careful not to have conflicting rules. Commands defined under specific <code>UniqueName</code>s will override commands defined under <code>StandardSupport</code>, but they can&#8217;t be defined under specific languages if they&#8217;re also in <code>ALL</code>.</p>

<h4>Commands</h4>

<p>Every <code>Application</code> contains elements with names like <code>C319</code>, where 319 is the <code>id</code> of a command in <code>mscmdkey.xml</code>. All of these command-elements have a type attribute:</p>

<ul>
<li>Types 1-4 take different kinds of undocumented magic numbers. Type 2 commands seem to be handled by Windows, rather than the active application, as they execute shell functions (open default browser, search window etc.), but that&#8217;s all I can figure out.</li>
<li>Type 7 commands take another type as a subtype. By default it&#8217;s only used for <code>OFFICE_TASK_PANE_COMMAND</code>, so I&#8217;m assuming it&#8217;s a hack just for that.</li>
</ul>

<p>The others are easier:</p>

<ul>
<li>Type 0 disables the key.</li>
<li><p>Type 6 takes an <code>Activator</code> which is passed to the window. Some of them are evidently application-specific &#8212; <code>IllustratorZoomin</code>, <code>IE7Save</code> &#8212; but others seem more general. An incomplete listing:</p>

<ul>
<li><code>ZoomIn</code></li>
<li><code>ZoomOut</code></li>
<li><code>ScrollUp</code></li>
<li><code>ScrollDown</code></li>
</ul></li>
</ul>

<p>Type 5 is the fun one, which takes a simple keyboard macro in its <code>KeySeq</code> attribute. As mentioned above, &#8220;Save&#8221; is implemented like this:</p>

<pre><code>&lt;C311 Type="5" KeySeq="ctrl s" /&gt;
</code></pre>

<p>i.e., it&#8217;s exactly the same as pressing &#8220;Ctrl&#8221; and &#8220;s&#8221;. Multiple chords can be separated with a <code>|</code> pipe character, so if you want a &#8220;Hello world!&#8221; button:</p>

<pre><code>&lt;C203 Type="5" KeySeq="shift h | e | l | l | o | 
    space | w | o | r | l | d | shift 1" /&gt;
</code></pre>

<p>Macros seem to be deliberately limited, possibly as a security feature. You can&#8217;t <code>alt tab</code> out, for example, or navigate menus with <code>alt | f | downarrow | downarrow | enter</code>. You <em>can</em> implement macros that reach into &#8220;Save As&#8221; or &#8220;Open&#8221; file-pickers, though, and presumably other kinds of dialog.</p>

<h3>See Also</h3>

<p>I wouldn&#8217;t even have considered looking for baroque XML configuration files if the internet hadn&#8217;t said it was possible. <a href="http://huddledmasses.org/hacking-the-natural-4000-keyboard/">Joel Bennett&#8217;s guide</a> has the most detail by far, plus a handy bit of XSL to remove the F-lock annoyance.</p>
]]></content:encoded>
			<wfw:commentRss>http://rephrase.net/days/08/02/intellitype-xml/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Sight and Sound Top Tens</title>
		<link>http://rephrase.net/days/07/10/sight-and-sound-top-tens</link>
		<comments>http://rephrase.net/days/07/10/sight-and-sound-top-tens#comments</comments>
		<pubDate>Sun, 28 Oct 2007 13:22:02 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
		
		<category>movies</category>

		<category>lists</category>

		<category>sight and sound</category>

		<category>unhealthy obsession</category>

		<guid isPermaLink="false">http://rephrase.net/days/07/10/sight-and-sound-top-tens</guid>
		<description><![CDATA[In 1952, Sight and Sound magazine followed up a Belgian poll of directors&#8217; favourite films with a similar referendum, this time for critics. The result was sixty-odd top-ten lists and an aggregate &#8220;ten best films&#8221;, with Vittorio De Sica&#8217;s Bicycle Thieves coming in at number one.

The poll would be of relatively little interest if it [...]]]></description>
			<content:encoded><![CDATA[<p>In 1952, <a href="http://www.bfi.org.uk/sightandsound/"><cite>Sight and Sound</cite></a> magazine followed up a Belgian poll of directors&#8217; favourite films with a similar referendum, this time for critics. The result was sixty-odd top-ten lists and an aggregate &#8220;ten best films&#8221;, with Vittorio De Sica&#8217;s <a href="http://imdb.com/title/tt0040522/"><cite>Bicycle Thieves</cite></a> coming in at number one.</p>

<p>The poll would be of relatively little interest if it had ended there, but it was repeated in 1962 &#8212; and 1972, 1982, 1992, 2002&#8230; Collected, the lists show the evolution of the cinematic canon (or at least the critical zeitgeist, which may not be precisely the same thing) over the last half-century. For example: 1962 saw <a href="http://imdb.com/title/tt0033467/"><cite>Citizen Kane</cite></a> move to first position, where it&#8217;s stayed ever since, but in 1952 it shared thirteenth. Ten years later, it was even further in front.</p>

<p>I suppose that watching items move up and down lists is only of interest to a certain kind of person, but that kind of person is me. It&#8217;s annoyed me no end that so many of the websites collecting lists of greatest films only provide the <cite>S&amp;S</cite> aggregate top tens: those by individual critics offer much greater variety, as well as scope for <a href="http://www.theyshootpictures.com/gf1000.htm">more interesting statistical projects</a>.</p>

<p>To that end, now that I&#8217;ve dug up the original magazines, here they are in full (or close to it):</p>

<ul>
<li><a href="/miscellany/07/ss/sightandsound52.txt">1952</a></li>
<li><a href="/miscellany/07/ss/sightandsound62.txt">1962</a></li>
<li><a href="/miscellany/07/ss/sightandsound72.txt">1972</a></li>
<li><a href="/miscellany/07/ss/sightandsound82.txt">1982</a></li>
<li><a href="/miscellany/07/ss/sightandsound92critics.txt">1992 critics</a> / <a href="/miscellany/07/ss/sightandsound92directors.txt">1992 directors</a></li>
</ul>

<p>The BFI has graciously put <a href="http://www.bfi.org.uk/sightandsound/topten/poll/">all of the 2002 results</a> online already.</p>

<p>Not every list was published in the magazine, though from 1962 onwards the effort was made. I haven&#8217;t included the comments, many to the effect of &#8220;you bastards, how can I pick just ten?&#8221;</p>

<p>There&#8217;s a remarkable range of creative interpretations of the words &#8220;top ten films&#8221;. Some included twelve or fifteen. Some included single entries like &#8220;The Apu Trilogy&#8221; (really three films), &#8220;Chaplin&#8217;s Mutual films&#8221; (more than ten), and in one case &#8220;Anthology of the works of W. C. Fields&#8221; (more than thirty). Some picked small extracts &#8212; like a single musical number &#8212; over films entire. One picked a specific, unreleased cut, subsequently destroyed by re-editing. Some sent in lists of directors.</p>

<h3>Note on accuracy</h3>

<p>Please forgive any missing diacritics: the OCR was hard on them, and I&#8217;m willing to sacrifice a cedilla here and an acute there to save time. All other corrections are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://rephrase.net/days/07/10/sight-and-sound-top-tens/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal Role</title>
		<link>http://rephrase.net/days/07/09/drupal-role</link>
		<comments>http://rephrase.net/days/07/09/drupal-role#comments</comments>
		<pubDate>Mon, 10 Sep 2007 05:40:56 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
		
		<category>PHP</category>

		<category>plugins</category>

		<category>drupal</category>

		<guid isPermaLink="false">http://rephrase.net/days/07/09/drupal-role</guid>
		<description><![CDATA[Drupal 4.2.0 was the first CMS I ever installed, back in 2003. A few weeks later it became the first CMS I botched an upgrade to, at which point I moved on to other pastures.

That was that until last week, when John demanded help with a custom module for his mountaineering club site, to enable [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://drupal.org/">Drupal</a> 4.2.0 was the first CMS I ever installed, <a href="http://web.archive.org/web/20031001233040/http://iluo.net/">back in 2003</a>. A few weeks later it became the first CMS I botched an upgrade to, at which point I moved on to other pastures.</p>

<p>That was that until last week, when <a href="http://home.netspeed.com.au/aistorm/">John</a> demanded help with a custom module for his mountaineering club site, to enable users to enter unique codes in their profile area and have their membership &#8220;upgraded&#8221; to a new role. I gather the point is to pass out the codes in meatspace when members join or pay their dues &#8212; it&#8217;s a clever idea.</p>

<p>A day or three later and the result was <a href="http://vs.rephrase.net/namor/php/drupal/rolecode/">this module</a>.</p>

<p>Most of my experience developing plugins for other people&#8217;s PHP comes from WordPress, so it was interesting to use such a dramatically different API. WordPress requires explicit registration of hook functions, e.g.</p>

<pre><code>add_action("edit_post", "my_edit_post_action");
</code></pre>

<p>But Drupal uses magic function names. If you have a module called &#8220;<code>mymodule</code>&#8220;, any function called <code>mymodule_init</code> will be automatically hooked into <a href="http://api.drupal.org/api/function/hook_init/5"><code>hook_init</code></a>.</p>

<p>It&#8217;s an elegant solution, though I favour the Pythonic &#8220;explicit is better than implicit&#8221; philosophy too much to be comfortable with it.</p>

<p>One of the best (and worst) things about the whole experience was the <a href="http://api.drupal.org/api/group/form/6">Forms API</a>. Instead of writing HTML, you just write some code like this:</p>

<pre><code>function mymodule_form() {
    $form['name'] = array(
      '#type' =&gt; 'textfield',
      '#title' =&gt; t('Name'),
      '#description' =&gt; t('What are you called?')
    );
    $form['submit'] = array(
      '#type' =&gt; 'submit',
      '#value' =&gt; t('Yield!'),
    );
    return $form;
}
</code></pre>

<p>Hook the function in at the appropriate place, and Drupal renders it, themed prettily, with anti-CSRF nonces already handled. More magic functions, hooked in as <code>mymodule_form_validate()</code> and <code>mymodule_form_submit()</code>, can be used for validation and form submission actions respectively.</p>

<p>As always, the downside of a leaky abstraction is that customizations not provided for in the API are much harder than they should be, but I expect that the vast majority of modules never have any problems.</p>

<p>Drupal has lots of other niceties missing from WordPress too, like the <a href="http://api.drupal.org/api/function/watchdog"><code>watchdog</code></a> logging system and <a href="http://api.drupal.org/">documentation that doesn&#8217;t suck</a>. I have issues with it as a user &#8212; the learning curve for administration is comparatively steep &#8212; but it&#8217;s flexible, powerful, and easy to extend. As a developer I&#8217;m extremely impressed.</p>
]]></content:encoded>
			<wfw:commentRss>http://rephrase.net/days/07/09/drupal-role/feed/</wfw:commentRss>
		</item>
		<item>
		<title>JavaScript Bayes</title>
		<link>http://rephrase.net/days/07/08/javascript-bayes</link>
		<comments>http://rephrase.net/days/07/08/javascript-bayes#comments</comments>
		<pubDate>Tue, 14 Aug 2007 14:10:53 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
		
		<category>projects</category>

		<category>JavaScript</category>

		<category>bayes</category>

		<category>pointless toys</category>

		<guid isPermaLink="false">http://rephrase.net/days/07/08/javascript-bayes</guid>
		<description><![CDATA[I wanted to have some Bayesian fun in a user-script, so did a quick JavaScript port of the fabulous Divmod Reverend Python module.

It&#8217;s somewhat limited, but dead easy to use:

var guesser = new Bayes();
guesser.train("hannibal", "I love to kill people and eat them.");
guesser.train("austen", "Come, let us have tea and scones in Mr. Bingley's gazebo.");
guesser.guess("Jane, these scones [...]]]></description>
			<content:encoded><![CDATA[<p>I wanted to have some Bayesian fun in a user-script, so did <a href="http://vs.rephrase.net/namor/javascript/bayes/">a quick JavaScript port</a> of the fabulous <a href="http://divmod.org/trac/wiki/DivmodReverend">Divmod Reverend</a> Python module.</p>

<p>It&#8217;s somewhat limited, but dead easy to use:</p>

<pre><code>var guesser = new Bayes();
guesser.train("hannibal", "I love to kill people and eat them.");
guesser.train("austen", "Come, let us have tea and scones in Mr. Bingley's gazebo.");
guesser.guess("Jane, these scones are simply delightful!");
// [["austen", 0.9999]]

guesser.train("hannibal", "I love to kill people and eat them with tea and scones.");
guesser.guess("Give me those scones or I'll kill and eat you.");
// [["hannibal", 0.9481433307479079], ["austen", 0.6203339133520634]]
</code></pre>

<p>It&#8217;s missing some stuff, but does enough to be getting along with.</p>

<p>As a test application, I went on and wrote up one of the examples given in the Reverend docs: <a href="http://rephrase.net/box/what-the-dickens/">a script to tell whether you write more like Charles Dickens or Jane Austen</a>. It&#8217;s both pointless and inaccurate, but I suppose it qualifies. <img src='http://rephrase.net/s/word/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://rephrase.net/days/07/08/javascript-bayes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Userscript: IMDb Decoder Ring</title>
		<link>http://rephrase.net/days/07/06/imdb-decoder</link>
		<comments>http://rephrase.net/days/07/06/imdb-decoder#comments</comments>
		<pubDate>Sat, 23 Jun 2007 12:22:00 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
		
		<category>JavaScript</category>

		<category>user-js</category>

		<category>greasemonkey</category>

		<category>imdb</category>

		<guid isPermaLink="false">http://rephrase.net/days/07/06/imdb-decoder</guid>
		<description><![CDATA[It seems to be a Greasemonkey kind of month. IMDb ratings are fuzzy in the middle, so Tom Moertel made a decoder ring listing what the rating means in terms of the movie&#8217;s per-genre percentile ranking. Leprechaun 5&#8217;s 3.2 rating seems bad enough even with an even distribution; in reality, it has a worse rating [...]]]></description>
			<content:encoded><![CDATA[<p>It seems to be a Greasemonkey kind of month. IMDb ratings are <a href="http://blog.moertel.com/articles/2006/01/17/mining-gold-from-the-internet-movie-database-part-1">fuzzy in the middle</a>, so Tom Moertel made a <a href="http://community.moertel.com/ss/space/IMDB+Movie-Rating+Decoder+Ring">decoder ring</a> listing what the rating means in terms of the movie&#8217;s per-genre percentile ranking. <a href="http://imdb.com/title/tt0413267/"><cite>Leprechaun 5</cite></a>&#8217;s 3.2 rating seems bad enough even with an even distribution; in reality, it has a worse rating than <em>90%</em> of movies in the database.</p>

<p>Anyhow, <a href="http://rephrase.net/box/user-js/scripts/imdb-percentile-ratings.user.js">this userscript</a> puts the data conveniently inline.</p>

<p>Before:</p>

<p><img src="http://rephrase.net/miscellany/07/imdb.decoder.before.png" alt="Shrek 3 at IMDb without the script" /></p>

<p>After:</p>

<p><img src="http://rephrase.net/miscellany/07/imdb.decoder.after.png" alt="Shrek 3 at IMDb with the script enabled" /></p>

<h3><a href="http://rephrase.net/box/user-js/scripts/imdb-percentile-ratings.user.js">Download</a></h3>
]]></content:encoded>
			<wfw:commentRss>http://rephrase.net/days/07/06/imdb-decoder/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Userscript: Reddit unread comments helper</title>
		<link>http://rephrase.net/days/07/06/reddit-greasemonkey-gears</link>
		<comments>http://rephrase.net/days/07/06/reddit-greasemonkey-gears#comments</comments>
		<pubDate>Mon, 18 Jun 2007 14:18:15 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
		
		<category>JavaScript</category>

		<category>user-js</category>

		<category>reddit</category>

		<category>google gears</category>

		<category>greasemonkey</category>

		<guid isPermaLink="false">http://rephrase.net/days/07/06/userscript-reddit-unread-comments-helper</guid>
		<description><![CDATA[Edit - 2008-05-27: Updated to work with the (horrid) Reddit redesign. I can&#8217;t be bothered updating the screenshots too.

Or: (ab)using Greasemonkey and Google Gears to add features that would be handled better server-side.

The script tracks comments you&#8217;ve seen at Reddit, then exposes the data in several small ways that each make your life a little [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Edit - 2008-05-27:</strong> Updated to work with the (horrid) Reddit redesign. I can&#8217;t be bothered updating the screenshots too.</p>

<p>Or: (ab)using <a href="http://greasespot.net/">Greasemonkey</a> and <a href="http://gears.google.com/">Google Gears</a> to add features that would be handled better server-side.</p>

<p><a href="http://vs.rephrase.net/namor/javascript/userscripts/redditunreadcommenthelper.user.js">The script</a> tracks comments you&#8217;ve seen at <a href="http://programming.reddit.com/">Reddit</a>, then exposes the data in several small ways that each make your life a little easier. Features:</p>

<ul>
<li><p>On the main Reddit list pages, replace the &#8220;<i>n</i> comments&#8221; links with &#8220;<i>x</i> unread comments (<i>n</i> total)&#8221;.</p>

<p>Before:</p>

<p><img src="http://rephrase.net/miscellany/07/reddit.us.list.before.png" alt="before the userscript is applied" /></p>

<p>After:</p>

<p><img src="http://rephrase.net/miscellany/07/reddit.us.list.after.png" alt="after the userscript is applied" /></p></li>
<li><p>On clicking through to a page where you&#8217;ve already read some of the comments,
jump to the first unread comment.</p></li>
<li><p>Highlight unread comments with a bright but non-distracting left margin.</p></li>
</ul>

<p><a href="http://vs.rephrase.net/namor/javascript/userscripts/redditunreadcommenthelper.user.js">Download or install it</a>.</p>

<h3>Notes</h3>

<p>My ulterior motive was testing the <a href="http://code.google.com/apis/gears/api_database.html">Gears DB</a> with Greasemonkey. More than once I&#8217;ve wished it had a binding to SQLite, and with Gears it does: it just got a thousand times more useful. It&#8217;d be nicer yet if I could save to an arbitrary cross-domain database, but this is still a tremendous step up.</p>

<p>This script uses a bit of a hack and writes itself directly into the window, rather than just manipulating the DOM from the usual plexiglass sandbox. Strictly speaking it&#8217;s not necessary, and only possible at all because I have no use for the <code>GM_*</code> API functions, but a userscript with Gears does require at least some meddling of this kind.</p>

<p>Gears prompts the user to allow it to run on a specific domain, but the dialog doesn&#8217;t appear if it&#8217;s initialized from within Greasemonkey; it has to be done from the unsafe window. Once it&#8217;s set up &#8212; once the local database has been created and what have you &#8212; Greasemonkey is fine, but that first step is critical.</p>

<p>Still, that&#8217;s basically the only hurdle, and it&#8217;s trivial to surmount. Gears is a dream: the API seems a little sparsely featured, but it&#8217;s so easy to build a platform around that the lack of convenience methods doesn&#8217;t matter. I wrote a very simple DB wrapper of my own, and others are already building full ORMs. There&#8217;s no sight of JavaScript on Jacks just yet, but it can&#8217;t be far off.</p>
]]></content:encoded>
			<wfw:commentRss>http://rephrase.net/days/07/06/reddit-greasemonkey-gears/feed/</wfw:commentRss>
		</item>
		<item>
		<title>E4X</title>
		<link>http://rephrase.net/days/07/06/e4x</link>
		<comments>http://rephrase.net/days/07/06/e4x#comments</comments>
		<pubDate>Sat, 16 Jun 2007 14:35:08 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
		
		<category>JavaScript</category>

		<category>e4x</category>

		<category>ECMAScript</category>

		<category>xml</category>

		<guid isPermaLink="false">http://rephrase.net/days/07/06/e4x</guid>
		<description><![CDATA[E4X, short for &#8220;ECMASCript for XML&#8221;, is an extension to ECMAScript (i.e. JavaScript, JScript, ActionScript&#8230;) with new syntax and built-in objects for more convenient handling of XML fragments. It seems to be used most frequently with ActionScript 3 (Flash), but is also available in recent Mozilla/Firefox releases.

I whipped up this guide after a quick read-through [...]]]></description>
			<content:encoded><![CDATA[<p>E4X, short for &#8220;ECMASCript for XML&#8221;, is an extension to ECMAScript (i.e. JavaScript, JScript, ActionScript&#8230;) with new syntax and built-in objects for more convenient handling of XML fragments. It seems to be used most frequently with ActionScript 3 (Flash), but is also available in recent Mozilla/Firefox releases.</p>

<p>I whipped up this guide after a quick read-through of <a href="http://www.ecma-international.org/publications/standards/Ecma-357.htm">the specification</a> and a bit of playing around. Corrections are more than welcome.</p>

<p>In order, it briefly outlines:</p>

<ul>
<li>The syntax for declaring literal XML values</li>
<li><code>XML</code> and <code>XMLList</code> objects</li>
<li>Variable interpolation in XML literals</li>
<li>The new syntax for traversal of XML objects</li>
<li>Namespace considerations</li>
<li>The methods of XML objects</li>
</ul>

<h3>First-class XML</h3>

<p>E4X XML objects can be created by passing a string to the <code>XML</code> constructor function, but that&#8217;s hardly exciting. Much more interesting is the new syntax for XML literals, similar to that in <a href="http://www.scala-lang.org/intro/xml.html">Scala</a>. It&#8217;s <em>exactly</em> what you&#8217;d expect:</p>

<pre><code>var x = &lt;elm id="1"&gt;
    &lt;a&gt;content&lt;/a&gt;
&lt;/elm&gt;;
</code></pre>

<p>There&#8217;s no more need to bother with painful string concatenation or backslashed line continuations.</p>

<p>Even better, XML objects are first-class citizens. They have properties and methods; they can be deleted, concatenated and iterated over.</p>

<pre><code>var y = x + &lt;elm id="2" /&gt;;
var name = &lt;xml /&gt;.name();
</code></pre>

<h3><code>XML</code> and <code>XMLList</code></h3>

<p>As well as <code>XML</code>, E4X defines the <code>XMLList</code>, an ordered collection of <code>XML</code> objects similar to the W3C DOM <code>NodeList</code>.</p>

<p>The literal syntax is rather less intuitive:</p>

<pre><code>var xl = &lt;&gt;
    &lt;a /&gt;
    &lt;b /&gt;
    &lt;c /&gt;
&lt;/&gt;;
</code></pre>

<p>Much of E4X&#8217;s expressive power comes from the blurring of the line between <code>XMLList</code> and <code>XML</code> objects. Both have a type of <code>xml</code>; <code>instanceof xml</code> returns true for both.</p>

<p>The advantage is that you rarely need to worry about which you have. A single-item <code>XMLList</code> is treated identically to an <code>XML</code> object, and even longer lists share many of the same methods. The <code>text()</code> method of an <code>XML</code> object returns its text content. On an <code>XMLList</code> it returns the concatenated text content of all list members.</p>

<p>If you do need to tell the difference, just check the <code>.length()</code>: an <code>XML</code> object&#8217;s length is always <code>1</code>.</p>

<h3>Literal Interpolation</h3>

<p>When declaring a literal, expressions inside braces (curly brackets) are automatically evaluated.</p>

<pre><code>var name = "bob^%*";
var tag = "person";
var p = &lt;{tag} id="3"&gt;{name.replace(/[^a-z]/ig, "")}&lt;/{tag}&gt;;
// &lt;person id="3"&gt;bob&lt;/person&gt;
</code></pre>

<p>Braced values are not, however, evaluated in <code>CDATA</code> sections, such as the contents of attribute values:</p>

<pre><code>var att = "id";
var val  = 3;
var a = &lt;person {att}="{val}"&gt;bob&lt;/person&gt;;
// &lt;person id="{val}"&gt;bob&lt;/person&gt;

var b = &lt;person {att}={val}&gt;bob&lt;/person&gt;;
// &lt;person id="3"&gt;bob&lt;/person&gt;
</code></pre>

<p>Interpolated attribute values are automatically quoted; any XML entities are automatically escaped.</p>

<pre><code>val = "\"&lt;&gt;";
b = &lt;person {att}={val}&gt;bob&lt;/person&gt;
// &lt;person id="&amp;quot;&amp;lt;&gt;"&gt;bob&lt;/person&gt;
</code></pre>

<p>Literal braces should be escaped as <code>&amp;#x7B;</code> and <code>&amp;x#7D;</code> for <code>{</code> and <code>}</code> respectively.</p>

<h3>Accessing XML Properties</h3>

<p>XML objects can be filtered and traversed using an object syntax similar to <a href="http://effbot.org/zone/element-index.htm">ElementTree</a> and <a href="http://www.crummy.com/software/BeautifulSoup/">BeautifulSoup</a>, with a bit of XPath thrown in.</p>

<p>A node&#8217;s child elements can be accessed as properties:</p>

<pre><code>var x = &lt;people class="example"&gt;
    &lt;person id="1"&gt;&lt;name&gt;sam&lt;/name&gt;&lt;/person&gt;
    &lt;person id="2"&gt;&lt;name&gt;elizabeth&lt;/name&gt;&lt;/person&gt;
&lt;/people&gt;;

var names = x.person.name;
var name  = x.person[0].name;

names.toXMLString();
// &lt;name&gt;sam&lt;/name&gt; &lt;name&gt;elizabeth&lt;/name&gt;
name.toXMLString();
// &lt;name&gt;sam&lt;/name&gt;
</code></pre>

<p><code>x.[name]</code> is the same as <code>x.child([name])</code>.</p>

<h3>Attributes</h3>

<p>As with XPath, &#8220;<code>@</code>&#8221; is used to access attributes.</p>

<pre><code>var id = x.person[0].@id;
</code></pre>

<p><code>x.@[name]</code> is identical to <code>x.attribute([name])</code>.</p>

<h3>Descendants</h3>

<p>The <code>..</code> operator accesses all descendants, not just the immediate children.</p>

<pre><code>var names = x..name;
var ids = x..@id;
</code></pre>

<p><code>x..[name]</code> is equivalent to <code>x.descendants([name])</code>.</p>

<h3>The Wildcard</h3>

<p>The &#8220;<code>*</code>&#8221; wildcard matches all names.</p>

<pre><code>var persons  = x.*;
var all      = x..*;
var attrs    = x..@*;
</code></pre>

<p>The wildcard is magic in more than one context, but in this one it&#8217;s equivalent to <code>QName(null, "*")</code>.</p>

<pre><code>var all = x.descendants(QName(null, "*"));
</code></pre>

<h3>Filtering Predicates</h3>

<pre><code>var me     = x.person.(name == "sam");
var either = x.person.(@id == 1 || @id == 2);
</code></pre>

<p>Predicates can be nested and quite complex:</p>

<pre><code>var me = x..*.(name == "sam" &amp;&amp; 
    name.parent().(@id == 1).name() == "person");
</code></pre>

<p>They&#8217;re not quite as useful as they could be, however. Unlike XPath, E4X expressions cannot easily be used to search ancestor axes.</p>

<p>The previous example illustrates a potential problem. It only works because the list of matches is reduced to one by <code>(name == "sam")</code> before the <code>parent()</code> method is invoked.</p>

<p>This expression, on the other hand, will raise an exception:</p>

<pre><code>x..*.(name.parent().@id == 1);
</code></pre>

<p>The filter does <em>not</em> examine the parent of every <code>name</code> in turn; it looks for the single parent of the entire list of <code>name</code>s together. It returns <code>undefined</code> unless every member shares the same parent.</p>

<h3>Deletion</h3>

<p>The <code>delete</code> keyword works on arbitrary E4X expressions:</p>

<pre><code>delete x.person.(@id == 1); // that's me gone 
delete x..person            // ... and everyone else
</code></pre>

<h3>Assignment</h3>

<p>You can also use the normal assignment operator:</p>

<pre><code>x..name[0] = "batman";
x.@pointless = "new attribute!";
x.person += &lt;person id="3"&gt;&lt;name&gt;alfred&lt;/name&gt;&lt;/person&gt;
</code></pre>

<p>In some circumstances you can also assign to an expression that would return a list:</p>

<pre><code>x.* = &lt;goodbye_previous_content /&gt;;
</code></pre>

<p>But those nodes were all together, so replacing them at once is a natural operation. This, on the other hand, is illegal:</p>

<pre><code>x.person.@newattributes = "for all";
</code></pre>

<h3>Iteration</h3>

<p>There are several ways to iterate over <code>XMLList</code> and <code>XML</code> objects, though for <code>XML</code> the exercise is meaningless:</p>

<pre><code>x[0] == x;
// true
</code></pre>

<p>Nevertheless. First, iteration over list indices:</p>

<pre><code>var i, elm;
for (i in x..*) {
    elm = x..*[i];
}
</code></pre>

<p>The same can be accomplished with a <code>for;;</code> loop and the <code>length()</code> method.</p>

<pre><code>for (i=0; i&lt;x.length(); ++i) {
    elm = x[i];
}
</code></pre>

<p>Most useful of all, though, is the new <code>for each .. in</code> syntax, allowing direct manipulation of matching nodes:</p>

<pre><code>var elm;
for each (elm in x.person) {
    elm.@id += 1;
}
</code></pre>

<h3>Namespaces</h3>

<p>E4X has robust namespace support, but (as anyone with XML experience must expect) they complicate an otherwise simple model.</p>

<pre><code>var x = &lt;xml&gt;
        &lt;v1&gt;value one&lt;/v1&gt;
        &lt;v2&gt;value two&lt;/v2&gt;
    &lt;/xml&gt;;

x.v1 == "value one";
// true
</code></pre>

<p>With namespaces, you have to use a qualified name.</p>

<pre><code>var x = &lt;xml xmlns="http://example.com/"&gt;
        &lt;v1&gt;value one&lt;/v1&gt;
        &lt;v2&gt;value two&lt;/v2&gt;
    &lt;/xml&gt;;

x.v1 == undefined;
// true

var example = Namespace("http://example.com/");
x.example::v1 == "value one";
// true
</code></pre>

<p>Note the use of the <code>::</code> scoping operator. You can also suggest a namespace prefix and/or or construct the QName directly:</p>

<pre><code>var example = Namespace("example", "http://example.com/");
var name = QName(example, "v1");
var same = QName("http://example.com/", "v1");
</code></pre>

<p>If more liberal matching is required, the <code>*</code> wildcard signifies any namespace.</p>

<pre><code>x.*::v1 == "value one";
// true
</code></pre>

<p>The wildcard anyname-namespace is different from the unnamed namespace, and can also be created by passing <code>null</code> to the <code>Namespace</code> constructor. The following are equivalent:</p>

<pre><code>x.*::v1
x.child(QName(null, "v1"));
</code></pre>

<h4>The default namespace</h4>

<p>Using perhaps the most self-explanatory syntax ever devised, you can set the default XML namespace in the current scope.</p>

<pre><code>var example = Namespace("http://example.com/");
default xml namespace = example;
// or
default xml namespace = "http://example.com/";

var x = &lt;xml /&gt;;
x.toXMLString();
// &lt;xml xmlns="http://example.com/"/&gt;
</code></pre>

<p>To reiterate: <em>in the current scope</em>.</p>

<h3><code>toString()</code> vs. <code>toXMLString()</code></h3>

<p>There is an important difference between the <code>toString</code> and <code>toXMLString</code> methods.</p>

<pre><code>var x = &lt;people&gt;
    &lt;person id="1"&gt;&lt;name&gt;sam&lt;/name&gt;&lt;/person&gt;
    &lt;person id="2"&gt;&lt;name&gt;elizabeth&lt;/name&gt;&lt;/person&gt;
&lt;/people&gt;;

var names = x.person.name;
var name = x.person[0].name;

names.toXMLString();
// &lt;name&gt;sam&lt;/name&gt; &lt;name&gt;elizabeth&lt;/name&gt;
name.toXMLString();
// &lt;name&gt;sam&lt;/name&gt;

names.toString();
// &lt;name&gt;sam&lt;/name&gt; &lt;name&gt;elizabeth&lt;/name&gt;
name.toString();
// sam
</code></pre>

<p><code>toString</code> returns different values depending on whether or not an object is considered &#8220;complex&#8221;. If there are no child elements (other types, such as XML comments, don&#8217;t count), it returns the element&#8217;s text content only. This is very useful in most cases but a painful gotcha in others.</p>

<h3>Extending E4X</h3>

<p>ECMAScript lets you do wonderful things by extending <a href="http://erik.eae.net/archives/2005/06/06/22.13.54/"><code>Object.prototype</code></a>, <code>String.prototype</code> etc. with new methods.</p>

<p>It&#8217;s much harder with E4X. The prototypes of <code>XML</code> and <code>XMLList</code> are read-only, so new methods can&#8217;t be added directly. Most of their existing methods throw exceptions if they are applied to any other object. Procedural code will have to do.</p>

<p>Future versions will have built-in support for custom types based on XML schemas.</p>

<h3>Global function reference</h3>

<h4><code>isXMLName( value ) : bool</code></h4>

<p>Is the value usable as an XML name?</p>

<h3><code>XML</code> Constructor Reference</h3>

<p>The <code>XML</code> constructor has several properties managing global settings for XML processing and serialization.</p>

<h4><code>XML.ignoreComments</code></h4>

<p>Ignore XML comments. (Default: <code>true</code>.)</p>

<h4><code>XML.ignoreProcessingInstructions</code></h4>

<p>Ignore XML processing instructions. (Default: <code>true</code>.)</p>

<h4><code>XML.ignoreWhitespace</code></h4>

<p>Ignore whitespace. (Default: <code>true</code>.)</p>

<h4><code>XML.prettyPrinting</code></h4>

<p>Pretty-print XML output with <code>toXMLString()</code> etc. (Default: <code>true</code>.)</p>

<h4><code>XML.prettyIndent</code></h4>

<p>Pretty indent level for child nodes. (Default: <code>2</code>.)</p>


<hr />


<p>There are also three methods to more easily apply and restore settings for use, say, within a function.</p>

<h4><code>XML.settings()</code></h4>

<p>Get an Object containing the above settings.</p>

<h4><code>XML.defaultSettings()</code></h4>

<p>Get an object containing the default settings.</p>

<h4><code>XML.setSettings([settings])</code></h4>

<p>Set XML settings from, e.g., an object returned by <code>XML.settings()</code>.</p>

<h3>XML Object Reference</h3>

<h4><code>addNamespace([namespace])</code></h4>

<p>Add a namespace declaration to the object.</p>

<h4><code>appendChild(child)</code></h4>

<p>Append a node to the object&#8217;s list of children.</p>

<h4><code>attribute(attributeName)</code></h4>

<p>Returns an <code>XMLList</code> of zero or one matching attributes.</p>

<p>Same as <code>element.@attributeName</code>.</p>

<h4><code>attributes()</code></h4>

<p>Returns an <code>XMLList</code> of attributes.</p>

<p>Same as `element.@*</p>

<h4><code>child(propertyName or index)</code></h4>

<p>Same as <code>element.propertyName</code> or <code>element[index]</code>.</p>

<h4><code>childIndex()</code></h4>

<p>Returns the node&#8217;s position in the parent&#8217;s list of children, or <code>-1</code> if there is no parent or its children are unordered.</p>

<h4><code>children()</code></h4>

<p>Returns an <code>XMLList</code> of children.</p>

<p>Same as <code>element.*</code>.</p>

<h4><code>comments()</code></h4>

<p>Returns an <code>XMLList</code> of child nodes that are comments.</p>

<p>Same as <code>element.(*.nodeKind() == 'comment')</code>.</p>

<h4><code>contains(value)</code></h4>

<p>Same as <code>element == value</code>.</p>

<h4><code>copy()</code></h4>

<p>Return a deep copy of the object, detached from its parent.</p>

<h4><code>descendants(name)</code></h4>

<p>Return all descendants with the given name, or, if name is null or undefined, all descendants.</p>

<p>Same as <code>element..name</code>.</p>

<h4><code>elements([name])</code></h4>

<p>Returns all child elements with the given name, or, if name is null or undefined, all child elements.</p>

<p>Same as <code>element.(*.nodeKind() == 'element')</code>.</p>

<h4><code>hasOwnProperty(prop)</code></h4>

<p>The same as on any other object.</p>

<h4><code>hasComplexContent()</code></h4>

<p>Returns true if the node has complex content (in effect, if it has child elements).</p>

<h4><code>hasSimpleContent()</code></h4>

<p>The opposite of <code>hasComplexContent</code>.</p>

<h4><code>inScopeNamespaces()</code></h4>

<p>Returns an <code>Array</code> of in-scope <code>Namespace</code> objects.</p>

<h4><code>insertChildAfter(anchor, child)</code></h4>

<h4><code>insertChildBefore(anchor, child)</code></h4>

<p>Insert a child node before or after the specified anchor node. If the anchor is <code>null</code>, insert before or after no nodes.</p>

<p>If the anchor is not in this XML object, do nothing.</p>

<h4><code>length()</code></h4>

<p>Return the length of the object. For <code>XML</code> objects always return <code>1</code>.</p>

<h4><code>localName()</code></h4>

<p>Return the local part of the qualified name. (A node&#8217;s name not including its namespace.)</p>

<h4><code>name()</code></h4>

<p>Return the qualified name. (Including namespace.)</p>

<pre><code>var x = &lt;xml xmlns="http://example.com/"&gt;abc&lt;/xml&gt;;
x.name() == "http://example.com/::xml";
x.localName() == "xml";
x.namespace() == "http://example.com/";
</code></pre>

<h4><code>namespace([prefix])</code></h4>

<p>Return the in-scope namespace specified by <code>prefix</code>, or:</p>

<ul>
<li>If no namespace matches, return <code>undefined</code>.</li>
<li>If <code>prefix</code> is not provided, return the default namespace.</li>
</ul>

<h4><code>namespaceDeclarations()</code></h4>

<p>Return an <code>Array</code> of <code>Namespace</code> objects representing namespaces declared (as in assigned a prefix) on this XML object.</p>

<h4><code>nodeKind()</code></h4>

<p>Returns the type of XML node, one of <code>attribute</code>, <code>element</code>, <code>comment</code>, <code>processing-instruction</code>, <code>text</code>.</p>

<h4><code>normalize()</code></h4>

<p>Merge adjacent text nodes and remove empty text nodes on this all descendants.</p>

<h4><code>parent()</code></h4>

<p>Return the parent node. On an <code>XMLList</code>, this method returns <code>undefined</code> unless all members share the same parent.</p>

<h4><code>processingInstructions([ name ])</code></h4>

<p>Returns all child processing instructions with the given name, or, if name is null or undefined, all child processing instructions.</p>

<p>Same as <code>element.(*.nodeKind() == 'processing-instruction')</code>.</p>

<h4><code>prependChild(value)</code></h4>

<p>Insert <code>value</code> at the beginning of the object&#8217;s child nodes.</p>

<h4><code>propertyIsEnumerable(prop)</code></h4>

<p>Will the specified property be enumerated in a <code>for .. in</code> loop? Same as for other objects.</p>

<h4><code>removeNamespace(namespace)</code></h4>

<p>If possible, remove the given namespace from the object and all descendants. <code>removeNamespace</code> will <em>not</em> remove a namespace if it is referenced in that object or any of its children.</p>

<h4><code>replace(propertyName, value)</code></h4>

<p>Replace value specified by <code>propertyName</code>, where <code>propertyName</code> is a name, numeric index or <code>*</code> wildcard, with <code>value</code>.</p>

<h4><code>setChildren(value)</code></h4>

<p>Replace the object&#8217;s children with <code>value</code>.</p>

<h4><code>setLocalName(name)</code></h4>

<p>Change the object&#8217;s local name using a string or the <code>localName</code> property of a <code>QName</code> object.</p>

<h4><code>setName(name)</code></h4>

<p>Set the object&#8217;s name and alter the in-scope namespaces to fit.</p>

<h4><code>setNamespace(ns)</code></h4>

<p>Replace the object&#8217;s default namespace with <code>ns</code>.</p>

<h4><code>text()</code></h4>

<p>Returns all child text nodes with the given name, or, if name is null or undefined, all child text nodes.</p>

<p>Same as <code>element.(*.nodeKind() == 'text')</code>.</p>

<h4><code>toString()</code></h4>

<p>Returns a string representation. Elements with simple content (i.e., no child elements) are returned as text; complex elements are returned as XML.</p>

<h4><code>toXMLString()</code></h4>

<p>An XML serialization of the object.</p>

<h4><code>valueOf()</code></h4>

<p>Return this object.</p>

<h3><code>XMLList</code> Reference</h3>

<p>Most methods are the same. Descendant methods such as <code>children()</code> and <code>text()</code> are simply applied to all members of the list and the results combined. Others, like <code>parent()</code>, don&#8217;t work when it isn&#8217;t logical that they do so &#8212; consult your common sense.</p>

<h3>Optional Features</h3>

<p>Implementations are allowed to include these optional features, or not. Currently Mozilla seems to be on the &#8220;or not&#8221; side of the fence, but they&#8217;re easy enough to implement in userspace if you need them.</p>

<h4><code>domNode()</code></h4>

<p>Return a W3C DOM node representation of the object.</p>

<h4><code>domNodeList()</code></h4>

<p>Return a W3C DOM NodeList representation.</p>

<h4><code>xpath(exp)</code></h4>

<p>Apply the XPath expression <code>exp</code> and either return an <code>XMLList</code> of results or throw a <code>TypeError</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://rephrase.net/days/07/06/e4x/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Sunshine</title>
		<link>http://rephrase.net/days/07/05/sunshine</link>
		<comments>http://rephrase.net/days/07/05/sunshine#comments</comments>
		<pubDate>Tue, 08 May 2007 11:27:26 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
		
		<category>General</category>

		<category>movies</category>

		<category>science</category>

		<category>religion</category>

		<guid isPermaLink="false">http://rephrase.net/days/07/05/sunshine</guid>
		<description><![CDATA[
  And, while with silent lifting mind I&#8217;ve trod
  The high, untrespassed sanctity of space,
  Put out my hand and touched the face of God.


&#8211; J.G. Magee, High Flight

Beware spoilers.

It&#8217;s a terrible shame that the second half of Event Horizon belonged to one of the worst science fiction films of the 1990s, [...]]]></description>
			<content:encoded><![CDATA[<blockquote>
  <p>And, while with silent lifting mind I&#8217;ve trod<br />
  The high, untrespassed sanctity of space,<br />
  Put out my hand and touched the face of God.</p>
</blockquote>

<p>&#8211; J.G. Magee, <a href="http://www.qunl.com/rees0008.html"><cite>High Flight</cite></a></p>

<div class="spoilers warning">Beware spoilers.</div>

<p>It&#8217;s a terrible shame that the second half of <a href="http://imdb.com/title/tt0119081/"><cite>Event Horizon</cite></a> belonged to one of the worst science fiction films of the 1990s, because the first half promised one of the best.</p>

<p>Dr. Weir (Sam Neill) and his team head into space to investigate an experimental spacecraft, thought lost seven years before when a test of its faster-than-light engine went awry. There&#8217;s a whole universe of possible explanations for its reappearance, from aliens to temporal anomalies to quantum somethings-or-others, until Weir speaks those ludicrous, devastating words: the ship has returned from &#8220;a dimension of pure evil&#8221;. It&#8217;s not just a wretched turn of phrase; it&#8217;s not just that the anticipated twist is the equivalent of &#8220;<a href="http://imdb.com/title/tt0075005/"><cite>Christine</cite></a> in space&#8221; or &#8220;HAL666&#8243;. It&#8217;s a betrayal.</p>

<p>Science fiction is <em>science</em> fiction, and scientific endeavour is founded on one basic principle: given time and study, given logic, curiosity and empirical investigation, we can figure it out. We can find out what makes it go. We can reverse-engineer the secrets of the universe.</p>

<p>By contrast, Weir gloats:</p>

<blockquote>
  <p>Did you really think you could destroy this ship? She&#8217;s defied space and time. She&#8217;s been to a place you couldn&#8217;t possibly imagine.</p>
</blockquote>

<p>Another character describes the ship&#8217;s destination as somewhere &#8220;beyond scientific reality&#8221;, &#8220;hell&#8221;. These are not the words of a scientist; they are the words of a priest. <cite>Event Horizon</cite> invokes the inexplicable supernatural and thereby becomes fantasy. Its moral is the moral of Babel or Icarus: who are we, mere mortals, to touch the sky?</p>

<p><a href="http://imdb.com/title/tt0448134/"><cite>Sunshine</cite></a>, written by Alex Garland (<a href="http://imdb.com/title/tt0289043/"><cite>28 Days Later</cite></a>) and directed by Danny Boyle (<a href="http://imdb.com/title/tt0117951/"><cite>Trainspotting</cite></a>), is a significantly better film, though its science is almost as dubious and it echoes its predecessor&#8217;s painful tumble into creature-feature horror. A team of astronauts are sent aboard the ship <i>Icarus II</i> to reignite our dying sun with a nuclear device, but events take a turn for the <cite>Horizon</cite> when they discover the <cite>Icarus I</cite>, thought lost seven years earlier when it failed in the same mission, intact but apparently abandoned.</p>

<p>When the crew have their corresponding encounter with an entity beyond easy understanding, it&#8217;s with nothing so abstruse as extradimensional evil: they find the sun. Even for the audience it approaches the spiritual. Like <a href="http://imdb.com/title/tt0062622/"><cite>2001: A Space Odyssey</cite></a>, some of the most memorable moments are long, slow shots of objects in space; and though the discordant post-rock score couldn&#8217;t be further from <cite>2001</cite>&#8217;s classical, the effect is the same. At once beautiful, frightening and inspiring, the images hint at the sublime. In <cite>Sunshine</cite>, they are images of the sun, so massive, so bright, so fundamentally alien to human experience that an emotional response is inevitable.</p>

<p>For the characters the experience is palpably religious. They dream about it at night; Searle (Cliff Curtis) sits in the observation chamber and bathes in light until he burns. Pinbacker (Mark Strong) makes it explicit: he looks into the sun and finds God there. The Icarus myth had already been registered in the names of the ships, but he invokes it again in his attempt to sabotage the mission. He is the instrument of God&#8217;s will: in accordance with the divine plan, humanity must be allowed to die.</p>

<p>Pinbacker is a murderous psychopath; the crew sensibly refuse to believe him. Humanity wins, and God&#8217;s plot (or Pinbacker&#8217;s interpretation of it) is foiled. That is not to say that the spiritual element of the film is diminished, but for the remaining characters it is a purely secular matter. Capa (Cillian Murphy) at one point comments that their computer simulations are inedaquate, because the high heat and the high gravity are enough to bend time and space. The phenomenon is graphically illustrated in the penultimate sequence, and though obviously unscientific &#8212; Boyle has quipped the warning, &#8220;Kids! Don&#8217;t stick your arm in the sun!&#8221; &#8212; it&#8217;s a figurative expression of the same sense of wonder that most of us find in our interactions with the natural world. A flower is no less perfect as the culmination of millions upon millions of evolutionary generations than it is as the work of a divine craftsman. The sun is no less magnificent as the product of purely natural energies. Even the irreligious can appreciate sublimity.</p>

<p>In <cite>Event Horizon</cite>&#8217;s defense, it&#8217;s not necessarily unscientific to claim something as unimaginable: human brains have limits. We evolved that way, coded to survive as hunter-gatherers. We were not coded to imagine the ten or eleven dimensions postulated by theories of quantum mechanics; it&#8217;s hard enough to accept that time is a fourth. (How do you visualize four dimensions on a three-dimensional plane?) Less esoteric but no less true, most of us couldn&#8217;t easily distinguish between a hot oven at 200°C and one at 250°C. To a primitive brain it hardly matters: both are hot enough to burn. How then can we deal with the surface of the sun, closer to 5000°C, or the core, over <em>12000000°C</em>? Death occurs too soon for nerve impulses to even reach the brain. &#8220;Unimaginable&#8221; is an appropriate label.</p>

<p>But imagination isn&#8217;t the end-all, and even if it fails we&#8217;re still capable of comprehending the difference between &#8220;two hundred&#8221; and &#8220;twelve million&#8221;. One of the many glories of science is that &#8220;unimaginable&#8221; is not the same as &#8220;indescribable&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://rephrase.net/days/07/05/sunshine/feed/</wfw:commentRss>
		</item>
		<item>
		<title>MPlayer</title>
		<link>http://rephrase.net/days/07/05/mplayer</link>
		<comments>http://rephrase.net/days/07/05/mplayer#comments</comments>
		<pubDate>Wed, 02 May 2007 13:15:08 +0000</pubDate>
		<dc:creator>Sam</dc:creator>
		
		<category>howto</category>

		<category>mplayer</category>

		<category>audio</category>

		<category>video</category>

		<category>applications</category>

		<guid isPermaLink="false">http://rephrase.net/days/07/05/mplayer</guid>
		<description><![CDATA[I am a man with an mplayer. Luckily, it&#8217;s less of a hammer and more of an absurd swiss army knife: there&#8217;s nothing it can&#8217;t do! The documentation is excellent but overly complicated for a beginner, hence this quick guide to some recipes I&#8217;ve found useful. I don&#8217;t want to have to work them out [...]]]></description>
			<content:encoded><![CDATA[<p>I am a man with an <code>mplayer</code>. Luckily, it&#8217;s less of a hammer and more of an <a href="http://www.wengerna.com/browse/product.jsp?prod_id=1260&amp;cat_id=1&amp;cat_name=Knives&amp;sub_cat_id=23">absurd swiss army knife</a>: there&#8217;s nothing it can&#8217;t do! The <a href="http://www.mplayerhq.hu/DOCS/man/en/mplayer.1.html">documentation</a> is excellent but overly complicated for a beginner, hence this quick guide to some recipes I&#8217;ve found useful. I don&#8217;t want to have to work them out from scratch again.</p>

<h3>Demux the audio from a video file</h3>

<p>A few days ago I used this to extract the audio from <a href="http://www.youtube.com/watch?v=7LmfCGy_ZLg">Neil Gaiman&#8217;s Authors@Google talk</a>. It ignores the video and dumps the audio straight to a file.</p>

<pre><code>mplayer &lt;input_file&gt; -dumpaudio -dumpfile &lt;output_file&gt;
</code></pre>

<p>The downside is that it&#8217;s only useful if the audio is playable on its own (in this case it was already an mp3). If not, <code>mencoder</code> can be used to convert arbitrary video files:</p>

<pre><code>mencoder &lt;input_file&gt; -ovc frameno -oac mp3lame -lameopts cbr:br=128 -of rawaudio -o &lt;output_file.mp3&gt;
</code></pre>

<p>The <code>-oac</code> option determines the output audio codec; here it&#8217;s the LAME mp3 encoder, set by <code>-lameopts</code> to encode as 128kbps CBR.</p>

<h3>Convert audio to mp3</h3>

<p>The method I&#8217;ve seen recommended elsewhere is to convert the file into raw PCM audio, typically a <code>.wav</code> file.</p>

<pre><code>mplayer &lt;input_file&gt; -novideo -ao pcm:file=&lt;output_file.wav&gt;
</code></pre>

<p>(This also works to extract the audio from a video file, incidentally.)</p>

<p>The downside is that <code>.wav</code> files are huge and useless, so we have to have plenty of spare disk space &#8212; 10MB per minute of audio! &#8212; and use a separate encoder, like LAME, for compression:</p>

<pre><code>lame --preset medium &lt;input.wav&gt; &lt;output.mp3&gt;
</code></pre>

<p><code>mencoder</code> only works on video files, but there is a dodgy method for forcing it to process audio. The trick is that it&#8217;s possible to specify an external audio file &#8212; the file we want to convert &#8212; to use in place of the video&#8217;s real audio stream. We just need a dummy video to pacify it:</p>

<pre><code>mencoder -ovc frameno -oac mp3lame -lameopts cbr:br=128 -of rawaudio -o &lt;output_file.mp3&gt; -audiofile &lt;input_file&gt; &lt;dummy_video_file&gt;
</code></pre>

<p>It&#8217;s a hack, but it does seem to work. If <code>mplayer</code> can play it, you can convert it, and <code>mplayer</code> can handle just about anything: RealMedia, FLV, AAC&#8230;</p>

<h3>Extract part of a video file</h3>

<pre><code>mencoder &lt;input_file&gt; -o &lt;output_file&gt; -oac copy -ovc copy -ss &lt;start&gt; -endpos &lt;time_since_start&gt;
</code></pre>

<p>Setting <code>-oac</code> and <code>-ovc</code> to &#8220;copy&#8221; &#8212; that is, to copy from the streams without encoding them &#8212; is fastest, but won&#8217;t always work. Try <code>-ovc lavc</code> and <code>-oac mp3lame</code> for decent defaults, or consult the &#8220;<a href="http://www.mplayerhq.hu/DOCS/HTML/en/encoding-guide.html">Encoding with MEncoder</a>&#8221; guide for the (extraordinarily complicated) details.</p>

<p>The time format is [[hh:]mm:]ss[.ms]. &#8220;15&#8243; is fifteen seconds; &#8220;10:05&#8243; is ten minutes and five seconds; &#8220;09:10:05&#8243; is nine hours, ten minutes and five seconds.</p>

<h3>Convert a video to a series of images</h3>

<pre><code>mplayer &lt;input_file&gt; -noaudio -vo jpeg
</code></pre>

<p><code>-vo gif89a</code> supposedly generates animated GIFs, but I can&#8217;t get it to work. Images can be resized or filtered like any other video stream, so that, for example, it&#8217;s possible to generate 100&#215;100 thumbnails:</p>

<pre><code>mplayer &lt;input_file&gt; -noaudio -vo jpeg -vf-add scale=100:100
</code></pre>

<h3>Rip streams</h3>

<p><code>mplayer</code> can play streaming audio and video, so it can rip streaming audio and video. The input file in any of the above examples can be replaced by a URL.</p>
]]></content:encoded>
			<wfw:commentRss>http://rephrase.net/days/07/05/mplayer/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
