<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3099671593541938429</id><updated>2011-11-07T14:54:40.278-08:00</updated><category term='Python'/><category term='Google+'/><category term='pc'/><category term='3d graphics'/><category term='contests'/><category term='gadgets'/><category term='Picasa Web Albums'/><category term='Xbox 360'/><category term='blender'/><category term='ICFP'/><category term='games'/><category term='F#'/><category term='Java'/><category term='OSX'/><category term='go'/><category term='Lisp'/><category term='xbmc'/><category term='opengl es'/><category term='BitTorrent'/><category term='C++'/><category term='Haskell'/><category term='htpc'/><category term='Larrabee'/><category term='android'/><category term='quake'/><category term='opengl'/><category term='Chrome'/><category term='Linux'/><category term='Mac'/><category term='car audio'/><category term='Project Natal'/><category term='educational'/><category term='Ubuntu'/><category term='droid'/><category term='JavaScript'/><title type='text'>Grammerjack</title><subtitle type='html'>Notes on programming and games</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default?start-index=101&amp;max-results=100'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>113</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-3376753933293481881</id><published>2011-10-16T07:56:00.000-07:00</published><updated>2011-10-16T20:23:06.062-07:00</updated><title type='text'></title><content type='html'>I translated Alexander Boswell's&amp;nbsp;&lt;span style="background-color: transparent;"&gt;&lt;a href="http://www.steckles.com/reyes1.html"&gt;toy REYES renderer&lt;/a&gt; from C++ to Google's new&amp;nbsp;&lt;a href="http://www.dartlang.org/"&gt;Dart&lt;/a&gt;&amp;nbsp;programming language.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's what the output looks like:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-oYeNzVyFNhg/TprvdVN_VjI/AAAAAAAATIs/2VtH4kaa538/s1600/bumpy+sphere.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-oYeNzVyFNhg/TprvdVN_VjI/AAAAAAAATIs/2VtH4kaa538/s320/bumpy+sphere.png" width="313" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Try It Yourself&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;If your browser supports the canvas tag and JavaScript, you can see the sphere being rendered here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jacks-hacks.appspot.com/reyes-dart/index.html"&gt;Render a REYES bumpy sphere in your browser&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;And the source is here:&amp;nbsp;&lt;a href="http://code.google.com/p/reyes-dart/"&gt;http://code.google.com/p/reyes-dart/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Translating C++ to Dart&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;It was pretty easy to translate the original code from C++ to Dart.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;The original code made use of classes and overloaded operators, both of which are also in the Dart language.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;The original code used the SDL library to display output. It was easy to switch to the HTML5 CANVAS tag.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="background-color: transparent;"&gt;I used an early version of the "Dart Editor" IDE. The Dart Editor IDE was helpful because of the compiler warnings and errors.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Debugging&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I used a variety of techniques to debug the code:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;&lt;b&gt;print()&lt;/b&gt; Dart has a built-in print function that logs to the JavaScript console. This was good for logging small amounts of data.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;&lt;b&gt;write() &lt;/b&gt;This is a utility function I wrote that appended&amp;nbsp;the argument text to the document body of my HTML document. This has several advantages over "print":&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;Easier to see output during development.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;Much easier to search and copy/paste large amounts of text.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;b&gt;Dumping 3D geometry as text&lt;/b&gt;. At one point I wanted to check whether or not my geometry was correct. The easiest way to check it was to dump the geometry out as a 3D text file using "write()", and then copy-and-paste that code into a file and view it in the blender3d.org Blender app.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Using Chrome&lt;/b&gt; to step through the compiled app.js code. This was pretty painful, but was occasionally useful. The stack crawls for exceptions usually gave good hits as to what was going wrong.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;b&gt;Dart Limitations&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;The Dart "dom" library is not yet complete. Currently it can't write to canvas imageData. As a work-around I draw each pixel of output as a little filled rectangle.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Dart Editor Limitations&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I wish the Dart Editor would support:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Formatting code.&lt;/li&gt;&lt;li&gt;Stripping whitespace from ends of lines on save.&lt;/li&gt;&lt;li&gt;Converting tabs to spaces on save.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-3376753933293481881?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/3376753933293481881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=3376753933293481881' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3376753933293481881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3376753933293481881'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2011/10/i-translated-alexander-boswells-reyes.html' title=''/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-oYeNzVyFNhg/TprvdVN_VjI/AAAAAAAATIs/2VtH4kaa538/s72-c/bumpy+sphere.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-2230357240544774896</id><published>2011-09-11T21:10:00.000-07:00</published><updated>2011-09-12T05:44:55.816-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Google+'/><category scheme='http://www.blogger.com/atom/ns#' term='Picasa Web Albums'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>A script to upload files to Picasa Web Albums</title><content type='html'>Today I backed up all my family pictures and videos to Picasa Web Albums.&lt;br /&gt;&lt;br /&gt;For several months I have been thinking of ways to backup my pictures to somewhere outside my house. I wanted something simple, scalable and inexpensive.&lt;br /&gt;&lt;br /&gt;When I read that &lt;a href="http://picasa.google.com/support/bin/http://picasa.google.com/support/bin/answer.py?answer=1224181"&gt;Google+ users can store unlimited pictures sized &amp;lt;= 2048 x 2048 and videos &amp;lt;= 15 minutes long&lt;/a&gt;, I decided to try using Google+ to back up my media.&lt;br /&gt;&lt;br /&gt;Full disclosure: I work for Google, which probably predisposes me to like and use Google technologies.&lt;br /&gt;&lt;br /&gt;Unfortunately I had my pictures in so many folders that it wasn't very convenient to use either &lt;a href="http://picasa.google.com/"&gt;Picasa&lt;/a&gt; or &lt;a href="http://picasa.google.com/mac_tools.html"&gt;Picasa Web Albums Uploader&lt;/a&gt; to upload them.&lt;br /&gt;&lt;br /&gt;Luckily, I'm a programmer, and Picasa Web Albums has a public API for uploading images. Over the course of an afternoon, I wrote a Python script to upload my pictures and videos from my home computer to my Picasa Web Album account.&amp;nbsp;I put it up on GitHub:&amp;nbsp;&lt;a href="https://github.com/jackpal/picasawebuploader"&gt;picasawebuploader&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Good things:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;a href="http://code.google.com/apis/gdata/"&gt;Google Data Protocol&lt;/a&gt;&amp;nbsp;is easy to use.&lt;/li&gt;&lt;li&gt;Python's built-in libraries made file and directory traversal easy.&lt;/li&gt;&lt;li&gt;OSX's built-in "sips" image processing utility made it easy to scale images.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Bad things:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;The documentation for the Google Data Protocol is not well organized or comprehensive.&lt;/li&gt;&lt;li&gt;It's undocumented how to upload videos. Luckily I found a&amp;nbsp;&lt;a href="http://nathanvangheem.com/news/moving-to-picasa-update"&gt;Flicker-to-Picasa-Web&lt;/a&gt; script that showed me how.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;To do:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Use multiple threads to upload images in parallel.&lt;/li&gt;&lt;li&gt;Prompt for password if not supplied on command line.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-2230357240544774896?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/2230357240544774896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=2230357240544774896' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2230357240544774896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2230357240544774896'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2011/09/script-to-upload-files-to-picasa-web.html' title='A script to upload files to Picasa Web Albums'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5914772280977167565</id><published>2011-08-20T10:23:00.000-07:00</published><updated>2011-08-20T10:23:26.150-07:00</updated><title type='text'>What am I up to?</title><content type='html'>I'm mostly posting on google+ these days, sorry!&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5914772280977167565?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5914772280977167565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5914772280977167565' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5914772280977167565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5914772280977167565'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2011/08/what-am-i-up-to.html' title='What am I up to?'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4821326830608361555</id><published>2010-12-20T07:08:00.000-08:00</published><updated>2010-12-20T07:08:46.596-08:00</updated><title type='text'>Asynchronous directory tree walk in node.js</title><content type='html'>I wrote an asynchronous directory tree walker in &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt;. Note the use of Continuation Passing Style in the fileCb callback. That allows the callback to perform its own asynchronous operations before continuing the directory walk.&lt;br /&gt;&lt;br /&gt;(This code is provided under the &lt;a href="http://www.apache.org/licenses/LICENSE-2.0.html"&gt;Apache Licence 2.0&lt;/a&gt;.)&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 11px; line-height: 14px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre style="font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font: normal normal normal 12px/normal Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;div class="line" id="LC1" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;// asynchronous tree walk&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;// root - root path&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;// fileCb - callback function (file, next) called for each file&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;// -- the callback must call next(falsey) to continue the iteration,&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;//    or next(truthy) to abort the iteration.&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;// doneCb - callback function (err) called when iteration is finished&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;// or an error occurs.&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;//&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;// example:&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;//&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;// forAllFiles('~/',&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;//     function (file, next) { sys.log(file); next(); },&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC13" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;//     function (err) { sys.log("done: " + err); });&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC14" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC15" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="kd" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;function&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;forAllFiles&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;root&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;fileCb&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;doneCb&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC16" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;fs&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;.&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;readdir&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;root&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="kd" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;function&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;processDir&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;files&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC17" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;if&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC18" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;fileCb&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC19" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt; &lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;else&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC20" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;if&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;files&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;.&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;length&lt;/span&gt; &lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi" style="color: #009999; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;0&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC21" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="kd" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;var&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;file&lt;/span&gt; &lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;=&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;root&lt;/span&gt; &lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;+&lt;/span&gt; &lt;span class="s1" style="color: #dd1144; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;'/'&lt;/span&gt; &lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;+&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;files&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;.&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;shift&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;();&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC22" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;fs&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;.&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;stat&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;file&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="kd" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;function&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;processStat&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;stat&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC23" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;if&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC24" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;doneCb&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC25" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt; &lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;else&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC26" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;if&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;stat&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;.&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;isFile&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;())&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC27" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;fileCb&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;file&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="kd" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;function&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC28" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;if&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC29" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;doneCb&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC30" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt; &lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;else&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC31" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;processDir&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="kc" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;false&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;files&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC32" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC33" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;});&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC34" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt; &lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;else&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC35" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;forAllFiles&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;file&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;fileCb&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="kd" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;function&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC36" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;if&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC37" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;doneCb&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;err&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC38" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt; &lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;else&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC39" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;processDir&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="kc" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;false&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;files&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC40" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC41" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;});&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC42" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC43" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC44" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;});&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC45" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt; &lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;else&lt;/span&gt; &lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC46" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nx" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;doneCb&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="kc" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;false&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC47" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC48" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC49" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;});&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC50" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4821326830608361555?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4821326830608361555/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4821326830608361555' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4821326830608361555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4821326830608361555'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/12/asynchronous-directory-tree-walk-in.html' title='Asynchronous directory tree walk in node.js'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5211755537776181711</id><published>2010-11-12T15:25:00.000-08:00</published><updated>2010-11-12T15:26:03.386-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSX'/><category scheme='http://www.blogger.com/atom/ns#' term='pc'/><category scheme='http://www.blogger.com/atom/ns#' term='educational'/><title type='text'>Getting Old Educational Software to Run on OSX 10.6</title><content type='html'>My kids' favorite piece of educational software is "&lt;a href="http://www.google.com/search?q=Clifford+thinking+adventures"&gt;Clifford The Big Red Dog Thinking Adventures&lt;/a&gt;" by Scholastic. We received it as a hand-me-down from their cousins. The CD was designed for Windows 95-98 and pre-OSX Macintosh. Unfortunately, it does not run on OS X 10.6. (I think it fails to run because it uses the PowerPC instruction set and Apple dropped support for emulating that instruction set in 10.6.)&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After some trial and error, I found the most reliable way to run Clifford on my Mac was:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Install &lt;a href="http://www.vmware.com/products/fusion/"&gt;VMWare Fusion&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Install &lt;a href="http://www.ubuntu.com/desktop/get-ubuntu/download"&gt;Ubuntu 10.10 32-bit&lt;/a&gt; in a Virtual Machine.&lt;/li&gt;&lt;li&gt;Install the VMWare Additions to make Ubuntu work better in the VM.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.multimediaboom.com/how-to-upgarde-to-latest-wine-1-3-5/"&gt;Install Wine on Ubuntu 10.10&lt;/a&gt;. (Wine provides partial Windows API emulation for Linux.)&lt;/li&gt;&lt;li&gt;Configure the audio for Wine. (I accepted the defaults.)&lt;/li&gt;&lt;li&gt;Insert the Clifford CD and manually run the installer.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;The result is that the Clifford game runs full screen with smooth animation and audio, even on my lowly first-generation Intel Mac Mini.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You may scoff at all these steps, but (a) it's cheap, and (b) it's less work than installing and maintaining a Windows PC or VM just to play this one game.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(It's too bad there isn't a Flash, HTML5, Android or iOS version of this game, it's really quite well done.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5211755537776181711?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5211755537776181711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5211755537776181711' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5211755537776181711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5211755537776181711'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/11/getting-old-educational-software-to-run.html' title='Getting Old Educational Software to Run on OSX 10.6'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-9153472622774649809</id><published>2010-09-05T19:42:00.000-07:00</published><updated>2010-09-05T20:26:06.229-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pc'/><title type='text'>Eulogy for a PC</title><content type='html'>This Labor Day weekend I decommissioned my tower PC.&lt;br /&gt;&lt;br /&gt;If memory serves, I bought it in the summer of 2002, in one last burst of PC hobby hacking before the birth of my first child. It's served me and my growing family well over the years, first as my main machine, later as a media server.&lt;br /&gt;&lt;br /&gt;But the world has changed, and it doesn't make much sense to keep it running any more. It's been turned off for the last year while I traveled to Taiwan. In that time I've learned to live without it.&lt;br /&gt;&lt;br /&gt;The specific reasons for&amp;nbsp;decommissioning&amp;nbsp;it now are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It needs a new CMOS battery.&lt;/li&gt;&lt;li&gt;It needs a year's worth of Vista service packs and security updates.&lt;/li&gt;&lt;li&gt;I don't use the media center feature any more.&lt;/li&gt;&lt;li&gt;After a year without a Windows machine I don't want to maintain one any more.&lt;/li&gt;&lt;li&gt;It's too noisy and uses too much energy to leave on as a server.&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;The decommissioning process&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I booted it, and combed through the directories. I carefully copied off all the photos, code projects, email and documents that had accumulated over the years. Lots of good memories!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;GMail Import&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I discovered some old Outlook Express message archives. I wrote a Python script to import them into GMail. I didn't like any of the complicated&amp;nbsp;recipes&amp;nbsp;I found on the web, so I did it the easy way: I wrote a toy POP3 server in Python that served the ".eml" messages from the archive directory. Once the toy POP3 server was running, GMail was happy to import all the email messages from my server.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Erasing the disks with Parted Magic&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Once I was sure I had copied all my data off the machine it was time to erase the disks. I&amp;nbsp;erased the disks using the &lt;a href="https://ata.wiki.kernel.org/index.php/ATA_Secure_Erase"&gt;ATA Secure Erase&lt;/a&gt; command. I did this using a small Linux distro, &lt;a href="http://partedmagic.com/"&gt;Parted Magic&lt;/a&gt;. I downloaded the distribution ISO file and burned my own CD. Once the CD was burned, I just rebooted the PC and it loaded Parted Magic from the CD.&lt;br /&gt;&lt;br /&gt;Parted Magic has a menu item, "Erase Disk". It lets you choose the disk and the erase method. The last method listed is the one I used. The other methods work too, but they don't use the ATA Secure Erase command.&lt;br /&gt;&lt;br /&gt;It took quite a while to erase the disks. Each disk took about two hours to erase. (They took 200 GB per hour, to be precise.) Unfortunately, due to the limitations of my ATA drivers,&amp;nbsp;I had to erase them one at a time.&lt;br /&gt;&lt;br /&gt;While I think the ATA Secure Erase command is the fastest and most reliable way to erase modern hard disks, there is another way: Instead of having the drive erase itself, you can copy data over every sector of the drive. The advantage of this&amp;nbsp;technique&amp;nbsp;is that it also works with older drives. If you choose to go this route, one of the easiest way to do it is to use&amp;nbsp;&lt;a href="http://www.dban.org/"&gt;Darik's Boot and Nuke&lt;/a&gt;&amp;nbsp;utility. This is a Linux distro that does nothing besides erasing all the hard disks of the computer you boot it on. You just boot the CD, then type "autonuke" to erase every disk connected to your computer.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Disposing of the computer&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;It's still a viable computer, so I will probably donate it to a local charity. The charity has a rule that the computer you donate must be less than 5 years old. I think while some parts of the computer are older than that, most of the parts are young enough to qualify.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reflections on the desktop PC platform&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Being able to upgrade the PC over the years is a big advantage of the traditional desktop tower form factor. Here's how I upgraded it over the years:&lt;br /&gt;&lt;br /&gt;Initial specs (2002)&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Windows XP&lt;/li&gt;&lt;li&gt;ASUS P4S533 motherboard&lt;/li&gt;&lt;li&gt;Pentium 4 at 1.8 GHz&lt;/li&gt;&lt;li&gt;ATI 9700 GPU&lt;/li&gt;&lt;li&gt;Dell 2001 monitor (1600 x 1200)&lt;/li&gt;&lt;li&gt;256 MB RAM&lt;/li&gt;&lt;li&gt;20 GB PATA HD&lt;/li&gt;&lt;li&gt;Generic case&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Final specs (2010)&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Windows Vista Ultimate&lt;/li&gt;&lt;li&gt;ASUS P4S533 motherboard&lt;/li&gt;&lt;li&gt;Pentium 4 at 1.8 GHz&lt;/li&gt;&lt;li&gt;ATI 9700 GPU&lt;/li&gt;&lt;li&gt;Dell 2001 monitor (1600 x 1200)&lt;/li&gt;&lt;li&gt;1.5 GB RAM&lt;/li&gt;&lt;li&gt;400 GB 7200 RPM PATA HD&lt;/li&gt;&lt;li&gt;300 GB 7200 RPM PATA HD&lt;/li&gt;&lt;li&gt;ATI TV Theater analog capture card&lt;/li&gt;&lt;li&gt;Linksys Gigabit Ethernet PCI card&lt;/li&gt;&lt;li&gt;Antec&amp;nbsp;Sonata&amp;nbsp;quiet case&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I think these specs show the problems endemic to the desktop PC market. Although I didn't know it at the time, the PC platform had already plateaued. In eight years of use I wasn't motivated to upgrade the CPU, motherboard, monitor, or GPU. If I hadn't been a Microsoft employee during part of this time I wouldn't have upgraded the OS either.&lt;br /&gt;&lt;br /&gt;What killed the PC for me wasn't the hardware wearing out, it was mission change. Like most people I now use the web rather than the local PC for most of my computer activity. Maintaining the local PC is pure overhead, and I've found it's easier to maintain a Mac than a PC.&lt;br /&gt;&lt;br /&gt;It was nostalgic to turn on the PC again and poke through the Vista UI. It brought back some good memories. (And I discovered some cute pictures of my kids that I'd forgotten about.)&lt;br /&gt;&lt;br /&gt;Thank you trusty PC. You served me and my family well!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-9153472622774649809?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/9153472622774649809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=9153472622774649809' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/9153472622774649809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/9153472622774649809'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/09/eulogy-for-pc.html' title='Eulogy for a PC'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-2340583276269271463</id><published>2010-08-29T08:47:00.000-07:00</published><updated>2010-08-29T09:20:43.765-07:00</updated><title type='text'>An update on my car stereo</title><content type='html'>It's been a year since &lt;a href="http://grammerjack.blogspot.com/2009/07/too-many-words-about-car-stereos.html"&gt;I bought my fancy car stereo&lt;/a&gt;. I wanted to mention that I've ended up not using most of the fancy features.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The built-in MP3 player had issues with my 1000-song / 100 album / 4 GB music collection:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;It took a long time to scan the USB storage each time the radio turned on.&lt;/li&gt;&lt;li&gt;It was difficult to navigate the album and song lists.&lt;/li&gt;&lt;li&gt;Chinese characters were not supported.&lt;/li&gt;&lt;li&gt;It took a long time to "continue" a paused item, especially a long item like a podcast.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;The bluetooth pairing only worked with one phone at a time, which was awkward in a two-driver family.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Here's how I use it now:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;I connect my phone using both the radio's USB (so the phone is being charged) and mini stereo plugs.&lt;/li&gt;&lt;li&gt;I use the phone's built-in music player.&lt;/li&gt;&lt;li&gt;I have the radio set to AUX to play the music from the stereo input plug.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;It's a little bit cluttered, because of the two cables, but it gets the job done. The phone's music player UI is so much better than the radio's UI.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In effect I have reduced the car stereo to serving as a volume control, an amplifier, and a USB charger.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-2340583276269271463?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/2340583276269271463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=2340583276269271463' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2340583276269271463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2340583276269271463'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/08/update-on-my-car-stereo.html' title='An update on my car stereo'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-1861769391679881165</id><published>2010-07-25T14:00:00.000-07:00</published><updated>2010-07-25T14:04:44.138-07:00</updated><title type='text'>What I did on my Winter Vacation</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: 'Lucida Grande'; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 11px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;I just returned to the US after eight months living in Taiwan. The trip was great fun for me and my family. But more than that, it was a very productive time for me to learn new programming technologies.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why was my trip so productive?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I think some of the reasons were:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;I was away from my home computer set up (including video game consoles and a large TV). All I had was a Mac Mini (for the family to use), a MacBook Pro (for work) and a Nexus One phone.&lt;/li&gt;&lt;li&gt;I commuted by bus rather than car. While my commute time was longer, it was much more productive. Instead of having to concentrate on driving, I had 40 minutes a day of free time to think, web surf, and even code.&lt;/li&gt;&lt;li&gt;I didn't follow local politics, and USA politics were made less interesting by distance and time zone. I stopped visiting political web sites and obsessing over current events.&lt;/li&gt;&lt;li&gt;The timezone difference between Taipei and the US ment that email became a once-a-day event, rather than a continuous stream of interruptions.&lt;/li&gt;&lt;li&gt;It's more time-efficient to live as a guest in a city than as a home owner in the suburbs. For example, my mother-in-law cooked our meals, and I didn't have nearly as many household chores as I do in America.&lt;/li&gt;&lt;li&gt;Location-based internet blocks ment that some of my favorite time-wasting web sites (Pandora, Hulu) were unavailable.&lt;/li&gt;&lt;li&gt;Having to explain and defend my technology opinions to my Google Taipei coworkers. "Go is a cool language" I would say. "Oh yeah? Why?" they would reply. I would struggle to explain, and usually both of us would end up more enlightened.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Beyond that, I think being in a new environment, and removed from my home, helped shake me loose from my mental ruts. I was learning how to live in a new physical environment, and that transfered over to how I used the web as well.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What did I do?&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;I visited&amp;nbsp;&lt;a href="http://news.ycombinator.com/"&gt;Hacker News&lt;/a&gt;&amp;nbsp;frequently. &amp;nbsp;It is a very good source of news on the startup business and new web technologies. &amp;nbsp;Hacker News was where I first learned about Node.js and CoffeeScript, two of my current interests.&lt;/li&gt;&lt;li&gt;I entered the &lt;a href="http://csclub.uwaterloo.ca/contest/"&gt;Google AI Challenge&lt;/a&gt;, a month long Game AI programming contest. I didn't place very high, but I had fun competing.&lt;/li&gt;&lt;li&gt;I gave two talks on the Go programming language. One at the Google Taiwan office, the other at the Open Source Developer Conference Taiwan OSDC.tw. Having to give a talk about a programming&amp;nbsp;language&amp;nbsp;helps increase one's understanding of that language.&lt;/li&gt;&lt;li&gt;An afternoon spent hanging out with JavaScript Mahatma Douglas Crockford. I worked with Douglas ages ago when we both worked at Atari. It was great to catch up with him and his work. (He was in town to give a speech at the OSDC conference.)&lt;/li&gt;&lt;li&gt;I joined GitHub, and started using it to host my new open source projects.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;I wrote Taipei-Torrent, a Bit Torrent client written in "Go".&lt;/li&gt;&lt;li&gt;I started summerTorrent, a Bit Torrent client written in JavaScript, based on node.js&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;node.js - an interesting server-side JavaScript environment.&lt;/li&gt;&lt;li&gt;CoffeeScript - a JavaScript preprocessor that looks like a promising&amp;nbsp;language.&lt;/li&gt;&lt;li&gt;PhoneGap - a cross-platform mobile JavaScript / HTML5 UI framework. I wrote a word scramble game using this framework.&lt;/li&gt;&lt;li&gt;DD-WRT routers. I bought four new DLink 300 routers (which are dirt cheap), installed DD-WRT on them, and used them to upgrade my Taiwan relatives' computer network.&lt;/li&gt;&lt;li&gt;My nephew bought a PS3, so I finally had a chance to see Little Big Planet and Flower, two games I had long wanted to know more about. I also got to see a lot of Guitar Hero being played. Unfortunately I didn't get a chance to actually play any of these games -- someone else always had a higher claim on the TV.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Keeping the Taipei Experience Alive&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm back in the US, and am already starting to slip back into my old ways. Here are some ways I'm trying to keep my productivity up:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Cool side projects.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;I'm going to continue to work on side projects to learn new things. I want to do something serious with CoffeeScript and Node.js.&lt;/li&gt;&lt;li&gt;iPad. I'm getting one in a few weeks, and looking to see if its a useful paradigm.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Get rid of distractions.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;I'm selling off (or just closeting) distractions like my older computers and my media center.&lt;/li&gt;&lt;li&gt;I edited my /etc/hosts file to block access to all my top time-wasting web sites. Hopefully I won't just replace these with a new generation of web sites.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Working at home. My work office here in the US is just too noisy for me to concentrate in. I'm going to start spending as much time as possible working from a quiet room at home.&lt;/li&gt;&lt;li&gt;Regular exercise. I got a lot of walking done in Taiwan. I'm going to take up running again. (Easy to do now, we'll see how it goes when the weather gets rough.)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;I may even get a pair of "Gorilla Shoes" for barefoot running.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-1861769391679881165?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/1861769391679881165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=1861769391679881165' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1861769391679881165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1861769391679881165'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/07/what-i-did-on-my-winter-vacation.html' title='What I did on my Winter Vacation'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-1768171402158929348</id><published>2010-06-18T05:54:00.000-07:00</published><updated>2010-06-18T06:22:12.725-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ICFP'/><title type='text'>ICFP 2010 contest is a bust for me</title><content type='html'>&lt;a href="http://icfpcontest.org/2010/"&gt;The ICFP 2010 contest rules&lt;/a&gt; have been posted, and I am quite disappointed by this year's contest.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This year's contest is difficult to describe. It's too clever by half, and it depends too much on time, and too much on repeated interaction with the organizer's servers.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The conceit is that you're designing "car engines", and "fuel for car engines".  A car engine is a directed graph with certain properties, and "fuel" is a directed graph with other properties that generates a set of coefficients that are fed to the engine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Layered on top of that is an encoding puzzle (you have to figure out how the engine and fuel directed graphs are encoded for submission to the IFCP servers.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Layered on top of that is an economy where you are encouraged to submit your own car engines and write optimal fuels for other people's car engines. There are benefits for finding better fuels for existing car designs. (You aren't provided the details of the other car designs.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Layered on top of that is that the instructions are not written very clearly. I had to read them multiple times to start to even begin to understand what was going on.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And finally, the contest registration / submission web site is returning 503 (Service Temporarily Unavailable) errors, either because it hasn't been turned on yet, or perhaps because hundreds of teams are trying to use it at once.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I suspect this contest is going to be difficult for teams with limited Internet connectivity. I also suspect the contest  servers are going to be very busy later in the contest as people start hitting them with automated tools repeatedly in order to start decoding engines.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I salute the contest organizers for trying to get contestants to interact with each other during the contest, and for coming up with an original idea.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I fault them for designing a "write your program in _our_ language, not yours" puzzle. I want to enjoy programming in the language of my choice, not design graphs and finite state automata for creating fuel coefficients and engines.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I am going to punt this year -- the contest just doesn't sound very fun.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;I hope next year's topic is more to my taste!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-1768171402158929348?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/1768171402158929348/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=1768171402158929348' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1768171402158929348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1768171402158929348'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/06/icfp-2010-contest-is-bust-for-me.html' title='ICFP 2010 contest is a bust for me'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5052686879068495545</id><published>2010-05-07T19:56:00.000-07:00</published><updated>2010-05-07T21:49:12.075-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Writing an Android application in JavaScript and HTML5</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_kmzTWylBF0o/S-TW75jjnJI/AAAAAAAADkk/zPPiAQ27QsY/s1600/game.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 240px; height: 400px;" src="http://1.bp.blogspot.com/_kmzTWylBF0o/S-TW75jjnJI/AAAAAAAADkk/zPPiAQ27QsY/s400/game.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5468732172085206162" /&gt;&lt;/a&gt;&lt;br /&gt;Happy Mother's Day everyone! This year I wrote an Android app for my wife for Mother's Day. How geeky is that? &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The reason I wrote it is that my wife's favorite Android application, Word Mix Lite, recently added annoying banner ads. While the sensible thing to do might have been to switch to another app, or perhaps upgrade to the paid version of Word Mix, I thought it might be interesting to see if I could write my own replacement.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And as long as I was writing the app, I though I'd try writing it using JavaScript. Normally Android applications are written in Java, but it's also possible to write them in JavaScript, by using a shell application such as &lt;a href="http://phonegap.pbworks.com/Getting-Started-with-PhoneGap-(Android)"&gt;PhoneGap&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why use JavaScript instead of Java? Well, hack value mostly. On the plus side it's a fun to write! Another potential plus is that it is theoretically possible to run the same PhoneGap application on both Android and Apple.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The drawback is that PhoneGap is not very popular yet, especially among Android developers, and so there is relatively little documentation. I ran into problems related to touch events and click events that I still haven't completely solved.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It took about three days to write the application. The first day was spent:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Finding &lt;a href="http://wordlist.sourceforge.net/12dicts-readme.html"&gt;a public domain word list&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Filtering the word list to just 3-to-6 character words.&lt;/li&gt;&lt;li&gt;Build a "trie" to make it fast to look up anagrams.&lt;/li&gt;&lt;li&gt;Output the trie as a JSON data structure.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;The second day was spent writing the core of the word jumble game.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;This was all done on a desktop, using Chrome's built-in Javascript IDE.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;The third day was spent:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Porting to PhoneGap.&lt;/li&gt;&lt;li&gt;Debugging Android-specific issues.&lt;/li&gt;&lt;li&gt;Tuning the gameplay for the phone.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;The project went pretty well. &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;JavaScript is a very easy language to work in.&lt;/li&gt;&lt;li&gt;CSS styling was fairly easy to learn.&lt;/li&gt;&lt;li&gt;Targeting a single browser made it relatively easy to use the DOM.&lt;/li&gt;&lt;li&gt;The Chrome JavaScript debugger was very helpful.&lt;/li&gt;&lt;li&gt;The web has a wealth of information on JavaScript and HTML / CSS programming information.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the end there were unfortunately a few button-event UI glitches I couldn't solve in time for Mother's Day. When I get some spare time I'd like to revisit this project and see if I could use the &lt;a href="http://www.jqtouch.com/"&gt;JQTouch&lt;/a&gt; library to solve my UI glitches. I'd also like to make an open source release of a reskinned (non-Mother's Day themed) version of this app. And then who knows? Maybe I'll release it for the other phones that PhoneGap supports as well. :-)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5052686879068495545?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5052686879068495545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5052686879068495545' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5052686879068495545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5052686879068495545'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/05/writing-android-application-in.html' title='Writing an Android application in JavaScript and HTML5'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_kmzTWylBF0o/S-TW75jjnJI/AAAAAAAADkk/zPPiAQ27QsY/s72-c/game.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4208577812980058451</id><published>2010-03-06T12:17:00.000-08:00</published><updated>2010-03-06T12:44:14.220-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='go'/><category scheme='http://www.blogger.com/atom/ns#' term='contests'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Google AI Challenge 2010</title><content type='html'>&lt;a href="http://csclub.uwaterloo.ca/contest/profile.php?user_id=1515"&gt;Team Blue Iris&lt;/a&gt; (that's me!) placed 77th out of 708 in the &lt;a href="http://csclub.uwaterloo.ca/contest/"&gt;Google AI Challenge 2010&lt;/a&gt; contest. The contest was to design an AI for a Tron lightcycle game.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My entry used the standard min/max approach, similar to many other entries. I guess that's why it performed similarly to so many other entries. :-) I didn't have any time to investigate better algorithms, due to other obligations.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In addition to my own entry (which was in C++), I also created starter packs for JavaScript and Google's Go language. These starter packs enabled people to enter the contest using JavaScript or Go. In the end, &lt;a href="http://csclub.uwaterloo.ca/contest/language_profile.php?lang=Go"&gt;6 people entered using Go&lt;/a&gt;, and &lt;a href="http://csclub.uwaterloo.ca/contest/language_profile.php?lang=JavaScript"&gt;4 people entered using JavaScript&lt;/a&gt;. I'm pleased to have helped people compete using these languages.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I initially wanted to use JavaScript and/or Go myself, but the strict time limit of the contest strongly favored the fastest language, and that made me choose a C++ implementation. Practically speaking, there wasn't much advantage to using another language. The problem didn't require any complicated data structures, closures, or dynamic memory allocation. And the submitted entries were run on a single-hardware-thread virtual machine, which meant that there wasn't a performance benefit for using threads.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This contest was interesting because it went on for a long time (about a month) and because the contestants freely shared algorithm advice during the contest. This lead to steadily improving opponents. My program peaked at about 20th place early in the contest, but because I didn't improve it thereafter, its rank gradually declined over the rest of the contest.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://a1k0n.net/blah/archives/2010/03/index.html"&gt;The contest winner's post-mortem&lt;/a&gt; reveals that he won by diligent trial-and-error in creating a superior evaluation function. Good job a1k0n!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Congratulations to the contest organizers for running an interesting contest very well. I look forward to seeing new contests from the University of Waterloo Computer Club in the future.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4208577812980058451?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4208577812980058451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4208577812980058451' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4208577812980058451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4208577812980058451'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/03/google-ai-challenge-2010.html' title='Google AI Challenge 2010'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-2798501398723709984</id><published>2010-01-23T05:27:00.000-08:00</published><updated>2010-01-23T06:17:29.275-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BitTorrent'/><category scheme='http://www.blogger.com/atom/ns#' term='go'/><title type='text'>Looking at the original BitTorrent client</title><content type='html'>I wanted to learn more about how the original BitTorrent client implemented "choking", so I downloaded the source to the original Python-based BitTorrent client from &lt;a href="http://sourceforge.net/projects/bittorrent/"&gt;SourceForge&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I was impressed, as ever, by the brevity and clarity of Python. The original BitTorrent client sources are very easy to read. (Especially now that I understand the problem domain pretty well.) The code has a nice OO design, with a clear separation of responsibilities.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I was also impressed by the extensive use of unit tests. About half the code in the BitTorrent source is unit tests of the different classes, to make sure that the program behaves correctly. This is a really good idea when developing a peer-to-peer application. The synthetic tests let you test things like your end-of-torrent logic immediately, rather than by having to find an active torrent swarm and wait for a real-world torrent to complete.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When I get a chance I'm going to refactor the Taipei-Torrent code into smaller classes and add unit tests like the original BitTorrent client implementation has.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And come to think of it, why didn't I check out the original BitTorrent client code sooner? It would have saved me some time and I'd probably have a better result. D'Oh! Oh well, live and learn!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-2798501398723709984?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/2798501398723709984/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=2798501398723709984' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2798501398723709984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2798501398723709984'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/01/comparing-taipei-torrent-to-original.html' title='Looking at the original BitTorrent client'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-7810156419861905754</id><published>2010-01-22T18:17:00.000-08:00</published><updated>2010-01-22T18:27:58.424-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d graphics'/><category scheme='http://www.blogger.com/atom/ns#' term='Project Natal'/><category scheme='http://www.blogger.com/atom/ns#' term='Xbox 360'/><title type='text'>Some details on Xbox Project Natal</title><content type='html'>From Scientific American: &lt;a href="http://www.scientificamerican.com/article.cfm?id=microsoft-project-natal"&gt;Binary Body Double: Microsoft Reveals the Science Behind Project Natal&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Short summary: They used machine-learning algorithms and lots of training data to come up with an algorithm that converts moving images into moving joint skeletons.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Given the huge variation in human body shapes and clothing, it will be interesting to see how well this performs in practice.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I bet people will have a lot of fun aiming the Natal camera at random moving object to see  what happens. I can already imagine the split-screen YouTube videos we'll see of Natal recognizing pets, prerecorded videos of people, puppets and marionettes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Oh, and of course, people will point Natal back at the TV screen and see if the video game character can control itself.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Great fun!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-7810156419861905754?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/7810156419861905754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=7810156419861905754' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7810156419861905754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7810156419861905754'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/01/some-details-on-xbox-project-natal.html' title='Some details on Xbox Project Natal'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5851793184287314306</id><published>2010-01-22T02:55:00.000-08:00</published><updated>2010-01-22T03:00:52.119-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='go'/><title type='text'>800 lines of code for a bencode serializer?!</title><content type='html'>&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;Wow, my Taipei-Torrent post made it to Hacker News and reddit.com/r/programming. I'm thrilled!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One comment on Hacker News was "800 lines for a bencode serializer?! It only took me 50 lines of Smalltalk!" That was a good comment! I replied:&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;A go bencode serialization library could be smaller if it just serialized the bencode data to and from a generic dictionary container. I think another go BitTorrent client, gobit, takes this approach.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But it's convenient to be able to serialize arbitrary application types. That makes the bencode library larger because of the need to use go's reflection APIs to analyze and access the application types. Go's reflection APIs are pretty verbose, which is why the line count is so high.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To make things even more complicated, the BitTorrent protocol has a funny "compute-the-sha1-of-the-info-dictionary" requirement that forces BitTorrent clients to parse that particular part of the BitTorrent protocol using a generic parser.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So in the end, the go bencode serializer supports both a generic dictionary parser and an application type parser, which makes it even larger.&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In general, Taipei-Torrent was not written to minimize lines-of-code. (If anything, I was trying to maximize functionality per unit of coding time.) One example of not minimizing lines-of-code is that I used a verbose error handling idiom:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;a, err := f()&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;if err != nil {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;return&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are alternative ways to handle errors in go. Some of the alternatives take fewer lines of code in some situations. The above idiom is my preference because it works correctly in all cases. But it has the drawback of adding 3 lines of code to every function call that might return an error.&lt;/div&gt;&lt;div&gt;The go authors are considering adding exceptions to the go language. If they do so it will probably dramatically improve the line count of Taipei-Torrent.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5851793184287314306?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5851793184287314306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5851793184287314306' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5851793184287314306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5851793184287314306'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/01/wow-my-taipei-torrent-post-made-it-to.html' title='800 lines of code for a bencode serializer?!'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-3578235840333377353</id><published>2010-01-19T23:34:00.001-08:00</published><updated>2010-01-22T03:19:53.740-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='go'/><title type='text'>A Taipei-Torrent postmortem: Writing a BitTorrent client in Go</title><content type='html'>&lt;div style="text-align: right;"&gt;&lt;i&gt;This is a BitTorrent client. There are many like it, but this one is mine.&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: right;"&gt;&lt;i&gt;-- the BitTorrent Implementer's Creed&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;For fun I've started writing a command-line BitTorrent client in Google's go programming language. The program, &lt;a href="http://github.com/jackpal/Taipei-Torrent"&gt;Taipei-Torrent&lt;/a&gt; , is about 70% done. It can successfully download a torrent, but there are still lots of edge cases to implement.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Go routines and channels are a good base for writing multithreaded network code. My design uses goroutines as follows:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;a single main goroutine contains most of the BitTorrent client logic.&lt;/li&gt;&lt;li&gt;each BitTorrent peer is serviced by two goroutines: one to read data from the peer, the other to write data to the peer.&lt;/li&gt;&lt;li&gt;a goroutine is used to communicate with the tracker&lt;/li&gt;&lt;li&gt;some "time.Tick" goroutines are used to wake the main goroutine up periodically to perform housekeeping duties.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;All the complicated data structures are owned by the main goroutine. The other goroutines just perform potentially blocking network I/O using channels, network connections, and []byte slices. For example, here's a slightly simplified version of the goroutine that handles writing messages to a peer:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new', serif;"&gt;&lt;div&gt;func (p *peerState) peerWriter(errorChan chan peerMessage,&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt; header []byte) {&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;_, err := p.conn.Write(header)&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;if err != nil {&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;goto exit&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;for msg := range p.writeChan {&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;err = writeNBOUint32(p.conn, uint32(len(msg)))&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;if err != nil {&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;goto exit&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;_, err = p.conn.Write(msg)&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;if err != nil {&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;goto exit&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;exit:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;errorChan &lt;- peerMessage{p, nil}&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;Good things about the Go language and standard packages for this project:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Even without IDE support it is easy to refactor go code. This ease-of-refactoring makes it pleasant to develop a program incrementally.&lt;/li&gt;&lt;li&gt;Goroutines and channels make networking code easy to write.&lt;/li&gt;&lt;li&gt;The log.Stderr() function makes debugging-by-printf fairly painless.&lt;/li&gt;&lt;li&gt;Go maps serve as pretty good one-size-fits-all collection classes.&lt;/li&gt;&lt;li&gt;I received very fast responses from the go authors to my bug reports.&lt;/li&gt;&lt;li&gt;The standard go packages are reliable and easy to use. I used the xml, io, http, and net packages pretty extensively in this project. I also used the source of the json package as a base for the bencode package.&lt;/li&gt;&lt;li&gt;gofmt -w is a great way to keep my code formatted.&lt;/li&gt;&lt;li&gt;Named return values, that are initialized to zero, are very pleasant to use.&lt;/li&gt;&lt;li&gt;The code writing process was very smooth and stress free. I rarely had to stop and think about how to achieve what I wanted to do next. And I could often add the next feature with relatively little typing. The feeling was similar to how it feels when I write Python code, only with fewer type errors. :-)&lt;/li&gt;&lt;li&gt;With the exception of using the reflect package I never felt like I was fighting the language or the compiler.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Minor Problems:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;It was a little tedious to write if err != nil {return} after every function call in order to handle errors.&lt;/li&gt;&lt;li&gt;The standard go http package is immature. It is missing some features required for real-world scenarios, especially in the client-side classes. In my case I needed to expose an internal func and modify the way a second internal func worked in order to implement a client for the UPnP protocol. The good news is that the http package is open source, and it was possible to copy and fork the http package to create my own version.&lt;/li&gt;&lt;/ul&gt;What wasted my time:&lt;br /&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Several hours wasted debugging why deserializing into a copy of a variable (rather than a pointer to the original variable) had no effect on the value of the original variable. I notice that I often make mistakes like this in go, because go hides the difference between a pointer and a value more than C does. And there're confusing differences in behavior between a struct (which you can pass by either value or reference) and an interface (which has reference semantics on its contents even though you pass the interface by value). When you are reading and reasoning about go code you must mentally keep track of whether a given type is a struct type or an interface type in order to know how it behaves.&lt;/li&gt;&lt;li&gt;Several hours wasted figuring out how to send and receive multicast UDP messages. This may be an OSX-specific bug, and it may already be fixed. I found the Wireshark packet sniffer very helpful in debugging this problem.&lt;/li&gt;&lt;li&gt;Several hours wasted with crashes and hangs related to running out of OS threads on OSX. This was due to my code instantiating time.Tick objects too frequently. (Each live time.Tick object consumes a hardware thread.)&lt;/li&gt;&lt;li&gt;Many hours spent trying to understand and use the reflect package. It is powerful, but subtle and mostly undocumented. Even now, some things remain a mystery to me, such as how to convert a []interface{} to an interface{} using reflection.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Project statistics:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Line count: Main program: 1500 lines, http package patches: 50 lines, UPnP support: 300 lines, bencode serialization package: 800 lines. Tests for bencode serialization: 300 lines&lt;/li&gt;&lt;li&gt;Executable size: 1.5 MB. Why so large? One reason is that go doesn't use shared libraries, so everything is linked into one executable. Even so, 1.5 MB seems pretty large. Maybe go's linker doesn't strip unused code.&lt;/li&gt;&lt;li&gt;Development time: ~8 days so far, probably 11 days total.&lt;/li&gt;&lt;li&gt;The source is available under a BSD-style license at: &lt;a href="http://github.com/jackpal/Taipei-Torrent"&gt;http://github.com/jackpal/Taipei-Torrent&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Edits since first post:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Added error reporting to code example.&lt;/li&gt;&lt;li&gt;Added a link to the source code.&lt;/li&gt;&lt;li&gt;Give more details about the line count. I had mistakenly included some test code in the lines-of-code for the main program.&lt;/li&gt;&lt;li&gt;Add a statistic about program size.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-3578235840333377353?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/3578235840333377353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=3578235840333377353' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3578235840333377353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3578235840333377353'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/01/writing-bittorrent-client-in-go.html' title='A Taipei-Torrent postmortem: Writing a BitTorrent client in Go'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5565937108256865847</id><published>2010-01-17T22:18:00.000-08:00</published><updated>2010-01-17T22:25:15.518-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d graphics'/><title type='text'>Objects vs. the L2 Cache</title><content type='html'>&lt;div&gt;An excellent little performance optimization presentation that shows how important memory layout is for today's processors:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://research.scee.net/files/presentations/gcapaustralia09/Pitfalls_of_Object_Oriented_Programming_GCAP_09.pdf"&gt;http://research.scee.net/files/presentations/gcapaustralia09/Pitfalls_of_Object_Oriented_Programming_GCAP_09.pdf&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The beginning of the talk makes the observation that since C++ was started in 1979 the cost of accessing uncached main memory has ballooned from 1 cycle to 400 cycles.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The bulk of the presentation shows the optimization of a graphics hierarchy library, where switching from a traditional OO design to a structure-of-arrays design makes the code run 3 times faster. (Because of better cache access patterns.)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5565937108256865847?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5565937108256865847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5565937108256865847' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5565937108256865847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5565937108256865847'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2010/01/objects-vs-l2-cache.html' title='Objects vs. the L2 Cache'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-3147400862173638861</id><published>2009-12-17T22:33:00.000-08:00</published><updated>2009-12-17T22:35:59.184-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d graphics'/><category scheme='http://www.blogger.com/atom/ns#' term='Larrabee'/><title type='text'>Tom Forsyth (Larrabee Dev) speaking at Stanford</title><content type='html'>I just noticed Tom Forsyth, aka tomf, is speaking at the &lt;a href="http://www.stanford.edu/class/ee380/"&gt;Stanford EE CS Colloquium&lt;/a&gt; on January 6, 2010. The video will hopefully be posted on the web afterwards.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The topic is "To be announced", but is very likely to be Larrabee related.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-3147400862173638861?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/3147400862173638861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=3147400862173638861' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3147400862173638861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3147400862173638861'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/12/tom-forsyth-larrabee-dev-speaking-at.html' title='Tom Forsyth (Larrabee Dev) speaking at Stanford'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-7423372358206949929</id><published>2009-11-26T15:09:00.000-08:00</published><updated>2009-11-26T15:18:24.796-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d graphics'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>3D toolchain musings</title><content type='html'>I'm writing a skinning sample for a future Android SDK. This has prompted me to construct a toolchain to get skinned animated models into Android applications.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm really only just getting started, but so far I'm thinking along these lines:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Wings 3D -&gt; Blender 2.5 -&gt; FBX ASCII -&gt; ad-hoc tool -&gt; ad-hoc binary file -&gt; ad-hoc loader.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For what it's worth, right now Blender 2.5 doesn't support FBX export, so I have to do Collada -&gt; FBX Converter -&gt; FBX. But Blender 2.5 support should be ready fairly soon.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You may wonder why I'm considering using the proprietary and undocumented FBX standard rather than the open source Collada standard. I'm doing it for the same reason so many other tool chains (e.g. Unity, XNA) do, namely that FBX is a simpler format that just seems to work more reliably when exchanging data between DCC applications.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-7423372358206949929?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/7423372358206949929/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=7423372358206949929' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7423372358206949929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7423372358206949929'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/11/3d-toolchain-musings.html' title='3D toolchain musings'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4161103413874797440</id><published>2009-11-26T15:01:00.000-08:00</published><updated>2009-11-26T15:09:36.886-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d graphics'/><category scheme='http://www.blogger.com/atom/ns#' term='blender'/><title type='text'>Blender 2.5 alpha 0 is looking pretty good</title><content type='html'>The open-source &lt;a href="http://www.blender.org/"&gt;Blender 3D&lt;/a&gt; DCC tool has long suffered from an ugly, non-standard, hard-to-learn UI. I'm very happy to see that the latest release, which just entered alpha status, has a much improved UI. It's not quite Modo quality, but it's starting to get into the same league as commercial DCC tools.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4161103413874797440?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4161103413874797440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4161103413874797440' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4161103413874797440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4161103413874797440'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/11/blender-25-alpha-0-is-looking-pretty.html' title='Blender 2.5 alpha 0 is looking pretty good'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5643960702900949286</id><published>2009-11-25T00:33:00.000-08:00</published><updated>2009-11-25T00:42:14.766-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><title type='text'>Two very good talks on ECMAScript 4, 5, and 6</title><content type='html'>Yahoo continues to be a source of excellent information on recent and future versions of JavaScript / ECMAScript. Here are two very good talks from November 2009 about the evolution of JavaScript from 2000 until now:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://developer.yahoo.com/yui/theater/video.php?v=crockford-yuiconf2009-state"&gt;Doug Crockford on ECMAScript 4 /5&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://developer.yahoo.com/yui/theater/video.php?v=eich-yuiconf2009-harmony"&gt;Brendan Eich on ECMAScript 4 / 5 and Harmony&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5643960702900949286?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5643960702900949286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5643960702900949286' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5643960702900949286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5643960702900949286'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/11/two-very-good-talks-on-ecmascript-4-5.html' title='Two very good talks on ECMAScript 4, 5, and 6'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4631289678813157192</id><published>2009-11-24T19:20:00.000-08:00</published><updated>2009-11-26T15:22:33.385-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>Prince of Persia Developer's blog</title><content type='html'>In the late 1980's Jordan Mechner single-handedly designed and programmed the original Apple II version of &lt;a href="http://en.wikipedia.org/wiki/Prince_of_Persia_(1989_video_game)"&gt;Prince of Persia&lt;/a&gt; and several other groundbreaking games. He published his &lt;a href="http://jordanmechner.com/old-journals/"&gt;development journals&lt;/a&gt; and &lt;a href="http://jordanmechner.com/wp-content/uploads/1989/10/popsource009.pdf"&gt;technical design documents&lt;/a&gt; on his web site. The journals touch on:&lt;div&gt;&lt;ul&gt;&lt;li&gt;The development of the stop-motion animation techniques used so effectively in PoP&lt;/li&gt;&lt;li&gt;The tension in Jordan's life between his two callings: game development and feature film scriptwriting / directing.&lt;/li&gt;&lt;li&gt;The difficulties involved in developing and selling a new game idea.&lt;/li&gt;&lt;li&gt;A view into the late 80's / early 90's pre-web game development business.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Although many games are now written by large teams of people, in the end, a lot of the business, artistic, and technical issues Jordan writes about remain relevant. I highly recommend these journals for anyone interested in an inside view of game development. (Or anyone interested in trying to break into Hollywood. :-) )&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4631289678813157192?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4631289678813157192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4631289678813157192' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4631289678813157192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4631289678813157192'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/11/prince-of-persia-developers-blog.html' title='Prince of Persia Developer&apos;s blog'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4189257426644286542</id><published>2009-11-10T19:44:00.000-08:00</published><updated>2009-11-11T01:06:03.852-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='go'/><title type='text'>A Multi-threaded Go Raytracer</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_kmzTWylBF0o/SvpD41F6d9I/AAAAAAAAC08/nwRcMOKe-qI/s1600-h/trace.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://2.bp.blogspot.com/_kmzTWylBF0o/SvpD41F6d9I/AAAAAAAAC08/nwRcMOKe-qI/s400/trace.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5402705346587949010" /&gt;&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Above is the output of the raytracer. Below is a diagnostic mode showing which goroutines raytraced which section of the screen. Each goroutine has its own color to outline the pixels it traces:&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_kmzTWylBF0o/SvpD41F6d9I/AAAAAAAAC08/nwRcMOKe-qI/s1600-h/trace.png"&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_kmzTWylBF0o/SvpD4rEwtUI/AAAAAAAAC00/YcQUJ7d-Nwc/s1600-h/cells.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" src="http://3.bp.blogspot.com/_kmzTWylBF0o/SvpD4rEwtUI/AAAAAAAAC00/YcQUJ7d-Nwc/s400/cells.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5402705343898760514" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;I wrote a simple multi-threaded ray tracer in Google's new "go" language. It's an adaptation of &lt;a href="http://www.ffconsultancy.com/languages/ray_tracer/comparison.html"&gt;Flying Frog Consultancy's Raytracer&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It runs single-threaded about 1/2 the speed of a comparable C++ version. I guess the C++ version benefits from a more optimizing compiler and the ability to inline small functions.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Compared to ordinary C/C++, the Go version was easier to multithread.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On my dual-core Macbook Pro I get an 1.80x speedup when running with GOMAXPROCS &gt; 1:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ GOMAXPROCS=1 time ./gotrace&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;        &lt;b&gt;1.52&lt;/b&gt; real         1.50 user         0.01 sys&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ GOMAXPROCS=2 time ./gotrace&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;        &lt;b&gt;0.82&lt;/b&gt; real         1.50 user         0.01 sys&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ GOMAXPROCS=3 time ./gotrace&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;        0&lt;b&gt;.81&lt;/b&gt; real         1.50 user         0.01 sys&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;On an eight-core, 16 Hyperthread HP Z600 running Ubuntu 9.10, (with the source code changed to use 16 goroutines instead of the default 8 goroutines) I get a 5.8x speedup:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:'courier new';"&gt; &lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ GOMAXPROCS=1 time ./gotrace&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;1.05user 0.01system 0:01.06elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;0inputs+1544outputs (0major+2128minor)pagefaults 0swaps&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;$ GOMAXPROCS=16 time ./gotrace&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;1.32user 0.00system 0:00.18elapsed 702%CPU (0avgtext+0avgdata 0maxresident)k&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;0inputs+1544outputs (0major+2190minor)pagefaults 0swaps&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Source code &lt;/span&gt;&lt;a href="http://jack.palevich.googlepages.com/gotracer.zip"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;gotracer.zip&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4189257426644286542?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4189257426644286542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4189257426644286542' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4189257426644286542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4189257426644286542'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/11/multi-threaded-go-raytracer.html' title='A Multi-threaded Go Raytracer'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_kmzTWylBF0o/SvpD41F6d9I/AAAAAAAAC08/nwRcMOKe-qI/s72-c/trace.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4334344451332077803</id><published>2009-11-07T11:37:00.001-08:00</published><updated>2009-11-07T11:44:39.350-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='droid'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>How about that new Verizon Droid?</title><content type='html'>I've been working part time on the "Droid" project for the last year, and it finally shipped today. I wrote some of the graphics libraries.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At first I was skeptical of the industrial design. The early prototypes looked very much like a 1970's American car dashboard. But Motorola really improved the industrial design in subsequent versions. I like the high-grip rubber on the battery cover. It makes the phone very comfortable to hold.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The phone hardware is very fast, and the high resolution screen is beautiful. I think people will enjoy owning and using this phone.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My favorite feature is the turn-by-turn navigation software. My second favorite feature is the "Droooid" default notification sound. Oh, and the camera flashlight is very nice too!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4334344451332077803?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4334344451332077803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4334344451332077803' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4334344451332077803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4334344451332077803'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/11/how-about-that-new-verizon-droid.html' title='How about that new Verizon Droid?'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-199781011349114381</id><published>2009-11-07T11:23:00.000-08:00</published><updated>2009-11-07T11:37:00.698-08:00</updated><title type='text'>Wired article about Demand Media's automated How To videos</title><content type='html'>Man, the web really does change everything!&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The company "&lt;a href="http://www.wired.com/magazine/2009/10/ff_demandmedia/all/1"&gt;Demand Media&lt;/a&gt;"  has developed a Google-like business model for creating how-to videos:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Use data mining to figure out what people are searching for.&lt;/li&gt;&lt;li&gt;Use semantic database to figure out what their search queries mean. (e.g. "how to draw a gun" vs. "how to draw a flower".)&lt;/li&gt;&lt;li&gt;Find out how much advertisers are willing to pay for an ad that appears next to the video.&lt;/li&gt;&lt;li&gt;Look at how much content already exists to answer the question.&lt;/li&gt;&lt;li&gt;Use 1-4 to calculate the expected lifetime value of the how-to video.&lt;/li&gt;&lt;li&gt;Automate the process of matching freelance writers, videographers, editors, and fact checkers to create the video as inexpensively as possible. (In the $30 per video range.)&lt;/li&gt;&lt;li&gt;Host the resulting videos on Youtube (and other video sites) and monetize with ad keywords.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;They say that the algorithm produces lifetime values about 5 times higher than human editors do.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;These guys have basically automated the "How to" video market. Amazing! I wonder if they will move up the video food chain into music videos, TV shows or movies? It might work for low budget children's programming.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Or even for casual games. Hmm.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-199781011349114381?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/199781011349114381/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=199781011349114381' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/199781011349114381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/199781011349114381'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/11/man-web-really-does-change-everything.html' title='Wired article about Demand Media&apos;s automated How To videos'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-240340779995435611</id><published>2009-10-20T11:57:00.000-07:00</published><updated>2009-10-20T12:04:04.811-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu 9.10 gets a clue!</title><content type='html'>I was pleasantly surprised to see that the latest version of Ubuntu, 9.10 b1, comes with a nice selection of desktop backgrounds. This makes a huge difference in how beginners perceive the product, at very little cost to Ubuntu.&lt;br /&gt;&lt;br /&gt;The new dark-brown default color scheme is also an improvement over the older schemes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-240340779995435611?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/240340779995435611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=240340779995435611' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/240340779995435611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/240340779995435611'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/10/ubuntu-910-gets-clue.html' title='Ubuntu 9.10 gets a clue!'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-6685777058681094757</id><published>2009-10-18T17:30:00.000-07:00</published><updated>2009-10-18T17:49:40.867-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>I published my first Android app</title><content type='html'>Now that the Android Native Development Kit has been released, I was finally able to publish the sources and binary to my &lt;a href="http://code.google.com/p/androidterm/"&gt;Android Terminal Emulator&lt;/a&gt;. It's a fairly plain Digital Equipment Corporation VT-100 terminal emulator, with some features from newer terminals (like colors.)&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is my first application in the Android Market. There are at least 10 other terminal emulators in the market; we'll see how this one is received.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A bit of history: This was my first Android application. I wrote it for the original "Sooner" Android devices, and have kept it updated for the successive generations of devices. It requires native code because there's no public Android Java APIs for dealing with PTYs.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A bit of ancient history: I wrote two terminal emulators for the Atari 800 back in the day: Chameleon, in 6502 assembly, and a version of Kermit in the excellent "Action!" programming language. Kermit was one of my first "open source" programs. If you poke around on the web you can still find it &lt;a href="http://atariwiki.strotmann.de/xwiki/bin/view/Code/ACTIONKermit"&gt;here and there&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-6685777058681094757?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/6685777058681094757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=6685777058681094757' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6685777058681094757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6685777058681094757'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/10/i-published-my-first-android-app.html' title='I published my first Android app'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-3055712468921063592</id><published>2009-10-01T19:48:00.000-07:00</published><updated>2009-10-04T10:11:58.029-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quake'/><category scheme='http://www.blogger.com/atom/ns#' term='opengl'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><category scheme='http://www.blogger.com/atom/ns#' term='opengl es'/><title type='text'>GLES Quake - a port of Quake to the Android platform</title><content type='html'>I've just published the source code to &lt;a href="http://code.google.com/p/glesquake"&gt;a port of Quake to the Android platform&lt;/a&gt;. This is something I did a while ago as a internal test application.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's not very useful as a game, because there hasn't been any attempt to optimize the controls for the mobile phone. It's also awkward to install because the end user has to supply the Quake data files on their own.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Still, I thought people might enjoy seeing a full-sized example of how to write a native code video game for the Android platform. So there it is, in all its retro glory.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;(Porting Quake II or Quake III is left as an exercise for the reader. :-)&lt;br /&gt;&lt;br /&gt;What's different about this particular port of Quake?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Converted the original application into a DLL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Android applications are written in Java, but they are allowed to call native languge DLLs, and the native language DLLs are allowed to call a limited selection of OS APIs, which include OpenGL ES and Linux File I/O.&lt;br /&gt;&lt;br /&gt;I was able to make the game work by using Java for:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The Android activity life-cycle&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Event input&lt;/li&gt;&lt;li&gt;View system integration&lt;/li&gt;&lt;li&gt;EGL initialization&lt;/li&gt;&lt;li&gt;Running the game in its own rendering loop, separate from the UI thread&lt;/li&gt;&lt;/ul&gt;And then I use C++ for the rest. The interface between Java and C is pretty simple. There are calls for:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;initialize&lt;br /&gt;&lt;/li&gt;&lt;li&gt;step - which does a game step, and draws a new frame.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;handle an input event (by setting variables that are read during the "step" call.)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;quit&lt;/li&gt;&lt;/ul&gt;The Java-to-C API is a little hacky. At the time I developed this game I didn't know very much about how to use JNI, so I didn't implement any C-to-Java calls, preferring to pass status back in return values. For example the "step" function returns a trinary value indicating:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;That the game wants raw PC keyboard events, because it is in normal gameplay mode.&lt;/li&gt;&lt;li&gt;That it wants ASCII character events, because it is in menu / console mode.&lt;/li&gt;&lt;li&gt;That the user has chosen to Quit.&lt;/li&gt;&lt;/ol&gt;This might better have been handled by providing a series of Java methods that the C code could call back. (But using the return value was easier. :-))&lt;br /&gt;&lt;br /&gt;Similarly, the "step" function takes arguments that give the current screen size. This is used to tell the game when the screen size has changed. It would be cleaner if this was communicated by a separate API call.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Converted the Quake code from C to C++&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I did this early in development, because I'm more comfortable writing in C++ than in C. I like the ability to use classes occasionally. The game remains 99% pure C, since I didn't rewrite&lt;br /&gt;very much of it. Also, as part of the general cleanup I fixed all gcc warnings. This was fairly easy to do, with the exception of aliasing warnings related to the "Quake C" interpreter FFI.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Converted the graphics from OpenGL to OpenGL ES&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This was necessary to run on the Android platform. I did a straightforward port. The most difficult part of the port was implementing texture conversion routines that replicated OpenGL functionality not present in OpenGL ES. (Converting RGB textures to RGBA textures, synthesizing MIP-maps and so forth.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Implemented a Texture Manager&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The original glQuake game allocated textures as needed, never releasing old textures. It relied upon the OpenGL driver to manage the texture memory, which in turn relied on the Operating System's virtual memory to store all the textures. But Android does not have enough RAM to store all the game's textures at once, and the Android OS does not implement a swap system to offload RAM to the Flash or SD Card. I worked around this by implementing my own ad-hoc swap system. I wrote a texture manager that uses a memory mapped file (backed by a file on the SD Card) to store the textures, and maintained a limited size LRU cache of active textures in the OpenGL ES context.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="font-weight: bold;"&gt;Faking a PC Keyboard&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Quake expects to talk to a PC keyboard as its primary input device. It handles raw key-down and key-up events, and handles the shift keys itself. This was a problem for Android because mobile phone devices have a much smaller keyboard. So a character like '[' might be unshifted on a PC keyboard, but is shifted on the Android keyboard.&lt;br /&gt;&lt;br /&gt;I solved this by translating Android keys into PC keys, and by rewriting the config.cfg file to use a different set of default keys to play the game. But my solution is not perfect, because it is essentially hard-coded to a particular Android device. (The T-Mobile G1). As Android devices proliferate there are likely to be new Android devices with alternate keyboard layouts, and they will not necessarily be able to control the game effectively using a G1-optimized control scheme.&lt;br /&gt;&lt;br /&gt;A better approach would be to redesign the game control scheme to avoid needing keyboard input.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;A Few Words about Debugging&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I did the initial bring-up of Android Quake on a Macintosh, using XCode and a special build of Android called "the simulator", which runs a limited version of the entire Android system as a native Mac OS application. This was helpful because I was able to use the XCode visual debugger to debug the game.&lt;br /&gt;&lt;br /&gt;Once the game was limping along, I switched to debugging using "printf"-style log-based debugging and the emulator, and once T-Mobile G1 hardware became available I switched to using real hardware.&lt;br /&gt;&lt;br /&gt;Using printf-style debugging was awkward, but sufficient for my needs. It would be very nice to have a source-level native code debugger that worked with Eclipse.&lt;br /&gt;&lt;br /&gt;Note that the simulator and emulator use a software OpenGL ES implementation, which is slightly different than the hardware OpenGL ES implementation available on real Android devices. This required extra debugging and coding. It seems that every time Android Quake is ported to a new OpenGL ES implementation it exposes bugs in both the game's use of OpenGL ES and the device's OpenGL ES implementation.&lt;br /&gt;&lt;br /&gt;Oh, and I sure wish I had a Microsoft PIX-style graphics debugger! It would have been very helpful during those head-scratching "why is the screen black" debugging sessions.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-3055712468921063592?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/3055712468921063592/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=3055712468921063592' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3055712468921063592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3055712468921063592'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/10/gles-quake-port-of-quake-to-android.html' title='GLES Quake - a port of Quake to the Android platform'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-686879768903305200</id><published>2009-09-23T06:24:00.000-07:00</published><updated>2009-09-23T07:13:15.406-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Larrabee'/><title type='text'>IDF 2009 Larrabee demo</title><content type='html'>Intel &lt;a href="http://www.semiaccurate.com/2009/09/22/larrabee-breaks-cover-last/"&gt;showed their new Larrabee GPU publicly for the first time&lt;/a&gt; at their annual developer conference. They showed &lt;a href="http://www.youtube.com/watch?v=b5TGA-IE85o"&gt;Larrabee running a ray tracer that was rendering QuakeWars geometry&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The enthusiast scene (e.g. &lt;a href="http://forum.beyond3d.com/showthread.php?t=55232"&gt;beyond3d&lt;/a&gt;) was not impressed by this demo, because, frankly, it wasn't very impressive at an emotional level. The scene was static, no people in it, just waves and a few very small helicopters. It's strange that they didn't even move the camera, which is something that a ray tracing engine should easily be able to to. The camera angle they chose was effective for showing dynamic reflections, but keeping the camera locked down meant a much less interesting demo.&lt;br /&gt;&lt;br /&gt;For the same amount of effort they could have come up with a much more visually and emotionally interesting demo. For example, a cascade of brightly colored chrome balls tumbling down a staircase, which would show off both physics and ray tracing.&lt;br /&gt;&lt;br /&gt;That they didn't use this early opportunity to sell Larrabee indicates that they don't know how to market add-on GPUs to consumers. Which makes sense, since it has been many years since they've needed to do this.&lt;br /&gt;&lt;br /&gt;Their current demos are all targeted to (a) test out Larrabee features, and (b) educate developers as to the potential strengths of Larrabee. They are similar to Microsoft DirectX samples. But I think Intal also needs to develop showy "&lt;a href="http://www.youtube.com/watch?v=4QCNS7BRFrc"&gt;AMD/ATI Ruby&lt;/a&gt;" style demos to win the hearts of enthusiasts.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.semiaccurate.com/2009/09/22/larrabee-breaks-cover-last/"&gt;Groo at semiaccurate.com&lt;/a&gt; suggests that the IDF demo was shown on early, barely functional Larrabee silicon. If true, that could help explain why the demo was so limited. But by this time in the GPU's lifecycle there should be more marketing -- even if totally pre-rendered -- showing what the GPU will do. So far the bland &lt;a href="http://www.youtube.com/watch?v=o7dGRewFmS4"&gt;GDC2009 meteor demo&lt;/a&gt; is the only thing we've seen. I think Larrabee needs more sizzle, like this &lt;a href="http://www.youtube.com/watch?v=jIyu4Aozwbw"&gt;early Sony Playstation 2 demo reel&lt;/a&gt;. (Sony also had some great interactive tech demos of things like feathers and pollen particles, but I haven't been able to find online videos in my limited searching.)&lt;br /&gt;&lt;br /&gt;Intel's current marketing approach seems to indicate that they are not serious about competing for the enthusiast add-on GPU market. Perhaps they are just waiting until it's closer to the time Larrabee is available for market, but my guess is that they just don't understand how to play the game. It would be a shame if Larrabee is a technical success but a sales failure due to poor marketing execution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-686879768903305200?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/686879768903305200/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=686879768903305200' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/686879768903305200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/686879768903305200'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/09/idf-2009-larrabee-demo.html' title='IDF 2009 Larrabee demo'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5215219092215831445</id><published>2009-09-14T07:44:00.000-07:00</published><updated>2009-09-22T16:13:39.307-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ICFP'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>ICFP 2009 contest final scores</title><content type='html'>Final scores are out, and my team Blue Iris scored &lt;a href="http://icfpcontest.org/scoreboard.php"&gt;80 out of 328&lt;/a&gt; in this year's ICFP contest. Not as good as last year, ah well. :-) Next year: More sleep!&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And here's a video of &lt;a href="http://www.vimeo.com/6613815"&gt;the contest results presentation from ICFP&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5215219092215831445?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5215219092215831445/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5215219092215831445' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5215219092215831445'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5215219092215831445'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/09/icfp-2009-contest-final-scores.html' title='ICFP 2009 contest final scores'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-69302750688821800</id><published>2009-09-07T20:58:00.000-07:00</published><updated>2011-10-16T07:45:41.182-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>Brick Break - a Javascript Breakout clone</title><content type='html'>&lt;a href="http://jack.palevich.googlepages.com/brickbreak.html"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5378941392688007618" src="http://2.bp.blogspot.com/_kmzTWylBF0o/SqXWsqLQScI/AAAAAAAACwU/05M9MVvNEHk/s400/brickbreak.png" style="cursor: pointer; float: left; height: 400px; margin: 0pt 10px 10px 0pt; width: 253px;" /&gt;&lt;/a&gt;&lt;br /&gt;This weekend I wrote a Javascript clone of the old Atari "Breakout" game. Thanks to the "Canvas" tag it was very easy to write, but I did run into a few problems:&lt;br /&gt;&lt;br /&gt;Javascript math is always floating point, so I had to use the "Math.floor" function to convert the results of a division to an integer. This was in the brick collision detection logic, where I am converting the ball's (x,y) coordinates to the bricks that the ball might be hitting.&lt;br /&gt;&lt;br /&gt;I was evaluating document.getElementById too early in the document lifecycle, before the corresponding elements existed. This took me a long time to diagnose -- I ended up just moving the getElementById calls to their run-time use, rather than trying to cache the results.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jacks-hacks.appspot.com/brickbreak/brickbreak.html"&gt;Jack's Brick Break Breakout clone&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-69302750688821800?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/69302750688821800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=69302750688821800' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/69302750688821800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/69302750688821800'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/09/brick-break-javascript-breakout-clone.html' title='Brick Break - a Javascript Breakout clone'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_kmzTWylBF0o/SqXWsqLQScI/AAAAAAAACwU/05M9MVvNEHk/s72-c/brickbreak.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5940385062164248789</id><published>2009-09-05T10:05:00.000-07:00</published><updated>2009-09-05T10:25:04.269-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>ICFP 2009 paper on Haskell in the Real World</title><content type='html'>Here's a good paper on using Haskell to write a commercial application. The authors are practical commercial programmers who tried Haskell to see if it was a more effective language than Ruby:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://portal.acm.org/ft_gateway.cfm?id=1596578&amp;amp;type=pdf&amp;amp;coll=portal&amp;amp;dl=ACM&amp;amp;CFID=505049525&amp;amp;CFTOKEN=505049525"&gt;Experience Report: Haskell in the “Real World”&lt;br /&gt;Writing a Commercial Application in a Lazy Functional Language&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Of special interest is the "Problems and Disadvantages" section. It seems that space leaks which are a continuing source of trouble in the authors' application.&lt;br /&gt;&lt;br /&gt;Reading this paper reminds me of &lt;a href="http://web.archive.org/web/20070701221306/wagerlabs.com/2006/01/01/haskell-vs-erlang-reloaded"&gt;Tenerife Skunkworks Haskell vs Erlang Reloaded&lt;/a&gt;. In that experiment a developer found that Erlang was much better than Haskell for real-time programming.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5940385062164248789?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5940385062164248789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5940385062164248789' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5940385062164248789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5940385062164248789'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/09/icfp-2009-paper-on-haskell-in-real.html' title='ICFP 2009 paper on Haskell in the Real World'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-3803706228570970791</id><published>2009-09-03T20:04:00.000-07:00</published><updated>2009-09-03T20:06:11.916-07:00</updated><title type='text'>Back to gnome</title><content type='html'>Well, 8 hours using wmii was enough for me. Too many apps didn't quite work right. So I'm back to plain-old-boring-but-familiar Gnome.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-3803706228570970791?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/3803706228570970791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=3803706228570970791' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3803706228570970791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3803706228570970791'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/09/back-to-gnome.html' title='Back to gnome'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-6270144235714772645</id><published>2009-09-02T19:31:00.000-07:00</published><updated>2010-02-20T21:40:10.817-08:00</updated><title type='text'>Technology Trends I'm Keeping an Eye On</title><content type='html'>In no particular order, here's what I've been studying lately:&lt;div&gt;&lt;ul&gt;&lt;li&gt;Javascript. I've avoided this language over the years because of its low speed and shoddy reputation. But the language implementations seem to be getting faster and the available libraries seem to be getting more interesting. I've just watched all of &lt;a href="http://search.yahoo.com/search?vs=developer.yahoo.com&amp;amp;vs=yuiblog.com&amp;amp;p=Crockford"&gt;Doug Crockford's YUI&lt;/a&gt; lectures on JavaScript, and I'm thinking about trying to use the language in some toy projects.&lt;/li&gt;&lt;li&gt;&lt;a href="http://linux.die.net/man/1/git-gui"&gt;git gui&lt;/a&gt; - this git command, available in recent builds of git, make Git changes pretty easy to author.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Undercover-Economist-Exposing-Poor-Decent/dp/0195189779"&gt;The Undercover Economist&lt;/a&gt; - this is a great book about economic theory. It's pretty easy to read while shaving, or waiting for compiles. Lots of good anecdotes and tools for modeling the behavior of consumers and firms. I took 3 economics classes in college, and they didn't teach me as much practical information as I've learned from reading this book.&lt;/li&gt;&lt;li&gt;&lt;a href="http://news.ycombinator.com/"&gt;Hacker News&lt;/a&gt; - this link voting site has replaced &lt;a href="http://alterslash.org/"&gt;alterslash&lt;/a&gt; and &lt;a href="http://reddit.com/r/programming"&gt;reddit programming&lt;/a&gt; as my daily comp-sci news site. I like the emphasis on start-up news.&lt;/li&gt;&lt;li&gt;&lt;a href="http://wmii.suckless.org/"&gt;wmii&lt;/a&gt; - yet another tiling window manager. I tried a bunch of tiling window managers, and this one seemed to "click" with me. I found that I could customize it easily, and it mostly "just worked" the way I wanted it to. We'll see if I stick with it or go back to Gnome. [Follow-up. I went back to Gnome (and then to OSX). Oh well.]&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.google.com/chrome"&gt;Chrome&lt;/a&gt; - now that the Linux and OSX versions have Flash support, Chrome has become my default web browser. I like its clean UI.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-6270144235714772645?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/6270144235714772645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=6270144235714772645' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6270144235714772645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6270144235714772645'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/09/technology-trends-im-keeping-eye-on.html' title='Technology Trends I&apos;m Keeping an Eye On'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-3516806254655150831</id><published>2009-09-02T19:12:00.001-07:00</published><updated>2009-09-02T19:31:08.850-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='car audio'/><category scheme='http://www.blogger.com/atom/ns#' term='gadgets'/><title type='text'>Dual XHD7714 Road Trip Report</title><content type='html'>After a month of using the &lt;a href="http://grammerjack.blogspot.com/2009/07/too-many-words-about-car-stereos.html"&gt;Dual XHD7714&lt;/a&gt;, during which my family and I took a 4000 mile road trip, I have to say it's a pretty nice system. We used it almost exclusively as an MP3 player, rather than an HD Radio or a CD player. I loaded 800 songs from our home music collection onto an 8GB memory stick. It was great introducing my kids to some new music. By the end of the trip their favorite songs were &lt;i&gt;Shock the Monkey&lt;/i&gt; and &lt;i&gt;The Magical Mr.  Mistoffelees&lt;/i&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some problems specific to the Dual XHD7714:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Bluetooth issues:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Bluetooth headset mode only syncs with one phone at a time. This seems to be a common limitation of low-end bluetooth car stereos, but it's quite frustrating for two-driver families like mine.&lt;/li&gt;&lt;li&gt;Bluetooth audio streaming mode doesn't sound very good on this radio. However, I didn't experiment with this very much, so it may have been source-material related.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;USB MP3 player issues:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;It takes about 5 seconds per GB to index USB stick music each time it starts up.&lt;/li&gt;&lt;li&gt;It only recognizes US-ASCII characters. If any non-ASCII characters are present in the album or song name the entire name is replaced with the string "Not supported". We had a lot of Chinese-language tracks that displayed that way, making them very difficult to navigate.&lt;/li&gt;&lt;li&gt;It can't fast-forward or rewind through MP3s.&lt;/li&gt;&lt;li&gt;When you turn on the radio, it does remember where in the current MP3 it is playing, _but_ it takes a long time to resume playing an MP3 in the middle. So it's awkward listening to long podcasts.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Still, even with all these flaws, I'm quite happy with the radio. We really enjoyed being able to conveniently listen to so many different songs during our trip.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-3516806254655150831?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/3516806254655150831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=3516806254655150831' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3516806254655150831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3516806254655150831'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/09/dual-xhd7714-road-trip-report.html' title='Dual XHD7714 Road Trip Report'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-6872531442941843904</id><published>2009-07-23T10:56:00.000-07:00</published><updated>2009-07-23T11:12:11.680-07:00</updated><title type='text'>Nehalem machines are very fast</title><content type='html'>I've just had a chance to use a Nehalem HP Z600 workstation&lt;span&gt;&lt;span&gt; with 2 Xeon E5520 CPUs. The machine has 8 cores, 16 hardware threads, and an absurd 12 GB of RAM.&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif; font-size: 13px; "&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's very fast. It's about 2.5 times as fast (when building the Android sources) as the previously fastest machine I'd used, which was an HP xw6600 with a single Xeon E5420 CPU.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The machine's relatively small, no larger than an ordinary ATX tower. One way that HP kept the case small is by making the motherboard an odd shape: it is "C" shaped, with a cutout that leaves room for the DVD drive.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-6872531442941843904?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/6872531442941843904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=6872531442941843904' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6872531442941843904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6872531442941843904'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/07/nehalem-machines-are-very-fast.html' title='Nehalem machines are very fast'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-9186959127150881770</id><published>2009-07-18T07:09:00.000-07:00</published><updated>2009-07-18T08:04:06.156-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gadgets'/><title type='text'>Too Many Words about Car Stereos</title><content type='html'>The other day my wife said to me, "Jack, we're going on a road trip soon. Is there any way we could hook up our MP3 player to the car stereo, so that the kids could listen to their favorite songs during the trip?"&lt;br /&gt;&lt;br /&gt;Twenty hours of web research and $250 later we've got a new car stereo.  It's a &lt;a href="http://www.dualav.com/mobileaudio/xhd7714.php"&gt;Dual XHD7714&lt;/a&gt; from &lt;a href="http://www.crutchfield.com/"&gt;Crutchfield&lt;/a&gt;. I'm getting it installed by Best Buy tomorrow. Let's hope their AV installers do a good job!&lt;br /&gt;&lt;br /&gt;First, why did I get a new stereo at all? Well, all I wanted to do was hook up an MP3 player. But there was no easy way to do that. My 2005 minivan came with a factory installed stereo that didn't have an auxiliary input. There are cheap FM transmitter systems that work with any radio, but they look clunky and the sound quality is supposed to be poor. A lot of web searching turned up some aftermarket accessories that allow hooking up either an audio input jack ($75 + $50 installation = $125) or an MP3 player and/or iPod ($125 + $50 = $175.) But the for just a little more money I was able to get a a whole new radio with lot of additional features.&lt;br /&gt;&lt;br /&gt;Why this particular model? It was well reviewed and relatively inexpensive. The features I was interested in were:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;MP3 player / USB memory stick player.&lt;/li&gt;&lt;li&gt;Hands-free bluetooth calling with a built-in microphone.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Streaming audio from a bluetooth phone.&lt;/li&gt;&lt;li&gt;Charging USB devices.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;HD radio.&lt;/li&gt;&lt;li&gt;Good fast text UI for navigating a MP3 player.&lt;/li&gt;&lt;li&gt;Play MP3s stored on CDs.&lt;/li&gt;&lt;li&gt;Wireless remote control for "back seat DJs"&lt;/li&gt;&lt;/ul&gt;General thoughts on the car stereo market&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Crutchfield is a good place to research and buy car stereos. For research purposes they have a wide selection, and they have very good information, especially in the form of user reviews. For buying they offer free shipping and more importantly a free installation and wiring kit. They also seem to offer very good telephone help for do-it-yourself installers.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The add-on car stereo market is in long-term decline. I think that in the next few years the car stereo will become little more than a mobile phone docking station. People will keep their music collection on their phone, or stream it from the internet.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Car stereo makers are not going down without a fight. They are experimenting with iPhone-inspired full-screen touch-screen UIs and built-in &lt;a href="http://www.wired.com/gadgetlab/2008/12/blaupunkt-and-m/"&gt;internet radios&lt;/a&gt;. While very creative, I don't think people will buy them. They will just use their phones instead.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Many people want to connect their iPods to their car stereo. In the short term Apple is making this difficult by changing their communication protocols with every generation of iPod. In the long term iPods are going to be replaced by iPhones, which will probably be forced to support bluetooth stereo streaming.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-9186959127150881770?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/9186959127150881770/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=9186959127150881770' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/9186959127150881770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/9186959127150881770'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/07/too-many-words-about-car-stereos.html' title='Too Many Words about Car Stereos'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-7623756533550737983</id><published>2009-07-07T11:31:00.001-07:00</published><updated>2009-07-07T11:39:03.042-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Using a Mac keyboard with Ubuntu Linux</title><content type='html'>I frequently switch between Mac and Linux, and it's been troublesome to remember to type Command-whatever on the Mac, but Control-whatever on Linux. (For copy-and paste, for example.)&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I did a quick web search and found out that it's easy to &lt;a href="http://ubuntuforums.org/archive/index.php/t-975229.html"&gt;make Ubuntu Linux recognize the Command keys as an extra set of control keys&lt;/a&gt;:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Choose menu: System : Preferences : Keyboard&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Select the Layouts tab&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Choose "Layout Options"&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Open the "Alt / Win Key Behaviour" tab&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Check the "Control is mapped to the Win-keys" checkbox.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:arial, serif;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-7623756533550737983?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/7623756533550737983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=7623756533550737983' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7623756533550737983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7623756533550737983'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/07/using-mac-keyboard-with-ubuntu-linux.html' title='Using a Mac keyboard with Ubuntu Linux'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-3042610624037841009</id><published>2009-06-28T11:41:00.001-07:00</published><updated>2009-07-01T14:29:19.673-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ICFP'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>ICFP 2009 contest blog - Team Blue Iris</title><content type='html'>I just threw in the towel on the &lt;a href="http://icfpcontest.org/"&gt;ICFP 2009 Programming Contest&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The problem this year was a set of 4 sub-problems related to orbital mechanics, plus a virtual machine spec. The virtual machine was used to enable the problems to be specified exactly, without worrying about differences in the order of math operations.&lt;br /&gt;&lt;br /&gt;Implementing the virtual machine was easy and fun. Unfortunately, actually solving the final sub-problem required learning too much math and physics. I was able to solve problems 1 and 2, and make an entry for the lightning  round. And I brute-forced a solution for problem 3. But now, 56 hours into the contest, I am giving up on problem 4.&lt;br /&gt;&lt;br /&gt;I can see the general outline of how to solve it, but it would take sharper tools than I have now. For example, I'd like a way of solving Lambert's equations, but I'm having trouble deriving the code on my own, and the best example I've found while searching the web is a &lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;ct=res&amp;amp;cd=1&amp;amp;url=http%3A%2F%2Fntrs.nasa.gov%2Farchive%2Fnasa%2Fcasi.ntrs.nasa.gov%2F19790079987_1979079987.pdf&amp;amp;ei=PjFHSqXdKoumMYCuibgC&amp;amp;usg=AFQjCNHuISp5Jo_Yt8zra20RmTRqlnlhHQ&amp;amp;sig2=rV_Rm4DYdppoeV-KyqObXA"&gt;30-year-old NASA Space Shuttle Fortran program&lt;/a&gt;. Also, I'm pretty tired, and this is affecting my judgment. I don't think it's worth going on at this point.&lt;br /&gt;&lt;br /&gt;Some fun things I did during the contest:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Learned &lt;a href="http://www.braeunig.us/space/orbmech.htm"&gt;Orbital Mechanics&lt;/a&gt;, the study of how bodies move in space.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Learned what a &lt;a href="http://en.wikipedia.org/wiki/Hohmann_transfer_orbit"&gt;Hohmann Transfer Orbit&lt;/a&gt; is and why to use it.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Learned what Lambert's Theorem is, and how to apply it to missile guidance.&lt;/li&gt;&lt;li&gt;Wrote a Python program that did efficient calculations by generating a C program, compiling it, and then running it and talking to it via a pipe.&lt;/li&gt;&lt;li&gt;Read a ton of Wikipedia articles, Google Books books and old NASA tech reports on orbit planning and course corrections.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Learned how old-school Q-system guided missiles work. Very clever use of ground-based computers to compute coefficient matrices that were fed into simple on-board analog computers for the duration of the flight.&lt;/li&gt;&lt;/ul&gt;Highlights of the contest:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Hanging out on IRC with 20 other contestants, trying to get the simulator to work.&lt;/li&gt;&lt;li&gt;Getting problems 1 and 2 to work.&lt;/li&gt;&lt;li&gt;Giving up on problem 3, then thinking of a brute-force way of solving it while in the parking lot, about to drive home. (Too bad I wasn't further inspired to solve problem 4.)&lt;/li&gt;&lt;li&gt;Seeing the pretty pictures of the satellite orbits for problem 4.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Low-lights of the contest:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Wasting an hour or so due to bugs in the specification&lt;/li&gt;&lt;li&gt;Wasting an hour writing a Tkinter alternative to turtle graphics, then not being able to get a Tkinter window to show up, then realizing that Tkinter graphics are so limited that there's no feature benefit over using the already-working turtle graphics.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The buggy scoring in problem 1 encourages people to program-to-the-scorer rather than solve the stated problem. I could probably increase my position in the standings by 10 places by hacking an "optimal" solution to problem 1 that uses all of the available fuel. But it seems like a waste of time.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Having to give up on problem 4.&lt;/li&gt;&lt;/ul&gt;My advice to (future) contest organizers:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Consider avoiding problems that require deep domain expertise. There's only so much orbital mechanics and numerical methods one can learn in 72 hours.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Do whatever it takes to ensure that your VM machine spec is correct. In this case,  just asking someone to spend a couple of hours implementing the spec would have exposed the show-stopping problems that everyone encountered.&lt;/li&gt;&lt;/ul&gt;Advice to myself for future contests:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Pace yourself on day two, to avoid burning out on day 3.&lt;/li&gt;&lt;li&gt;Be sure you understand the scoring system. For example problem 4 had partial credit, so a solution for problem 3 might have worked on problem 4.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Scheduling work and family life to enable a free weekend for the contest worked out very well.&lt;/li&gt;&lt;li&gt;Do more planning, and keep an eye on how the work is progressing, to avoid spending too much time on unnecessary work. "What's the simplest thing that could possibly work", and "you aint going to need it" are both good mottoes for this kind of contest.&lt;/li&gt;&lt;li&gt;Take a little time to refactor the code as you go along, to avoid slowing down due to barnacles. (Example, passing the problem number all over the place because it was one of the inputs to the simulation, rather than special-casing it and setting it once in the VM.)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-family:trebuchet ms;font-size:130%;"  &gt;Analysis of programming languages I used in the contest&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I used Python and C. I actually completed the lightning round in pure Python.&lt;br /&gt;&lt;br /&gt;Benefits of Python&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Rapid development due to no compilation time, clean sparse syntax, well designed libraries, plenty of documentation and help available on-line.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Turtle graphics made it dead simple to display satellite orbits&lt;/li&gt;&lt;li&gt;The "struct" package made it dead simple to import and export binary data.&lt;/li&gt;&lt;li&gt;The "subprocess" package made it easy to start and control other programs.&lt;/li&gt;&lt;li&gt;Python 3.1's exact printout of floating point values made it easier to tell what the math was doing. (Other projects ran into problems with almost-zero values printing as zero.)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Drawbacks of Python&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Slow. I had to switch the simulation to C to have it run fast enough for problems 3 and 4&lt;/li&gt;&lt;li&gt;Global Interpreter Lock (GIL) - meant I couldn't use multiple calculation threads written in Python in one process. (And my machine's got 8 hardware threads. :-) )&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Lack of static type checking is frustrating when program run times are long: I had a half-hour period wasted debugging simple errors that only occurred after 2 minutes of simulation run-time that a static type checker would have caught immediately. To be fair, I could also have caught them with unit testing.&lt;/li&gt;&lt;/ul&gt;Benefits of C&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Very simple to write code.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Runs really fast. :-)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-family:trebuchet ms;" &gt;Why My VM's Cool&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;I wanted to explain how my VM implementation worked, because I think it probably ran faster than most other VMs.&lt;br /&gt;&lt;br /&gt;I wrote a Python-based VM as a reference. Then I wrote a VM generator that would read a VM spec and generate hard-coded C to implement that specific spec. I used a "comparer" VM to compare the output of the two VMs to make sure that there were no bugs in the generated C version.&lt;br /&gt;&lt;br /&gt;The hard-coded C VM was really hard coded to each problem. All the VM instruction interpretation  overhead was removed. In addition, because the VM didn't have any indirection, the "mem" array was replaced by hundreds of individual local variables. This allowed the C compiler to do a very good job of optimizing the code, because it could easily tell there was no aliasing.&lt;br /&gt;&lt;br /&gt;I included a simple interactive shell in each generated hard-coded C program. The console let you set inputs, run "n" simulation steps, and read the outputs. This made it easy for me to control the simulation from Python. It also made it easy to hand-test the C simulation.&lt;br /&gt;&lt;br /&gt;One feature I meant to add, but ran out of time/energy for, was to save and restore the state of the simulation. This would have been very helpful in solving problem 4.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-family:trebuchet ms;"&gt;How I solved the problems&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Problem 1: Wrote Python VM. Implemented Hohmann transfers as described in &lt;a href="http://en.wikipedia.org/wiki/Hohmann_transfer_orbit"&gt;a Wikipedia article&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Problem 2: Calculated the correct time to start the Hohmann transfer analytically. (I read about how to do this in a textbook I found through Google books.) Added simple brute-force docking code to match orbits exactly. No fancy "S" curves for me. (And wasted about an hour wondering why I didn't score, because early versions of the contest problem spec didn't say you had to turn off your engine for 900 seconds. I finally figured this out by disassembling the VM to see why the score wasn't being set properly.)&lt;br /&gt;&lt;br /&gt;Problem 3: Used my fast VM to compute a table of where the satellites would be over time, then wrote a set of nested for loops that tried various Hohmann transfers at various times looking for a solution. The precomputed tables meant I could just look up where the target satellite would be for any time in the future, rather than having to do complex elliptical math.&lt;br /&gt;&lt;br /&gt;Problem 4: Only got as far as simulating and visualizing this one (boy the orbits are pretty!) Too tired to continue. I was planning on using a variation of the brute-force approach that solved problem 3, with save-and-restore of the simulator state, because I would have to recompute the table of locations for my rocket each time its orbit changed.&lt;br /&gt;&lt;span style="font-weight: bold;font-family:trebuchet ms;" &gt;&lt;br /&gt;Conclusions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Upon reflection, I think that this particular contest, especially problems 3 and 4, is best suited to a C/C++ solution. This is due to the heavy reliance on numerical methods to calculate the optimal trajectories.&lt;br /&gt;&lt;br /&gt;I liked that there were multiple versions of each problem. It made it easier to tell if we were making progress, and also allowed whole-program-level parallelization to make use of muticore machines to solve the problems in parallel.&lt;br /&gt;&lt;br /&gt;While I expect the ultimate contest winners will code in a mutable-state static-type-checked compiled language like C/C++, I predict Haskell will do fairly well in the contest, due to its speed and the ease with which it handles math. However, the winners will probably have a good grasp of orbital mechanics, and it seems that someone who knows the math is more likely to be using C-like-languages.&lt;br /&gt;&lt;br /&gt;Well that's it, now I'm looking forward to next year!&lt;br /&gt;&lt;br /&gt;P.S. Here's a Wiki with other team writeups:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://wiki.freaks-unidos.net/icfp/2009/"&gt;FUN Team ICFP 2009 Writeup / Wiki&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-3042610624037841009?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/3042610624037841009/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=3042610624037841009' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3042610624037841009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3042610624037841009'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/06/icfp-2009-contest-blog.html' title='ICFP 2009 contest blog - Team Blue Iris'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-6594328909320760598</id><published>2009-06-15T07:17:00.001-07:00</published><updated>2011-10-16T07:46:45.679-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome'/><title type='text'>Dandy in JavaScript</title><content type='html'>&lt;a href="http://jack.palevich.googlepages.com/dandy.html"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5347559699009026434" src="http://3.bp.blogspot.com/_kmzTWylBF0o/SjZZNrKguYI/AAAAAAAACaw/LxWK6Qoj5Y0/s400/Picture+1.png" style="cursor: pointer; height: 201px; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This weekend I wrote a JavaScript version of my old Atari 800 game Dandy.&lt;br /&gt;&lt;br /&gt;Check it out: &lt;a href="http://jacks-hacks.appspot.com/dandy/dandy.html"&gt;Web Dandy&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It was my first JavaScript application. It was about as easy as writing the Python version. I have only tested it in two browsers so far (Firefox 3.0 and Chrome), and only on one platform OSX. I have already run into differences between the two browsers: Firefox 3.0 for OSX seems to double-post keydown events.&lt;br /&gt;&lt;br /&gt;No sound or multiplayer yet. Oh, and I use the CANVAS tag, so I think older browsers (like IE 7) won't work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-6594328909320760598?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/6594328909320760598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=6594328909320760598' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6594328909320760598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6594328909320760598'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/06/dandy-in-javascript.html' title='Dandy in JavaScript'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_kmzTWylBF0o/SjZZNrKguYI/AAAAAAAACaw/LxWK6Qoj5Y0/s72-c/Picture+1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-694317953250221802</id><published>2009-05-31T20:56:00.000-07:00</published><updated>2009-05-31T21:12:54.708-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSX'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Living La Vida Linux at Work</title><content type='html'>Android system-level development can be done on either Linux or OSX. For the past few years I've been using OSX, but recently I've switched over to using Linux.&lt;br /&gt;&lt;br /&gt;Why? Mostly for the higher performance. The full Android system build takes about 30% less time under Ubuntu 8.04 LTS than it does on OSX 10.5 on the same hardware. Not to mention that it's much cheaper to buy a generic PC workstation than the equivalent Mac Pro.&lt;br /&gt;&lt;br /&gt;I have had some early troubles:&lt;br /&gt;&lt;br /&gt;It took me a while to get used to typing the "Ctrl" key instead of the "Command" key, and the ugly Linux fonts bothered me for a few days.&lt;br /&gt;&lt;br /&gt;But since I'm mostly using the exact same programs on Linux as I was on OSX (FireFox, Eclipse, Android), after a few days everything clicked, and I think that I'm just as productive as I was before. And the faster builds and file system stuff (like grep) are wonderful.&lt;br /&gt;&lt;br /&gt;It helped a lot to install the Blubuntu theme and some nice wallpaper to get away from the awful Ubuntu brown/orange color scheme.&lt;br /&gt;&lt;br /&gt;Oh, and I'm using Chromium for Linux, which works pretty well, except that it doesn't support Flash. I still fire up Firefox occasionally to watch Flash videos.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-694317953250221802?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/694317953250221802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=694317953250221802' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/694317953250221802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/694317953250221802'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/05/living-la-vida-linux-at-work.html' title='Living La Vida Linux at Work'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-7599131227510660058</id><published>2009-05-31T20:43:00.000-07:00</published><updated>2009-05-31T20:56:34.019-07:00</updated><title type='text'>See, this is why we can't have nice things (Ubuntu 9.04 Intel Drivers)</title><content type='html'>A few years ago I tried Ubuntu and predicted it would become a serious challenger to Windows, in about 18 months.&lt;br /&gt;&lt;br /&gt;Well, it's about 18 months later, was I right?&lt;br /&gt;&lt;br /&gt;Not exactly. Ubuntu seems to have stood still, if not actually gone backwards. In particular, the newer releases have much worse sound and video performance on my hardware (Intel CPU/GPU Mac Minis)  than earlier releases.&lt;br /&gt;&lt;br /&gt;The sound driver issue is because Linux, in its typical decentralized fashion, is trying to figure out how to provide a standard audio subsystem, and has two or three competing standards that are duking it out. Since they all suck it seems odd that people defend them so much. Just pick one already.&lt;br /&gt;&lt;br /&gt;The video driver issue is because Intel decided to take several years to rewrite their Linux video driver stack, and Ubuntu decided to ship the new broken drivers rather than continue to use the old unbroken drivers. Very very lame on both Intel and especially Ubuntu's part.&lt;br /&gt;&lt;br /&gt;And Phoronix's performance tests show that the performance of Ubuntu has gone downhill slightly over the last few releases. (With no offsetting user-visible feature improvements.) So we see the problem's larger than just sound and video drivers.&lt;br /&gt;&lt;br /&gt;It's almost as if the Linux community doesn't _want_ to be successful.&lt;br /&gt;&lt;br /&gt;Microsoft must be laughing all the way to the bank on this one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-7599131227510660058?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/7599131227510660058/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=7599131227510660058' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7599131227510660058'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7599131227510660058'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/05/see-this-is-why-we-cant-have-nice.html' title='See, this is why we can&apos;t have nice things (Ubuntu 9.04 Intel Drivers)'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4700609302503686883</id><published>2009-05-02T07:21:00.000-07:00</published><updated>2009-05-02T08:33:11.024-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='htpc'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><title type='text'>The diNovo Edge is a nice keyboard for HTPC</title><content type='html'>I just bought a &lt;a href="http://www.logitech.com/index.cfm/keyboards/keyboard/devices/4741&amp;amp;cl=us,en"&gt;Logitech diNovo Edge Mac Edition&lt;/a&gt; keyboard for my Mac Mini HTPC.&lt;br /&gt;&lt;br /&gt;I bought the diNovo instead of the Apple Bluetooth keyboard because:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Built-in trackpad.&lt;/li&gt;&lt;li&gt;Built in volume control slider.&lt;/li&gt;&lt;li&gt;Dedicated media transport controls.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Nifty dock / recharger stand.&lt;/li&gt;&lt;/ol&gt; It's my first Bluetooth device. So far I think Bluetooth works a lot better than IR, because you don't have to point it at an IR receiver.&lt;br /&gt;&lt;br /&gt;The diNovo does have some flaws:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No key backlighting, which makes it hard to use in the dark.&lt;/li&gt;&lt;li&gt;The mouse buttons below the trackpad are mushy and hinged at the outer edges, making them hard to press. (Happily tapping works and there is a separete left-mouse-button on the left edge of the keyboard. So for typical Mac usage you don't need to use the mushy buttons.)&lt;/li&gt;&lt;li&gt;A skim of the Logitech support forums indicates that the function keys are not as programmable as some people wish. I don't use function keys that much so this hasn't been an issue for me yet.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;My TV is a 40" LCD, and I sit about 15 feet away from it. At this distance the 1920 x 1280 desktop is just too high resolution for my eyes, so I reduced my screen resolution to 1366 x 720. That seems to work well for now. Apparently I need to get a bigger TV :-)&lt;br /&gt;&lt;br /&gt;Using a keyboard/trackpad instead of a button-based remote control is nice. I like being able to use all the ordinary apps that I already know how to use, rather than have to learn a new set of apps and UI commands. I also like not having to switch input devices depending upon what I'm trying to do. (For example if I want to use a web browser to look up some fact about a video that I just watched, it just works.)&lt;br /&gt;&lt;br /&gt;The diNovo is very smartly designed, so that it's easy to use the mouse while holding the keyboard in two hands. Of course I'm a right hander. A left hander might have a different opinion, as the trackpad is located where it can be used easily with the right hand, but not the left hand.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What about Linux?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have been able to use the same keyboard with both Mac and Kubuntu 9.04. With Kubuntu there were some issues around the initial pairing: You need a working keyboard and mouse in order to pair a new Bluetooth device. You even need to reboot once, and answer one final dialog box using a working keyboard / mouse, before the new device pairing is complete.&lt;br /&gt;&lt;br /&gt;A second issue for HTPC use is that the Mac Mini video driver on Kubuntu does not have the flexability to slightly lower the resolution of the screen. I blame Intel for this, as they are in the middle of converting to a new driver model and their current drivers are pretty bare bones.&lt;br /&gt;&lt;br /&gt;One final issue for dual booting Mac systems is that it seems to take a while for the keyboard to reconnect after a restart. This is an issue if you have reFit installed and you're trying to send keystrokes to reFit during the reboot. I found I had to press multiple keys multiple times until reFit started recognizing keys, after which the keyboard acted normally.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4700609302503686883?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4700609302503686883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4700609302503686883' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4700609302503686883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4700609302503686883'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/05/dinovo-edge-is-nice-keyboard-for-htpc.html' title='The diNovo Edge is a nice keyboard for HTPC'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4445019902536080447</id><published>2009-03-30T02:53:00.000-07:00</published><updated>2009-04-01T16:25:52.806-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d graphics'/><category scheme='http://www.blogger.com/atom/ns#' term='Larrabee'/><title type='text'>Larrabee Instruction Set Talks</title><content type='html'>&lt;h3 class="post-title entry-title"&gt; &lt;/h3&gt;  &lt;div class="post-body entry-content"&gt; Here's the first public version of the slides from Tom Forsyth and Michael Abrash's GDC 2009 talks on Larrabee's instruction set, by way of Japanese magazine PC Watch, as seen on Beyond 3D's Forums. (You have to manually click on each of the little thumbnails of each slide.):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://pc.watch.impress.co.jp/docs/2009/0330/kaigai498.htm"&gt;http://pc.watch.impress.co.jp/docs/2009/0330/kaigai498.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Hopefully Intel (or GDC) will release a better version of these slide decks sometime soon.&lt;br /&gt;&lt;br /&gt;Say, was it just me, or was blogging really light about GDC this year? In past years I was a lot more technical writeups than I saw this year. I wonder if blogging is down in general? Is everyone on Facebook and Twitter now? I can't imagine Twitter being very useful for reporting technical information.&lt;br /&gt;&lt;br /&gt;Here's Michael Abrash's Doctor Dobbs Journal article on the Larrabee instruction set.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ddj.com/hpc-high-performance-computing/216402188"&gt;http://www.ddj.com/hpc-high-performance-computing/216402188&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here's the &lt;a href="http://software.intel.com/en-us/articles/intel-at-gdc/"&gt;Intel GDC 2009&lt;/a&gt; Larrabee talks:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://software.intel.com/file/15542"&gt;&lt;strong style="font-weight: normal;"&gt;Rasterization on Larrabee: A First Look at the Larrabee New Instructions (LRBni) in Action&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://software.intel.com/file/15545"&gt;&lt;strong style="font-weight: normal;"&gt;SIMD Programming on Larrabee: A Second Look at the Larrabee New Instructions (LRBni) in Action&lt;/strong&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4445019902536080447?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4445019902536080447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4445019902536080447' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4445019902536080447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4445019902536080447'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/03/larrabee-instruction-set-talks.html' title='Larrabee Instruction Set Talks'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5345170011325301619</id><published>2009-03-27T08:23:00.000-07:00</published><updated>2009-03-27T19:46:23.876-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='xbmc'/><title type='text'>Using XBMC on Mac Mini using both OSX and Linux</title><content type='html'>The Xbox Media Center (XBMC) is a nifty open-source application for watching videos. It was originally designed for use on modified Xbox video game consoles, but has more recently become popular for Intel-based Home Theater Personal Computers. It has been ported to Windows, Mac, and Linux. It has no PVR features, instead it concentrates on displaying streaming and downloaded videos. Its big advantage over using the Xbox 360's similar application is that it handles a much wider variety of streaming video sources and downloaded video codecs.&lt;br /&gt;&lt;br /&gt;I've been running &lt;a href="http://www.plexapp.com/"&gt;Plex&lt;/a&gt;, an OSX-specific version of the Xbox Media Center, on my Mac Mini for several months now. Overall it's a good product, but I had some issues for my application. I wanted Plex to serve as a consumer electronic device that my mother-in-law (who doesn't use computers and can't read English) could use by herself to watch videos. The system I put together didn't work very well for her. The problems we ran in to were:&lt;br /&gt;&lt;br /&gt;1) The integration with the 6-button Apple Remote Control into the Plex/XBMC UI leaves a lot to be desired. The XBMC UI was designed to be used with a full-featured remote, and the Apple Remote mapping is just too hard to use. My mother-in-law would end up in the weeds of some obscure corner of the Plex UI, without knowing how she had gotten there or how to get back. The Plex software contributed to this problem by having a very sluggish interface to the Apple Remote, that frequently missed clicks. When you couple this with the overloading of "short" and "long" presses to try and give the Apple Remote more logical buttons, it became quite difficult (even for me) to reliably drive the UI. Even a task as simple as backing out of a playing video was difficult to do reliably.&lt;br /&gt;&lt;br /&gt;2) OSX (and Plex) have trouble running in consumer-electronics mode, without a keyboard or mouse. OSX and Plex both liked to bring up modal dialogs to report errors or software updates. I was always having to drag out a keyboard and mouse to dismiss these dialogs.&lt;br /&gt;&lt;br /&gt;Now, a sensible person would work around these issues by buying a Bluetooth keyboard and mouse, and software like "&lt;a href="http://www.iospirit.com/index.php?mode=view&amp;amp;obj_type=infogroup&amp;amp;obj_id=24&amp;amp;sid=9214373G9cd3975527aa3499"&gt;Remote Buddy&lt;/a&gt;" that enables the use of a full-featured remote. A somewhat more ambitious person might have rescripted the Plex UI to work better with the Apple Remote, or even dug into the sources to try and fix the sluggish event problem. But I'm restless, and wanted an excuse to try out Linux on the Mac Mini anyway. So this week I decided to see if the Linux version of XBMC worked any better.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Installing Linux XBMC&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Installing Linux is alot like the old pre-Windows 95 days of DOS. I spent a lot of time trying different things and fiddling with hardware issues. Here's what finally worked for me:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Installed &lt;a href="http://refit.sourceforge.net/"&gt;rEFIt&lt;/a&gt; to allowing easy dual-booting between Mac and Linux&lt;/li&gt;&lt;li&gt;Installed &lt;a href="http://releases.ubuntu.com/8.10/"&gt;Ubuntu 8.10 32-bit&lt;/a&gt; version.&lt;/li&gt;&lt;li&gt;&lt;a href="http://xbmc.org/wiki/?title=HOW-TO_compile_XBMC_for_Linux_from_source_code"&gt;Compiled XBMC from the tip-of-tree svn sources&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Installed the LIRC infrared remote control driver (apt-get install lirc) and used an old USB-based Windows Media Center remote control that I already had.&lt;/li&gt;&lt;/ul&gt;So far (one day) this has worked well. The full-functioned remote control make a big difference in usability.&lt;br /&gt;&lt;span style="font-weight: bold;font-family:arial;font-size:130%;"  &gt;&lt;br /&gt;Some issues I ran into&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ubuntu 9.04 beta problems with OpenGL accelleration for the Mac Mini&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Ubuntu 9.04 beta Intel 945 OpenGL driver does not hardware accelerate as many features of OpenGL as in older versions of Ubuntu. XBMC's user interface runs very slowly. This is not XBMC-specific. Try using apt-get to install the "amoeba" OpenGL demo. It runs smoothly on Ubuntu 8.10, but is a 2-frame-per-second slide-show on Ubuntu 9.04 beta. I hope this regression gets fixed in future versions of Ubuntu 9.04, as it otherwise looks like a good system.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The prebuilt "PPA" XBMC binaries will crash on Ubuntu 8.10 when pausing video&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I had to build XBMC from the subversion sources in order to fix a bug where pausing a video would immediately cause XBMC to crash. (I used a build from Thursday March 26th. I'm sorry but this is the first time I've used subversion, so I don't know how to figure out which revision number I'm synced to.) This is a bug that's been reported several times in the XBMC forums. It seems to be solved by compiling from source, without making any other changes. I'm suspicious that this may be due to some subtle difference between the libraries that you install to compile and the libraries that are installed when you install the prebuilt binary. (But that's just a guess. The real reason may be something completely different.)&lt;br /&gt;&lt;br /&gt;Well, after all this the system seems to work pretty well for my application. Too bad my mother-in-law's finished her visit with us and gone back home. At least now I've got plenty of time to work out the bugs before her next visit.&lt;br /&gt;&lt;br /&gt;[Revision notes]&lt;br /&gt;3/27/09 - Updated for Ubuntu 9.04 beta.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5345170011325301619?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5345170011325301619/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5345170011325301619' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5345170011325301619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5345170011325301619'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/03/using-xbmc-on-mac-mini-using-both-osx.html' title='Using XBMC on Mac Mini using both OSX and Linux'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4268790345047520156</id><published>2009-03-25T14:37:00.000-07:00</published><updated>2009-03-25T15:00:03.659-07:00</updated><title type='text'>Intel describes Larrabee instruction set</title><content type='html'>Perhaps in preparation for Friday's GDC talks by Michael Abrash and Tom Forsyth, Intel has described the Larrabee instruction set:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://software.intel.com/en-us/articles/prototype-primitives-guide/"&gt;Prototype Primitives Guide&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Intel includes a C source file that implements their new instruction set, so people can play around with the instructions before Larrabee ships.&lt;br /&gt;&lt;br /&gt;The instruction set looks alot like a typical GPU shader instruction set. Lots of "log" and "rsqrt" type instructions. But there are also some interesting variations on MADD, such as &lt;strong style="font-weight: normal;"&gt;MADD233_{PI,PS}, which&lt;/strong&gt; I assume help shave cycles off of inner loops. The compress and expand instructions also look very useful. I look forward to reading code examples from Abrash and Forsyth in the near future!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4268790345047520156?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4268790345047520156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4268790345047520156' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4268790345047520156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4268790345047520156'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/03/intel-describes-larrabee-instruction.html' title='Intel describes Larrabee instruction set'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-3803871991600585424</id><published>2009-03-06T10:50:00.000-08:00</published><updated>2009-03-06T11:09:00.988-08:00</updated><title type='text'>Listening to my home music at work with SqueezeCenter and Softsqueeze</title><content type='html'>For some time I've wanted to listen to my home music collection on my computer at work. I tried a bunch of different approaches, and finally came up with one that works pretty well:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I run the free &lt;a href="http://www.slimdevices.com/pi_features.html"&gt;SqueezeCenter&lt;/a&gt; program on my home machine to serve music.&lt;/li&gt;&lt;li&gt;I run the free &lt;a href="http://softsqueeze.sourceforge.net/"&gt;Softsqueeze&lt;/a&gt; program on my work machine to listen to the music.&lt;/li&gt;&lt;li&gt;To keep the whole world from listening to my music, &lt;a href="http://softsqueeze.sourceforge.net/ssh.html"&gt;I set up an SSH tunnel&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;The resulting system works pretty well.&lt;br /&gt;&lt;br /&gt;In case you're wondering, the SqueezeCenter program's main use is to serve music to the Squeezebox brand of internet radios. The ability to use it with a regular computer, without purchasing a Squeezebox internet radio, is a nice gesture on the part of the Logitec company that makes and sells Squeezebox internet radios.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-3803871991600585424?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/3803871991600585424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=3803871991600585424' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3803871991600585424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/3803871991600585424'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/03/listening-to-my-home-music-at-work-with.html' title='Listening to my home music at work with SqueezeCenter and Softsqueeze'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-8435039123707208824</id><published>2009-02-16T21:25:00.000-08:00</published><updated>2009-02-16T21:41:22.516-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Larrabee'/><title type='text'>Future GPU.org for cryptic Larrabee news</title><content type='html'>Phil Taylor, a long-time Microsoft graphics and gaming evangelist is now working for Intel on graphics tools evangelism. He started a blog, called &lt;a href="http://www.futuregpu.org/"&gt;Future GPU&lt;/a&gt;, where he drops hints and links about Larrabee development. He also tells Microsoft war stories for people in the mood for inside-baseball information about Microsoft's DirectX and game groups.&lt;br /&gt;&lt;br /&gt;Back when I was working at WebTV and just learning about the 3D graphics world, Phil was nice enough to give me and a few of my WebTV co-workers tickets to the super-desirable GDC DirectX party. These parties were intended for external developers, so it was very hard for non-DirectX Microsofties to attend. Thanks Phil!!! :-)&lt;br /&gt;&lt;br /&gt;From reading Phil's blog it sounds like &lt;a href="https://www.cmpevents.com/GD09/a.asp?option=C&amp;amp;V=11&amp;amp;SessID=9262"&gt;Intel's developing a set of graphics debugging tools that they're going to announce at GDC&lt;/a&gt;. Could it be PIX-for-Larrabee?&lt;br /&gt;&lt;br /&gt;I found Phil's site through a "&lt;a href="http://www.google.com/alerts"&gt;Google Alert&lt;/a&gt;" that I set up for Larrabee news. It does a weekly search for Larrabee news. The web's so big and sparsely connected that I'm finding that I've never heard of any of the web sites that the Alert is dredging up. Most of the sites mentioned in the Google Alert are not worth visiting, but a few (like Phil's site) are very interesting indeed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-8435039123707208824?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/8435039123707208824/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=8435039123707208824' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/8435039123707208824'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/8435039123707208824'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/02/future-gpuorg-for-cryptic-larrabee-news.html' title='Future GPU.org for cryptic Larrabee news'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-8603889872500114608</id><published>2009-01-07T20:32:00.000-08:00</published><updated>2009-01-07T20:55:55.328-08:00</updated><title type='text'>"Pixar Quality Graphics" is 720 Gflops</title><content type='html'>For at least 10 years GPU vendors have been talking about "Pixar Quality" graphics. But what does that mean? Well, according to this lecture on &lt;a href="http://graphics.stanford.edu/courses/cs448a-01-fall/lectures/lecture16/walk002.html"&gt;The Design of Renderman&lt;/a&gt;, the original goals for the REYES architecture were&lt;br /&gt;&lt;ul&gt;&lt;li&gt;3000 x 1667 pixels (5 MP)&lt;/li&gt;&lt;li&gt;80M Micropolygons (each 1/4th of a pixel in size, depth complexity of 4)&lt;/li&gt;&lt;li&gt;16 samples per pixel&lt;/li&gt;&lt;li&gt;150K geometric primitives&lt;/li&gt;&lt;li&gt;300 shading flops per micropolygon&lt;/li&gt;&lt;li&gt;6 textures per primitive&lt;/li&gt;&lt;li&gt;100 1MB textures&lt;/li&gt;&lt;/ul&gt;That's a shading rate of 80M * 300 * 30 Hz = 720 Gflops. (They were probably more concerned about 24 Hz, but for games 30Hz is better.)&lt;br /&gt;&lt;br /&gt;In comparison I think the peak shader flops of high-end 2008-era video cards are in the 1 TFlop range. (Xbox 360 Xenos is 240 Gflops, PS3 is a bit less.). Now, GPU vendors typically quote multiply-accumulate flops, because that doubles the number of flops. So it's more realistic to say that 2008-era video cards are in the 500 Gflop range.  So we really are entering the era of "Pixar Quality" graphics.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-8603889872500114608?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/8603889872500114608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=8603889872500114608' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/8603889872500114608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/8603889872500114608'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2009/01/pixar-quality-graphics-is-720-gflops.html' title='&quot;Pixar Quality Graphics&quot; is 720 Gflops'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-6004628733559848431</id><published>2008-12-31T06:33:00.000-08:00</published><updated>2008-12-31T06:50:07.016-08:00</updated><title type='text'>Tech Talk on Wii security model (and breaking it)</title><content type='html'>A very thorough talk describing the Nintendo Wii game console security model and the bugs and weaknesses that allowed the Wii to be compromised:&lt;br /&gt;&lt;a href="http://events.ccc.de/congress/2008/Fahrplan/events/2799.en.html"&gt;Console Hacking 2008: Wii Fail&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In a nutshell, security is provided by an embedded ARM CPU that sits between the CPU and the IO devices, and handles all the IO. The two main flaws were (a) A bug in the code that compared security keys, such that it was possible to forge security keys, and (b) secret break-once-run-everywere information was stored un-encrypted in RAM, where it could be extracted using hardware modifications.&lt;br /&gt;&lt;br /&gt;There's a nice table at the end of the presentation showing a number of recent consumer devices, what their security model was, and how long it took to break them.&lt;br /&gt;&lt;br /&gt;The PS3 is the only console that's currently unbroken. The PS3's security model seems similar to the Xbox 360, but somewhat weaker. But it remains unbroken. This seems to due to the existence of an official PS3 Linux port, which means most Linux kernel hackers are not motivated to hack the PS3 security. (Only the ones who want full access to the GPU from Linux are motivated, and only to the extent that they can access the GPU.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-6004628733559848431?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/6004628733559848431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=6004628733559848431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6004628733559848431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6004628733559848431'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/12/tech-talk-on-wii-security-model-and.html' title='Tech Talk on Wii security model (and breaking it)'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4967587687720995443</id><published>2008-12-25T18:51:00.000-08:00</published><updated>2008-12-25T19:35:05.226-08:00</updated><title type='text'>Larrabee papers from SIGGRAPH Asia 2008</title><content type='html'>...as seen on the &lt;a href="http://forum.beyond3d.com/showthread.php?p=1251413#post1251413"&gt;Beyond3D GPGPU forum&lt;/a&gt;, here are the presentations from the recent (December 12th 2008) "Beyond Programmable Shading" course:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://sa08.idav.ucdavis.edu/"&gt;SIGGRAPH Asia 2008: Parallel Computing for Graphics: Beyond Programmable Shading&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There are good presentations from both GPU vendors and academics. My favorite presentations are the Intel ones on Larrabee, just because I'm so interested in that architecture:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://sa08.idav.ucdavis.edu/foley-programming-larrabee.pdf"&gt;Parallel Programming on Larrabee&lt;/a&gt; - describes the Larrabee fiber/task programming model.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://sa08.idav.ucdavis.edu/foley-nextgen.pdf"&gt;Next-Generation Graphics on Larrabee&lt;/a&gt; - how Larrabee's standard renderer is structured, and how it can be extended / modified.&lt;br /&gt;&lt;br /&gt;IBM / Sony missed a bet by not presenting here. That's too bad, because Cell sits between the ATI / NVIDIA parts and Larrabee in terms of programmability. And Cell's been available for long enough that there should be a number of interesting results to report.&lt;br /&gt;&lt;br /&gt;Note to self: consider buying a PS3 and learning Cell programming, just to get ready for Larrabee. Heh, yeah, that's the ticket. Being able to play PS3-specific games like Little Big Planet and Flower would be just a coincidental bonus.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4967587687720995443?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4967587687720995443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4967587687720995443' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4967587687720995443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4967587687720995443'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/12/larrabee-papers-from-siggraph-asia-2008.html' title='Larrabee papers from SIGGRAPH Asia 2008'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5208231402654580539</id><published>2008-12-08T10:35:00.000-08:00</published><updated>2008-12-08T10:49:55.199-08:00</updated><title type='text'>Fun with Git</title><content type='html'>This weekend I reorganize my home source code projects. I have a number of machines, and over the years each one had accumulated several small source-code projects. (Python scripts, toy games, things like that.) I wanted to put these projects under source code control. I also wanted to make sure they were backed-up. Most of these little projects are not ready to be published, so I didn't want to use one of the many web-based systems for source-code management.&lt;br /&gt;&lt;br /&gt;After some research, I decided to use replicated git repositories.&lt;br /&gt;&lt;br /&gt;I created a remote git repository on an Internet-facing machine, and then created local git repositories on each of my development machines. Now I can use git push and git pull to keep the repositories synchronized. I use git's built-in ssh transport, so the only thing I had to do on the Internet-facing-machine was make sure that the git executables were in the non-interactive-ssh-shell's path. (Which I did by adding them in my .bashrc file.)&lt;br /&gt;&lt;br /&gt;Git's ability to work off-line came in handy this Sunday, as I was attending an elementary-school chess tournament with my son. Our local public schools don't have open WiFi, so there was no Internet connectivity. But I was able to happily work away using my local git, and later easily push my changes back to the shared repository.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5208231402654580539?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5208231402654580539/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5208231402654580539' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5208231402654580539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5208231402654580539'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/12/fun-with-git.html' title='Fun with Git'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-2159248065434436049</id><published>2008-11-19T10:17:00.000-08:00</published><updated>2008-11-19T12:13:21.390-08:00</updated><title type='text'>Microsoft New Xbox Experience Avatars</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://avatar.xboxlive.com/avatar/Grammerjack/avatar-body.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 150px; height: 300px;" src="http://avatar.xboxlive.com/avatar/Grammerjack/avatar-body.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I just tried creating an avatar on Microsoft's new Xbox dashboard. As you can see (at least when the Microsoft server isn't being hammered) on the left, they provide a URL for displaying your current Avatar on a web page.&lt;br /&gt;&lt;br /&gt;The character creation system is not too bad. In some ways it's more flexible than Nintendo's Mii (for example more hair styles and clothing), but in other ways it's more limited (less control over facial feature placement).&lt;br /&gt;&lt;br /&gt;My avatar looks better on the Xbox than it does here -- they should consider sharpening the image. For example, the T-shirt my avatar is wearing has a thin-lined Xbox symbol.&lt;br /&gt;&lt;br /&gt;I think they do a good job of avoiding the Uncanny Valley effect. I look forward to seeing how avatars end up being used in the Xbox world.&lt;br /&gt;&lt;br /&gt;In othe Xbox-related news I'm enjoying playing Banjo Kazooie Nuts &amp;amp; Bolts with my son. All we have right now is the demo, but it's great fun for anyone who likes building things. It's replaced Cloning Clyde as my son's favorite Xbox game.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-2159248065434436049?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/2159248065434436049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=2159248065434436049' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2159248065434436049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2159248065434436049'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/11/microsoft-new-xbox-experience-avatars.html' title='Microsoft New Xbox Experience Avatars'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-7021460703196264441</id><published>2008-11-19T05:24:00.000-08:00</published><updated>2008-11-19T05:34:07.531-08:00</updated><title type='text'>Internals of the Azul Systems Multi-core Java processor</title><content type='html'>I'm a big fan of CPU architectures. Here's a conversation between David Moon formerly of Symbolics Lisp Machines and Cliff Click Jr. of Azule Systems. They discuss details of both the Lisp Machine architecture and Azule's massively multi-core Java machine.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.azulsystems.com/cliff/2008/11/a-brief-conversation-with-david-moon.html"&gt;http://blogs.azulsystems.com/cliff/2008/11/a-brief-conversation-with-david-moon.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The claim (from both Symbolics and Azule) is that adding just a few instructions to an ordinary RISC instruction set can make GC much faster. With so much code being run in Java these days I wonder if we'll see similar types of instructions added to mainstream architectures.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-7021460703196264441?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/7021460703196264441/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=7021460703196264441' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7021460703196264441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7021460703196264441'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/11/internals-of-azul-systems-multi-core.html' title='Internals of the Azul Systems Multi-core Java processor'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4272230081364202086</id><published>2008-10-20T00:54:00.001-07:00</published><updated>2008-10-20T00:59:54.378-07:00</updated><title type='text'>Can a comic strip make you more productive?</title><content type='html'>This one can:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://xkcd.com/386/"&gt;XKCD: Someone is Wrong on the Internet&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;--- this comic's punchline has saved me at least an hour of a week since it came out. That's more than I've saved by learning Python. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4272230081364202086?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4272230081364202086/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4272230081364202086' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4272230081364202086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4272230081364202086'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/10/can-comic-strip-make-you-more.html' title='Can a comic strip make you more productive?'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-6094952657645902608</id><published>2008-09-30T10:01:00.000-07:00</published><updated>2008-09-30T10:18:43.553-07:00</updated><title type='text'>Next gen video console speculation suggests we aim low</title><content type='html'>The next generation of video game consoles should start in 2011. (Give or take a year). It takes about three years to develop a video game console, so work should be ramping up at all three video game manufacturers.&lt;br /&gt;&lt;br /&gt;Nintendo's best course-of-action is pretty clear: Do a slightly souped-up Wii. Perhaps with lots of SD-RAM for downloadable games. Probably with low-end HD resolution graphics. Definately with an improved controller (for example with the recent gyroscope slice built in.)&lt;br /&gt;&lt;br /&gt;Sony and Microsoft have to decide whether to aim high or copy Nintendo.&lt;br /&gt;&lt;br /&gt;Today a strong rumor has it that Sony is polling developers to see what they think of a PlayStation 4 that is similar to a cost-reduced PlayStation 3 (same Cell, cheaper RAM, cheap launch price.)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://forum.beyond3d.com/showthread.php?t=50037"&gt;http://forum.beyond3d.com/showthread.php?t=50037&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That makes sense as Sony has had problems this generation due to the high launch cost of the PS3. The drawback of this scheme is that it does nothing to make the PS4 easy to program.&lt;br /&gt;&lt;br /&gt;In the last few weeks we've seen other rumors that Microsoft's being courted by Intel to put the Larrabee GPU in the next gen Xbox. I think that if Sony aims low, it's likely that Microsoft will be foreced to aim low too, which would make a Larrabee GPU unlikely. That makes me sad --  in my dreams, I'd love to see an Xbox 4 that used a quad-core x86 CPU and a 16-core Larrabee GPU.&lt;br /&gt;&lt;br /&gt;Well, the great thing is that we'll know for sure, in about 3 years. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-6094952657645902608?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/6094952657645902608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=6094952657645902608' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6094952657645902608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6094952657645902608'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/09/next-gen-video-console-speculation.html' title='Next gen video console speculation suggests we aim low'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-7833872836063205707</id><published>2008-09-24T07:46:00.000-07:00</published><updated>2008-09-24T07:54:06.933-07:00</updated><title type='text'>Woot! I'm 19th place in the ICFP 2008 Programming Contest</title><content type='html'>Team Blue Iris (that's me and my kids!) took 19th place, the top finish for a Python-based entry!&lt;br /&gt;&lt;br /&gt;Check out the  &lt;a href="http://video.google.com/videoplay?docid=-4697764813432201693"&gt;ICFP Programming Contest 2008 Video&lt;/a&gt;. The winning team list is given at 41:45.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-7833872836063205707?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/7833872836063205707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=7833872836063205707' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7833872836063205707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7833872836063205707'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/09/woot-im-19th-place-in-icfp-2008.html' title='Woot! I&apos;m 19th place in the ICFP 2008 Programming Contest'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-8048864408495542806</id><published>2008-09-19T07:01:00.000-07:00</published><updated>2008-09-19T07:29:40.127-07:00</updated><title type='text'>Will Smart Phones replace PCs?</title><content type='html'>That's the question &lt;a href="http://www.realworldtech.com/forums/index.cfm?action=detail&amp;amp;id=93355&amp;amp;threadid=93355&amp;amp;roomid=2"&gt;Dean Kent asks over at Real World Tech&lt;/a&gt;'s forums. I replied briefly there, but thought it would make a good blog post as well.&lt;br /&gt;&lt;p&gt;I'm an Android developer, so I'm probably biased, but I think most people in the developed world will have a smart phone eventually, just as most people already have access to a PC and Internet connectivity.&lt;/p&gt;&lt;p&gt;I think the ratio of phone / PC use will vary greatly depending upon the person's lifestyle. If you're a city-dwelling 20-something student you're going to be using your mobile phone a lot more than a 60-something suburban grandpa.&lt;/p&gt;&lt;p&gt;This isn't because the grandpa's old fashioned, it's because the two people live in different environments and have different patterns of work and play.&lt;/p&gt;Will people stop using PCs? Of course not. At least, not most people. There are huge advantages to having a large screen and a decent keyboard and mouse. But I think people will start to think of their phone and their PC as two views on the same thing -- the Internet. And that will shape what apps they use on both the phone and the PC.&lt;br /&gt;&lt;br /&gt;And this switching will be a strong force towards having people move their data into the Internet cloud, so that they can access their data from whatever device they're using. This tendency will be strongest with small-sized data that originates in the cloud (like email), but will probably extend to other forms of data over time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-8048864408495542806?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/8048864408495542806/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=8048864408495542806' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/8048864408495542806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/8048864408495542806'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/09/will-smart-phones-replace-pcs.html' title='Will Smart Phones replace PCs?'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4389929454732326374</id><published>2008-09-19T06:55:00.000-07:00</published><updated>2008-09-19T07:01:27.396-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>Peter Moore on Xbox</title><content type='html'>&lt;a href="http://www.guardian.co.uk/technology/gamesblog/2008/sep/11/playstation.microsoft1?gusrc=rss&amp;amp;feed=technology"&gt;Peter Moore on Xbox&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I always liked Peter Moore, and I was sorry when he left Xbox for EA. He's given a very good interview on his time at Sega and Microsoft. (He ran the Xbox game group at Microsoft before moving on to Electronic Arts.) Lots of insight into the Xbox part of the game industry.&lt;br /&gt;&lt;br /&gt;Here he is talking about Rare:&lt;br /&gt;&lt;blockquote&gt;...and you know, Microsoft, we'd had a tough time getting Rare back – Perfect Dark Zero was a launch title and didn't do as well as Perfect Dark… but we were trying all kinds of classic Rare stuff and unfortunately I think the industry had past Rare by – it's a strong statement but what they were good at, new consumers didn't care about anymore, and it was tough because they were trying very hard - Chris and Tim Stamper were still there – to try and recreate the glory years of Rare, which is the reason Microsoft paid a lot of money for them and I spent a lot of time getting on a train to Twycross to meet them. Great people. But their skillsets were from a different time and a different place and were not applicable in today's market.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4389929454732326374?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4389929454732326374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4389929454732326374' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4389929454732326374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4389929454732326374'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/09/peter-moore-on-xbox.html' title='Peter Moore on Xbox'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-1985800599829369618</id><published>2008-09-16T07:28:00.001-07:00</published><updated>2008-09-16T07:42:57.081-07:00</updated><title type='text'>Pro tip: Try writing it yourself</title><content type='html'>Sometimes I need to get a feature into the project I'm working on, but the developer who owns the feature is too busy to implement it. A trick that seems to help unblock things is if I hack up an implementation of the feature myself and work with the owner to refine it.&lt;br /&gt;&lt;br /&gt;This is only possible if you have an engineering culture that allows it, but luckily both Google and Microsoft cultures allow this, at least at certain times in the product lifecycle when the tree isn't frozen.&lt;br /&gt;&lt;br /&gt;By implementing the feature myself, I'm (a) reducing risk, as we can see the feature sort of works, (b) making it much easier for the overworked feature owner to help me, as they only have to say "change these 3 things and you're good to go", rather than having to take the time to educate me on how to implement the feature, (c) getting a chance to implement the feature exactly the way I want it to work.&lt;br /&gt;&lt;br /&gt;Now, I can think of a lot of situations where this approach won't work: at the end of the schedule where no new features are allowed, in projects where the developer is so overloaded that they can't spare any cycles to review the code at all, or in projects where people guard the areas they work on.&lt;br /&gt;&lt;br /&gt;But I've been surprised how well it works. And it's getting easier to do, as distributed version control systems become more common, and people become more comfortable working with multiple branches and patches.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-1985800599829369618?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/1985800599829369618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=1985800599829369618' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1985800599829369618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1985800599829369618'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/09/pro-tip-try-writing-it-yourself.html' title='Pro tip: Try writing it yourself'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-2715885881151365435</id><published>2008-09-15T06:19:00.001-07:00</published><updated>2008-09-15T06:34:18.102-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d graphics'/><category scheme='http://www.blogger.com/atom/ns#' term='Larrabee'/><title type='text'>Tim Sweeney on the Twilight of the GPU</title><content type='html'>Ars Technica published an excellent interview with Tim Sweeney on the &lt;a href="http://arstechnica.com/articles/paedia/gpu-sweeney-interview.ars"&gt;Twilight of the GPU&lt;/a&gt;. As the architect of the Unreal Engine series of game engines, Tim has almost certainly been disclosed on all the upcoming GPUs. Curiously he only talks about NVIDIA and Larrabee. Is ATI out of the race?&lt;br /&gt;&lt;br /&gt;Anyway, Tim says a lot of sensible things:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Graphics APIs at the DX/OpenGL level are much less important than they were in the fixed-function-GPU era.&lt;/li&gt;&lt;li&gt;DX9 was the last graphics API that really mattered. Now it's time to go back to software rasterization.&lt;/li&gt;&lt;li&gt;It's OK if NVIDIA's next-gen GPU still has fixed-function hardware, as long as it doesn't get in the way of pure-software rendering. (ff hardware will be useful for getting high performance on legacy games and benchmarks.)&lt;/li&gt;&lt;li&gt;Next-gen NVIDIA will be more Larrabee-like than current-gen NVIDIA.&lt;/li&gt;&lt;li&gt;Next Gen programming language ought-to-be vectorized C++ for both CPU and GPU.&lt;/li&gt;&lt;li&gt;Possibly the GPU and CPU will be the same chip on next-gen consoles.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-2715885881151365435?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/2715885881151365435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=2715885881151365435' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2715885881151365435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2715885881151365435'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/09/tim-sweeney-on-twilight-of-gpu.html' title='Tim Sweeney on the Twilight of the GPU'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4157746715281472546</id><published>2008-08-12T07:48:00.000-07:00</published><updated>2008-08-12T08:49:45.446-07:00</updated><title type='text'>The Future of Graphics APIs</title><content type='html'>The OpenGL 3.0 spec was released this week, just in time for SigGraph. It turns out to be a fairly minor update to OpenGL, little more than a codification of existing vendor extensions. While this disappoints OpenGL fans, it's probably the right thing to do. Standards tend to be best when they codify existing practice, rather than whey they try to invent new ideas.&lt;br /&gt;&lt;br /&gt;What about the future? The fundamental forces are:&lt;br /&gt;&lt;br /&gt;+ GPUs and CPUs are going to be on the same die&lt;br /&gt;+ GPUs are becoming general purpose CPUs.&lt;br /&gt;+ CPUs are going massively multicore&lt;br /&gt;&lt;br /&gt;Once a GPU &lt;span style="font-style: italic;"&gt;is&lt;/span&gt; a general purpose CPU, there's little reason to provide a standard all-encompasing rendering API. It's simpler and easier to give an OS and a C compiler, and a reference rendering pipeline. Then let the application writer customize the pipeline for their application.&lt;br /&gt;&lt;br /&gt;The big unknown is whether any of the next-generation video game consoles will adopt the CPU-based-graphics approach. CPU-based graphics may not be cost competitive soon enough for the next generation of game consoles.&lt;br /&gt;&lt;br /&gt;Sony's a likely candidate - it's a natural extension to the current Cell-based PS3. Microsoft would be very comfortable with a Larrabee-based solution, given their OS expertiese and their long and profitable relationship with Intel. Nintendo's pretty unlikely, as they have made an unbelievable amount of money betting on low-end graphics. (But they'd switch to CPU-based graphics in an instant if it provided cost savings. And for what it's worth, the N64 did have DSP-based graphics.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4157746715281472546?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4157746715281472546/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4157746715281472546' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4157746715281472546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4157746715281472546'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/08/future-of-graphics-apis.html' title='The Future of Graphics APIs'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-2046155477450725247</id><published>2008-07-27T05:38:00.000-07:00</published><updated>2008-07-27T22:02:07.512-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='htpc'/><title type='text'>Mac Min HTPC take two</title><content type='html'>I just bought another Mac Mini to use as a HTPC (home theater PC). I tried this a year ago, but was not happy with the results. But since then I've become more comfortable with using OS X, so today I thought I'd try again.&lt;br /&gt;&lt;br /&gt;Here's my quick setup notes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I'm using a Mac Mini 1.83 Core 2 Duo with 1 GB of RAM. This is the cheapest Mac Mini that Apple currently sells. I thought about getting an AppleTV, but I think the Mini is easier to modify, has more CPU power for advanced codecs, and can be used as a kid's computer in the future, if I don't like using it as an HTPC. I also have dreams of writing a game for the Mini that uses Wiimotes. I think this would be easier to do on a Mini than an AppleTV, even though the AppleTV has a better GPU.&lt;/li&gt;&lt;li&gt;I'm using "Plex" as for viewing problem movies, and I think it may end up becoming my main movie viewing program. It's the OSX version of Xbox Media Center. (Which is a semi-legal program for a hacked original Xbox. The Plex version is legal because it doesn't use the unlicensed Xbox code.) The UI is a little rough. (Actually, by Mac standards it's _very_ rough. :-) ) Plex has very good codec support and lots of options for playing buggy or non-standard video files.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I connected my Mac Mini to my media file server using gigabit ethernet. This made Front Row feel much snappier than when I was using an 802.11g wireless connection.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I installed the &lt;a href="http://perian.org/"&gt;Perian&lt;/a&gt; plugin adds support for many popular codecs to Quicktime and Front Row.&lt;/li&gt;&lt;li&gt;I set up my Mac Mini to automatically mount my file server share at startup and when coming out of sleep. &lt;a href="http://forums.mactalk.com.au/13/42160-solution-how-auto-reconnect-network-drive-after-resuming-sleep.html"&gt;Detailed instructions here.&lt;/a&gt; Synopsis: Create an AppleScript utility to mount the share, put the utility in your Login Items so that it's run automatically at startup, and finally use &lt;a href="http://www.bernhard-baehr.de/"&gt;SleepWatcher&lt;/a&gt; to run the script after a sleep.&lt;/li&gt;&lt;li&gt;I added FrontRow to my Login Items (Apple Menu:System Preferences...:Accounts:Login Items) to start Front Row at startup.&lt;/li&gt;&lt;li&gt;I administer my Mini HTPC using VNC from a second computer. I don't have a keyboard or mouse hooked up to the HTPC normally. I disabled the Bluetooth keyboard detection dialog using Apple Menu:System Preferences...:Bluetooth:Advanced... then uncheck "Open Bluetooth Setup Assistant at startup when no input device present".&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Things I'm still working on:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No DVR-MS codec support in Perian, and therfore none in Front Row. I have to use my trusty Xbox 360 or VLC to view my Microsoft Windows Media Center recordings.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-2046155477450725247?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/2046155477450725247/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=2046155477450725247' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2046155477450725247'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2046155477450725247'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/07/mac-min-htpc-take-two.html' title='Mac Min HTPC take two'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5595780757627939519</id><published>2008-07-14T06:07:00.000-07:00</published><updated>2008-07-14T07:18:55.669-07:00</updated><title type='text'>ICFP 2008 post-mortem</title><content type='html'>This year's &lt;a href="http://www.icfpcontest.org/"&gt;ICFP&lt;/a&gt;&lt;a href="http://www.icfpcontest.org/"&gt; contest&lt;/a&gt; was a traditional one: Write some code that solves an optimization problem with finite resources, debug it using sample data sets, send it in, and the judging team will run it on secret (presumably more difficult) data sets, and see whose program does the best. The problem was to create a control program for an idealized Martian rover that had to drive to home base while avoiding craters, boulders, and moving enemies.&lt;br /&gt;&lt;br /&gt;I read the problem description at noon on Friday, but didn't have time to work on the contest until Saturday morning.&lt;br /&gt;&lt;br /&gt;The first task was to choose a language. On the one hand, the strict time limit argued for an easy-to-hack "batteries included" language like Python, for which libraries, IDEs, and cross-platform runtime  were all readily available. On the other hand, the requirement for high performance and ability to correctly handle unknown inputs argued for a type safe, compiled language like ML or O'Caml.&lt;br /&gt;&lt;br /&gt;I spent a half an hour trying to set up an O'Caml IDE under Eclipse, but unfortunately was not able to figure out how to get the debuger to work. Then I switched to Python and the &lt;a href="http://pydev.sourceforge.net/index.html"&gt;PyDev IDE&lt;/a&gt;, and never ran into a problem that made me consider switching back.&lt;br /&gt;&lt;br /&gt;I realize that the resulting program is much slower than a compiled O'Caml would be, and it probably has lurking bugs that the O'Caml type system would have found at compile time. But it's the best I could do in the limited time available for the contest.&lt;br /&gt;&lt;br /&gt;It was very pleasant to develop in Python. It's got a very nice syntax. I was never at a loss for how to proceed. Either it "just worked", or else a quick web search would immediately find a good answer. (Thanks Google!)&lt;br /&gt;&lt;br /&gt;The main drawback was that the Python compiler doesn't catch simple mistakes like uninitialized variables until run time. Fortunately that wasn't too much of a problem for this contest, as the compile-edit-debug cycle was only a few seconds long, and it only took a few minutes to run a whole test suite.&lt;br /&gt;&lt;br /&gt;The initial development went smoothly: I wrote was the code to connect to the simulation server and read simulation data from the server. Then I created classes for the various types of objects in the world, plus a class to model the world as a whole. I then wrote a method that examined the current state of the world and decided what the Martian rover should do next. Finally I wrote a method that compared the current and desired Martian rover control state, and sent commands back to the simulation server to update the Martian rover control state.&lt;br /&gt;&lt;br /&gt;The meat of the problem is deciding how to move the rover. The iterative development cycle helped a lot here -- by being able to run early tests, I quickly discovered that the presence of fast-moving enemies put a premium on high speed movement. You couldn't cautiously analyze the world and proceed safely, you had to drive for the goal as quickly as possible.&lt;br /&gt;&lt;br /&gt;My initial approach was to search for the closest object in the path of the rover, and steer around it. This worked, but had issues in complicated environments. Then I switched to an idea from Craig Reynolds' &lt;a href="http://www.red3d.com/cwr/nobump/nobump.html"&gt;Not Bumping Into Things&lt;/a&gt; paper: I rendered the known world into a 1D frame buffer, and examined the buffer to decide which way to go. That worked well enough that I used it in my submission.&lt;br /&gt;&lt;br /&gt;I spent about fourteen hours on the contest: Two hours reading the problem and getting the IDE together, ten hours over two days programming and debugging, and about two hours testing the program on the Knoppix environment and figuring out how to package and submit the results.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Things I wish I had had time to do&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;My rover is tuned for the sample data sets. The organizers promised to use significantly different data sets in the real competition. Unfortunately, I didn't have time to adapt the program to these other data sets, beyond some trivial adjustments based on potential differences in top speed or sensor range.&lt;/li&gt;&lt;li&gt;I model the world at discreet times, and don't account for the paths objects take over time. I can get away with this because I'm typically traveling directly towards or away from important obstacles, so their relative motion is low. But I would have trouble navigating through whirling rings of Martians.&lt;/li&gt;&lt;li&gt;I don't take any advantage of knowledge of the world outside the current set of sensor data. The game explicitly allows you to remember the world state from run to run during a trial. This could be a big win for path planning when approaching the goal during the second or later trials.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I don't do any sort of global path planning. A simple maze around the goal would completely flummox my rover.&lt;/li&gt;&lt;/ul&gt;I very much enjoyed the contest this year. I look forward to finding out how well I did, as well as reading the winning programs. The contest results will be announced at the actual &lt;a href="http://www.icfpconference.org/"&gt;ICFP conference&lt;/a&gt; in late September.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5595780757627939519?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5595780757627939519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5595780757627939519' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5595780757627939519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5595780757627939519'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/07/icfp-2008-post-mortem.html' title='ICFP 2008 post-mortem'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-6633530270807126130</id><published>2008-07-09T03:47:00.000-07:00</published><updated>2008-07-09T04:20:11.716-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ICFP'/><title type='text'>Getting ready for ICFP 2008</title><content type='html'>The rules for this year's &lt;a href="http://www.icfpcontest.org/"&gt;ICFP contest&lt;/a&gt; have just been posted. Although the actual problem won't be posted until Friday July 11th, the rules themselves are interesting:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Your code will be run on a 1GB RAM 4GB swap 2GHz single-processor 32-bit AMD x86 Linux environment with no access to the Internet.&lt;/li&gt;&lt;li&gt;You have to submit source code.&lt;/li&gt;&lt;li&gt;You may optionally submit an executable as well (useful if for example you use a language that isn't one of the short list of languages provided by the contest organizers.)&lt;/li&gt;&lt;li&gt;Teams are limited to 5 members or less.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;I have mixed feelings about these rules. The good news is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It should be possible for most interested parties to recreate the contest environment by using the contest-provided Live CD. A computer capable of running the contest could be purchased new for around $350.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;It seems that the focus will be on writing code in the language of the contestant's choice, rather than writing code in the language of the contest organizer's choice. This wasn't the case in some previous year's contests.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;It provides a level playing field in terms of CPU resources available to contestants.&lt;/li&gt;&lt;li&gt;It ensures that the winning entry is documented. (A few years ago the contest winner never wrote up their entry, which was quite disappointing.)&lt;/li&gt;&lt;/ul&gt;The bad news is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It penalizes contestants with low Internet bandwidth. The Live CD image is not yet available for download, and I anticipate some contestants will have difficulty downloading it in time to compete in the contest.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;It penalizes non-Linux users, who are forced to use an alien development environment and operating system.&lt;/li&gt;&lt;li&gt;It penalizes languages too obscure to make the contest organizer's list. That goes against the whole "prove your language is the best" premise of the contest.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The target system is 32 bits and single core, which is at least five years out of date, and does little to advance the state of the art. This  penalizes many languages and runtimes. For example OCaml has a harsh implementation limit on array size in 32 bit runtimes that is relaxed in 64-bit runtimes.&lt;/li&gt;&lt;li&gt;It seems as if there won't be any during-the-contest scoring system, so we will have to wait until the ICFP conference to find out how the contestants did.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Still, I'm hopeful that the contest itself will still be enjoyable. I look forward to reading the actual programming problem on Friday.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-6633530270807126130?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/6633530270807126130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=6633530270807126130' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6633530270807126130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6633530270807126130'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/07/getting-ready-for-icfp-2008.html' title='Getting ready for ICFP 2008'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-6799393939541804251</id><published>2008-06-28T12:03:00.000-07:00</published><updated>2008-07-01T04:04:40.329-07:00</updated><title type='text'>Network Attached Storage Notes</title><content type='html'>I just bought a &lt;a href="http://www.buffalotech.com/products/network-storage/linkstation/linkstation-mini/"&gt;Buffalo LinkStation Mini 500GB&lt;/a&gt; Networked Attached Storage (NAS) device. It's a very small fanless Linux file server with two 250 GB hard drives, 128 MB of RAM, a 266 MHz ARM CPU and a gigabit Ethernet port.&lt;br /&gt;&lt;h2&gt;My reasons for buying a NAS&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;I wanted to provide a reliable backup of family photos and documents, and I was getting tired of burning CDs and DVDs.&lt;/li&gt;&lt;li&gt;I wanted a small Linux-based server I could play with.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;My reason for buying the LinkStation Mini&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;It's fanless.&lt;/li&gt;&lt;li&gt;It's tiny. &lt;/li&gt;&lt;li&gt;Buffalo has a good reputation for NAS quality.&lt;/li&gt;&lt;li&gt;There is a decent sized Buffalo NAS hacking community. &lt;/li&gt;&lt;li&gt;Fry's had it on sale. :-)&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Setting it up&lt;/h2&gt;Setup was very easy -- I unpacked the box, pluged everything in, and installed a CD of utility programs. The main feature of the utility program is that it helps find the IP address of the NAS. All the actual administration of the NAS is done via a Web UI.&lt;br /&gt;&lt;h2&gt;To RAID or not to RAID&lt;/h2&gt;The LinkStation Mini comes with two identical drives, initially set up as RAID0. This means that files are split across the two drives, which means that if either drive fails all your files will be lost. Using the Web UI, I reformatted the drives to RAID1, which means that each file is stored on both drives. This of course halves the amount of disk space available to store files, but I thought the added security was worth it. This process of switching over was fairly easy to do, but it erases all the data on the drives and it takes about 80 minutes.&lt;br /&gt;RAID1 is more secure than RAID0, but it is not perfectly secure. There's still a chance of losing all the data if the controller goes bad, or if the whole device is stolen or destroyed. So for extra security I will probably end up buying a second NAS (or USB 2.0 drive), and setting up an automatic backup of the backup device. The Mini can be set to perform periodic automatic backups to a second LinkStation for this very reason. Once I do that, I'll probably reformat my NAS's drives back to RAID0 to enjoy the extra storage space.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Getting Access to Linux root&lt;/h2&gt;There is a program called &lt;a href="http://buffalo.nas-central.org/index.php/Open_Stock_Firmware"&gt;acp_commander&lt;/a&gt;, that enables you to remotely log in as root on any Buffalo LinkStation Mini on the same LAN as your PC. Once logged in as root you can read and write any file on the NAS. You can use this power to install software and reconfigure your system.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Yes, this is a security hole -- it means anyone with access to your local LAN can bypass all the security on the file server.&lt;/b&gt; &lt;a href="http://buffalo.nas-central.org/forums/viewtopic.php?f=37&amp;t=6806"&gt;Very advanced users can patch the security hole by following the instructions at this web forum.&lt;/a&gt; I think it's extremely negligent of Buffalo to configure their NAS devices in this way. Imagine the uproar if Microsoft shipped a product with this kind of security hole.&lt;br /&gt;&lt;h2&gt;Playing with Linux&lt;/h2&gt;Once I obtained root access to the Mini I was able to install additional software. I installed the &lt;a href="http://www.nslu2-linux.org/wiki/MSSII/HomePage"&gt;Optware&lt;/a&gt; package system, which gives access to a wide variety of precompiled utility programs, as well as tools for writing new programs.&lt;br /&gt;(Yeah, I know, it's crazy to run software on a file server that's supposed to be backing up important data. Right now I'm just having fun playing with my new toy, but eventually I'm going to have to get serious about making it work reliably.)&lt;br /&gt;&lt;br /&gt;From looking at what other people have done, I am thinking that I might set up a small web server, or perhaps a media server for streaming music and video.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Thinking of the Future&lt;/h2&gt;There's an active LinkStation hacking community at &lt;a href="http://buffalo.nas-central.org/"&gt;buffalo.nas-central.org&lt;/a&gt;. Unfortunately the Linkstation Mini is so new that &lt;a href="http://buffalo.nas-central.org/forums/viewtopic.php?f=61&amp;t=9156"&gt;nobody in the NAS hacking community knows much about it.&lt;/a&gt; Right now it seems to be &lt;a href="http://buffalo.nas-central.org/forums/viewtopic.php?f=61&amp;t=7776"&gt;similar to a LinkStation Pro Duo&lt;/a&gt;, but only experience will show if this is true.&lt;br /&gt;The Mini comes with a USB 2.0 port, to which you can attach a printer and/or a hard disk.  While the hard disk isn't part of a RAID array, it could be used to back up the RAID array, providing an additional layer of security.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Alternatives&lt;/h2&gt;There must be 20 different NAS vendors, although many of them just repackage reference designs made by the SOC vendors. SOC mean System on Chip. Marvell seems to be the dominant player in the NAS SOC market these days. A good overview of available NAS products can be found by visiting &lt;a href="http://www.smallnetbuilder.com/component/option,com_nas/Itemid,190"&gt;Small Net Builder&lt;/a&gt;. Some brands like &lt;a href="http://www.revogear.com/"&gt;Revolution&lt;/a&gt;, &lt;a href="http://www.qnap.com/"&gt;QNAP&lt;/a&gt; and &lt;a href="http://www.synology.com/enu/products/index.php"&gt;Synology&lt;/a&gt; cater to enthusiasts who are interested in using the NAS as a mini Linux server. The only thing that stopped me from buying those brands is that (a) they're more expensive, and (b) they don't currently have fanless RAID1 form factors.&lt;br /&gt;The Revolution brand is actually owned by Buffalo. They add hardware daughter boards to standard Buffalo products. The daughter boards have extra flash chips and I/O connectors. It's possible that there will be a Revolution "Kuro box" version of the Mini some day.&lt;br /&gt;&lt;br /&gt;The venerable (out-of-production, but still available in stores) &lt;a href="http://www.nslu2-linux.org/"&gt;Linksys NSLU2&lt;/a&gt; product is fanless and cheap, and &lt;a href="http://www.nslu2-linux.org/"&gt;very popular with hackers&lt;/a&gt;, but you need to add hard drives, and I don't think its networking performace is very good compared to more recent products.&lt;br /&gt;&lt;br /&gt;Another approach is to use a PC, either running a regular OS like Windows XP, Windows Server, OSX or Linux, or a special-purpose stripped-down NAS version. I do have an old PC currently running Windows Media Center that I could use for this purpose, but I didn't seriously consider this option because I wanted something small, low-power, and quiet. (And I was looking for an excuse to learn how to administer a Linux system anyway.)&lt;br /&gt;&lt;br /&gt;Apple makes NAS products too. Their the Airport Extreme and Time Capsule products both look OK, but neither one supports RAID1. And there doesn't seem to be a software hacking community around these products. There is a software hacking community around the AppleTV, which you could make into a NAS by adding some USB 2.0 hard drives.&lt;br /&gt;&lt;br /&gt;Some routers (like the Apple Airport Extreme mentioned above) have USB 2.0 ports, but I think they avoid advertising themselves as NAS products because they don't have enough RAM (or CPU) to act as both routers and file servers. As a result, these products tend to have relatively low NAS performance.&lt;br /&gt;&lt;br /&gt;Some people would laugh at a NAS that has only 240GB of storage. They are more interested in the high-end NASes that use four or five 1GB disks. When formatted in RAID5 configuration those NASes have 3GB of usable space. But they also cost $600 plus the cost of the drive ($160 each). Which is much more than I wanted to spend. Besides the cost, another drawback is that these products are nearly as large and noisy as regular PCs. Still, if you've got a lot of video (or are anticipating generating a lot of video in the future) the larger NASs are the way to go.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;A NAS in Every Garage?&lt;/h2&gt;While all my friends and I are setting up file servers to store their family's videotapes, I'm not sure if the product will become universally popular. I think it will depend on how people's secure storage needs evolve.&lt;br /&gt;We're already seeing small files (email, photos, low-res videos) being stored in the cloud. It seems like it's just a matter of time before everything is. Unless people suddenly come up with compelling new applications that use dramatically more data (holographic TV perhaps?), it seems likely that people's personal storage needs are going to top out in the next decade. If disk capacity and network bandwidth keep growing at a rapid pace for several decades beyond that, then it seems inevitable that cloud storage will eventually take over.&lt;br /&gt;&lt;br /&gt;In any event, by the time this happens my little Mini will long since have been retired. (I remember paying $100 apiece for 1GB Jaz disks back in the day. It's amazing how far and how fast storage prices have fallen.) If all goes well, my my family's photos and other important documents will still be around!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-6799393939541804251?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/6799393939541804251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=6799393939541804251' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6799393939541804251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6799393939541804251'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/06/network-attached-storage-notes.html' title='Network Attached Storage Notes'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5024655428316931666</id><published>2008-06-07T20:14:00.001-07:00</published><updated>2008-06-07T20:43:31.811-07:00</updated><title type='text'>I saw the original Spacewar! on a PDP-1 today</title><content type='html'>I went to the &lt;a href="http://www.computerhistory.org/"&gt;Computer History Museum&lt;/a&gt; today. I saw the Visual Storage exhibit, which is a collection of famous computers, the Babbage Difference Engine, which is a very elaborate reproduction of a never-actually-built Victorian era mechanical calculator, and the PDP-1 demo. This last demo was very special to me, because I finally got to play the original &lt;a href="http://en.wikipedia.org/wiki/Spacewar%21"&gt;Spacewar!&lt;/a&gt; game, and meet and chat with  &lt;a href="http://en.wikipedia.org/wiki/Steve_Russell"&gt;Steve Russell&lt;/a&gt;, the main developer. (Perusing Wikipedia I now realize that Steve was also an early Lisp hacker. D'Oh!, I was going to ask a question about Lisp on the PDP-1, but I got distracted.)&lt;br /&gt;&lt;br /&gt;There's a &lt;a href="http://spacewar.oversigma.com/"&gt;Java Spacewar! emulator&lt;/a&gt;, but it doesn't properly convey the look of the PDP-1 radar-scope-based display. The scope displays individual dots, 20,000 times per second. Each dot starts as a fuzzy bright blue-white dot, but then fades quickly to a dim yellow-green spot, which takes another 10 seconds to fade to black. This means that dim yell0w-green trails form behind the ships as they fly around. These trails add a lot to the game's distinctive look. (In addition, due to time multi-plexing, the stars of the starfield are much dimmer than the space ships or the sun.) The fuzzyness of the dots means that the spaceships look much smoother on the PDP-1 scope than they do in the Java simulator.&lt;br /&gt;&lt;br /&gt;According to Steve Russel and the other doscents, the Java version also runs faster than a real PDP-1.&lt;br /&gt;&lt;br /&gt;I also got to see serveral other cool PDP-1 hacks, including the original Munching Squares, 4-voice square-wave computer synthezed music, and the famed Minskeytron. The author of the music synth program, &lt;a href="http://www.computerhistory.org/pdp-1/index.php?f=theme&amp;amp;s=4&amp;amp;ss=5"&gt;Peter Sampson&lt;/a&gt;, was present, and explained how he carefully patched into four of the console lights to make a four-voice D/A converter to get music out of the machine.&lt;br /&gt;&lt;br /&gt;They keep all the hacks loaded into the PDP-1 core at the same time, and just use the front panel to decide which one to jump to. The core memory is non-volitile. The PDP-1 even booted in a few seconds -- just the time it took the power supply to come up to speed.&lt;br /&gt;&lt;br /&gt;The PDP-1 demo is given twice a month, on the second and fourth Saturdays. I highly recommend it for adults and children over 12. (It's 45 minutes long, so younger kids might get bored.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5024655428316931666?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5024655428316931666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5024655428316931666' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5024655428316931666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5024655428316931666'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/06/i-saw-original-spacewar-on-pdp-1-today.html' title='I saw the original Spacewar! on a PDP-1 today'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4705010906529113372</id><published>2008-06-05T13:34:00.000-07:00</published><updated>2008-06-05T14:11:48.568-07:00</updated><title type='text'>Thoughts on In-Flight Entertainment systems</title><content type='html'>I recently spent a lot of time using two different in-flight entertainment systems: one on Eva Air, and another on Virgin Atlantic. For people who haven't flown recently, I should explain that these systems consist of a touch-sensitive TV monitor combined with a remote-control-sized controller. The systems typically offer music, TV, movies, flight status, and video games.&lt;br /&gt;&lt;br /&gt;I believe both systems were based on Linux. I saw the Eva system crash and reboot, and the Virgin Air system has a number of Linux freeware games.&lt;br /&gt;&lt;br /&gt;The GUI frameworks were pretty weak -- both systems made poor use of the touch screen and had obvious graphical polish issues. The Virgin system was much higher resolution, and was 16:9 aspect ratio. I expect it was running on slightly higher-spec hardware.&lt;br /&gt;&lt;br /&gt;Both systems worked pretty well for playing music and watching TV or movies. The media controls were pretty limited - neither system allowed seeking to a particular point in a movie, or even reliably fast forwarding. Both systems provided enough media to entertain your average customer for the duration of the flight.&lt;br /&gt;&lt;br /&gt;One cool feature of the EVA system was backwards compatibility mode with the older "channel" music system from the 70's. The controller came with the traditional "channel" UI. If you used the channel buttons, the system simply acted like the old system, cycling through a limited number of preset channels. One nice difference from the old channel system is that these new virtual channels always started when you switched to them, rather than having to join the looping presentation at whatever point it happened to be in.&lt;br /&gt;&lt;br /&gt;The game portions of both sysetems were very weak. None of the games were very good. Perhaps the best game was a port of the shareware Doom game on the Virgin Atlantic system. (I used an in-flight entertainment system on Singapore Air many years ago that had Nintendo games. It was more fun.)&lt;br /&gt;&lt;br /&gt;The Virgin system allowed you to order food and drink, which was nice. Both systems had credit card swipers, and offered some for-pay options. Both systems allowed you to make in-flight phone calls. EVA allowed you to send SMS messages and emails.&lt;br /&gt;&lt;br /&gt;Both systems allowed you to create "play lists" of music tracks that would then be played while you did other tasks. I enjoyed this, but I suspect it's not used much, as anyone with the sophistication and interest to use this UI would probably have their own MP3 player.&lt;br /&gt;&lt;br /&gt;The Virgin system had two other very nice features: 1) laptop power in most seats (although only two plugs for every three seats), and 2) Ethernet connections. Unfortunately the ethernet connections were not yet active.&lt;br /&gt;&lt;br /&gt;Virgin allowed you to "chat" between seats. I didn't try this, but it seems like it would be fun for some situations (e.g. when a high school class takes a trip.) I expect that the Doom game can play between seats as well, but didn't investigate.&lt;br /&gt;&lt;br /&gt;Virgin also had normal mini  stereo headphone plugs, which I think was a good idea. Eva had two kinds of audio plug, but neither one was the normal mini stereo plug. I tried using "Skull candy" noise-canceling headphones with the Virgin system, and while they helped suppress the airplane noise, they didn't eliminate it completely.&lt;br /&gt;&lt;br /&gt;It will be interesting to see how these systems evolve over time. I think that once in-plane internet access becomes practical people will prefer to surf the Internet to using most of the other services. (besides movie watching) And with the in-seat power, I think many people will prefer using their own laptop to the in-seat system. On the other hand, the in-seat system is very space efficient. There's a chance people will use it as a remote display for their own laptop or mobile phone, which could then remain tucked away in the carry-on luggage.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4705010906529113372?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4705010906529113372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4705010906529113372' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4705010906529113372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4705010906529113372'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/06/thoughts-on-in-flight-entertainment.html' title='Thoughts on In-Flight Entertainment systems'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5202082190151135328</id><published>2008-05-31T17:20:00.000-07:00</published><updated>2008-05-31T17:26:51.439-07:00</updated><title type='text'>Wii long term strategy</title><content type='html'>Here's a very long, quite good post on Nintendo's strategy with the Wii:&lt;br /&gt;&lt;a href="http://malstrom.50webs.com/birdman.html"&gt;&lt;br /&gt;http://malstrom.50webs.com/birdman.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The  thesis is that the mainstream video game market arms race of every-more-complicated games ended up overshooting enough of the potential game market to allow an opening for simpler "down-market" games, and that Wii was able to exploit this opening. The article predicts that Nintendo will now move up-market, producing more complicated games over time, pushing PS3 and Xbox 360 into very up-market niches. Sort of how consoles took over from PC games.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5202082190151135328?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5202082190151135328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5202082190151135328' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5202082190151135328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5202082190151135328'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/05/wii-long-term-strategy.html' title='Wii long term strategy'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-8952819946496514830</id><published>2008-05-14T00:04:00.000-07:00</published><updated>2008-05-14T00:14:02.148-07:00</updated><title type='text'>OS X will hang if your VPN connection is flakey</title><content type='html'>OS X is by and large a good OS, but once you get past the sexy UI you find a lot of rough edges.&lt;br /&gt;&lt;br /&gt;For example, this month I've been working remotely over a flakey DSL connection. I ran into a very frustrating problem: if you're using a PPTP-based VPN, and your network connection is poor quality, the whole Apple UI will frequently freeze up with the "Spinning beachball" cursor for minutes at a time.&lt;br /&gt;&lt;br /&gt;Luckily for me the work-around is to reboot my DSL modem. But it seems like poor system design for the VPN packet performance to affect the UI of non-networked applications.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-8952819946496514830?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/8952819946496514830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=8952819946496514830' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/8952819946496514830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/8952819946496514830'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/05/os-x-will-hang-if-your-vpn-connection.html' title='OS X will hang if your VPN connection is flakey'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5714617180570339141</id><published>2008-05-13T20:29:00.000-07:00</published><updated>2008-05-13T20:41:42.138-07:00</updated><title type='text'>Yegge's rant on dynamic languages</title><content type='html'>Another superb rant by Steve Yegge on dynamic languages:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://steve-yegge.blogspot.com/2008/05/dynamic-languages-strike-back.html"&gt;http://steve-yegge.blogspot.com/2008/05/dynamic-languages-strike-back.html&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;The comment section's good too -- especially the long comment by Dan Weinreb of Lisp / ITA software fame.&lt;br /&gt;&lt;br /&gt;Steve's got the same problem some of my self-taught friends do (hi Bob, hi Jim!): he'll say something in a strongly opinionated way, without giving supporting evidence. I think that makes people think he doesn't know what he's talking about. So people tend to write him off. But if you talk with him, it almost always turns out his strong opinions are backed by some pretty deep experience and insight. I've learned to give Steve (and my self-taught friends) the benefit of the doubt.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5714617180570339141?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5714617180570339141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5714617180570339141' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5714617180570339141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5714617180570339141'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/05/yegges-rant-on-dynamic-languages.html' title='Yegge&apos;s rant on dynamic languages'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-1879018508139861526</id><published>2008-04-18T09:53:00.001-07:00</published><updated>2008-04-18T10:00:11.431-07:00</updated><title type='text'>Wow, TVs are complicated</title><content type='html'>Check out this &lt;a href="http://www.bunniestudios.com/blog/?p=243"&gt;teardown of a Sony OLED TV&lt;/a&gt;. It looks like Sony has a standardized architecture for their TVs, which makes sense, but which also means that some TVs have unused capabilities (such as a multi-core CPU powerful enough to run a web browser. I wish an enterprising hacker would  figure out how to download code and run them on the TVs -- my understanding from reading Sony's GPL web site is that they already have Linux and busybox installed. Oh well, maybe GPL 3.0 will force Sony to make their TVs user-upgradable in the future.&lt;br /&gt;&lt;br /&gt;It's significant that Sony's not using the Cell CPU in their TVs. That was part of the justification for spending so much on Cell. I assume this means that Cell's just not cost-effective for TVs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-1879018508139861526?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/1879018508139861526/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=1879018508139861526' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1879018508139861526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1879018508139861526'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/04/wow-tvs-are-complicated.html' title='Wow, TVs are complicated'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5347946540729967230</id><published>2008-04-18T09:49:00.000-07:00</published><updated>2008-04-18T09:53:11.926-07:00</updated><title type='text'>Tom Forsyth on Larrabee</title><content type='html'>Tom Forsyth, who recently left RAD to work at Intel on the Larrabee project, has posted to his tech blog explaining that Larrabee is going to be primarily a traditional OpenGL/DirectX rasterizer, not some crazy raytracer:&lt;br /&gt;&lt;a href="http://home.comcast.net/%7Etom_forsyth/blog.wiki.html#%5B%5BLarrabee%20and%20raytracing%5D%5D"&gt;Larrabee and Raytracing&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5347946540729967230?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5347946540729967230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5347946540729967230' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5347946540729967230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5347946540729967230'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/04/tom-forsyth-on-larrabee.html' title='Tom Forsyth on Larrabee'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-9192751587468882551</id><published>2008-04-06T10:56:00.000-07:00</published><updated>2008-04-06T11:00:03.310-07:00</updated><title type='text'>Dusty Decks</title><content type='html'>Back in the '90s I had a home page where I posted some of my code hacks and articles. If you want to see what I was doing 10 years ago, check out:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jack.palevich.googlepages.com/home"&gt;Jack's Hacks&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(Mostly Java and Anime. Both of which were leading-edge back then, but are kind of main-stream now.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-9192751587468882551?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/9192751587468882551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=9192751587468882551' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/9192751587468882551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/9192751587468882551'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/04/dusty-decks.html' title='Dusty Decks'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5786739858981707540</id><published>2008-03-30T00:23:00.000-07:00</published><updated>2008-03-30T00:50:49.900-07:00</updated><title type='text'>ThinLisp</title><content type='html'>Some notes on ThinLisp, a dialect of Lisp for real-time systems. Thin Lisp was written by Gensym Corporation in the '90s. The general idea is that you develop your program using a subset of Common Lisp, and then compile it into efficient C. Garbage collection is avoided by using object pools, arenas, and similar tricks familiar to advanced C programmers.&lt;br /&gt;&lt;br /&gt;The current home of ThinLisp seems to be &lt;a href="http://vsedach.googlepages.com/code.html"&gt;Vladimir Sedach's Code Page&lt;/a&gt; . Vladimir seems to have used it for "one small OpenGL" project before abandoning it. He seems to be happily hacking &lt;a href="http://common-lisp.net/project/parenscript/"&gt;ParenScript&lt;/a&gt; (a Lisp to Javascript translator) these days.&lt;br /&gt;&lt;br /&gt;The Scheme guys have similar, but more modest, sysems: &lt;a href="http://www-swiss.ai.mit.edu/%7Ejaffer/Docupage/schlep.html"&gt;Schelp&lt;/a&gt;, and PreScheme (part of &lt;a href="http://s48.org/"&gt;Scheme48&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5786739858981707540?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5786739858981707540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5786739858981707540' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5786739858981707540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5786739858981707540'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/03/thinlisp.html' title='ThinLisp'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-7848323874743062099</id><published>2008-03-26T08:10:00.000-07:00</published><updated>2008-03-26T08:49:56.199-07:00</updated><title type='text'>One year at Google!</title><content type='html'>Happy Anniversary to me! Google's automated HR script just emailed me its congratulations.&lt;br /&gt;&lt;br /&gt;Although I miss my friends and former colleagues at Microsoft, and I miss the games industry, overall I'm still glad I made the switch. I'm enjoying the new work, and learning all the cool Google technologies. Now if only the stock price didn't keep going down. :-)&lt;br /&gt;&lt;br /&gt;Some things I like:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Switching from Window to Macintosh. It took me six months to get used to the subtle differences, but as a user I'm just happier with the Mac. It's easier for me to use. Now, to be fair, at home I still maintain a Windows Vista machine for the excellent Windows Media Center, but for everything else I use the Mac.&lt;/li&gt;&lt;li&gt;Better corporate politics. There seems to be less infighting between groups. And while my overall compensation is about the same as it was at Microsoft, the way it's managed and delivered makes it seem less competitive than MS. Perhaps it's an illusion, but it feels better.&lt;/li&gt;&lt;li&gt;Better equipment. I love using a 30" LCD monitor and a high-end laptop, and I love the "we'll just give it to you" technical support. At MS sometimes I felt that I had to fight to justify minor hardware purchases.&lt;/li&gt;&lt;li&gt;Fancier food in the cafeterias. I usually eat lunch and diner at work, so the tasty and relatively healthy food is much appreciated. Interestingly enough, I think Google Seattle uses the same food caterer as Microsoft does. I guess we just asked them to cook different food.&lt;/li&gt;&lt;li&gt;More connected to the Web / Valley culture. Microsoft's pretty insular. It was good to get closer to the Silicon Valley culture again.&lt;/li&gt;&lt;li&gt;Able to use open-source projects. Sometimes the open-source projects are the best way of doing something. But Microsoft's not able to use it, due to a combination of pride, loyalty to its own products, and fear of viral licenses. For example, using Linux for embedded devices is &lt;span style="font-style: italic;"&gt;much&lt;/span&gt; better than Windows CE. I also find I liked using non-Microsoft technologies like Java, Python and Ruby.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Since you may be wondering, what do I miss from Microsoft?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I miss the Xbox project. Right now my old team is probably starting to plan the next generation of Xbox, and it would have been a blast to have been a part of that process.&lt;/li&gt;&lt;li&gt;I miss the free game betas, and using beta software in general. (I'm a sucker for new features!)&lt;/li&gt;&lt;li&gt;I miss some of the Microsoft-specific technologies like C# (still better than Java), Visual Studio (still better than Eclipse), and F#.&lt;/li&gt;&lt;li&gt;Surprisingly, I don't miss my old single-person office very much. It's true that a group office is distracting. But it's also helpful for sharing ideas and for keeping focused on the project.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Well, that's it, better get back to work!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-7848323874743062099?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/7848323874743062099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=7848323874743062099' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7848323874743062099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7848323874743062099'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/03/one-year-at-google.html' title='One year at Google!'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-6991936716513895483</id><published>2008-03-18T09:44:00.000-07:00</published><updated>2008-03-18T10:13:43.914-07:00</updated><title type='text'>Insomniac Games Shares Technology</title><content type='html'>One very nice habit of Western game companies is that many of them share their technical knowledge with competitors. Insomniac Games is a very good third party console game developer that has concentrated mostly on the PlayStation platform.   Their recent games include the shooter "Resistance Fall of Man" and the action platform Rachet and Clank series.&lt;br /&gt;&lt;br /&gt;At this year's GDC they announced the "&lt;a href="http://nocturnal.insomniacgames.com/"&gt;Nocturnal&lt;/a&gt;" initiative. It's not a whole game engine, but rather a collection of useful utilities. Things like logging code, C++ object serialization, and a cross-platform performance monitor. Some of the utilities are Playstation 3 specific, but most are applicable to any modern game platform.&lt;br /&gt;&lt;br /&gt;Much of this code would be right at home in a "Game Gems" book, but it's even better to have it freely available, on the web, with a BSD-style license. Good for you Insomniac!&lt;br /&gt;&lt;br /&gt;Insomniac also publishes technical papers in a GDC-presentation-like format on their &lt;a href="http://www.insomniacgames.com/tech/techpage.php"&gt;Game R &amp;amp; D Page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Why do so many game companies share information like this? I think it's for a number of mutually supportive reasons:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;It's a form of advertising, to show off how smart and competent the developers are. This is helpful in attracting job applicants and impressing publishers and game reviewers.&lt;/li&gt;&lt;li&gt;It educates all game developers, some of whom will eventually end up working for the original developer.&lt;/li&gt;&lt;li&gt;It encourages other developers to share their technology, which benefits the original game developers.&lt;/li&gt;&lt;li&gt;It reduces the value of middleware, driving down the cost of middleware.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Game developers can give away source code because, unlike other kinds of software, the major intellectual property in the game is in the copyrighted and trademarked art assets, (the data) rather than in the code. Yet, at the same time, game quality is directly tied to the performance of the code. This creates a unique economy in which it is profitable for game developers to exchange performance tips with their competitors.&lt;br /&gt;&lt;br /&gt;And it's a lot of fun for armchair developers like me. Now if only we can get Naughty Dog to open-source their GOOL and GOAL Lisp-based game engines. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-6991936716513895483?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/6991936716513895483/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=6991936716513895483' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6991936716513895483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6991936716513895483'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/03/insomniac-games-shares-technology.html' title='Insomniac Games Shares Technology'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-7001126202449766355</id><published>2008-03-15T22:08:00.000-07:00</published><updated>2008-03-15T22:16:28.614-07:00</updated><title type='text'>TaxCut 2007 vs. Case-sensitive file systems</title><content type='html'>OS X allows you to format your file system as case-insensitive (the default) or case sensitive (like Linux.) I use case-sensitive, to simplify porting and working on Linux software.&lt;br /&gt;&lt;br /&gt;Unfortunately, H&amp;amp;R Block's TaxCut 2008 program won't work if installed on a case-sensitive file system. It fails because it can't find files, probably due to differences between the case of the file name used by the programmer and the actual case of the file name on disk.&lt;br /&gt;&lt;br /&gt;A work-around is to use the Disk Utility program to create a case-insensitive image, and install Tax Cut on the image. I used a 600 MB image, so that I can store all my tax forms there too, and eventually burn the whole thing to CD to archive it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-7001126202449766355?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/7001126202449766355/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=7001126202449766355' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7001126202449766355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7001126202449766355'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/03/taxcut-2007-vs-case-sensitive-file.html' title='TaxCut 2007 vs. Case-sensitive file systems'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-6660202068128114565</id><published>2008-03-15T22:03:00.000-07:00</published><updated>2008-03-15T22:07:31.949-07:00</updated><title type='text'>Tim Sweeney Too - DX 10 last relevant graphics API</title><content type='html'>A good, three-part interview with Tim Sweeney (the other FPS graphics guru):&lt;br /&gt;&lt;br /&gt;Part 1: http://www.tgdaily.com/content/view/36390/118/&lt;br /&gt;Part 2: http://www.tgdaily.com/content/view/36410/118/&lt;br /&gt;Part 3: http://www.tgdaily.com/content/view/36436/118/&lt;br /&gt;&lt;br /&gt;His main thesis is that soon GPUs will be come so programmable that you won't bother using a standard Graphics API to program them. You'll just fire up a C compiler.&lt;br /&gt;&lt;br /&gt;I think he's right.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-6660202068128114565?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/6660202068128114565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=6660202068128114565' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6660202068128114565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/6660202068128114565'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/03/tim-sweeney-too-dx-10-last-relevant.html' title='Tim Sweeney Too - DX 10 last relevant graphics API'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-5769929368207972525</id><published>2008-03-12T15:53:00.000-07:00</published><updated>2008-03-12T16:06:07.080-07:00</updated><title type='text'>Carmack speaks on real next-gen graphics</title><content type='html'>John Carmack is experimenting with a "sparse octree" data structure for accelerating 3D graphics rendering:&lt;br /&gt;&lt;br /&gt;http://www.pcper.com/article.php?aid=532&amp;amp;type=overview&lt;br /&gt;&lt;br /&gt;Best quote:&lt;br /&gt;&lt;br /&gt;"The direction that everybody is looking at for next generation, both console and eventual graphics card stuff, is a "sea of processors" model, typified by Larrabee or enhanced CUDA and things like that, and everybody is sort of waving their hands and talking about “oh we’ll do wonderful things with all this” but there is &lt;span style="font-weight: bold;"&gt;very little in the way of real proof-of-concept work &lt;/span&gt;going on.  There’s no one showing the demo of like, here this is what games are going to look like on the next generation when we have 10x more processing power - nothing compelling has actually been demonstrated and &lt;span style="font-weight: bold;"&gt;everyone is busy making these multi-billion dollar decision&lt;/span&gt;s about what things are going to be like 5 years from now in the gaming world.  I have a direction in mind with this but until everybody can actually make movies of what this is going to be like at subscale speeds, &lt;span&gt;it’s distressing to me that there is so much effort going on&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; without anybody showing exactly what the prize is that all of this is going to give us.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;Second-best quote is that he wants lots of bit-twiddling operations-per-second to traverse the data structures rather than lots of floating-point-operations-per-second. Must be scary for the Larrabee and NVIDIA CPU architects to hear that, this late in their design cycles.&lt;br /&gt;&lt;br /&gt;Hopefully John will come up with a cool demo that helps everyone understand whether his approach is a good one or not. Hopefully the Larrabee / NVIDIA architectures are flexible enough to cope. (Interestingly, no mention of ATI -- have they bowed out of the high-end graphics race?)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-5769929368207972525?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/5769929368207972525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=5769929368207972525' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5769929368207972525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/5769929368207972525'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/03/carmack-speaks-on-real-next-gen.html' title='Carmack speaks on real next-gen graphics'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4843057197003861406</id><published>2008-03-09T10:46:00.000-07:00</published><updated>2008-03-09T10:52:40.350-07:00</updated><title type='text'>ForumWarz - a game about the web forum culture</title><content type='html'>This is an interesting role-playing-game set in current-day web forum culture:&lt;br /&gt;&lt;br /&gt; http://www.forumwarz.com/&lt;br /&gt;&lt;br /&gt;It's somewhat not-safe-for-work, and the humor is pretty low-brow. But what's neat is that you play it through your browser, and it recreates the look-and-feel of web forum culture perfectly. It wouldn't surprise me if the authors just captured the HTML for various real-world forums to create the resources for the game. (Or alternately, created their own fictional forums using web tools, and then captured the HTML from those fictional forums.)&lt;br /&gt;&lt;br /&gt;The actual game didn't hold my interest for very long, but it's free and it's fun for a few days.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4843057197003861406?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4843057197003861406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4843057197003861406' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4843057197003861406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4843057197003861406'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/03/forumwarz-game-about-web-forum-culture.html' title='ForumWarz - a game about the web forum culture'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-2245610635339107084</id><published>2008-02-21T08:44:00.000-08:00</published><updated>2008-02-21T09:11:02.688-08:00</updated><title type='text'>Good web site for following the Microsoft / Yahoo Merger</title><content type='html'>&lt;a href="http://www.alleyinsider.com/microsoft-yahoo/"&gt;Silicon Alley Insider&lt;/a&gt; seems to have the best coverage of the Microsoft / Yahoo Merger.&lt;br /&gt;&lt;br /&gt;But for the grumpy inside-Microsoft point-of-view you can't beat&lt;span style="text-decoration: underline;"&gt; &lt;/span&gt;&lt;a href="http://minimsft.blogspot.com/"&gt;Mini-Microsoft&lt;/a&gt; .&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-2245610635339107084?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/2245610635339107084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=2245610635339107084' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2245610635339107084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2245610635339107084'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/02/good-web-site-for-following-microsoft.html' title='Good web site for following the Microsoft / Yahoo Merger'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-1314504601479115935</id><published>2008-02-21T06:38:00.000-08:00</published><updated>2008-02-21T07:20:02.752-08:00</updated><title type='text'>We write for posterity</title><content type='html'>The Google Analytics numbers for this blog are dismal.  (Hi Mom! Hi Friends!) I think it's because right now I don't have much to say that's both unique and interesting. Partly this is because so much of my life is off limits: I don't want to talk about the joys &amp;amp; cares of raising a family, and I musn't talk about the joys &amp;amp; cares of raising a new product. What's left are comments on the general state of the web, and essays on general topics like this one.&lt;br /&gt;&lt;br /&gt;Why write then, and who am I writing for? I write because something inside me compells me to, and because it helps me think to get my ideas down in written form. Who do I write for? From my Analytics numbers it's clear that I'm  writing primarily for  search engines (Hi Googlebot!) rather than people. And that's something interesting to think about: Baring a world-wide disaster or cultural revoloution, what I write today will persist for thousands and probably even millions of years, and will be read countless times by search engines, and only occasionally, if at all, by people.&lt;br /&gt;&lt;br /&gt;My words will be torn apart and merged with other web pages from other authors, becoming a mulch out of which new insights will be gleaned. (Hmm, not unlike how my body will be recyled when I die, its atoms used to make new things.)&lt;br /&gt;&lt;br /&gt;Perhaps the last time my essay will ever be read by a live human is in some far distant future when some graduate student is writing an essay on early-web-era civilization, and is trying to find out what those poor benighted souls thought of the future. (Hi posterity!)&lt;br /&gt;&lt;br /&gt;No doubt my words will be automatically translated from 21st-century English into whatever language wins the world-wide language wars. Perhaps my essay will even be automatically annotated, with a description of who I was, and a best guess at what I looked like, from searching the world's photo archives. There will be footnotes and links to explain the archaic topics I'm referencing. "Search engine" - they used to store data in seperate computers, and brute-force building the search index. How primitive! How quaint!&lt;br /&gt;&lt;br /&gt;And no doubt the grad-student-of-the-future will glance over my words, then move on to the hundreds of other essays on similar themes. (Good luck with your own essay, future-guy!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-1314504601479115935?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/1314504601479115935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=1314504601479115935' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1314504601479115935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1314504601479115935'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/02/we-write-for-posterity.html' title='We write for posterity'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4831198834462051755</id><published>2008-01-29T19:24:00.000-08:00</published><updated>2008-01-29T19:34:42.736-08:00</updated><title type='text'>Hey, Paul Graham's arc programming language is out!</title><content type='html'>I just noticed (while reading the 4chan prog forum for the first time) that Paul Graham has put up a web site for his minimal Lisp language Arc:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://arclanguage.org/"&gt;http://arclanguage.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The language looks like a nice quiet Scheme-like Lisp dialect. And it has &lt;a href="http://ycombinator.com/arc/tut.txt"&gt;a nice tutorial&lt;/a&gt;, as you would expect from a Paul Graham language.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4831198834462051755?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4831198834462051755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4831198834462051755' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4831198834462051755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4831198834462051755'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/01/hey-paul-grahams-arc-programming.html' title='Hey, Paul Graham&apos;s arc programming language is out!'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-446082999446417726</id><published>2008-01-25T18:54:00.000-08:00</published><updated>2008-01-25T19:21:09.266-08:00</updated><title type='text'>3dMark price/performance charts</title><content type='html'>3DMark is a GPU/CPU benchmark used by PC gamers to measure system performance. Here are some great charts showing&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.yougamers.com/hardware/stats/3dmark06/alltime/"&gt;What GPU/CPU/RAM/OS/Screen size gamers have, and how it's changed over time&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.yougamers.com/hardware/stats/3dmark06/priceandperformance/"&gt;The best bang-per-buck for GPUs and CPUs&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;My home computer system is very weak compared to these charts, except in one dimension, which is that my 1600 x 1200 display puts me in the top 10% of gamers. Woot!&lt;br /&gt;&lt;br /&gt;While many people (myself included) have switched to laptops and/or all-in-ones, if you're planning on building a new desktop, check out the &lt;a href="http://arstechnica.com/guides/buyer/guide-200801.ars"&gt;Ars Technica&lt;/a&gt;&lt;a href="http://arstechnica.com/guides/buyer/guide-200801.ars"&gt; system guide&lt;/a&gt;. The guide does a good job of speccing out a "Budget Box", a "Hot Rod", and a "God Box", and it's updated every quarter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-446082999446417726?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/446082999446417726/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=446082999446417726' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/446082999446417726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/446082999446417726'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/01/3dmark-priceperformance-charts.html' title='3dMark price/performance charts'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4253026559027851305</id><published>2008-01-24T21:36:00.000-08:00</published><updated>2008-01-24T21:43:47.269-08:00</updated><title type='text'>Languages that look interesting</title><content type='html'>Currently I'm reading up on the following computer languages:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://python.org/"&gt;Python&lt;/a&gt; - fun, easy to learn, batteries included&lt;br /&gt;&lt;a href="http://boo.codehaus.org/"&gt;Boo&lt;/a&gt; - fun like Python, but with macros and type declarations so that it can run fast.&lt;br /&gt; &lt;a href="http://www.erlang.org/"&gt;Erlang&lt;/a&gt; - very brief code. I'm impressed by how concise the Wings3D source code is.&lt;br /&gt;&lt;a href="http://www.ccs.neu.edu/home/samth/typed-scheme/"&gt;Typed Scheme&lt;/a&gt; - Scheme with type checking. (Could in theory run fast.)&lt;br /&gt;&lt;br /&gt;I may try implementing my old "Dandy" game in these languages to see how they feel.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4253026559027851305?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4253026559027851305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4253026559027851305' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4253026559027851305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4253026559027851305'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/01/languages-that-look-interesting.html' title='Languages that look interesting'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-1581618609127437597</id><published>2008-01-24T21:25:00.000-08:00</published><updated>2008-01-24T21:35:55.237-08:00</updated><title type='text'>Darwin Ports issue with "patch"</title><content type='html'>Ever since I've upgraded to Apple Macintosh OS X 10.5 Leopard, I've run into problems using the Darwinports "port" command to install new software.&lt;br /&gt;&lt;br /&gt;The problem is that for some reason the version of GNU "patch" that I have installed in /usr/bin/patch is version 2.5.8, and it doesn't operate the way that Darwin ports expects. A typical error message is:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;---&gt;  Applying patches to erlang&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Error: Target org.macports.patch returned: shell command " cd "/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_lang_erlang/work/erlang-R12B-0" &amp;amp;&amp;amp; patch -p0 &lt; '/opt/local/var/macports/sources/rsync.macports.org/release/ports/lang/erlang/files/patch-toolbar.erl'" returned error 2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Command output: Get file lib/toolbar/src/toolbar.erl from Perforce with lock? [y] &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Perforce client error:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    Connect to server failed; check $P4PORT.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    TCP connect to perforce failed.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    perforce: host unknown.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;patch: **** Can't get file lib/toolbar/src/toolbar.erl from Perforce&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Error: Status 1 encountered during processing.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The work-around is to define the environment variable POSIXLY_CORRECT=1 , as in:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;POSIXLY_CORRECT=1 sudo port install erlang&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now, I've done some web searching, and I haven't seen anyone else complaining about this problem, so perhaps there's something odd about my setup.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-1581618609127437597?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/1581618609127437597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=1581618609127437597' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1581618609127437597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1581618609127437597'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/01/darwin-ports-issue-with-patch.html' title='Darwin Ports issue with &quot;patch&quot;'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-1080688812261989281</id><published>2008-01-07T06:13:00.001-08:00</published><updated>2008-01-20T02:20:08.664-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Web scraping in Java, F#, Python, and not Lisp</title><content type='html'>Yesterday I wrote a web scraper. A web scraper is a program that crawls over a set of web pages, following links and collecting data. Another name for this kind of program is a "spider", because it "crawls" the web.&lt;br /&gt;&lt;br /&gt;In the past I've written scrapers in &lt;a href="http://www.java.com/en/"&gt;Java&lt;/a&gt; and &lt;a href="http://research.microsoft.com/fsharp/fsharp.aspx"&gt;F#&lt;/a&gt;, with good results. But yesterday, when I wanted to write a new scraper, I though I'd try using a dynamically-typed language instead.&lt;br /&gt;&lt;br /&gt;What's a dynamically-typed language you ask? Well, computer languages can generally be divided into two camps, depending on whether they make you declare the type of data that can be stored in a variable or not. Declaring the type up front can make the program run faster, but it's more work for the developer.  Java and F#, the languages I previously used to write a web scraper, are statically typed languages, although F# uses type inference so you don't actually have to declare types very often -- the computer figures it out for you.&lt;br /&gt;&lt;br /&gt;In order to scrape HTML you need three things:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;a language&lt;/li&gt;&lt;li&gt;a library that fetches HTTP pages&lt;/li&gt;&lt;li&gt;a library that parses the HTML into a tree of HTML tags&lt;/li&gt;&lt;/ol&gt;Unless you're using Mono or Microsoft's Common Language Runtime, the language you choose will restrict the libraries that you can use.&lt;br /&gt;&lt;br /&gt;So, the first thing I needed to do was choose a dynamic language.&lt;br /&gt;&lt;br /&gt;Since I just finished reading "&lt;a href="http://www.gigamonkeys.com/book/"&gt;Practical Common Lisp&lt;/a&gt;", an excellent advanced tutorial on the Lisp language, I though I'd try using Lisp. But that didn't work out very well at all. Lisp has neither a standard implementation nor a set of standard libraries for downloading web pages and parsing HTML. I did some Googling to try and find some combination of parts that would work for me. Unfortunately, it seemed that every web page I visited recommended a different combination of libraries, and none of the combinations I tried worked for me. In the end I just gave up in frustration.&lt;br /&gt;&lt;br /&gt;Then, I turned to &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt;. I had not used Python much, but I knew it had a reputation as an easy-to-use language with a lot of easy-to-use libraries. And you know what? It really was easy! I did some web searches, copied some example code, and voila, I had a working web spider in about an hour. And the program was easy to write every step of the way. I used the standard CPython implementation for the language, Python's built-in urllib2 library to fetch the web data, and the &lt;a href="http://www.crummy.com/software/BeautifulSoup/"&gt;Beautiful Soup&lt;/a&gt; library for parsing the HTML.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How does the Python compare to Java and F# for web scraping?&lt;br /&gt;&lt;br /&gt;Python Benefits:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Very brief, easy to write code&lt;/li&gt;&lt;li&gt;Libraries built in or easy to find&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Lots of web examples&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I didn't have to think: I just used for loops and subroutine calls.&lt;/li&gt;&lt;li&gt;Very fast turn-around.&lt;/li&gt;&lt;li&gt;Easy to create and iterate over lists of strings.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Python non-issues for this application:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Didn't matter that the language was slow, because this task is totally I/O bound.&lt;/li&gt;&lt;li&gt;Didn't matter that the IDE is poor, using print and developing interactively was fine&lt;/li&gt;&lt;/ul&gt;F# Benefits:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Good IDE (Visual Studio)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Both URL fetching and HTML parsing libraries built in to CLR&lt;/li&gt;&lt;/ul&gt;F# Non-issues:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Small community, few examples. (A non-issue because there is &lt;a href="http://cs.hubfs.net/forums/thread/94.aspx"&gt;an example of how to write a multi-threaded web scraper&lt;/a&gt;!)&lt;/li&gt;&lt;/ul&gt;F# Drawbacks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The CLR libraries for URL fetching and HTML parsing are more difficult to use than Python. It takes more steps to complete similar operations.&lt;/li&gt;&lt;li&gt;Strong typing gets in the way of writing simple code.&lt;/li&gt;&lt;li&gt;odd language syntax compared to Algol-derived languages.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Hard-to-understand error messages from the compiler.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Mixed functional/imperative programming is more complicated than just imperative programing.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The language and library encourages you to use advanced concepts to do simple things. In my web scraper I wrote a lot of classes and had methods that took  complicated curried functions as arguments. This made the code hard to debug. In retrospect perhaps I should have just used lists of strings, the same as I did in Python. Since F# supports lists of strings pretty well, maybe this is my problem rather than F#'s. ;-)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Java benefits:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Good debugger&lt;/li&gt;&lt;li&gt;Good libraries&lt;/li&gt;&lt;li&gt;Multithreading&lt;/li&gt;&lt;/ul&gt;Java drawbacks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Very wordy language&lt;/li&gt;&lt;li&gt;Very wordy libraries&lt;/li&gt;&lt;/ul&gt;Lisp drawbacks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No standard implementation&lt;/li&gt;&lt;li&gt;No standard libraries&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Looking to the future, I'd be interested in writing a web scraper in IronPython, which has good IDE support, and in C# 3.0, which has some support for type inference.&lt;br /&gt;&lt;br /&gt;In any event, I'm left with a very favorable impression of Python, and plan to look into it some more. In the past I was put off from it because it was slow, but now I see how useful it is when speed doesn't matter.&lt;br /&gt;&lt;br /&gt;[Note: When I first wrote this article I was under the impression that CPython didn't support threads. I since discovered (by reading the Python in a Nutshell book) that it does support threads. Once I knew this, I was able to easily add multi-threading to the web scraper. CPython's threads are somewhat limited: only one thread is allowed to run Python code at a time. But that's fine for this application, where the multiple threads spend most of their time blocked waiting for C-based network I/O. ]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-1080688812261989281?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/1080688812261989281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=1080688812261989281' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1080688812261989281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1080688812261989281'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2008/01/web-scraping-in-java-f-python-and-not.html' title='Web scraping in Java, F#, Python, and not Lisp'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-2968522608994975982</id><published>2007-12-29T10:32:00.000-08:00</published><updated>2007-12-29T11:04:12.984-08:00</updated><title type='text'>Hot Chips Conference archives</title><content type='html'>Curious about the internal designs of GPUs, CPUs, and game consoles? Tired of lame articles full of uninformed speculation and fanboy rants? Then check out the archives of the "&lt;a href="http://www.hotchips.org/archives/"&gt;Hot Chips&lt;/a&gt;" conference, an annual conference where computer chip designers get together to brag about their latest chips. The conference presentation slides are all online, and they're full of good technical information on GPUs, CPUs. and even game consoles. Of course, presenters often gloss over any technical problems with their chips, so you won't get the full picture. But these presentations offer a detailed technical look inside otherwise secret system architectures.&lt;br /&gt;&lt;br /&gt;(For what it's worth the web site is poorly organized, and many links are broken -- you sometimes have to edit the URLs slightly to find the correct links.)&lt;br /&gt;&lt;br /&gt;Some highlights:&lt;br /&gt;&lt;a href="http://www.hotchips.org/archives/hc9/3_Tue/HC9.S10/HC9.10.2.pdf"&gt;&lt;br /&gt;Reality Co-Processor, Ken Hayes (Silicon Graphics, Inc.)&lt;/a&gt; - All about the Nintendo 64.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/www.hotchips.org/archives/hc13/2_Mon/06ibm-gekko.pdf"&gt;Gekko: A PowerPC compatible processor supporting high-performance 3D Graphics&lt;/a&gt; - Gamecube CPU&lt;br /&gt;&lt;a href="http://www.hotchips.org/archives/hc17/index.htm"&gt;&lt;br /&gt;Multiple Cell Papers (PS3)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.hotchips.org/archives/hc17/3_Tue/HC17.S8/HC17.S8T4.pdf"&gt;Xbox 360 System Architecture&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-2968522608994975982?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/2968522608994975982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=2968522608994975982' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2968522608994975982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2968522608994975982'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/12/hot-chips-conference-archives.html' title='Hot Chips Conference archives'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-8992669513706114778</id><published>2007-12-29T10:10:00.000-08:00</published><updated>2007-12-29T10:32:06.025-08:00</updated><title type='text'>Nintendo Wii security defeated by the Tweezer Attack</title><content type='html'>According to a presentation at the &lt;a href="http://events.ccc.de/congress/2007/Fahrplan/track/Hacking/2279.en.html"&gt;24th Chaos Communication Congress&lt;/a&gt;, hackers have apparently been able to defeat the Nintendo Wii game console's security system using tweezers to bypass the hardware memory protection.&lt;br /&gt;&lt;br /&gt;The way it works is that the Wii runs in two modes: a GameCube emulation mode, which has access to just 1/8th of the total memory, and Wii mode, that has access to all the memory.&lt;br /&gt;&lt;br /&gt;Hackers had already figured out how to run their own code in GameCube mode. So the trick was to run their code in GameCube mode, then use the tweezers to short out the address lines to allow the hacker's code to access parts of rest of the memory. By shorting different address lines different portions of memory were made available. By collecting enough shards they eventually mapped all of memory.&lt;br /&gt;&lt;br /&gt;Apparently the Wii operating system keeps its digital signature keys in this protected memory, and once the digital signatures were found it was possible to sign and run homebrew code on the Wii.&lt;br /&gt;&lt;br /&gt;It is not clear to me whether the attack is a per-machine attack or a break-once-run-everywhere attack.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-8992669513706114778?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/8992669513706114778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=8992669513706114778' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/8992669513706114778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/8992669513706114778'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/12/nintendo-wii-security-defeated-by.html' title='Nintendo Wii security defeated by the Tweezer Attack'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-1690345734275356046</id><published>2007-12-29T09:28:00.000-08:00</published><updated>2007-12-31T05:11:46.782-08:00</updated><title type='text'>Searching for old web pages: The Wayback machine is cool!</title><content type='html'>I was searching for information on LINJ, a Lisp language that compiles into human-readable Java code. Unfortunately, the LINJ web site http://www.evaluator.pt/linj.html, is currently offline.&lt;br /&gt;&lt;br /&gt;Luckily, it turned out that the Internet Archive &lt;a href="http://www.archive.org/web/web.php"&gt;Wayback machine&lt;/a&gt; had cached both that page, and the download files that that page had pointed to. Very cool!&lt;br /&gt;&lt;br /&gt;Similarly, I was looking for the source to the Windows CE port of Quake 3, and found that the project's web site http://www.noctemware.com/q3ce.html had been abandoned and taken over by spammers. Luckily the Wayback machine had cached both the original web page and the downloads.&lt;br /&gt;&lt;br /&gt;Let this be a lesson to you aspiring open source developers out there: It's better to store small open-source projects in a large "won't-ever-go-away" source repository like &lt;a href="http://www.sourceforge.net/"&gt;SourceForge&lt;/a&gt; or &lt;a href="http://code.google.com/"&gt;Google Code&lt;/a&gt; than to use your own vanity domain hosting. Of course, even using a large popular repository is not failure-proof. Some large code repositories from the early days of the Internet, like DEC's ftp site, have gone away after their owning company was bought by another company. Perhaps some sort of distributed system of discoverable git repositories is the answer.&lt;br /&gt;&lt;br /&gt;In the case of Quake 3 for Windows CE, I've contacted the author, Christien Rioux, and with his kind permission I've set up a code.google.com project so that other people can more easily find the sources (and binaries): &lt;a href="http://code.google.com/p/q3ce"&gt;http://code.google.com/p/q3ce&lt;/a&gt; .&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-1690345734275356046?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/1690345734275356046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=1690345734275356046' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1690345734275356046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1690345734275356046'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/12/wayback-machine-is-cool.html' title='Searching for old web pages: The Wayback machine is cool!'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-579297387757401021</id><published>2007-12-27T19:51:00.000-08:00</published><updated>2007-12-27T20:13:48.000-08:00</updated><title type='text'>Why the Farmers won</title><content type='html'>I've been thinking about Lisp lately. A powerful language, with many excellent features, but not hugely successful. And I thought of one reason why:&lt;br /&gt;&lt;br /&gt;The excellent book Guns, Germs and Steel hypothesizes that agriculture displaced hunting and gathering  because  people who practiced  agriculture stayed in one place, and were able to have one child per year, as opposed to the hunter-gatherers, who had to wait until their children were old enough to walk before having another child. This reproductive rate difference was amplified by the ability for a given unit of land to support more farmers than hunters. As a result, agriculture displaced hunting even though individual hunters were far healthier (as seen by their skeleton height) than the farmers that displaced them.&lt;br /&gt;&lt;br /&gt;So it is possible for a poorer technology to displace a better one, if it has compensating advantages. And I think that's what's hit Lisp. C  and Java, which are each less powerful and more wordy than Lisp, are more successful for reasons other than power and brevity. Perhaps because both languages allow lots of reusable code to be written by ordinary programmers. Maybe Lispers are like healthy hunters, being displaced by hordes of sickly farmers.&lt;br /&gt;&lt;br /&gt;Well, no doubt the Lispers will take some comfort in the Java and C programmers being displaced in turn by whatever language next becomes even more successful, just as hunter-gatherers may take pleasure in the trend that farmers are gradually being displaced by urban dwellers. (Come to think of it, Lispers have already seen their original competitor Fortran displaced by C/C++, and in turn much of C++ has been displaced by Java and C#.)&lt;br /&gt;&lt;br /&gt;I think something similar is happening in productivity applications, as a generation of not-very-good-but-web-based productivity applications is displacing the Microsoft Office suite. (For example, I am typing this blog entry into a simple and ugly HTML-based web form rather than a beautiful Word document.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-579297387757401021?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/579297387757401021/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=579297387757401021' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/579297387757401021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/579297387757401021'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/12/why-farmers-won.html' title='Why the Farmers won'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-2406860634276646325</id><published>2007-12-23T03:57:00.000-08:00</published><updated>2007-12-23T04:01:48.212-08:00</updated><title type='text'>Back to Mac</title><content type='html'>This week I converted my family's main computer from Vista to OS X. (It's a Mac Mini).&lt;br /&gt;&lt;br /&gt;We pretty much use it for web surfing, web email, really old DOS children's games, and photo editing. Macs do that pretty well.&lt;br /&gt;&lt;br /&gt;I still have a Vista machine that I use for the excellent Windows Media Center -- love the record-by-keyword feature and the free programming guide.&lt;br /&gt;&lt;br /&gt;But for day-to-day use we're back to the Mac.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-2406860634276646325?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/2406860634276646325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=2406860634276646325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2406860634276646325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2406860634276646325'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/12/back-to-mac.html' title='Back to Mac'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4258228923429112109</id><published>2007-12-23T03:50:00.000-08:00</published><updated>2007-12-23T03:57:44.183-08:00</updated><title type='text'>Alternative language blues</title><content type='html'>I've spent roughly 4 years of midnight-engineering time looking into the cool languages to see if they would make game programming easier or more fun. Haskell, Ocaml, F#, Erlang, Scheme, Lisp, D, Factor, Scala, Python, I've looked at them all.&lt;br /&gt;&lt;br /&gt;F# held my attention for quite a while, but now my platform-of-choice has moved away from F#'s design center. (I'm into Linux-based mobile platforms now.) And to be honest, I'm still happier in a C-like language.&lt;br /&gt;&lt;br /&gt;I'm depressed. Sure, I learned a lot about fancy language features, but I could have written quite a few games in plain-old-C++ (or C#, or Java or Flash or Basic) in the same time.&lt;br /&gt;&lt;br /&gt;P.S. Someone else has done this more impressively than I have. Do a Google Groups search for Brandon van Every, who has had a five year odyssey to find the perfect non-C++ game programming language. I corresponded with him back when we were both interested in O'Caml. Since then he's managed to annoy pretty much everyone by harping on their favorite language's shortcomings. In the end (at least as of six months ago) he'd given up and gone back to C++. I look forward to seeing what he does next.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4258228923429112109?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4258228923429112109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4258228923429112109' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4258228923429112109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4258228923429112109'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/12/alternative-language-blues.html' title='Alternative language blues'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4883002688238747</id><published>2007-12-23T03:13:00.000-08:00</published><updated>2007-12-23T03:50:38.755-08:00</updated><title type='text'>Lisp Hacking and Science Fiction</title><content type='html'>I've been poking around with Lisp and Scheme again, and am reminded of some of my favorite science fiction books (&lt;span style="font-weight: bold;"&gt;warning, plot spoilers follow&lt;/span&gt;):&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Verner Vinge's "A Fire Upon the Deep"  begins with a group of scientists mining an ancient civilization's web archives. They need to build interpreters for the ancient civilization's programs. All goes well until they reconstitute a malevolent AI that they spend the rest of the book fighting.&lt;/li&gt;&lt;li&gt;Piers Anthony's Macroscope involves a group of people trying to decode an Extra-Terestrial message, that other ETs are trying to jam. Over the course of the book your opinion as to which group of ETs has humanity's best interests at heart changes back and forth several times.&lt;/li&gt;&lt;li&gt;Any number of SF stories are set in the far future where people poke around in the ruins of a once-great civilization. (See Gene Wolfe, Cordwainer Smith.)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Working with Lisp reminds me of these books. Lisp's a seductive, ancient, powerful language that has been worked on for years by very smart, very motivated hackers. Pretty much everything one can think of to do with Lisp has been done, multiple times, by really smart people.&lt;br /&gt;&lt;br /&gt;For example, I want to have a system where I can interactively write a game, changing code on the fly while the game is running. I want to be able to use macros and garbage collection and free serialization and inspection and all that cool stuff that Lisp provides.&lt;br /&gt;&lt;br /&gt;And Naughty Dog had all that, in GOAL, for the PS2. Their implementation was apparently much better (more efficient, less buggy, more features) than one I could cobble together out of open-source-Lisp parts. And they had used it to successfully write two or three games. But they they walked away from it. Gave it up. Went back to C++.&lt;br /&gt;&lt;br /&gt;They said it was because they had a lot of pressure from their parent company to make their engine more reusable. But I think it's also because the results they were getting just weren't that much better than the results that all the other developers, who use C++-and-some-cheap-scripting-language-like-Lua, were getting.&lt;br /&gt;&lt;br /&gt;I think Lisp is like a powerful alien technology that may not be in your best interests to use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4883002688238747?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4883002688238747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4883002688238747' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4883002688238747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4883002688238747'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/12/lisp-hacking-and-science-fiction.html' title='Lisp Hacking and Science Fiction'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-1217357179113850110</id><published>2007-12-04T09:58:00.000-08:00</published><updated>2007-12-04T10:04:47.340-08:00</updated><title type='text'>More evidence that garbage collection is expensive</title><content type='html'>As seen on &lt;a href="http://lambda-the-ultimate.org/node/2552"&gt;Lambda the Ultimate.org&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-weight: bold;"&gt;Quantifying the Performance of Garbage Collection vs. Explicit Memory Management&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We compare explicit memory management to both copying and non-copying garbage collectors across a range of benchmarks, and include real (non-simulated) runs that validate our results. These results quantify the time-space tradeoff of garbage collection: with five times as much memory, an Appel-style generational garbage collector with a non-copying mature space matches the performance of explicit memory management. With only three times as much memory, it runs on average 17% slower than explicit memory management. However, with only twice as much memory, garbage collection degrades performance by nearly 70%. When physical memory is scarce, paging causes garbage collection to run an order of magnitude slower than explicit memory management.&lt;blockquote&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-1217357179113850110?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/1217357179113850110/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=1217357179113850110' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1217357179113850110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/1217357179113850110'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/12/more-evidence-that-garbage-collection.html' title='More evidence that garbage collection is expensive'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-749139532347792082</id><published>2007-12-04T08:31:00.000-08:00</published><updated>2007-12-04T09:57:59.523-08:00</updated><title type='text'>The Economics of Selling a MacBook on Craig's List vs. Ebay</title><content type='html'>I just sold my MacBook over the web. I sold it on &lt;a href="http://www.craigslist.org/"&gt;Craig's List&lt;/a&gt;. I also considered using &lt;a href="http://www.ebay.com/"&gt;eBay&lt;/a&gt;, but Craig's List turned out to be a better deal, for both buyer and seller.&lt;br /&gt;&lt;br /&gt;The reason is that listing and selling on Craig's List is free, while selling on eBay is expensive, especially for items priced higher than $500. First, there's the listing fee of $0.20, then the Final Value fee of $0.50 + 3.25% * price. But wait, there's more: EBay all-but-requires you to use their PayPal service to settle transactions, and PayPal in turn requires you to use a "Premier" account if you receive more than $500 in eBay payments in one month, which you automatically would if the item you're selling is more than $500. Using a "Premier" account requires that you pay PayPal 2.9%+$0.30 per transaction, even for cash transactions. (The processing fee is less if you are doing a high volume of business through them.)&lt;br /&gt;&lt;br /&gt;So the total eBay selling cost is in the range of 6.15%. That's $50 on a $800 item.&lt;br /&gt;&lt;br /&gt;You could avoid accepting PayPal, but since accepting PayPal is the norm on eBay, it's very likely that your auction will be shunned, and you will receive a lower price.&lt;br /&gt;&lt;br /&gt;Besides the hefty fees, using PayPal is riskier for the seller than using cash. This is because it is possible for a disgruntled buyer to reverse the transaction. (Of course this same ability is a plus for the buyer, as is the ability to use credit cards.)&lt;br /&gt;&lt;br /&gt;Even without using eBay to sell the product, it makes sense to use eBay as a price setter. eBay makes this easy to do by reporting the final price for closed auctions that you are "watching". Since auctions last between 3 and 10 days, and an auction must be active in order for you to watch it, you will need at least a week to track enough auctions of similar items to make a fairly accurate estimate of the market price.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-749139532347792082?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/749139532347792082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=749139532347792082' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/749139532347792082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/749139532347792082'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/12/economics-of-selling-macbook-on-craigs.html' title='The Economics of Selling a MacBook on Craig&apos;s List vs. Ebay'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-7029357737333467823</id><published>2007-11-30T10:27:00.001-08:00</published><updated>2007-11-30T10:38:39.886-08:00</updated><title type='text'>Xbox 360 Fall 2007 update adds DIVX/MP4 video support</title><content type='html'>The Fall 2007 Xbox 360 dashboard  update (coming December 4th) will add support for DivX and MP4 playback.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/xboxteam/archive/2007/11/30/december-2007-video-playback-faq.aspx"&gt;Video FAQ&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is great news for Xbox 360 owners who want to watch video encoded in these formats. I'm surprised that Microsoft did this, because these formats compete with Microsoft's own WMV format. While the benefit to consumers is obvious, I'm not sure what the benefit is to Microsoft. I'm guessing they did this to both improve the "watch your PC's videos on your Xbox" story, and also to match an existing PS3 feature.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-7029357737333467823?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/7029357737333467823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=7029357737333467823' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7029357737333467823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7029357737333467823'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/11/xbox-360-fall-2007-update-adds-divxmp4.html' title='Xbox 360 Fall 2007 update adds DIVX/MP4 video support'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-7082392614804068514</id><published>2007-11-21T12:39:00.000-08:00</published><updated>2007-11-21T12:48:11.046-08:00</updated><title type='text'>Game resolution issues</title><content type='html'>This morning I fired up Mario Galaxy 64 on my new Wii for some early-morning platforming. I happened to sit closer to the screen than I normally do. Yuck! The jaggies were suddenly very apparent and very distracting. But when I  moved back to my normal viewing distance, the jaggies were gone, blurred out by my poor vision.&lt;br /&gt;&lt;br /&gt;It's no wonder that HDTV and HD gaming in general is not taking off as quickly as consumer electronics companies hoped -- the benefits are just not that apparent to normal eyes at normal viewing distance.&lt;br /&gt;&lt;br /&gt;Jaggies aside, Mario Galaxy 64 is great fun! A very smooth difficulty curve, and gorgeous graphics.  Right now I'm working my way through the candy level. (I have seven stars.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-7082392614804068514?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/7082392614804068514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=7082392614804068514' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7082392614804068514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/7082392614804068514'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/11/game-resolution-issues.html' title='Game resolution issues'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-4916799740491324891</id><published>2007-11-21T12:34:00.000-08:00</published><updated>2007-11-29T19:44:52.051-08:00</updated><title type='text'>Had brunch at Salty's</title><content type='html'>I had a very nice birthday brunch at &lt;a href="http://maps.google.com/?q=Salty%27s%20Alki"&gt;Salty's on Alki&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here's a variety of different ways of linking to Salty's on Google Maps:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://maps.google.com/?ie=UTF8&amp;amp;cd=1&amp;amp;ll=47.227029,-122.527771&amp;amp;spn=2.378105,2.666931&amp;amp;z=9&amp;amp;iwloc=A&amp;amp;om=1"&gt;Search Result&lt;/a&gt;&lt;br /&gt;&lt;a href="http://maps.google.com/maps?q=salty%27s+alki&amp;amp;sll=37.0625,-95.677068&amp;amp;sspn=84.608181,85.341797&amp;amp;ie=UTF8&amp;amp;cd=1&amp;amp;ll=47.227029,-122.527771&amp;amp;spn=2.378105,2.666931&amp;amp;z=9&amp;amp;iwloc=A&amp;amp;om=1&amp;amp;layer=t"&gt;Search Result with traffic&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://maps.google.com/maps?mrestrict=xhtmlonly&amp;amp;site=maps&amp;amp;q=4021+ridge+st+fair+oaks+ca+95628"&gt;A place that isn't Salty's at all&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-4916799740491324891?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/4916799740491324891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=4916799740491324891' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4916799740491324891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/4916799740491324891'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/11/had-brunch-at-saltys.html' title='Had brunch at Salty&apos;s'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3099671593541938429.post-2302327091425705954</id><published>2007-11-12T03:34:00.001-08:00</published><updated>2007-11-12T04:31:59.181-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>My initial Wii impressions</title><content type='html'>I finally got a Nintendo Wii this weekend. Wii's are in fairly short supply right now, so I couldn't find one at a reasonable price on-line. If you live in the Seattle area, here's my Wii-finding tip: Fred Meyer stores get deliveries on Wednesdays, Fridays, and Sundays, meaning that calling a Fred Meyer store at 7am on Sunday morning to check if they received a new shipment is a good way to find a Wii.&lt;br /&gt;&lt;br /&gt;The total cost, with tax, an extra controller, and a component video cable was around $350.&lt;br /&gt;&lt;br /&gt;I've got Wii Sports, Wii Play, and will be picking up Mario Galaxy this week. The primary users will probably be my kids, although I am very interested in trying out Mario Galaxy.&lt;br /&gt;&lt;br /&gt;As a former Xbox 360 developer, I couldn't help comparing the Wii to the Xbox 360. So far I give the Wii high marks for:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It's small and quiet.&lt;/li&gt;&lt;li&gt;It starts up quickly.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The dashboard UI is very clean and pleasant.&lt;/li&gt;&lt;li&gt;The low-res (480p component) graphics are quite good. I did occasionally see jaggies, for example on the edges of the bowling pins during close-ups in Wii bowling. But the Wii encourages you to play fairly far away from the screen, which masks the lower resolution.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The Wii remotes are great! I love the new gesture "verbs" that are available for game play, and I found it much easier to enter text with the Wii than with an Xbox controller.&lt;/li&gt;&lt;li&gt;The TV station metaphor for the top-level UI is a good metaphor. It makes it easy to take in the available options at a glance. And the Wii remote makes it low-effort to pick the channel you want.&lt;/li&gt;&lt;li&gt;Having built-in wireless was a nice touch.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The Mii avatars are pure genius. Both the fun of designing them and then having them appear in the sports-style games. This is something that the other consoles should copy, and I'm surprised they haven't. Maybe it's patented in some way that makes it difficult to copy.&lt;/li&gt;&lt;li&gt;I thought it was a nice touch that I could name my console, but I didn't see the name used anywhere.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;My two three-year-old daughters were strongly attracted to the Wii dashboard and games' graphics and sounds, saying things like "pretty!" and "I like it!" They never said this about the Xbox 360 dashboard or games.&lt;/li&gt;&lt;li&gt;My five-year-old son really got into acting out the moves in the baseball game. And he has not yet played real-world baseball. It will be interesting to see how he does when he starts playing real-world baseball next spring.&lt;/li&gt;&lt;li&gt;The UI of the Wii online store is very good. The Mario themed downloading bar is pure genius -- you know you have a good UI when people _enjoy_ watching the download progress bar.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Some things I didn't like about the Wii:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The UI for pairing a second wireless controller to the console was hard to discover. (I will give Nintendo big props for pre-pairing the in-the-box controller with the console. I'm sure that adds cost to manufacturing, but it makes for a great out-of-box experience.)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The network connection UI gave very little feedback on why the network connection failed. When you test network connectivity you get a 20 second "testing" animation, followed by a cryptic five-digit error code. I had to make two changes to my router configuration to get networking to work. I would have preferred the Xbox 360's UI, that gives more step-by-step information about network connectivity issues.&lt;/li&gt;&lt;li&gt;My three-year-olds can't handle the Wii controller very well. There are too many buttons to accidentally press, and the required gestures are too complicated for them.&lt;/li&gt;&lt;li&gt;No downloadable games demos. And very few downloadable games at all.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The walled-garden Internet channels are pretty weak, especially the Everybody Votes channel.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Not many current or upcoming games that I want to play. After Mario Galaxy, I don't know what my next purchase will be. Luckily, the current games should keep my kids happy for quite a while. (My son's been working his way through Cloning Clyde on Xbox 360 for the past year, I can only imagine how much fun he's going to have with Mario Galaxy!)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;In conclusion, I'd have to rate the Wii as a much better "family" console than either the Xbox 360 or the PS3. And by family I mean "small children". I'm lucky that I like the Wii's UI and game style, because I have a feeling I'll be hearing and seeing a lot of it over the next few years. As for my trusty 360, I suspect it will be mostly relegated to "Media Center Extender" status. (Although I am definitely looking forward to Alan Wake and I have high hopes for the next Banjo game. And I might get "The Orange Box" -- Portal and Team Fortress 2 look like a lot of fun.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3099671593541938429-2302327091425705954?l=grammerjack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grammerjack.blogspot.com/feeds/2302327091425705954/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3099671593541938429&amp;postID=2302327091425705954' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2302327091425705954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3099671593541938429/posts/default/2302327091425705954'/><link rel='alternate' type='text/html' href='http://grammerjack.blogspot.com/2007/11/my-initial-wii-impressions.html' title='My initial Wii impressions'/><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
