<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>tlrobinson.net blog</title>
	<atom:link href="http://tlrobinson.net/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://tlrobinson.net/blog</link>
	<description></description>
	<lastBuildDate>Mon, 06 Apr 2009 08:37:15 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Using OLPC XO as an ebook reader for O&#039;Reilly&#039;s Safari Books Online</title>
		<link>http://tlrobinson.net/blog/2009/04/using-olpc-xo-as-an-ebook-reader-for-oreillys-safari-books-online/</link>
		<comments>http://tlrobinson.net/blog/2009/04/using-olpc-xo-as-an-ebook-reader-for-oreillys-safari-books-online/#comments</comments>
		<pubDate>Mon, 06 Apr 2009 08:37:15 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[XO]]></category>

		<guid isPermaLink="false">http://tlrobinson.net/blog/?p=101</guid>
		<description><![CDATA[A year ago I received an OLPC XO (the &#8220;$100 laptop&#8221;) through their Give One Get One program. I played with it for a few days and found it essentially useless due to unstable and slow software (and lack of &#8230; <a href="http://tlrobinson.net/blog/2009/04/using-olpc-xo-as-an-ebook-reader-for-oreillys-safari-books-online/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A year ago I received an <a href="http://laptop.org/">OLPC</a> XO (the &#8220;$100 laptop&#8221;) through their Give One Get One program. I played with it for a few days and found it essentially useless due to unstable and slow software (and lack of WPA support), so it quickly began gathering dust on a shelf (it has since improved).</p>
<p>Last week I was thinking about how <a href="http://www.amazon.com/Kindle-Safari-Online-Access-Support/forum/FxBVKST06PWP9B/Tx13VFZZSWRC994/1?_encoding=UTF8&#038;asin=B000FI73MA">cool it would be</a> if <a href="http://amazon.com/kindle">Amazon&#8217;s Kindle</a> supported <a href="http://www.safaribooksonline.com/">O&#8217;Reilly&#8217;s Safari Books Online</a> service, and I decided to dust off the XO to see if it could be used as an ebook reader for Safari Books. With a little help, it can.</p>
<p>In ebook mode you can scroll in all four directions, page up/down, and jump to the top or bottom of a page, but you cannot click the next/previous buttons within Safari Books. However, GreaseMonkey and a simple userscript can solve that.</p>
<p>The first step is to install the <a href="http://wiki.laptop.org/go/Activities/All#General_Search_and_Discovery">Firefox &#8220;Activity&#8221;</a>, or a <a href="http://www.olpcnews.com/forum/index.php?topic=4053.0l">version of Linux</a> that runs a stock Firefox. Then install <a href="https://addons.mozilla.org/en-US/firefox/addon/748">GreaseMonkey</a>. Finally, install this userscript:</p>
<p><a href="http://tlrobinson.net/userscripts/xo-safari.user.js">http://tlrobinson.net/userscripts/xo-safari.user.js</a></p>
<p>This simple userscript intercepts page up and page down (the &#8220;O&#8221; and &#8220;X&#8221; game pad) buttons and maps them to &#8220;previous&#8221; and &#8220;next&#8221; actions in Safari Books, allowing you to easily switch pages in ebook mode.</p>
]]></content:encoded>
			<wfw:commentRss>http://tlrobinson.net/blog/2009/04/using-olpc-xo-as-an-ebook-reader-for-oreillys-safari-books-online/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ropen: Remote &quot;open&quot; command for opening remote files locally on OS X</title>
		<link>http://tlrobinson.net/blog/2009/04/ropen-remote-open-command/</link>
		<comments>http://tlrobinson.net/blog/2009/04/ropen-remote-open-command/#comments</comments>
		<pubDate>Sun, 05 Apr 2009 04:40:15 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Command line]]></category>
		<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://tlrobinson.net/blog/?p=94</guid>
		<description><![CDATA[The Problem &#8212;&#8212;&#8212;&#8211; Most Mac OS X power users know about the ["open"](http://tuvix.apple.com/documentation/Darwin/Reference/ManPages/man1/open.1.html) command line tool which opens the files specified as arguments in their default (or a specified) OS X application. Additionally, many OS X text editors, such as &#8230; <a href="http://tlrobinson.net/blog/2009/04/ropen-remote-open-command/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The Problem<br />
&#8212;&#8212;&#8212;&#8211;</p>
<p>Most Mac OS X power users know about the ["open"](http://tuvix.apple.com/documentation/Darwin/Reference/ManPages/man1/open.1.html) command line tool which opens the files specified as arguments in their default (or a specified) OS X application. Additionally, many OS X text editors, such as TextMate (&#8220;mate&#8221;) and SubEthaEdit (&#8220;see&#8221;), come with command line tools which can be used to open files.</p>
<p>These are great when working locally, but obviously do no work remotely. Often when working on remote servers you end up using command line editors which you may not be as familiar with.</p>
<p>ropen&#8217;s Solution<br />
&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>The [ropen](http://github.com/tlrobinson/ropen) tool solves this problem using two simple shell scripts, which make use of MacFuse&#8217;s sshfs. You run the &#8220;ropen&#8221; program on your remote machine(s) when you want to open a remote file locally (this is equivalent to the OS X &#8220;open&#8221; command). The &#8220;ropend&#8221; daemon runs on your local OS X machine waiting for open requests, and the &#8220;ropen.php&#8221; PHP script proxies requests from ropen to ropend.</p>
<p>How it works<br />
&#8212;&#8212;&#8212;&#8212;</p>
<p>1. When ropen is executed it makes an HTTP request to ropen.php with the paths to be opened and application to open them with, if any, as well as the SSH user, host, and port of the remote machine.<br />
2. ropen.php stores this open request in a queue that is tied to ROPEN_SECRET via PHP&#8217;s sessions.<br />
3. ropend polls ropen.php every 1 second waiting for open requests. When it receives one it mounts the remote filesystem using sshfs (if it&#8217;s not already mounted) and opens the files or directories specified.</p>
<p>More information<br />
&#8212;&#8212;&#8212;&#8212;</p>
<p>See more information about ropen on the [ropen project page](http://github.com/tlrobinson/ropen).</p>
]]></content:encoded>
			<wfw:commentRss>http://tlrobinson.net/blog/2009/04/ropen-remote-open-command/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Determining the absolute absolute path of a shell script</title>
		<link>http://tlrobinson.net/blog/2009/03/determining-the-absolute-absolute-path-of-a-shell-script/</link>
		<comments>http://tlrobinson.net/blog/2009/03/determining-the-absolute-absolute-path-of-a-shell-script/#comments</comments>
		<pubDate>Mon, 30 Mar 2009 15:04:24 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Command line]]></category>
		<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://tlrobinson.net/blog/?p=91</guid>
		<description><![CDATA[In the course of working on projects like server-side Objective-J, jack, and now narwhal, I&#8217;ve often had to write shell scripts that needed to know their location in the filesystem. Rather than hardcoding it, I prefer to infer it automatically &#8230; <a href="http://tlrobinson.net/blog/2009/03/determining-the-absolute-absolute-path-of-a-shell-script/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In the course of working on projects like server-side <a href="http://cappuccino.org">Objective-J</a>, <a href="http://jackjs.org">jack</a>, and now <a href="http://github.com/tlrobinson/narwhal">narwhal</a>, I&#8217;ve often had to write shell scripts that needed to know their location in the filesystem. Rather than hardcoding it, I prefer to infer it automatically at runtime. Unfortunately this isn&#8217;t as easy as you would expect.</p>
<p>If the script is invoked with an absolute path (&#8220;/foo/bar/baz&#8221;) or from your PATH (&#8220;baz&#8221;), then &#8220;$0&#8243; in the script will contain the absolute of the script (&#8220;/foo/bar/baz&#8221;). However, if it is invoked using a relative path (&#8220;./bar/baz&#8221; from &#8220;/foo&#8221;) then $0 will contain the relative path (&#8220;./bar/baz&#8221;). Furthermore, if the path to the script is actually a symbolic link, you&#8217;ll get the symlink&#8217;s path instead of the original.</p>
<p>Surprisingly, I couldn&#8217;t find a definitive solution that handles all these cases, so I took the various ones I did find and created one which I think handles all the cases I&#8217;m aware of:</p>
<p><script src="http://gist.github.com/87785.js"></script></p>
<p>If you don&#8217;t want to resolve the symlinks remove the second half.</p>
]]></content:encoded>
			<wfw:commentRss>http://tlrobinson.net/blog/2009/03/determining-the-absolute-absolute-path-of-a-shell-script/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Embedding and loading a JNI library from a jar</title>
		<link>http://tlrobinson.net/blog/2009/03/embedding-and-loading-a-jni-library-from-a-jar/</link>
		<comments>http://tlrobinson.net/blog/2009/03/embedding-and-loading-a-jni-library-from-a-jar/#comments</comments>
		<pubDate>Mon, 09 Mar 2009 08:05:47 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://tlrobinson.net/blog/?p=85</guid>
		<description><![CDATA[When I searched for ways to load a JNI library from a jar there were numerous hints of how to do it, but no code that I could find. So here&#8217;s my solution: import java.net.URL; import java.util.zip.ZipFile; import java.io.File; import &#8230; <a href="http://tlrobinson.net/blog/2009/03/embedding-and-loading-a-jni-library-from-a-jar/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>When I searched for ways to load a JNI library from a jar there were numerous <a href="http://forums.sun.com/thread.jspa?threadID=393971">hints</a> of how to do it, but no code that I could find. So here&#8217;s my solution:</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#881350;">import</span><span style="color:#683821;"> java.net.URL;</span><br />
<span style="color:#881350;">import</span><span style="color:#683821;"> java.util.zip.ZipFile;</span><br />
<span style="color:#881350;">import</span><span style="color:#683821;"> java.io.File;</span><br />
<span style="color:#881350;">import</span><span style="color:#683821;"> java.io.FileOutputStream;</span><br />
<span style="color:#881350;">import</span><span style="color:#683821;"> java.io.InputStream;</span></p>
<p><span style="color:#881350;">public</span> <span style="color:#881350;">abstract</span> <span style="color:#881350;">class</span> UnixDomainSocket {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">static</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">try</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#236e25;">// get the class object for this class, and get the location of it<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">final</span> <span style="color:#440088;">Class</span> c = UnixDomainSocket.class;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">final</span> <span style="color:#440088;">URL</span> location = c.<span style="color:#003369;">getProtectionDomain</span>().<span style="color:#003369;">getCodeSource</span>().<span style="color:#003369;">getLocation</span>();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#236e25;">// jars are just zip files, get the input stream for the lib<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#440088;">ZipFile</span> zf = <span style="color:#881350;">new</span> <span style="color:#440088;">ZipFile</span>(location.<span style="color:#003369;">getPath</span>());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#440088;">InputStream</span> in = zf.<span style="color:#003369;">getInputStream</span>(zf.<span style="color:#003369;">getEntry</span>(<span style="color:#760f15;">&quot;libunixdomainsocket.jnilib&quot;</span>));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#236e25;">// create a temp file and an input stream for it<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#440088;">File</span> f = File.<span style="color:#003369;">createTempFile</span>(<span style="color:#760f15;">&quot;JARLIB-&quot;</span>, <span style="color:#760f15;">&quot;-libunixdomainsocket.jnilib&quot;</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#440088;">FileOutputStream</span> out = <span style="color:#881350;">new</span> <span style="color:#440088;">FileOutputStream</span>(f);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#236e25;">// copy the lib to the temp file<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">byte</span>[] buf = <span style="color:#881350;">new</span> <span style="color:#881350;">byte</span>[<span style="color:#0000ff;">1024</span>];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">int</span> len;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">while</span><span style="color:#003369;"> </span>((len = in.<span style="color:#003369;">read</span>(buf)) &gt; <span style="color:#0000ff;">0</span>)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.<span style="color:#003369;">write</span>(buf, <span style="color:#0000ff;">0</span>, len);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in.<span style="color:#003369;">close</span>();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.<span style="color:#003369;">close</span>();<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#236e25;">// load the lib specified by it&#8217;s absolute path and delete it<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.<span style="color:#003369;">load</span>(f.<span style="color:#003369;">getAbsolutePath</span>());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f.<span style="color:#003369;">delete</span>();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <span style="color:#881350;">catch</span><span style="color:#003369;"> </span>(<span style="color:#440088;">Exception</span> e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.<span style="color:#003369;">printStackTrace</span>();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.<span style="color:#003369;">exit</span>(<span style="color:#0000ff;">1</span>);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#236e25;">// &#8230;<br />
</span>}</div>
<p>This particular example is for <a href="http://code.google.com/p/juds/">JUDS</a>.</p>
<p>It could be extended to load one of several libraries for different architectures, .jnilib or .dylib for Mac OS X, .so for Linux, and .dll for Windows.</p>
<p>This seems like a lot of hoops to jump through, but I couldn&#8217;t find an easier way to do it. If you know of a better way, please let me know in the comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://tlrobinson.net/blog/2009/03/embedding-and-loading-a-jni-library-from-a-jar/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Game of Life text and image generator generator</title>
		<link>http://tlrobinson.net/blog/2009/02/game-of-life-generator/</link>
		<comments>http://tlrobinson.net/blog/2009/02/game-of-life-generator/#comments</comments>
		<pubDate>Sun, 08 Feb 2009 03:03:08 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Game of Life]]></category>

		<guid isPermaLink="false">http://tlrobinson.net/blog/?p=78</guid>
		<description><![CDATA[I saw this image the other day on Hacker News and Reddit: It&#8217;s a Game of Life pattern that prints out &#8220;Golly&#8221;. Neat, but I wanted my own. After about 5 minutes of playing around with the Golly logo pattern &#8230; <a href="http://tlrobinson.net/blog/2009/02/game-of-life-generator/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I saw this image the other day on <a href="http://news.ycombinator.com">Hacker News</a> and <a href="http://www.reddit.com/">Reddit</a>:</p>
<p><img src="http://golly.sourceforge.net/ticker.gif" alt="Golly Ticker" /></p>
<p>It&#8217;s a <a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life">Game of Life</a> pattern that prints out &#8220;Golly&#8221;. Neat, but I wanted my own. After about 5 minutes of playing around with the Golly logo pattern <em>in</em> <a href="http://golly.sourceforge.net/">Golly</a> (a program for experimenting with the Game of Life), I gave up and wrote a program to do it.</p>
<p>The program takes the top and bottom portions of a template pattern (based on the Golly pattern) and positions them, then fills in the gliders between them for the correct number of columns. Then it duplicates the entire pattern for each row. Finally it &#8220;draws&#8221; some text (using the sample font from <a href="http://pentacom.jp/soft/ex/font/">here</a>) by deleting the gliders corresponding to empty space.</p>
<p>This was great, but I had essentially created a dot matrix printer that could draw anything, so it would be a waste to not draw images with it. A few lines of Ruby/RMagick code later, I had a program that did just that. Here&#8217;s an example using the Reddit Logo (<a href="http://vimeo.com/3124876">watch it in HD</a> for the best results):</p>
<p><object width="640" height="360"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=3124876&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=FF7700&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=3124876&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=FF7700&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="640" height="360"></embed></object></p>
<p>The code is <a href="http://github.com/tlrobinson/life-gen/">available on GitHub</a>. It requires Ruby, and RMagick for images. Pass it &#8220;-s yourtext&#8221; to generate a text based pattern, or &#8220;-i imagepath&#8221; for an image pattern.</p>
<p>Download <a href="http://golly.sourceforge.net/">Golly</a> to open up the generated &#8220;.rle&#8221; files.</p>
]]></content:encoded>
			<wfw:commentRss>http://tlrobinson.net/blog/2009/02/game-of-life-generator/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Ant Tasks for Git</title>
		<link>http://tlrobinson.net/blog/2008/11/ant-tasks-for-git/</link>
		<comments>http://tlrobinson.net/blog/2008/11/ant-tasks-for-git/#comments</comments>
		<pubDate>Fri, 14 Nov 2008 06:20:30 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Git]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://tlrobinson.net/blog/?p=75</guid>
		<description><![CDATA[Ant has tasks for CVS and Subversion, but none that I could find for Git. I threw together these simple Ant macros to get started: &#60;macrodef name = &#34;git&#34;&#62; &#160;&#160;&#160;&#160;&#60;attribute name = &#34;command&#34; /&#62; &#160;&#160;&#160;&#160;&#60;attribute name = &#34;dir&#34; default = &#8230; <a href="http://tlrobinson.net/blog/2008/11/ant-tasks-for-git/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Ant has tasks for CVS and Subversion, but none that I could find for Git. I threw together these simple Ant macros to get started:</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#881280;">&lt;macrodef </span><span style="color:#994500;">name</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;git&quot;</span><span style="color:#881280;">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;attribute </span><span style="color:#994500;">name</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;command&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;attribute </span><span style="color:#994500;">name</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;dir&quot;</span><span style="color:#881280;"> </span><span style="color:#994500;">default</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;element </span><span style="color:#994500;">name</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;args&quot;</span><span style="color:#881280;"> </span><span style="color:#994500;">optional</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;true&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;sequential&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;echo </span><span style="color:#994500;">message</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;git @{command}&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;exec </span><span style="color:#994500;">executable</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;git&quot;</span><span style="color:#881280;"> </span><span style="color:#994500;">dir</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;@{dir}&quot;</span><span style="color:#881280;">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;arg </span><span style="color:#994500;">value</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;@{command}&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;args/&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;/exec&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;/sequential&gt;</span><br />
<span style="color:#881280;">&lt;/macrodef&gt;</span></p>
<p><span style="color:#881280;">&lt;macrodef </span><span style="color:#994500;">name</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;git-clone-pull&quot;</span><span style="color:#881280;">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;attribute </span><span style="color:#994500;">name</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;repository&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;attribute </span><span style="color:#994500;">name</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;dest&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;sequential&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;git </span><span style="color:#994500;">command</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;clone&quot;</span><span style="color:#881280;">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;args&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;arg </span><span style="color:#994500;">value</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;@{repository}&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;arg </span><span style="color:#994500;">value</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;@{dest}&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;/args&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;/git&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;git </span><span style="color:#994500;">command</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;pull&quot;</span><span style="color:#881280;"> </span><span style="color:#994500;">dir</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;@{dest}&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;/sequential&gt;</span><br />
<span style="color:#881280;">&lt;/macrodef&gt;</span></div>
<p>The first one, &#8220;git&#8221; just runs git with whatever command you provide to it (clone, pull, etc) along with any arguments you pass to it. Clone:</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#881280;">&lt;git </span><span style="color:#994500;">command</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;clone&quot;</span><span style="color:#881280;">&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;args&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;arg </span><span style="color:#994500;">value</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;git://github.com/280north/ojunit.git&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;arg </span><span style="color:#994500;">value</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;ojunit&quot;</span><span style="color:#881280;"> /&gt;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881280;">&lt;/args&gt;</span><br />
<span style="color:#881280;">&lt;/git&gt;</span>
</div>
<p>And pull:</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#881280;">&lt;git </span><span style="color:#994500;">command</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;pull&quot;</span><span style="color:#881280;"> </span><span style="color:#994500;">dir</span><span style="color:#881280;"> = </span><span style="color:#1a1aa6;">&quot;repository_path&quot;</span><span style="color:#881280;"> /&gt;</span></div>
<p>(Other git command will likely work, these are just the ones I needed)</p>
<p>The second one, &#8220;git-clone-pull&#8221; uses the first one to clone a repository then pull from it. This effectively clones the repository if it hasn&#8217;t already been cloned, otherwise it pulls. However, since ant is fairly limited in what sorts of conditional execution you can perform, it just does both (clone will fail if it&#8217;s already been cloned, and pull will always be executed, even immediately after a the initial clone). Obviously not ideal, but it works, and I couldn&#8217;t figure out a better way without writing actual code.</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#881280;">&lt;git-clone-pull </span><span style="color:#994500;">repository</span><span style="color:#881280;">=</span><span style="color:#1a1aa6;">&quot;git://github.com/280north/ojunit.git&quot;</span><span style="color:#881280;"> </span><span style="color:#994500;">dest</span><span style="color:#881280;">=</span><span style="color:#1a1aa6;">&quot;ojunit&quot;</span><span style="color:#881280;"> /&gt;</span></div>
<p>There is plenty of room for improvement, but I suspect a proper Ant task written in Java is the right way to go.</p>
]]></content:encoded>
			<wfw:commentRss>http://tlrobinson.net/blog/2008/11/ant-tasks-for-git/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>&quot;Mark Old As Read&quot; for NetNewsWire</title>
		<link>http://tlrobinson.net/blog/2008/11/mark-old-as-read-for-netnewswire/</link>
		<comments>http://tlrobinson.net/blog/2008/11/mark-old-as-read-for-netnewswire/#comments</comments>
		<pubDate>Fri, 14 Nov 2008 01:58:28 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[AppleScript]]></category>
		<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Mac]]></category>

		<guid isPermaLink="false">http://tlrobinson.net/blog/?p=73</guid>
		<description><![CDATA[I recently heard about an RSS reader (can&#8217;t remember which) that had a feature to mark all messages older than a certain threshold as &#8220;read&#8221;. I thought this was an incredibly useful feature, since I often forget to check my &#8230; <a href="http://tlrobinson.net/blog/2008/11/mark-old-as-read-for-netnewswire/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I recently heard about an RSS reader (can&#8217;t remember which) that had a feature to mark all messages older than a certain threshold as &#8220;read&#8221;. I thought this was an incredibly useful feature, since I often forget to check my feeds for days at a time, and end up with hundreds of unread items that I don&#8217;t have time to read.</p>
<p>Luckily my current RSS reader, <a href="http://www.newsgator.com/INDIVIDUALS/NETNEWSWIRE/">NetNewsWire</a>, has AppleScript built in, so I whipped up this script that prompts for the number of days you want to keep as unread, and marks the rest as read.</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#0b0bff;">tell</span> <span style="color:#0b0bff;">application</span> &quot;NetNewsWire&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;display dialog &quot;How many days old to mark read?&quot; default answer &quot;7&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0b0bff;">set</span> numDays <span style="color:#0b0bff;">to</span> text returned <span style="color:#0b0bff;">of</span> <span style="color:#0b0bff;">result</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0b0bff;">set</span> threshold <span style="color:#0b0bff;">to</span> (current date) &#8211; (numDays * <span style="color:#0b0bff;">days</span>)<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#0b0bff;">set</span> isRead <span style="color:#0b0bff;">of</span> (headlines <span style="color:#0b0bff;">of</span> subscriptions <span style="color:#0b0bff;">where</span> (isRead <span style="color:#0b0bff;">is</span> <span style="color:#0b0bff;">equal</span> <span style="color:#0b0bff;">to</span> <span style="color:#0b0bff;">false</span> <span style="color:#0b0bff;">and</span> date published &lt; threshold)) <span style="color:#0b0bff;">to</span> <span style="color:#0b0bff;">true</span><br />
<span style="color:#0b0bff;">end</span> <span style="color:#0b0bff;">tell</span></div>
]]></content:encoded>
			<wfw:commentRss>http://tlrobinson.net/blog/2008/11/mark-old-as-read-for-netnewswire/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A Better BugMeNot Bookmarklet</title>
		<link>http://tlrobinson.net/blog/2008/11/a-better-bugmenot-bookmarklet/</link>
		<comments>http://tlrobinson.net/blog/2008/11/a-better-bugmenot-bookmarklet/#comments</comments>
		<pubDate>Sun, 09 Nov 2008 10:46:21 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Hacks]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://tlrobinson.net/blog/?p=71</guid>
		<description><![CDATA[BugMeNot is a great little service for bypassing the registration process for websites that really shouldn&#8217;t require it (ahem, nytimes.com). The bookmarklet brings up BugMeNot for the current website you&#8217;re viewing, and gives you login/password pairs which you can then &#8230; <a href="http://tlrobinson.net/blog/2008/11/a-better-bugmenot-bookmarklet/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.bugmenot.com/">BugMeNot</a> is a great little service for bypassing the registration process for websites that really shouldn&#8217;t require it (ahem, nytimes.com). The bookmarklet brings up BugMeNot for the current website you&#8217;re viewing, and gives you login/password pairs which you can then copy and paste.</p>
<p>But wouldn&#8217;t it be better if it automagically filled in the username and password for you? I thought so, so I wrote a few lines of code in the form of a bookmarklet and a JSONP web service to do this.</p>
<p>BugMeNot doesn&#8217;t provide an API so I had to do a little screen scraping with <a href="https://code.whytheluckystiff.net/hpricot/">Hpricot</a>. They also try to obfuscate the usernames and passwords by shifting the characters by some offset calculated from a &#8220;key&#8221; then Base64 encoding the string, and prepending 4 characters. Luckily their obfuscation was no match for a single line of Ruby:</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#881350;">def</span> bmn_decode(input, offset)<br />
&nbsp;&nbsp;<span style="color:#236e25;"># decode base64, strip first 4 chars, convert chars to ints, substract offset, convert back ints back to chars<br />
</span>&nbsp;&nbsp;input.unpack(<span style="color:#760f15;">&quot;m*&quot;</span>)[<span style="color:#0000ff;">0</span>][<span style="color:#0000ff;">4.</span>.<span style="color:#0000ff;">-1</span>].unpack(<span style="color:#760f15;">&quot;C*&quot;</span>).map{|c| c &#8211; offset }.pack(<span style="color:#760f15;">&quot;C*&quot;</span>)<br />
<span style="color:#881350;">end</span></div>
<p>The bookmarklet makes the request via an injected &lt;script&gt; tag. When it&#8217;s callback gets called it finds the most likely input elements for the username and password and fills them in with the result.</p>
<p>The Rails app consists of a single action that makes a request to bugmenot.com for the specified site, extracts and decodes the usernames and passwords, and picks the one with the highest rating. It then returns the result as JSON wrapped in a function callback (i.e. JSONP)</p>
<p>I&#8217;m not going to post the location of the live JSONP web service since BugMeNot limits the number of requests you can make, but the code is available <a href="http://github.com/tlrobinson/tlrobinson/tree/master/bbmn">on GitHub</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://tlrobinson.net/blog/2008/11/a-better-bugmenot-bookmarklet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Open new Terminal tab in current directory (updated!)</title>
		<link>http://tlrobinson.net/blog/2008/10/open-new-terminal-tab/</link>
		<comments>http://tlrobinson.net/blog/2008/10/open-new-terminal-tab/#comments</comments>
		<pubDate>Thu, 23 Oct 2008 08:47:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Command line]]></category>
		<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Mac]]></category>

		<guid isPermaLink="false">http://tlrobinson.net/blog/?p=68</guid>
		<description><![CDATA[This is an updated shell script / AppleScript for opening a new tab in your current directory (or the specified directory). The last version was for the pre-tabbed version of Terminal. #!/bin/sh - if [ $# -ne 1 ]; then &#8230; <a href="http://tlrobinson.net/blog/2008/10/open-new-terminal-tab/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This is an updated shell script / AppleScript for opening a new <em>tab</em> in your current directory (or the specified directory). The <a href="http://tlrobinson.net/blog/2007/09/07/open-new-terminal-window-in-current-or-other-specified-directory/">last version</a> was for the pre-tabbed version of Terminal.</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#236e25;">#!/bin/sh -<br />
</span><br />
<span style="color:#881350;">if</span> [ <span style="color:#c4620a;">$#</span> -ne <span style="color:#0000ff;">1</span> ]; <span style="color:#881350;">then</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;PATHDIR=<span style="color:#660088;">`pwd`</span><br />
<span style="color:#881350;">else</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;PATHDIR=<span style="color:#c4620a;">$1</span><br />
<span style="color:#881350;">fi</span></p>
<p>/usr/bin/osascript &lt;&lt;-EOF<br />
activate application <span style="color:#760f15;">&quot;Terminal&quot;</span><br />
tell application <span style="color:#760f15;">&quot;System Events&quot;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;keystroke <span style="color:#760f15;">&quot;t&quot;</span> using {<span style="color:#440088;">command</span> down}<br />
end tell<br />
tell application <span style="color:#760f15;">&quot;Terminal&quot;</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;repeat with win <span style="color:#881350;">in</span> windows<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">if</span> get frontmost of win is <span style="color:#880088;">true</span> <span style="color:#881350;">then</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">do</span> script <span style="color:#760f15;">&quot;cd </span><span style="color:#c4620a;">$PATHDIR</span><span style="color:#760f15;">; clear&quot;</span> <span style="color:#881350;">in</span><span style="color:#003369;"> </span>(selected tab of win)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end <span style="color:#881350;">if</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end try<br />
&nbsp;&nbsp;&nbsp;&nbsp;end repeat<br />
end tell<br />
EOF
</div>
]]></content:encoded>
			<wfw:commentRss>http://tlrobinson.net/blog/2008/10/open-new-terminal-tab/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Automagically Wrapping JavaScript Callback Functions</title>
		<link>http://tlrobinson.net/blog/2008/10/wrapping-javascript-callbacks/</link>
		<comments>http://tlrobinson.net/blog/2008/10/wrapping-javascript-callbacks/#comments</comments>
		<pubDate>Wed, 22 Oct 2008 11:43:30 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Hacks]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://tlrobinson.net/blog/?p=59</guid>
		<description><![CDATA[One very nice thing about JavaScript is it&#8217;s support for first-class functions and closures. Crockford calls JavaScript &#8220;Lisp in C&#8217;s Clothing&#8221;. I&#8217;m no Lisper, but I enjoy I discovering new tricks or applications of functional programming in JavaScript. I wanted &#8230; <a href="http://tlrobinson.net/blog/2008/10/wrapping-javascript-callbacks/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>One very nice thing about JavaScript is it&#8217;s support for first-class functions and closures. Crockford calls JavaScript <a href="http://www.crockford.com/javascript/javascript.html">&#8220;Lisp in C&#8217;s Clothing&#8221;</a>. I&#8217;m no Lisper, but I enjoy I discovering new tricks or applications of functional programming in JavaScript.</p>
<p>I wanted to hook all the browser&#8217;s asynchronous JavaScript &#8220;entry points&#8221; : events, timers, asynchronous XMLHttpRequests, script tags, and &#8220;javascript:&#8221; URLs. This article deals with the first two, events and timers.</p>
<p>To do this, I figured I could somehow &#8220;wrap&#8221; all the callback functions passed to setTimeout(), setInterval(), and addEventListener(). By &#8220;wrapped&#8221; I mean another function that <em>we specify</em> calls the original function, rather than the original function getting called directly. This allows us do whatever we want right before and after calling the original function, including manipulating the arguments and return value, logging to the console, calling other functions, putting it in a try/catch, etc.</p>
<p>Here&#8217;s the implementation of &#8220;callbackWrap&#8221;, the function that does all the work:</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#881350;">function</span> <span style="color:#003369;">callbackWrap</span>(object, property, argumentIndex, wrapperFactory, extra) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">var</span> original = object[property];<br />
&nbsp;&nbsp;&nbsp;&nbsp;object[property] = <span style="color:#881350;">function</span>() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arguments[argumentIndex] = <span style="color:#003369;">wrapperFactory</span>(arguments[argumentIndex], extra);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">return</span> original.<span style="color:#003369;">apply</span>(<span style="color:#881350;">this</span>, arguments);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">return</span> original;<br />
}</div>
<p>To use it, you need function that takes another function as a parameter and returns a wrapped version of that function which does whatever you want it to. In this case it just prints out &#8220;whoooaaaaa:&#8221; followed by the &#8220;extra&#8221; parameter:</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#881350;">function</span> <span style="color:#003369;">logWrapper</span>(func, extra) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">return</span> <span style="color:#881350;">function</span>() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.<span style="color:#003369;">log</span>(<span style="color:#760f15;">&quot;whoooaaaaa: &quot;</span> + extra);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">return</span> func.<span style="color:#003369;">apply</span>(<span style="color:#881350;">this</span>, arguments);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</div>
<p>Finally, to actually use this, we call callbackWrap with the object that contains the function we want to wrap, the name of the function property, the index of the callback argument to the function (0 for setTimeout/setInterval, 1 for addEventListener), a wrapper &#8220;factory&#8221; function, and optionally an extra argument that&#8217;s made available (via the closure) to the wrapped function. The extra parameter can be used for any data you need to pass to the wrapper function, or it can be ignored.</p>
<p>Here&#8217;s how this would be used on setTimeout, setInterval, and addEventListener on window, Element.prototype and Document.prototype (so it applies to all Elements and Documents):</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#003369;">callbackWrap</span>(window, <span style="color:#760f15;">&quot;setTimeout&quot;</span>, <span style="color:#0000ff;">0</span>, logWrapper, <span style="color:#760f15;">&quot;wrapped a window.setTimeout!&quot;</span>);<br />
<span style="color:#003369;">callbackWrap</span>(window, <span style="color:#760f15;">&quot;setInterval&quot;</span>, <span style="color:#0000ff;">0</span>, logWrapper, <span style="color:#760f15;">&quot;wrapped a window.setInterval!&quot;</span>);<br />
<span style="color:#003369;">callbackWrap</span>(window, <span style="color:#760f15;">&quot;addEventListener&quot;</span>, <span style="color:#0000ff;">1</span>, logWrapper, <span style="color:#760f15;">&quot;wrapped a window.addEventListener!&quot;</span>);<br />
<span style="color:#003369;">callbackWrap</span>(Element.prototype, <span style="color:#760f15;">&quot;addEventListener&quot;</span>, <span style="color:#0000ff;">1</span>, logWrapper, <span style="color:#760f15;">&quot;wrapped a Element.addEventListener!&quot;</span>);<br />
<span style="color:#003369;">callbackWrap</span>(Document.prototype, <span style="color:#760f15;">&quot;addEventListener&quot;</span>, <span style="color:#0000ff;">1</span>, logWrapper, <span style="color:#760f15;">&quot;wrapped a Document.addEventListener!&quot;</span>);</div>
<p><a href="http://tlrobinson.net/misc/wrap.html">Here&#8217;s a live example.</a> <em>(edit: the button example seems to be broken in Firefox)</em></p>
<p>The first thing callbackWrap does is save the original function (window.setTimeout, for this example) in a local variable, &#8220;original&#8221;, since we&#8217;ll need it later. We then replace the original with a new function. When this new function is called (the new window.setTimeout), we first call the &#8220;wrapperMaker&#8221; function (&#8220;logWrapper&#8221; in the example), passing it the callback function, which is the argument at the argumentIndex position, and the optional &#8220;extra&#8221; argument. That function returns a new function which replaces the original callback argument, before we then call the original function (saved in the local variable &#8220;original&#8221;) with the same arguments (except the callback is now wrapped).</p>
<p>So really this blog post should have been called <em>&#8220;a function that wraps other functions such that all callback functions passed to it are wrapped by yet another function&#8221;</em>. There&#8217;s <em>two</em> levels of wrapping going on: the original function is wrapped, such that <em>it</em> wraps every <em>callback</em> given to it. If you&#8217;re confused I don&#8217;t blame you.</p>
<p>Why would I want to do this, you ask? There are a couple scenarios I had in mind, and I&#8217;m sure you can think of others.</p>
<p>First, I wanted to catch all uncaught exceptions for a debugging tool I&#8217;m working on. Sure, you can assign an error handler to the &#8220;onerror&#8221; property of the window object, but this only gives you the error name, file name, and line number – I wanted the full exception object to be caught by a try/catch.</p>
<p>Here&#8217;s a wrapper that catches all uncaught exceptions and alerts them:</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#881350;">function</span> <span style="color:#003369;">exceptionWrapper</span>(func, extra) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">return</span> <span style="color:#881350;">function</span>() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">try</span> {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">return</span> func.<span style="color:#003369;">apply</span>(<span style="color:#881350;">this</span>, arguments);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <span style="color:#881350;">catch</span><span style="color:#003369;"> </span>(e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#003369;">alert</span>(e);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</div>
<p>Second, in <a href="http://cappuccino.org">Cappuccino</a> we mimic Cocoa&#8217;s concept of a &#8220;run loop&#8221;, but due to the way browsers work the implementation is a bit different. A consequence of this was that we couldn&#8217;t automatically call &#8220;[[CPRunLoop currentRunLoop] performSelectors];&#8221; at the end of each run loop, which is required for various pieces of Cappuccino. If you&#8217;ve ever come across a situation where you perform some action but the UI doesn&#8217;t update until you move the mouse, it&#8217;s probably because performSelectors isn&#8217;t being called. This isn&#8217;t common, since Cappuccino encapsulates events, XMLHttpRequests, and now timers with CPEvent, CPURLConnection, and CPTimer, respectively. These Cappuccino classes handle calling performSelectors for you. However, if you wanted to integrate with a third party library or use setTimeout, XMLHttpRequest, etc directly, currently you would need to call performSelectors manually. With this new trick we can call it automagically.</p>
<p>Here&#8217;s the wrapper that does exactly that (note the inline Objective-J call to &#8220;[[CPRunLoop currentRunLoop] performSelectors]&#8221;):</p>
<div style="text-align:left;color:#000000; background-color:#ffffff; border:solid black 1px; padding:0.5em 1em 0.5em 1em; overflow:auto;font-size:small; font-family:monospace; "><span style="color:#881350;">function</span> <span style="color:#003369;">performSelectorsWrapper</span>(func, extra) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">return</span> <span style="color:#881350;">function</span>() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">var</span> result = func.<span style="color:#003369;">apply</span>(<span style="color:#881350;">this</span>, arguments);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#881350;">return</span> [[CPRunLoop currentRunLoop] performSelectors];<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</div>
<p>One minor feature I didn&#8217;t demonstrate was that callbackWrap returns the original function that it wrapped. If you need the original for any reason you can save it to some other variable.</p>
<p>callbackWrap could use a few improvements. Currently this breaks on cases where you pass a string instead of a function. A simple check for the argument type, and appropriate handling would solve this (either skipping the wrapping, or compiling the the string with a &#8220;new Function()&#8221; call). But using strings instead of functions is considered poor practice anyway.</p>
]]></content:encoded>
			<wfw:commentRss>http://tlrobinson.net/blog/2008/10/wrapping-javascript-callbacks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

