<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DUEMRHkyfSp7ImA9WxJbEE4.&quot;"><id>tag:blogger.com,1999:blog-22367266</id><updated>2009-07-19T17:08:05.795-04:00</updated><title>pmuellr</title><subtitle type="html">Patrick Mueller's blog</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://pmuellr.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>192</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/pmuellr" type="application/atom+xml" /><entry gd:etag="W/&quot;CUAHQX8_fSp7ImA9WxJUFko.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-9136489873112747713</id><published>2009-07-15T12:01:00.000-04:00</published><updated>2009-07-15T12:02:10.145-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-15T12:02:10.145-04:00</app:edited><title>web beep()</title><content type="html">&lt;p&gt;I've blogged before about making use of audible feedback for debugging.  One of the things I'd like to eventually get around to doing for WebKit's Web Inspector is to add first class audible breakpoints.  Just like you can "click" on a line to add a breakpoint where the debugger will stop the next time that location is reached in your program, an audible breakpoint wouldn't stop, but play a sound clip instead.
    
&lt;p&gt;There's some infrastructure that needs to be added to Web Inspector before tackling that feature, so I figured I'd go on the cheap instead.  Using HTML5's new &lt;a href="http://dev.w3.org/html5/spec/Overview.html#audio"&gt;&lt;code&gt;audio&lt;/code&gt;&lt;/a&gt; element, I created a &lt;code&gt;beep()&lt;/code&gt; function which just plays a sound clip when invoked.  Wherever you might put a &lt;code&gt;console.log()&lt;/code&gt; invocation, you can put a &lt;code&gt;beep()&lt;/code&gt; invocation instead.  Actually, I created a &lt;code&gt;boop()&lt;/code&gt; function also; a single sound is rather boring.
    
&lt;p&gt;Of course, having to modify your source for debugging is so 1980's.  So my &lt;code&gt;beep()&lt;/code&gt; functions can also act as wrappers.  Pass them a function, and they'll return a new function you can use as a replacement of the original function.  When that new function is invoked, it beeps (or boops, or whatever), then invokes the original function.  The new function also contains a reference to the old function, so you can unwrap as needed.  Using this, you can augment addressable functions from within your &lt;a href="http://en.wikipedia.org/wiki/Read-eval-print_loop"&gt;REPL&lt;/a&gt;-y JavaScript debugger console, without having to muck with your source.
    
&lt;p&gt;The sample code is up here: &lt;a href="http://muellerware.org/projects/web-beep/"&gt;web-beep&lt;/a&gt;.  Seems to run fine in Safari and FireFox 3.5.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-9136489873112747713?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/GjhQ0Q-LDDg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/9136489873112747713/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=9136489873112747713" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/9136489873112747713?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/9136489873112747713?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/GjhQ0Q-LDDg/web-beep.html" title="web beep()" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/07/web-beep.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QMQ307eip7ImA9WxJUEU0.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-65111506432117660</id><published>2009-07-08T22:05:00.003-04:00</published><updated>2009-07-08T22:09:42.302-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-08T22:09:42.302-04:00</app:edited><title>A Survey of Data Display in JavaScript Debuggers</title><content type="html">&lt;p&gt;My mom has been asking me about the differences in the way data is displayed in some JavaScript debuggers, so I &lt;a href="http://muellerware.org/papers/js-debug-data-display/js-debug-data-display.html"&gt;wrote something up&lt;/a&gt; for her.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-65111506432117660?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/VxyD-2TSSU4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/65111506432117660/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=65111506432117660" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/65111506432117660?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/65111506432117660?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/VxyD-2TSSU4/survey-of-data-display-in-javascript.html" title="A Survey of Data Display in JavaScript Debuggers" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/07/survey-of-data-display-in-javascript.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMDRHs_eyp7ImA9WxJXGUQ.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-8999112317998909839</id><published>2009-06-14T12:08:00.002-04:00</published><updated>2009-06-14T12:21:15.543-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-14T12:21:15.543-04:00</app:edited><title>offline web application cache abuse</title><content type="html">&lt;!--
http://diveintopython.org/
http://diveintopython-cached.muellerware.org/

http://www.w3.org/TR/offline-webapps/
http://developer.apple.com/safari/library/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/OfflineApplicationCache/OfflineApplicationCache.html#//apple_ref/doc/uid/TP40007256-CH7-SW1

.htaccess
AddType text/cache-manifest manifest

http://www.feedbooks.com/
http://www.pg-news.org/20090320/epub-books-now-available-at-project-gutenberg/
http://pragdave.blogs.pragprog.com/pragdave/2009/05/displaying-code-on-the-kindle.html
--&gt;

&lt;p&gt;I've been a user of hand-held computers since 1997, when IBM bought me a Palm Pilot to use in a customer demo I was putting together.  Since then, I've been through a number of Palm devices, and up till last week had been using a &lt;a href="http://pmuellr.blogspot.com/2008/03/nokia-n800.html"&gt;Nokia N800&lt;/a&gt; device.  This week, I caved, and bought myself an iPod Touch.
    
&lt;p&gt;One of the main uses I've had for these devices is reading.  On the Palm, I used the wonderful &lt;a href="http://www.isilo.com/"&gt;iSilo&lt;/a&gt; program to convert HTML to some binary format that the Palm reader rendered as good as it could - good enough - even on a 160x160 pixel display.  On the N800, HTML content could just be copied to an SD disk, and then you could view it via the built-in web browser using &lt;tt&gt;file:&lt;/tt&gt; URLs.
    
&lt;p&gt;It turns out that I've been able to find plenty of material over the years, in HTML, that renders well enough on my hand-held devices.  Either ready made, or built via scraping, or whatever.
    
&lt;p&gt;&lt;b style="font-size:120%;"&gt;what to use on an iPhone or iPod Touch&lt;/b&gt;
    
&lt;p&gt;So, what are the options for reading on the iPhone/iPod Touch?  &lt;a href="http://www.lexcycle.com/"&gt;Stanza&lt;/a&gt; is the only generic reader I've looked at so far, and it's not bad.  It's particularly nice to have access to &lt;a href="http://www.feedbooks.com/"&gt;FeedBooks&lt;/a&gt; and &lt;a href="http://www.gutenberg.org/wiki/Main_Page"&gt;Project Gutenberg&lt;/a&gt; books, which can be downloaded and then read later if you aren't online.  Compared to &lt;a href="http://books.google.com/m"&gt;Google Books&lt;/a&gt; which appears to only support reading while online.  There's also &lt;a href="http://www.amazon.com/gp/feature.html?ie=UTF8&amp;amp;docId=1000301301"&gt;Kindle&lt;/a&gt;, but I don't have any need to buy books, there's plenty of free content to be had.  More importantly with Kindle is the &lt;a href="http://pragdave.blogs.pragprog.com/pragdave/2009/05/displaying-code-on-the-kindle.html"&gt;1995 level of HTML support&lt;/a&gt;, and that's a big problem for me; I like to read technical content with code samples, etc.
    
&lt;p&gt;Beyond generic readers, there are also content-specific readers from content producers like the New York Times, the BBC, and AP News.  The BBC one is especially strange.  When displaying a full article, they seem to be displaying the same content that's on their web page.  Various navigation and other links eating up space in the left and right side of the page.  You can double-tap the middle content to get that to zoom, but why wouldn't they do that in the first place?  If you actually happen to click a link on the page, even to another story on the BBC, it exits their app, and launches a browser on that page.  Amazing, and not in a good sense.
    
&lt;p&gt;Stanza seems like the most useful reader at present, at least for literature.  I'm not really happy about the page-turning metaphor; I prefer to scroll pages vertically.  I can probably learn to live with it.
    
&lt;p&gt;But how can I get my own content on there, or more generally, rando HTML content on there?

&lt;p&gt;&lt;b style="font-size:120%;"&gt;EPUB&lt;/b&gt;
    
&lt;p&gt;If you look at the formats of "documents" that Stanza supports, one particular format is &lt;a href="http://en.wikipedia.org/wiki/EPUB"&gt;EPUB&lt;/a&gt;.  I've not been able to make my way through the morass that is the specifications surrounding this format, but if you're interested, here's how to get started: an EPUB file is a .zip file, expand with your favorite zip utility; you'll find a number of XML files inside, you can kinda get a clue for how everything fits together by browsing those files.
    
&lt;p&gt;The "meat" of an EPUB document consists of XHTML, CSS, and image files.  Hmmm.  Sounds like the web.  Could you take some existing web site and easily "EPUB" it?

&lt;p&gt;&lt;b style="font-size:120%;"&gt;HTML5 Offline Application Cache&lt;/b&gt;
    
&lt;p&gt;Turns out, there's something in HTML5, and more importantly, available on iPhone and iPod Touch devices, that can take an existing web site and make it available even if you aren't connected to a network.  There is a W3C Working Group Note for this available as&lt;a href="http://www.w3.org/TR/offline-webapps/"&gt;&lt;i&gt;"Offline Web Applications"&lt;/i&gt;&lt;/a&gt;.  Apple has documentation on their support of this in the document &lt;a href="http://developer.apple.com/safari/library/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/OfflineApplicationCache/OfflineApplicationCache.html"&gt;&lt;i&gt;"HTML 5 Offline Application Cache"&lt;/i&gt;&lt;/a&gt;.  See also the &lt;a href="http://dev.w3.org/html5/spec/Overview.html#offline"&gt;WHAT-WG version&lt;/a&gt; under development.
    
&lt;p&gt;The basic idea is to do the least possible work.  You need to create a new "manifest" file which lists all the files which should be cached for offline usage.  And you need to identify that file in the &lt;tt&gt;&amp;lt;html&amp;gt;&lt;/tt&gt; element of your document.  That's all!  The browser will arrange to cache all the content listed in the manifest.
    
&lt;p&gt;I decided to try out how well this works with Mark Pilgrim's &lt;a href="http://diveintopython.org/"&gt;&lt;i&gt;"Dive Into Python"&lt;/i&gt;&lt;/a&gt; book.  I downloaded a copy of the book as separate HTML files, ran &lt;tt&gt;find&lt;/tt&gt; on the result to create the manifest, whacked the &lt;tt&gt;&amp;lt;html&amp;gt;&lt;/tt&gt; elements with a multi-file search-and-replace in my text editor, set up the files on my machine's local server, browsed to it from my iPod Touch, worked like a champ.  
    
&lt;p&gt;It seems to take 20-30 seconds to get all the files downloaded, and during that time there is no indication of what's going on in the browser.  I was &lt;tt&gt;tail&lt;/tt&gt;'ing my server's access log to tell when I was done.  Presumably some of those events specified in the WHAT-WG version of the spec will help out with issues like that.  After the files got downloaded, I could turn the wifi off on my device, and continue to browse the content.

&lt;p&gt;&lt;i&gt;"Dive Into Python"&lt;/i&gt; seemed like a good test case; non-trivial markup, especially code snippets; a significant amount of content (3MBs fully expanded), and presumably not really designed to be read on a hand-held device.  I'm satisfied with the results, though I think most people will find the font sizes too small.  The font sizes are too small for me when displaying in portrait mode, so make sure you try landscape as well.  Tough decision point there, make the fonts bigger and then you'll either get text wrapping or have to do side-to-side scrolling.  

&lt;p&gt;I've got the files available on one of my servers, &lt;a href="http://diveintopython-cached.muellerware.org/"&gt;http://diveintopython-cached.muellerware.org/&lt;/a&gt;, which I'll leave up until my hosting provider kills me - each access to the page from an enabled browser will download the whole book (if it's not already been downloaded).  Presumably this might work on other WebKit-based browsers, like the one on an Android device, or the Palm Pre.
    
&lt;p&gt;On the iPhone or iPod Touch, after displaying the initial page, add a bookmark by clicking the &lt;tt&gt;+&lt;/tt&gt; button, and then the "Add to Home Screen" button.  Remember to wait 30 seconds or so after the initial page load before doing this, to make sure all the content gets downloaded.  This will add the book as a new "app" on the main application screen.  I've also done the &lt;a href="http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html"&gt;appropriate horkiness&lt;/a&gt; to get the cover of Mark's book to show up as the application icon.

&lt;p&gt;&lt;b style="font-size:120%;"&gt;questions&lt;/b&gt;

&lt;p&gt;This experience raises a number of questions regarding the HTML5 Offline Application Cache support:
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;How much space does the browser set aside for this cache?  I assume there's a fixed upper limit for the cache, but does it compete with all other browser caching?  Or is there a per-site or per-url cache limit?

&lt;li&gt;&lt;p&gt;How can I be informed when my cache content is thrown out of the cache?  Is the entire set of files listed in the manifest thrown out atomically?

&lt;li&gt;&lt;p&gt;Is there enough functionality in the existing and proposed APIs to make reliable use of this capability?
    
&lt;/ul&gt;

&lt;p&gt;I'm left wondering if it wouldn't just be better off to provide a full-function JavaScript API to the cache in general, although clearly this could be done as well as this declarative approach.  My fear is the declarative approach might take you 80% of the way there, but leave out critical capability in that missing 20%.  
    
&lt;p&gt;More experimentation required.  Have at it.
    
&lt;p&gt;Or maybe this is just simple abuse of the capability.  Instead of caching web sites, you could certainly get more control by having all the book content stored in a client-side SQL database, and then build an HTML application to navigate through it.  It's just a lot more work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-8999112317998909839?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/d1A0aKov2DI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/8999112317998909839/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=8999112317998909839" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/8999112317998909839?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/8999112317998909839?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/d1A0aKov2DI/offline-application-cache-abuse.html" title="offline web application cache abuse" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/06/offline-application-cache-abuse.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UGQXk-cCp7ImA9WxJXEU4.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-8733954051068059387</id><published>2009-06-04T13:04:00.001-04:00</published><updated>2009-06-04T13:07:00.758-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-04T13:07:00.758-04:00</app:edited><title>debugger friendly</title><content type="html">&lt;p&gt;(this is a bit of a followup to my previous blog post - &lt;a href="http://pmuellr.blogspot.com/2009/04/debugging.html"&gt;&lt;i&gt;"debugging"&lt;/i&gt;&lt;/a&gt;)

&lt;p&gt;Hit a milestone yesterday, submitting my first patch to WebKit, in support of &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=25475"&gt;&lt;i&gt;"Bug 25474: Show the filename and first line for '(program)' in the Profiler/Debugger"&lt;/i&gt;&lt;/a&gt;.  The patch provides the same support that Firefox provides to allow JavaScript &lt;tt&gt;eval()&lt;/tt&gt; invocations and &lt;tt&gt;Function()&lt;/tt&gt; constructor invocations to name the code they are injecting into the environment, by adding a comment to the source interpreted:
    
&lt;pre&gt;
//@ sourceURL=some-url-goes-here
&lt;/pre&gt;

&lt;p&gt;Presumably &lt;tt&gt;&lt;i&gt;some-url-goes-here&lt;/i&gt;&lt;/tt&gt; is replaced in your source by some kind of moniker that will be useful to you.
    
&lt;p&gt;Why is this useful?  Here's what your "list of scripts" looks like when developing a Dojo app, without this support: &lt;a href="https://bugs.webkit.org/attachment.cgi?id=30852"&gt;[link]&lt;/a&gt;; here's what it looks like with this support: &lt;a href="https://bugs.webkit.org/attachment.cgi?id=30853"&gt;[link]&lt;/a&gt;.  A &lt;i&gt;little&lt;/i&gt; more useful.
    
&lt;p&gt;Last month, another interesting feature for debugging was added to WebKit - the ability to 'name' anonymous functions, after they've been created.  A full description of this, and the value it provides, was written up a blog entry
&lt;a href="http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/"&gt;&lt;i&gt;"Building a Better JavaScript Profiler with WebKit"&lt;/i&gt;&lt;/a&gt;.  In a nutshell, you can add a property &lt;tt&gt;&lt;i&gt;displayName&lt;/i&gt;&lt;/tt&gt; to a function which will be used as it's name in the debugger and profiler if the function doesn't otherwise have a name.

&lt;p&gt;Quick notes:

&lt;ul&gt;
&lt;li&gt;the &lt;tt&gt;sourceURL&lt;/tt&gt; feature is not yet committed to WebKit, and even if/when it is, would only be available in &lt;a href="http://nightly.webkit.org/"&gt;WebKit nightlies&lt;/a&gt;.
&lt;li&gt;the &lt;tt&gt;displayName&lt;/tt&gt; feature is only available in &lt;a href="http://nightly.webkit.org/"&gt;WebKit nightlies&lt;/a&gt; right now.
&lt;li&gt;the &lt;tt&gt;sourceURL&lt;/tt&gt; feature does not currently work with the WebKit profiler, just the debugger.  
&lt;li&gt;the &lt;tt&gt;displayName&lt;/tt&gt; feature works in the WebKit profiler and debugger.  
&lt;li&gt;Firefox supports (and invented!) the &lt;tt&gt;sourceURL&lt;/tt&gt; feature, but AFAIK does not support the &lt;tt&gt;displayName&lt;/tt&gt; feature.  
&lt;li&gt;Dojo currently has support for &lt;tt&gt;sourceURL&lt;/tt&gt; feature, but only if you're running in a Mozilla-based browser - chime in &lt;a href="http://bugs.dojotoolkit.org/ticket/9374"&gt;here&lt;/a&gt; for WebKit support.  &lt;li&gt;Dojo has no support for the &lt;tt&gt;displayName&lt;/tt&gt; feature - chime in &lt;a href="http://bugs.dojotoolkit.org/ticket/9375"&gt;here&lt;/a&gt; on that issue.
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;enhanced object display&lt;/b&gt;
    
&lt;p&gt;Here's what I'm going to look into next:
    
&lt;p&gt;In the WebKit bug, &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=25724"&gt;&lt;i&gt;"Bug 25724: Incorrect collection output for Javascript console evaluation"&lt;/i&gt;&lt;/a&gt;, the reporter claims that the output when displaying the result of a jQuery function invocation is incorrect.  Incorrect isn't fair; it's better to say that it's not what the user expected, but then, as jjb mentions in comment #6, "we can't read [the user's] mind".
    
&lt;p&gt;It's certainly true that the current output isn't useful, and it's certainly the case that the developer of a debugger can't read a user's mind, so the obvious answer is to let the user decide how to see their output.  In Smalltalk, the debugger would call &lt;tt&gt;debugPrintOn:&lt;/tt&gt; instead of the more typical &lt;tt&gt;printOn:&lt;/tt&gt; method (&lt;tt&gt;printOn:&lt;/tt&gt; being analogous to &lt;tt&gt;toString&lt;/tt&gt; in Java or JavaScript).  This allowed developers to provide a debug-friendly version of the human-readable representation of an object, without impacting runtime code.  JavaScript debuggers should do the same thing.
    
&lt;p&gt;The other bit that needs to be done is to somehow augment the "properties" that you see associated with an object in the debugger.  Literally what you see in the debugger is the implementation goop of an object.  Not terribly useful, especially if values associated with objects are computed lazily, via a function invocation.  Seeing a function instead of perhaps the lazily computed value provides little value (though it is obviously much safer!).
    
&lt;p&gt;What I'd like to do is provide an optional method on a function which can be called to obtain "debug properties".  For instance, the debug properties for a jQuery object might return the array of matching DOM elements.  DOM elements themselves might return, instead of the goop currently returned, their parent DOM object, their children, and their next/previous siblings.  These DOM element's might have a "debug toString" that actually showed the HTML representation of the node (which the debuggers already support in some cases).
    
&lt;p&gt;Of course feel free to post additional ideas on this to the &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=25724"&gt;existing but report&lt;/a&gt;.

&lt;p&gt;&lt;b&gt;soundpoints&lt;/b&gt;

&lt;p&gt;Here's something I did back in the Smalltalk days; would be fun to do this for JavaScript as well:
    
&lt;p&gt;We all know what breakpoints are, but I extended the concept in Smalltalk with &lt;i&gt;soundpoints&lt;/i&gt; (stole the idea from somewhere).  Instead of having the debugger pause the execution of the program when a breakpoint is reached, the debugger would play a sound when a soundpoint is reached.  The nice thing about this capability is that you get some feedback without having to stop your program.  You can set soundpoints to let you know when you venture into code you're not expecting to venture into (some kind of beep/boop), or set a very short blip sound for a soundpoint you expect to hit a lot - giving you a kind of geiger counter.  Since WebKit already has &lt;a href="http://webkit.org/blog/140/html5-media-support/"&gt;programmatic support for playing audio&lt;/a&gt;, the "hard" part of this is already done.  What's needed is to integrate into the debugger framework.  OK, &lt;b&gt;that&lt;/b&gt; is the hard part.
    
&lt;p&gt;As sort of a side issue, when I did this in Smalltalk, I was able to do this with user-land code; I didn't need to be some kind of core developer to get the function added.  That's not true today in WebKit.  You need to modify existing WebKit code to add functionality like this; there's no simple way of me just adding it to my environment.  That would be a nice thing then also, having a way of extending the debugging environment through plugins or equivalent.  See &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=24273"&gt;&lt;i&gt;"Bug 24273: Inspector Plugins or Extend Capability"&lt;/i&gt;&lt;/a&gt;.  Also note that I believe FireFox has or will have the ability to extend FireBug via plugins.  I think it's too much to ask to have portable plugins, at this point, but something to think about.

&lt;p&gt;&lt;b&gt;what else&lt;/b&gt;
    
&lt;p&gt;What else can we do beyond all that?  What are your frustrations with JavaScript debugging?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-8733954051068059387?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/eF-tlNYzwpI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/8733954051068059387/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=8733954051068059387" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/8733954051068059387?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/8733954051068059387?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/eF-tlNYzwpI/debugger-friendly.html" title="debugger friendly" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/06/debugger-friendly.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUAHSHo5eCp7ImA9WxJTGU4.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-1342683718317116882</id><published>2009-04-28T11:47:00.001-04:00</published><updated>2009-04-28T11:48:59.420-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-28T11:48:59.420-04:00</app:edited><title>debugging</title><content type="html">&lt;p&gt;Apparently, I tend to &lt;a href="http://www.google.com/search?q=site:pmuellr.blogspot.com+debugging"&gt;write a log about debugging&lt;/a&gt;. To me, it's the other "fun" part of programming, the first fun bit being writing code to begin with.  Debugging comes into play, in that oh so rare case, where the code doesn't do what you &lt;i&gt;meant&lt;/i&gt; it to do.  Like writing code, I tend to view debugging as an art, more than a science.  Especially after seeing how some people debug code - I've got some scary stories I can share over a beer.

&lt;p&gt;And so it was interesting to see the subject of debugging come up in relation to the issue of "tail calls" in Python, in Guido's post &lt;a href="http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html"&gt;"Final Word on Tail Calls"&lt;/a&gt;. Specifically, Guido claims that usage of tail calls &lt;i&gt;"does make debugging harder"&lt;/i&gt;.  No doubt, assuming your debugger doesn't realize what's going on.

&lt;p&gt;Guido also gives an example of why I like debuggers: 

&lt;blockquote&gt;&lt;i&gt; The elimination of stack traces for some calls but not others would certainly confuse many users, who have not been raised with tail call religion but might have learned about call semantics by tracing through a few calls in a debugger. &lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;i&gt;Learning&lt;/i&gt; is the key.  There is really no better way to visualize how your program operates than to watch it running, line by line.  Typically, if you have everything set up right, you can also learn how those mysterious frameworks and library functions you're using work as well, by tracing into them.  This is especially important if the frameworks and functions you're using are underdocumented; which they probably are.

&lt;p&gt;Debugging also came up in reference to new WebKit goodies, as mentioned in &lt;a href="http://hanblog.info/blog/post/2009/04/23/WebKit-s-week-8"&gt;"WebKit's week - #8"&lt;/a&gt;, and more specifically, &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=25171"&gt;"Bug 25171: It should be possible to manually set the name of an anonymous function"&lt;/a&gt;.  I tried a little test, but noticed the debugger itself doesn't really have a place to make use of this information; but the profiler does.  My little test made use of a &lt;i&gt;decorator&lt;/i&gt;, like so:

&lt;blockquote&gt;&lt;pre&gt;
function function_named(name, func) {
    func.displayName = name
    return func
}
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;You could use a function like that to wrap anonymous function usage if you don't otherwise hold onto the function in a variable or property.

&lt;p&gt;I &lt;b&gt;LOVE&lt;/b&gt; to see changes like this, made by the implementations.  Eventually something like this might make it into a standard, but we need implementations to figure out the best way to do it before we standardize on it.  

&lt;p&gt;Other candidates to aid in debugging:

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;tt&gt;toStringDebug()&lt;/tt&gt; - this method would get called, if available, from a debugger when it's showing you a value.  Stolen from Smalltalk's &lt;tt&gt;#debugPrintOn:&lt;/tt&gt; message that did the same thing. As in Smalltalk, you'd add this method to Object, with the default implementation returning the result of &lt;tt&gt;this.toString()&lt;/tt&gt;

&lt;li&gt;&lt;p&gt;Ability to "name" &lt;tt&gt;eval()&lt;/tt&gt;'d code.  In WebKit's Web Inspector, these show up as &lt;tt&gt;"(program)"&lt;/tt&gt; in the scripts dropdown.  FireBug is a little better, it shows you the first bit of the &lt;tt&gt;eval()&lt;/tt&gt;'d code.  While playing with a framework that used &lt;tt&gt;eval()&lt;/tt&gt; all over the place, I ended up using a convention of making the first line in the script that was &lt;tt&gt;eval()&lt;/tt&gt;'d a comment with a 'file name' at the beginning.  Very useful for FireBug. But I think we can do better. 
&lt;p&gt;Why not recognize a keyword in a comment instead?
&lt;blockquote&gt;&lt;pre&gt;
// @eval-name "foo-blatz"
...
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;That would end up showing the name &lt;tt&gt;foo-blatz&lt;/tt&gt; along size other script names wherever such script names get displayed.

&lt;li&gt;&lt;p&gt;Class hierarchy browsing; many of the JavaScript frameworks have a notion of building "classical" class hierarchies in JavaScript.  Whether that's good or bad, dunno, but it's the way it is.  It would be nice to be able to visualize these.  Since each of the frameworks does things differently, there is no single way to handle this.  Some options would be to invent some new meta-variables like the examples above that you could augment your "classes" and maybe even "values" with - &lt;tt&gt;__class__&lt;/tt&gt; property on an object points to it's "class", &lt;tt&gt;__superclass__&lt;/tt&gt; on a a "class" points to it's superclass, etc.  Perhaps better would be a way to allow each of the frameworks to define it's own viewers by allowing the debuggers to be extended with additional code wholesale.  &lt;a href="http://getfirebug.com/extensions/index.html"&gt;FireBug already does this&lt;/a&gt;, and you could presumably hack WebKit's Web Inspector yourself to do this.

&lt;li&gt;&lt;p&gt;What else?

&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-1342683718317116882?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/dGEwY0lkF4E" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/1342683718317116882?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/1342683718317116882?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/dGEwY0lkF4E/debugging.html" title="debugging" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2009/04/debugging.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIMSXs6cSp7ImA9WxJTFE8.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-4941206980563517461</id><published>2009-04-22T14:55:00.000-04:00</published><updated>2009-04-22T14:56:28.519-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-22T14:56:28.519-04:00</app:edited><title>nitro_pie</title><content type="html">&lt;p&gt;One of the things I wanted to start doing in the
&lt;a href="http://pmuellr.blogspot.com/2009/03/new-job-webkit.html"&gt;new job&lt;/a&gt;
was to play with the 
&lt;a href="http://developer.apple.com/documentation/Carbon/Reference/WebKit_JavaScriptCore_Ref/index.html#//apple_ref/doc/framework/javascriptcore_fw"&gt;JavaScriptCore framework&lt;/a&gt;.
But it's a C language framework, and I don't typically associate C with "play".
Good news is, if there's a C API, then there's a good chance you can talk to 
it from Python via the 
&lt;a href="http://www.python.org/doc/2.5.1/lib/module-ctypes.html"&gt;&lt;tt&gt;ctypes&lt;/tt&gt;&lt;/a&gt;
module.

&lt;p&gt;I started down that route a little over a month ago, 
and it's gotten to the point where you
can do some non-trivial things with it, so I got it all cleaned up, tagged, etc.
It's called &lt;b&gt;nitro_pie&lt;/b&gt; (Nitro is 
the new sexy name of JavaScriptCore), is available up at 
&lt;a href="http://github.com/pmuellr/nitro_pie/tree/master"&gt;GitHub&lt;/a&gt;, with a 
downloadable .tar.gz available on the
&lt;a href="http://github.com/pmuellr/nitro_pie/downloads"&gt;downloads&lt;/a&gt; page.

&lt;p&gt;Here's an example of what you can do with it: 
&lt;a href="http://github.com/pmuellr/nitro_pie/blob/55efaee97fde3a93451d5cbce8c66b68bf2bb610/nps/nps.py"&gt;nps.py&lt;/a&gt;;
nps standing for &lt;b&gt;n&lt;/b&gt;itro_&lt;b&gt;p&lt;/b&gt;ie &lt;b&gt;s&lt;/b&gt;hell.  This Python program takes a JavaScript file name
as a command-line argument, and runs it.  It injects a new function,
&lt;tt&gt;print()&lt;/tt&gt;, into the JavaScript global environment, so you can actually see it
do something.  And of course that function is implemented in plain old Python.
Here's "Hello World", which does what you would expect under &lt;tt&gt;nps.py&lt;/tt&gt;:

&lt;blockquote&gt;
&lt;pre&gt;
print("Hello", " ", "World", "!")
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Couldn't resist writing a simple benchmark to sum numbers from 1 to ?, and 
comparing Python and JavaScript:

&lt;blockquote&gt;
&lt;pre&gt;
---------------------------------------------------
Python
---------------------------------------------------
sum(100): 5050
...
sum(100000000): 5000000050000000

real    0m30.397s
user    0m29.799s
sys     0m0.126s

---------------------------------------------------
JavaScriptCore
---------------------------------------------------
sum(100.0): 5050.0
...
sum(100000000.0): 5.00000005e+15

real    0m7.685s
user    0m7.468s
sys     0m0.081s
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The floats you see in the JavaScript version are because JavaScript only
has floats.  Well, kind of.  One of the things I learned was that JavaScriptCore
actually internally supports 31-bit (or so) integers as well 
(as &lt;a href="http://en.wikipedia.org/wiki/Tagged_pointer"&gt;tagged pointers&lt;/a&gt;).
I suspect the conversion to float in this case happened when I converted to
a string at the end.

&lt;p&gt;Another interesting factoid I discovered, not having used &lt;tt&gt;eval()&lt;/tt&gt;
much in JavaScript:

&lt;blockquote&gt;
&lt;pre&gt;
eval("{a:1; b:2}") == 2
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Can you see why?  Here's a 
&lt;a href="https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Statements/Label"&gt;hint&lt;/a&gt;.
The correct syntax for what I had &lt;i&gt;intended&lt;/i&gt; was:

&lt;blockquote&gt;
&lt;pre&gt;
eval("({a:1, b:2})")
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Usual caveats apply; early code, it uses ctypes so will occaisonally go 
all &lt;tt&gt;Bus error&lt;/tt&gt;-y on ya if you're sloppy, not many diagnostics, etc.   
Only
runs on Mac OS X, as that's the only place I know of that has a separate
JavaScriptCore library.  But good news is, you just need the &lt;tt&gt;nitro_pie.py&lt;/tt&gt;
file, because you already have JavaScriptCore and Python installed.

&lt;p&gt;I also belatedly discovered that Apple already ships JavaScriptCore bindings
for Python, which you can get by doing an &lt;tt&gt;import&amp;nbsp;JavaScriptCore&lt;/tt&gt;
But that's
only the raw bindings, which doesn't take too long to implement - making them
usable is the real work here.

&lt;p&gt;So now that I've got this beast, it's probably time to start playing 
with the 
&lt;a href="https://wiki.mozilla.org/ServerJS"&gt;ServerJS&lt;/a&gt; stuff again, 
especially since no one else was looking at JavaScriptCore.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-4941206980563517461?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/wX13JN5NfYw" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4941206980563517461?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4941206980563517461?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/wX13JN5NfYw/nitropie.html" title="nitro_pie" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2009/04/nitropie.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcGQnw9cCp7ImA9WxVaF0o.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-1015954277026266906</id><published>2009-04-15T01:20:00.002-04:00</published><updated>2009-04-15T01:23:43.268-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-15T01:23:43.268-04:00</app:edited><title>shiny simian scripts</title><content type="html">&lt;p&gt;We know them as &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/748"&gt;Greasemonkey Scripts&lt;/a&gt;, but in &lt;a href="http://www.aaronboodman.com/2009/04/content-scripts-in-chromium.html"&gt;Aaron Boodman's recent blog post&lt;/a&gt;, he says the new name may be &lt;i&gt;"Content Scripts"&lt;/i&gt;. Kinda boring.  How about &lt;i&gt;Slick Gorilla Scripts&lt;/i&gt;? &lt;i&gt;Shiny Simian Scripts&lt;/i&gt;?  Ach, "Content Scripts" sound pretty good I guess.

&lt;p&gt;Aaron's post is chock full of meaty information; looks really good from 50K feet.  Nice to see multiple files will be supported, including .css and resources like images.

&lt;p&gt;I still use Greasemonkey for a few scripts I've written, but found the environment a bit limiting to get into it too deeply. Debugging was difficult, installation/deployment a bit unwieldy. And of course the endless issues having to do with writing screen scrapers, reacting to changes in your target's pages. I tried writing a few scripts for the Moz-based browser on my N800, which supports a flavor of GreaseMonkey via an system-installable update, but that was really painful.  I hope we see a simpler workflow for developing these extensions, eventually.

&lt;p&gt;The reason I'm so interested in this stuff is that I think user-scriptability provides a big paradigm shift. Much like writing editor macros for emacs or XEDIT or similar, it transforms an already powerful and useful tool into an extendable one. If you combine this sort of extensibility with the ability to publish/deploy and install these extensions easily, you have an actual platform on your hands.

&lt;p&gt;It's easy to imagine, for instance, the sort of "content scripting" you could do, might subsume the whole "mashup" scenario; kind of flip it on it's head.  Instead of having to host an environment to pull and push content from other environments, you can do it right from the primary content site.

&lt;p&gt;Eventually this drives us to the point where the web applications we use are actually installed (ok, cached) on our machines, as extensions, and just push and pull data via HTTP/XMPP/whatever to data/service servers as needed.  Of course, we've had a good 15 years of being able to do this, in theory, and are still stuck with icky, unusuable web sites that trap our data behind inscrutable wads of HTML.  But things seem to be changing for the better here, over time; REST and all.

&lt;p&gt;Something like Giles Bowkett's &lt;a href="http://gilesbowkett.blogspot.com/2009/04/miniapp-hacker-newspaper.html"&gt;Hacker Newspaper&lt;/a&gt; could just be an extension, instead of having to be a 'site' with a 'server'.  Who wants to deal with that junk?

&lt;p&gt;Beyond all the content scripting stuff, Aaron also mentioned: &lt;i&gt;"There is a team in Chromium working on an out-of-process version of the web inspector."&lt;/i&gt;  This is great news. WebKit's Web Inspector is quite useful, but as an "in browser" debugger, it is also clearly totally unsuited for debugging on small devices. You know, like all those devices that are using WebKit?  An external debugger is required for such situations.  Something like &lt;a href="http://trac.webkit.org/wiki/Drosera"&gt;Drosera&lt;/a&gt;. Both modes of debugging are nice to have - in browser and external; I want them both.

&lt;p&gt;All GREAT stuff.  Of course all of this is for Chrome, and not for WebKit.  Which makes you start to wonder how we can get all this stuff into WebKit so all the WebKit consumers will have access.  Either that, or start considering Chromium to be a platform to consume instead of WebKit.  If these Chrome extensions heavily depend on things not already in WebKit, like V8, the multi-process model, etc, there would be even more reason to consider Chromium as the lower level platform rather than just WebKit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-1015954277026266906?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/LUcE7vHhzRY" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/1015954277026266906?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/1015954277026266906?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/LUcE7vHhzRY/shiny-simian-scripts.html" title="shiny simian scripts" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2009/04/shiny-simian-scripts.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkICQnc5fip7ImA9WxVaF0s.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-2209190044696355972</id><published>2009-04-14T21:50:00.001-04:00</published><updated>2009-04-14T21:56:03.926-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-14T21:56:03.926-04:00</app:edited><title>ordered javascript properties</title><content type="html">&lt;p&gt;So all this time, I believed what I had read regarding the ordering
of properties when enumerating JavaScript 
objects with the &lt;tt&gt;for...in&lt;/tt&gt; statement, with this being a typical description:

&lt;blockquote&gt;&lt;i&gt;A for...in loop iterates over the properties of an object in an arbitrary order.&lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;That's from the
&lt;a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/for...in"&gt;Mozilla Developer Center&lt;/a&gt;
JavaScript reference.

&lt;p&gt;Turns out that's not quite true.  See John Resig's blog post
&lt;a href="http://ejohn.org/blog/javascript-in-chrome/"&gt;"JavaScript in Chrome"&lt;/a&gt;, 
and scroll down to the section &lt;i&gt;"for loop order"&lt;/i&gt;.  In particular, John writes:
&lt;i&gt;"All modern implementations of ECMAScript iterate through object properties 
in the order in which they were defined. Because of this the Chrome team has deemed 
this to be a bug and will be fixing it."&lt;/i&gt;  Follow the links to the bugs John points
out in his blog post for more discussion.

&lt;p&gt;I couldn't resist trying this out myself, so created a little test case, 
&lt;a href="http://pmuellr.bingodisk.com/public/ordered-javascript-properties.html"&gt;here&lt;/a&gt;.
WebKit Nightlies and FireFox 3.0 behave the same for all the cases, but Opera 9.23
acts a little differently in one of the cases.

&lt;p&gt;John makes a couple of points I can't agree with, in his comments in the 
&lt;a href="http://code.google.com/p/chromium/issues/detail?id=883#c12"&gt;Chromium bug that he referenced&lt;/a&gt;.

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;i&gt;The specification does not define how an implementation should handle it -
therefore an implementation should conform with other implementations.&lt;/i&gt;
&lt;p&gt;What?  How does not having an explicit definition in the spec imply that all implementations
should conform with each other?

&lt;li&gt;&lt;p&gt;&lt;i&gt;The argument that they're doing it to "keep the engine fast and lean" is bogus.
There are two other, faster, ECMAScript engines out there: SquirrelFish and TraceMonkey and
they both implement the looping indentically.&lt;/i&gt;
&lt;p&gt;John is referencing a previous comment which claimed that V8 did not respect the 
'definition order' because doing so could impact memory usage and/or peformance.  But the
rationale John makes is that since there are two faster engines which DO implement
the 'definition order', the memory/performance rationale is bogus.  Which makes
no sense of course.  I would imagine the typical implementation of 'definition order'
would trade space over speed, so you could make the property access "fast enough" by 
spending some additional space to maintain the order as well as the presumably
speedy hash access.  Complete guess on my part.  But to me, it's hard to imagine
that implementing 'definition order' isn't going to cost you SOMEWHERE, over
not implementing it.  I'm cheap, I don't like to pay for things I don't need.

&lt;/ul&gt;

&lt;p&gt;So not only was I surprised by the property ordering, I'm kind of sad because
it means JavaScript has some built-in waste for a feature few objects will probably
ever need.  Kind of like Java's monitors in every object.  Ah well.

&lt;p&gt;A few folks pointed out to me that upcoming EcmaScript standards would likely
standardize on this ordering behavior.  While it's difficult (for me anyway) to
track down EcmaScript standard stuff, I did find 
&lt;a href="http://wiki.ecmascript.org/doku.php?id=es3.1:es3.1_proposal_working_draft"&gt;this set of drafts&lt;/a&gt;
which seemed ... recent ... and looking at the "23 Feb 2009" version, you can see
phrases like 
&lt;i&gt;"An ECMAScript object is an unordered collection of properties"&lt;/i&gt;
(page 14) have been changed to
&lt;i&gt;"An ECMAScript object is a collection of properties"&lt;/i&gt;.
Hardly a ringing endorsement of defined property ordering, but a step in
that direction, no doubt.

&lt;p&gt;So, I guess change is coming.  Next question, how can we make use of this?

&lt;p&gt;One thought is with JSON.  Typically with JSON you think of object definitions
with key/value properties, all defined "at once".  Meaning things like "streaming"
JSON objects don't really make sense.  Only now, maybe it kinda does.  
Or you could do something like add a property to an object first, called
something like &lt;tt&gt;"__type__"&lt;/tt&gt; which would provide some shape information, which a 
serializer could make use of, because it would see that before other properties.

&lt;p&gt;That's nice.  And is fairly logical.  But the memory/performance impact 
will probably always bug me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-2209190044696355972?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/ISVmo_zOS-g" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2209190044696355972?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2209190044696355972?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/ISVmo_zOS-g/ordered-javascript-properties.html" title="ordered javascript properties" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2009/04/ordered-javascript-properties.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYGSXo9cCp7ImA9WxVUE0Q.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-6078922302607813046</id><published>2009-03-18T11:26:00.001-04:00</published><updated>2009-03-18T11:28:48.468-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-18T11:28:48.468-04:00</app:edited><title>new job: WebKit</title><content type="html">&lt;div&gt;
 
&lt;p&gt;Well, it's nearly Spring, which means, for me, a new job.  Right?
Seems that way, looking back over the last few years.  I've had some difficulty
carving out some space for myself in the groups I worked with, what with the
great talent already working there.  Many chefs in the kitchen and all that.&lt;/p&gt;

&lt;p&gt;For this new job, I'm on my own, at least within IBM.  I'm now IBM's 
"&lt;a href="http://webkit.org"&gt;WebKit&lt;/a&gt; Center of Competency" person.  
Officially, what I put on my Moo cards and in the corporate directory was 
"WebKit Stuff".
&lt;/p&gt; 

&lt;p&gt;What does that mean?  Not sure yet.  But apparently WebKit is interesting
enough now, that my bosses thought someone should focus on it full time.  I
guess I kinda helped out there, having sent various notes over the years,
to my new bosses, that said things like "Why aren't we doing anything with WebKit?!?"
My new
bosses are Dave Boloker, and his boss is Rod Smith.  I've moved over from
Rational to the Emerging Technologies group.&lt;/p&gt;

&lt;p&gt;There is some ongoing work in Emerging Technologies that is very much 
browser-centric, and so I'm going to be hearing this week what they're up to,
and to see what I can do to help.  Beyond that, my assumption is that in the
future we'll have more folks needing to integrate with WebKit in various ways,
so I'll start laying some groundwork for IBMers to help make that a little 
easier.&lt;/p&gt;

&lt;p&gt;Beyond that, I'm particularly interested in focusing on JavaScript, and
making JavaScript developers' lives better.  My secret dream is to make
the browser a better Smalltalk than Smalltalk.  You gotta have a dream.
&lt;/p&gt;

&lt;p&gt;I was ecstatic to hear that my management expects me to be contributing code
back to WebKit.  One thing I haven't 
done in IBM is any open source contribution.  There's clearly no better way to learn
a code base than to have to tinker with it, and then submit that to public
shaming.&lt;/p&gt;

&lt;p&gt;So all in all, this is really shaping up to be a great job for me; 
subject matter that deeply interests me, the open source angle, and
of course the fact that it's a scary huge mound of mainly C++ code that I'm completely
unfamiliar with.  What more could you ask for?&lt;/p&gt;

&lt;p&gt;I'm definitely a little bummed that I won't have a chance to work with  
&lt;a href="http://rollerweblogger.org/roller/entry/joining_ibm"&gt;Dave Johnson&lt;/a&gt;,
who will be starting a job with Rational at IBM at the end of the month.
It's a small world though - I think Dave will be sitting next to me, and 
will be taking a spot on the Rational CTO team, which is the team I just left.&lt;/p&gt;

&lt;p&gt;I'll also be a little bummed if something were to happen to one of my 
new Emerging Technology teammates, 
&lt;a href="http://intertwingly.net/blog/2009/03/03/Interesting-Times"&gt;Sam Ruby&lt;/a&gt;.
&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-6078922302607813046?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/DF6QNoOxi6k" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/6078922302607813046?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/6078922302607813046?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/DF6QNoOxi6k/new-job-webkit.html" title="new job: WebKit" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2009/03/new-job-webkit.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MDQHc-fSp7ImA9WxVWFkg.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-5148837001048720003</id><published>2009-02-26T08:36:00.001-05:00</published><updated>2009-02-26T08:37:51.955-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-26T08:37:51.955-05:00</app:edited><title>size matters</title><content type="html">&lt;div&gt;

&lt;p&gt;Fellow IBMer Bob Blainey recently posted a blog entry 
"&lt;a href="http://bblainey-a.blogspot.com/2009/02/are-you-pakled.html"&gt;Are you a Pakled?&lt;/a&gt;"
which touched on software bloat.
This is a subject near and dear to my heart, burned into me after
spending a good five years or so in the embedded software space.
&lt;/p&gt;

&lt;p&gt;At the time, the devices that we were targeting would typically have something
like 2MB ROM and 2MB RAM available.  Think of the ROM like hard drive space,
and the RAM is the memory in a computer today.  We worked with devices
that had less memory, sometimes, and near the end of my run, worked with devices that
had much more memory available.  But the 2/2 story was sort of the rule
of thumb.&lt;/p&gt;

&lt;p&gt;That's not a lot of space, so you worry about every byte.  You worry about
every new library that you need to add to your runtime.  Not just in terms of
it's disk footprint, which ate ROM, but the runtime footprint, which
ate RAM.  There were always hilarious situations where we'd be talking
to product groups with no embedded experience, where they'd die laughing
when we told them their library had to fit in 10K bytes; or 
it would be us laughing when they
told us their runtime &lt;i&gt;only&lt;/i&gt; required 1MB of RAM.&lt;/p&gt;

&lt;p&gt;If you enjoy the "solving puzzles" aspect of software development, this
is just an additional challenge on top of all the other challenges, which
made it, for me, a terribly fun working experience.&lt;/p&gt;

&lt;p&gt;You can imagine the "sticker shock" that hit me, when my first position
after leaving the embedded world, involved J2EE.  Whoa.  And the sticker shock 
continues to this day, in every new piece of work I'm involved in.  But it's
not just me; most of my colleagues back in the embedded days seem to 
experience this sticker shock in their day-to-day jobs, which is something
that I think most developers just don't think very much about.
Like the kid in "The Sixth Sense", we see bloat - everywhere.&lt;/p&gt;

&lt;p&gt;It's heartening to see the resurgence in interest in embedded development,
in places like the iPhone and Android, since I hope this means we'll be seeing a lot more folks
taking an interest in software bloat.&lt;/p&gt;

&lt;p&gt;Aside: the Pakleds, referenced in Bob's post, were one of the most memorable races for me in the Star Trek series,
but I wasn't able to find any video clips from the show.  I did find a
&lt;a href="http://pmuellr.bingodisk.com/public/Pakleds.mp3"&gt;little audio clip&lt;/a&gt; 
though; this is Riker asking a Pakled what they need.&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-5148837001048720003?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/2aEmNy5B0Bc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/5148837001048720003/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=5148837001048720003" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5148837001048720003?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5148837001048720003?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/2aEmNy5B0Bc/size-matters.html" title="size matters" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/02/size-matters.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UCQXoyeyp7ImA9WxVWFk0.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-5538787081354912319</id><published>2009-02-25T18:35:00.001-05:00</published><updated>2009-02-25T18:41:00.493-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-25T18:41:00.493-05:00</app:edited><title>web ui progress</title><content type="html">&lt;div&gt;
 
&lt;p&gt;The hotness of the day (well, yesterday) appears to be video at 
&lt;a href="http://280atlas.com/"&gt;280atlas.com&lt;/a&gt;
(permalink at Viddler
&lt;a href="http://www.viddler.com/explore/boucher/videos/1/"&gt;here&lt;/a&gt;).
It's technically very impressive.  But I'm also a bit saddened.
I worked on similar technology 15 years ago, for desktop applications.
You know what I'm talkin' 'bout.  I won't say the word.&lt;/p&gt;

&lt;p&gt;Sad because, even 15 years ago, web browsers were around, in some state.
Why has it taken this long for things to progress this far?  It's nuts.
Seems like a lost decade, to me.  Of course, 
it's not like we were even really innovating in this space, 
back then, either.  
&lt;a href="http://en.wikipedia.org/wiki/Interface_Builder"&gt;Interface Builder&lt;/a&gt;
goes back even further.
&lt;/p&gt;

&lt;p&gt;Feh, always with the rock throwing.  So let me shine a little brightness, as well.&lt;/p&gt;

&lt;p&gt;First and foremost, hats off to the folks at
&lt;a href="http://280north.com/"&gt;280north.com&lt;/a&gt;.  Getting all this to work
on the clumsy web browsers we use today is surely no small feat.  It looks gorgeous.
The layering is interesting, built on
&lt;a href="http://cappuccino.org/"&gt;Cappuccino and Objective-J&lt;/a&gt;.  Stuff to
look into.&lt;/p&gt;

&lt;p&gt;Two things I saw in the demo that I liked, in terms of UI constructs:
"Layout Support" and "Split Views".&lt;/p&gt;  

&lt;p&gt;The "Layout Support" appears to be similar to what we used to call "Form attachments",
back in the day, that allowed you to specify
how widgets were attached to things - other widgets, parents, etc - and how
they would resize.  Ours 
were based on 
&lt;a href="http://lesstif.sourceforge.net/Lessdox/XmForm.html"&gt;Motif's XmForm&lt;/a&gt;
constraint resources.  (Aside: isn't it hilarious that the first reference
I found to XmForm was in the lesstif online doc?)  Although kind of crazy complicated, and really easy
to screw up when you were coding by hand, and requiring you implement a 
constraint solver IIRC,
you could do some incredible
stuff in terms of making windows full of widgets which responded in a nice
way to resize requests.  And even just doing (non-absolute) layout by specifying which things
were next to other things, and letting the system figure everything out based
on default sizes.&lt;/p&gt;

&lt;p&gt;"Split Views" are similar to what we called "Split Panes" (think that's what we called them),
that were a late edition to our product, but to me added the 
last little bit of UI goodness for users.  Instead of providing either
fixed width, or perhaps proportional width child windows inside a parent,
Split Panes gave users the ability to resize those child windows as they
saw fit.
After they got added to the product, there was really not much else that I found
I needed, to be able to whip up a nice little UI with intelligently resizable
innards.  Separate the top level bits of a window into Split Panes, and
then layout those children using Form attachments, or perhaps recurse with
another Split Pane.&lt;/p&gt;

&lt;p&gt;Sure would be nice if these were native capabilities provided by our 
browsers.  CSS (and Tables!!) and Framesets just don't cut the mustard.
Ah, not to worry, we'll have a 
&lt;tt&gt;&amp;lt;video&amp;gt;&lt;/tt&gt; element we can use in our applications soon,
and that will more than make up for the lack of these other,
much less interesting capabilities.&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-5538787081354912319?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/dOmYGahdjAM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/5538787081354912319/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=5538787081354912319" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5538787081354912319?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5538787081354912319?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/dOmYGahdjAM/web-ui-progress.html" title="web ui progress" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/02/web-ui-progress.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YEQ3k5eSp7ImA9WxVWEEs.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-2626161985557345675</id><published>2009-02-19T11:28:00.002-05:00</published><updated>2009-02-19T11:31:42.721-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-19T11:31:42.721-05:00</app:edited><title>on bespin</title><content type="html">&lt;div&gt;

 &lt;div style='width:240; float:right; text-align:right; font-size:small; border-width:1px; border-color:#444444; border-style:none; padding:3px; margin-bottom:30px; margin-left:30px;'&gt;
 &lt;img width='240' height='160' alt='Millennium Falcon approaches Bespin Cloud City' src='http://farm4.static.flickr.com/3101/3240260379_bbe0114415_m.jpg'&gt;
 &lt;br/&gt;
 &lt;a href='http://flickr.com/photos/futursimple/3240260379/'&gt;Millennium Falcon approaches Bespin Cloud City&lt;/a&gt;
 &lt;br/&gt;&amp;copy;
 &lt;a href='http://flickr.com/people/futursimple'&gt;M&amp;deg; F&amp;deg;&lt;/a&gt;
 &lt;br/&gt;&lt;a href='http://creativecommons.org/licenses/by-nc/2.0/'&gt;&lt;img src='http://i.creativecommons.org/l/by-nc/2.0/80x15.png' title='used under a Creative Commons Attribution-NonCommercial License' width='80' height='15' border='0'/&gt;&lt;/a&gt;
 &lt;/div&gt;

&lt;p&gt;Could you have possibly missed the news on 
&lt;a href="http://labs.mozilla.com/projects/bespin/"&gt;Bespin&lt;/a&gt;,
a project from Mozilla Labs?  Don't see how.  But read up if you haven't.&lt;/p&gt;

&lt;p&gt;Bunch of rambling thoughts here:&lt;/p&gt;

&lt;ul&gt;
 
&lt;li&gt;&lt;p&gt;Also check out Sun's
&lt;a href="http://research.sun.com/projects/lively/"&gt;Lively Kernel&lt;/a&gt;.  In particular,
make sure you click on the "Development Tools" link (blue globe/basketball thing)
after you 
&lt;a href="http://research.sun.com/projects/lively/index.xhtml"&gt;"Enter the Lively Kernel"&lt;/a&gt;
to see their take on Smalltalk-like browsers for JS.
&lt;/p&gt;&lt;/li&gt;
 
&lt;li&gt;&lt;p&gt;Bespin works it's magic with HTML Canvas, Lively Kernel uses SVG.
Interesting, because these are two completely different low-level programming
models, though perhaps we'll end up seeing
widget toolkits built with both.
&lt;/p&gt;&lt;/li&gt;
 
&lt;li&gt;&lt;p&gt;Implementing text editors with HTML Canvas and SVG leads you into the
&lt;a href="http://billhiggins.us/weblog/2007/05/17/the-uncanny-valley-of-user-interface-design/"&gt;Uncanny Valley&lt;/a&gt;,
as such low-level things as clipboard operations, cursor movement, etc all have
to be implemented with user-land code.  Doesn't sound like a great proposition,
it's at least a crap-load of work to get all the expected text editing 
behaviors implemented.
&lt;/p&gt;&lt;/li&gt;
 
&lt;li&gt;&lt;p&gt;But you know what, I think Uncanny Valley may not really apply to text
editors.  I use a large number of text editors in my day-to-day computer
usage, and almost none of them are using any kind of a common "text editor
component".  Eclipse, TextMate, Notes, vi, etc.  You just have to get used
to them.  There are certainly programs I use that DO use a "system-level"
common text editor - in my case, the one Mac OS X provides.  Forms within
Safari, Twitterific, other apps presenting text areas, etc, all use the
baked in text editor control, which is nice, because I get the same kind of
spell checking, cursor movement, etc.  I think extending the usage out to 
"code" editing (eg, syntax highlighting) just isn't going to work though.  Or
let's say it hasn't happened yet.
&lt;/p&gt;&lt;/li&gt;
 
&lt;li&gt;&lt;p&gt;Although most of the focus on Bespin is on the browser bits, 
the impacts/opportunities for server bits isn't lost on
&lt;a href="http://wiki.eclipse.org/E4/Bespin"&gt;some&lt;/a&gt;
&lt;a href="https://twitter.com/trevoro/status/1206940105"&gt;people&lt;/a&gt;.
In fact, this may well be a more interesting piece; if you imagine an 
interesting set of back-end "IDE services" being defined for Bespin, why couldn't
desktop editors also take advantage of them?
&lt;/p&gt;&lt;/li&gt;
 
&lt;/ul&gt;

&lt;p&gt;May you live in exciting times.&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-2626161985557345675?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/Ws8-l7TKQUw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/2626161985557345675/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=2626161985557345675" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2626161985557345675?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2626161985557345675?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/Ws8-l7TKQUw/millennium-falcon-approaches-bespin.html" title="on bespin" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/02/millennium-falcon-approaches-bespin.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAEQX86eCp7ImA9WxVQGEU.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-824465991728623575</id><published>2009-02-05T21:14:00.001-05:00</published><updated>2009-02-05T21:18:20.110-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-05T21:18:20.110-05:00</app:edited><title>it's alive!  JavaScript modules</title><content type="html">&lt;p&gt;Less than a month ago, I posted one of my long-winded blog entries, the subject
being
"&lt;a href="http://pmuellr.blogspot.com/2009/01/javascript-modules.html"&gt;JavaScript Modules&lt;/a&gt;".
A week ago, Kevin Dangoor posted a blog entry titled
"&lt;a href="http://www.blueskyonmars.com/2009/01/29/what-server-side-javascript-needs/"&gt;What Server Side JavaScript needs&lt;/a&gt;".
One of the issues Kevin raised was:&lt;/p&gt;

&lt;p style='margin-left:3em'&gt;&lt;i&gt;JavaScript needs a standard way to include other 
modules and for those modules to live in discreet namespaces. There are easy 
ways to do namespaces, but there's no standard programmatic way to load a 
module (once!). This is really important, because server side apps can 
include a lot of code and will likely mix and match parts that meet those 
standard interfaces.
&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;Kevin's post led to the creation of the
&lt;a href="http://groups.google.com/group/serverjs"&gt;serverjs Google group&lt;/a&gt;
then a 
&lt;a href="https://wiki.mozilla.org/ServerJS"&gt;wiki&lt;/a&gt;
and an IRC channel on freenode - #serverjs.&lt;/p&gt;

&lt;p&gt;Well, yeeee haw!&lt;/p&gt;

&lt;p&gt;While Kevin's post is really aimed at server-side JavaScript, a lot of
the concepts he talks about are actually interesting to think about in 
the context of web browsers as well, as far as I'm concerned.  And I'm not alone.
There are also folks who don't give a flip about the browser and that's fine
too.
&lt;/p&gt;

&lt;p&gt;With regards to "modules", there is a proposal for something that's
pretty similar to what I blogged about, which I'm obvious partial to.
And there are other alternatives.  And spirited debate.  Come join 
the fun!&lt;/p&gt;

&lt;p&gt;Now there's talk of
&lt;a href="http://groups.google.com/group/serverjs/msg/bef448f3a776e633?hl=en"&gt;test cases&lt;/a&gt;.
Good lord!  In a week!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-824465991728623575?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/nZ8I06RlLYQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/824465991728623575/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=824465991728623575" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/824465991728623575?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/824465991728623575?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/nZ8I06RlLYQ/its-alive-javascript-modules.html" title="it's alive!  JavaScript modules" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/02/its-alive-javascript-modules.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0AGRn4yeyp7ImA9WxVSFk4.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-4609425538155641219</id><published>2009-01-10T16:58:00.001-05:00</published><updated>2009-01-10T18:55:27.093-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-10T18:55:27.093-05:00</app:edited><title>spring break in canada?</title><content type="html">&lt;div&gt;

&lt;div style='width:240; float:right; text-align:right; font-size:small; border-width:1px; border-color:#444444; border-style:solid; padding:3px; margin-bottom:30px; margin-left:30px;'&gt;
&lt;img width='240' height='180' alt='snowed in' src='http://farm1.static.flickr.com/17/21844570_266891b26c_m.jpg'&gt;
&lt;br/&gt;
&lt;a href='http://flickr.com/photos/pmuellr/21844570/'&gt;snowed in&lt;/a&gt;
&lt;br/&gt;&amp;copy;
&lt;a href='http://flickr.com/people/pmuellr'&gt;Patrick Mueller&lt;/a&gt;
&lt;br/&gt;&lt;a href='http://creativecommons.org/licenses/by-nc-sa/2.0/'&gt;&lt;img src='http://i.creativecommons.org/l/by-nc-sa/2.0/80x15.png' title='used under a Creative Commons Attribution-NonCommercial-ShareAlike License' width='80' height='15' border='0'/&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;My wife has this bizarre problem.  She likes snow.  Apparently, it's
genetic, as my children suffer from this as well.  Despite the fact that
we sometimes get deluged with snow (per the included image), most of the
time, we get nothing, or not enough to count.&lt;/p&gt;

&lt;p&gt;I've suggested to my wife several times that we should take a vacation
in Canada some time; I hear they got lots of the white stuff up there.
She's taking me seriously now; desperation is setting in, it appears.&lt;/p&gt;

&lt;p&gt;The current thought on time frame is
spring break, which for us falls at the beginning of April.  Seems pretty
dicey to me as to whether they'll still be any snow around by then.&lt;/p&gt;  

&lt;p&gt;I've been to
&lt;a href="http://www.tremblant.ca/index.htm"&gt;Mont Tremblant&lt;/a&gt;
and
&lt;a href="http://www.fairmont.com/montebello/"&gt;the big log cabin at Montebello&lt;/a&gt;,
for "work related meetings",
both of which are the kind of thing I'm thinking about, though I'm guessing
more expensive than I'd like.&lt;/p&gt;

&lt;p&gt;Any suggestions from the lazy web?&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-4609425538155641219?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/-94PwL5LaYY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/4609425538155641219/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=4609425538155641219" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4609425538155641219?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4609425538155641219?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/-94PwL5LaYY/spring-break-in-canada.html" title="spring break in canada?" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/01/spring-break-in-canada.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04ARnk8eyp7ImA9WxVSFEU.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-4226987403281345781</id><published>2009-01-09T01:03:00.001-05:00</published><updated>2009-01-09T01:19:07.773-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-09T01:19:07.773-05:00</app:edited><title>JavaScript modules</title><content type="html">&lt;!--
&lt;style&gt;
pre, xmp {
    border-color:       #CBCBCB;
    background:         #FFF8ED;
    color:              #000000;
    overflow:           auto;
    border-width:       1px;
    border-style:       dotted;
    padding-top:        0.4em;
    padding-bottom:     0.4em;
    padding-left:       1.4em;
    padding-right:      1.4em;
    margin-left:        1.4em;
    margin-right:       1.4em;
}
&lt;/style&gt; 
--&gt;

&lt;div&gt;
 
&lt;p&gt;When I see code like this,
&lt;a href="http://developer.yahoo.com/yui/examples/layout/adv_layout.html"&gt;an example I pulled from YUI&lt;/a&gt;, 
I simply want to cry.  Things need not be so ugly.  I don't mean to callout
Yahoo here, it's just an example I found.  Most of the non-trivial
'package-ized' JavaScript I see is like this.&lt;/p&gt;

&lt;p&gt;Issues:&lt;/p&gt;

&lt;ul&gt;
 
&lt;li&gt;&lt;p&gt;Everyone of these files is a single anonymous top-level function that
is invoked to execute it at the bottom of the file.  Icky.  Why do we need this?&lt;/p&gt;
&lt;p&gt;This is done because the method of compositing function into your 
application is done by including the source of that function into the
big, single namespace known as your JavaScript environment.  To
keep from having source you are compositing into your app not "infect"
it with additional global variables, you use the trick of putting all your
code in a function body and executing it.  The function can be (and should
be) anonymous.  No infection, or controlled infection, as long as you use var 
on all your variables
(argh), as the variables at the top level of the function are local to the
function, and not the "environment" (basically, globals). 
&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;We have functions defined in functions defined in functions here,
two levels of which are asynchronous callbacks.&lt;/p&gt;
&lt;p&gt;I don't have a big beef with nested functions, except when it gets 
silly.  Like, in this case. One of the big offenders is definition of the
&lt;tt&gt;loader&lt;/tt&gt; function, whose purpose is to load the code, pre-reqs,
etc, defined as callbacks presumably because the loading of such
files isn't necessarily provided as a synchronous capability from
the browser.&lt;/p&gt;  
&lt;/li&gt;

&lt;li&gt;&lt;p&gt;I bet the folks that wrote this had editor macros set for the text
&lt;tt&gt;YAHOO.example.app&lt;/tt&gt;&lt;p&gt;
&lt;p&gt;Frankly, there's no defense for this; the code should probably be using
"shortcut" variables for the "package names", and even just some of the
functions, like &lt;tt&gt;YAHOO.log&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;I assume there is some kind of taboo over using shortcut variables here;
or are people depending on fully qualified function names for code completion
or other source analysis tools?  Yikes.&lt;/p&gt;
&lt;/li&gt;
 
&lt;/ul&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;How can we make this nicer looking?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I think we need a better way of packaging up the pieces of our composite
applications.&lt;/p&gt;

&lt;p&gt;Packages.  Modules.  Bundles.  Whatever.&lt;/p&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;Google Gears WorkerPools, again&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I've previously blogged about 
&lt;a href="http://pmuellr.blogspot.com/2008/11/javascript-service-frameworks.html"&gt;using Google Gears Worker Pools to build service frameworks&lt;/a&gt;.
For certain types of functionality, this makes a lot of sense.  
It certainly has the characteristic of compositing function into your
application in a clean, infection-free manner.  But it also
has the following characteristics:&lt;/p&gt;

&lt;ul&gt;
 
&lt;li&gt;&lt;p&gt;All message sense are asynchronous.  While this sort of programming
style might be comfortable to some people, and in fact might be the best
way to program in the end, it's not terribly friendly for most programmers
who have been using mostly/only synchronous function calls their entire programming
life.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Out of the box, you're always going to be 'sending messages'
instead of 'calling functions'.There's technically not much of a distinction between sending a message and
a function invocation, you might say, besides the invocation style of the
two.  But again, for most programmers, function invocation is
the norm.  And probably requires less syntax per invocation.
Shorter programs == good.&lt;/li&gt;
 
&lt;/ul&gt;

&lt;p&gt;So while I don't have any problem with WorkerPools per se, and in fact,
I think they are a great pattern for handling asynchronous, parallel work,
they also aren't really going to provide the best pattern for modularity.&lt;/p&gt;

&lt;p&gt;But I &lt;b&gt;really&lt;/b&gt; love the 
&lt;a href="http://code.google.com/apis/gears/api_workerpool.html#isolation"&gt;cleanliness aspect&lt;/a&gt;.&lt;/p&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;So here is what I want&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://docs.python.org/tutorial/modules.html"&gt;Python modules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And here's the thing.  I think we can add support for this fairly unobtrusively.&lt;/p&gt;

&lt;p&gt;The basic idea is to define a new function, say &lt;tt&gt;loadModule()&lt;/tt&gt; which
is used to 'reference' another module by passing it's name
as a parameter (URI to the name, prolly).  A module is just a JavaScript file.
Only instead of working the way &lt;tt&gt;&amp;lt;script&amp;nbsp;src=""&amp;gt;&lt;/tt&gt; does,
it actually defines a new separate, empty namespace and loads the 
JavaScript into that namespace (just like the way Google Gears WorkPools does).
The process of running &lt;tt&gt;loadModule()&lt;/tt&gt; on a module the first time is that
the JavaScript source is executed.  The object returned is a 'module' object,
whose propertes include all the global variables in the module's private
namespace.  For &lt;tt&gt;loadModule()&lt;/tt&gt; calls with the same module beyond the first, 
the code is not
executed again, but the same 'module' object is returned.
&lt;/p&gt;

&lt;p&gt;Or other varieties thereof.  It's fairly simple to play with this kind
of stuff from with 
&lt;a href="http://www.mozilla.org/rhino/"&gt;Rhino&lt;/a&gt;,
though your brain will be hurting after getting all the prototype and
context linkages set up right.
I assume you can do this sort of multi-environment stuff in other 
JavaScript implementations.&lt;/p&gt;

&lt;p&gt;I want it in the browser.&lt;/p&gt;

&lt;p&gt;This isn't the kind of code you can write in userland JavaScript,
because JavaScript doesn't give you low-level access to it's innards.
Needs to be yet another function the browser injects into
the JavaScript environment, probably not even implemented in JavaScript,
but in C, C++, Java, etc.&lt;/p&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;What changes&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;This makes individual JavaScript files a little cleaner by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not requiring the anonymous function wrapper.&lt;/li&gt;
&lt;li&gt;Letting you get away with making your namespace a mess without worrying
about infecting someone else's namespace.&lt;/li&gt;
&lt;li&gt;Letting you use shorter names, because imports beyond the first
are crazy cheap, so every module would probably just import everything
they needed as one-level modules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sure would be nice if we could make that &lt;tt&gt;loadModule()&lt;/tt&gt; function 
synchronous, otherwise &lt;tt&gt;loadModule()&lt;/tt&gt; would really have to be a function
which took the URI to the module and a callback, and invoked the callback
after the module load.  Back into some ickys-ville.  Is 
&lt;tt&gt;&amp;lt;script&amp;nbsp;src=""&amp;gt;&lt;/tt&gt; synchronous?&lt;/p&gt;

&lt;p&gt;It's not a lot.  But it's a start.&lt;/p&gt;
 
&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;Additional advantages&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;It's easy to imagine that the process of reloading a module which
has changed (you just edited it while you were debugging) would be a little
more straight-forward; largely only the module itself is affected, though
presumably there are some imported object references that would also need to be 
fixed up (using short-cut variables causes issues here - is that one of
the reason the Yahoo example used fully-qualified names?).  Some 
lower-level VM help
could get even those references fixed up, I'm thinking.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Better than &lt;tt&gt;eval()&lt;/tt&gt;.  Yeah, you could code something up
to do this using &lt;tt&gt;eval()&lt;/tt&gt;, I suppose.  Or get close.  The
problem with &lt;tt&gt;eval()&lt;/tt&gt; is the code becomes disassociated from it's source
location.  This makes it difficult/impossible to debug.  Or save, after
I make my changes in the debugger (some day).  With an import story, the
original location of the source can be associated with the code, just like
all the files &lt;tt&gt;&amp;lt;script&amp;nbsp;src=""&amp;gt;&lt;/tt&gt;'d into your page get
associated with their source location.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;You could imagine the keeping byte- or machine-code versions of those
modules, in their pre-executed state, cached in memory for future 
interpreter invocations that imported the module.  And cached on disk.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;As a simple function, you can imagine have embellished versions that
handled things like version numbering, pre-reqs, etc.
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;Example&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I coded up an implementation of &lt;tt&gt;loadModule()&lt;/tt&gt; for Rhino tonight, along
with a simple example that 
uses four modules:&lt;/p&gt;

&lt;!-- ============================== --&gt;
&lt;p&gt;&lt;tt&gt;main.js:&lt;/tt&gt;&lt;/p&gt;

&lt;pre style="margin-left:3em"&gt;&lt;code&gt;
&lt;span style="color: #000;"&gt;print&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #F39;"&gt;"loading&amp;nbsp;module:&amp;nbsp;"&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;+&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;__FILE__&lt;/span&gt;&lt;span style="color: #000;"&gt;)

&lt;/span&gt;&lt;span style="color: #000;"&gt;abc&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;=&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;loadModule&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #F39;"&gt;"abc.js"&lt;/span&gt;&lt;span style="color: #000;"&gt;)
&lt;/span&gt;&lt;span style="color: #000;"&gt;def&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;=&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;loadModule&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #F39;"&gt;"def.js"&lt;/span&gt;&lt;span style="color: #000;"&gt;)

&lt;/span&gt;&lt;span style="color: #000;"&gt;abc&lt;/span&gt;&lt;span style="color: #000;"&gt;.&lt;/span&gt;&lt;span style="color: #000;"&gt;sayHello&lt;/span&gt;&lt;span style="color: #000;"&gt;()
&lt;/span&gt;&lt;span style="color: #000;"&gt;def&lt;/span&gt;&lt;span style="color: #000;"&gt;.&lt;/span&gt;&lt;span style="color: #000;"&gt;sayHello&lt;/span&gt;&lt;span style="color: #000;"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;!-- ============================== --&gt;
&lt;p&gt;&lt;tt&gt;abc.js:&lt;/tt&gt;&lt;/p&gt;

&lt;pre style="margin-left:3em"&gt;&lt;code&gt;
&lt;span style="color: #000;"&gt;print&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #F39;"&gt;"loading&amp;nbsp;module:&amp;nbsp;"&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;+&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;__FILE__&lt;/span&gt;&lt;span style="color: #000;"&gt;)

&lt;/span&gt;&lt;span style="color: #000;"&gt;sayer&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;=&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;loadModule&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #F39;"&gt;"sayer.js"&lt;/span&gt;&lt;span style="color: #000;"&gt;)

&lt;/span&gt;&lt;span style="color: #00C;"&gt;function&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;sayHello&lt;/span&gt;&lt;span style="color: #000;"&gt;()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;sayer&lt;/span&gt;&lt;span style="color: #000;"&gt;.&lt;/span&gt;&lt;span style="color: #000;"&gt;say&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #F39;"&gt;"hello"&lt;/span&gt;&lt;span style="color: #000;"&gt;)
}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;!-- ============================== --&gt;
&lt;p&gt;&lt;tt&gt;def.js:&lt;/tt&gt;&lt;/p&gt;

&lt;pre style="margin-left:3em"&gt;&lt;code&gt;
&lt;span style="color: #000;"&gt;print&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #F39;"&gt;"loading&amp;nbsp;module:&amp;nbsp;"&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;+&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;__FILE__&lt;/span&gt;&lt;span style="color: #000;"&gt;)

&lt;/span&gt;&lt;span style="color: #000;"&gt;sayer&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;=&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;loadModule&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #F39;"&gt;"sayer.js"&lt;/span&gt;&lt;span style="color: #000;"&gt;)

&lt;/span&gt;&lt;span style="color: #00C;"&gt;function&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;sayHello&lt;/span&gt;&lt;span style="color: #000;"&gt;()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;sayer&lt;/span&gt;&lt;span style="color: #000;"&gt;.&lt;/span&gt;&lt;span style="color: #000;"&gt;say&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #F39;"&gt;"world"&lt;/span&gt;&lt;span style="color: #000;"&gt;)
}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;!-- ============================== --&gt;
&lt;p&gt;&lt;tt&gt;sayer.js:&lt;/tt&gt;&lt;/p&gt;

&lt;pre style="margin-left:3em"&gt;&lt;code&gt;
&lt;span style="color: #000;"&gt;print&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #F39;"&gt;"loading&amp;nbsp;module:&amp;nbsp;"&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;+&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;__FILE__&lt;/span&gt;&lt;span style="color: #000;"&gt;)

&lt;/span&gt;&lt;span style="color: #00C;"&gt;function&lt;/span&gt;&lt;span style="color: #000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;say&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #000;"&gt;message&lt;/span&gt;&lt;span style="color: #000;"&gt;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000;"&gt;print&lt;/span&gt;&lt;span style="color: #000;"&gt;(&lt;/span&gt;&lt;span style="color: #000;"&gt;message&lt;/span&gt;&lt;span style="color: #000;"&gt;)
}
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;!-- ============================== --&gt;

&lt;p&gt;Each module prints a line indicating it's being loaded; the environment
I set up defines the &lt;tt&gt;__FILE__&lt;/tt&gt; variable containing the module source file name
(my C roots are showing),
and a &lt;tt&gt;print()&lt;/tt&gt; function which prints a line to stdout.&lt;/p&gt;

&lt;p&gt;&lt;tt&gt;main.js&lt;/tt&gt; loads two modules, &lt;tt&gt;abc.js&lt;/tt&gt; and &lt;tt&gt;def.js&lt;/tt&gt;.
It then calls 
the &lt;tt&gt;sayHello()&lt;/tt&gt; function in the &lt;tt&gt;abc&lt;/tt&gt; module,
followed by 
the &lt;tt&gt;sayHello()&lt;/tt&gt; function in the &lt;tt&gt;def&lt;/tt&gt; module.&lt;/p&gt;

&lt;p&gt;&lt;tt&gt;abc.js&lt;/tt&gt; and &lt;tt&gt;def.js&lt;/tt&gt; are identical, except for the message
printed from the &lt;tt&gt;sayHello()&lt;/tt&gt; function at the bottom of the file.
Both modules load the &lt;tt&gt;sayer.js&lt;/tt&gt; module.  They also both define
a function with the same name - &lt;tt&gt;sayHello()&lt;/tt&gt; - but that's ok
because they live in separate namespaces and can be accessed separately
by code that imports them, like &lt;tt&gt;main.js&lt;/tt&gt; does above.&lt;/p&gt;

&lt;p&gt;&lt;tt&gt;sayer.js&lt;/tt&gt; defines a &lt;tt&gt;say()&lt;/tt&gt; function prints a string 
(my REXX roots are showing).&lt;/p&gt;

&lt;p&gt;Here's the output of running the main.js module:&lt;/p&gt;

&lt;pre style="margin-left:3em"&gt;
loading module: main.js
loading module: abc.js
loading module: sayer.js
loading module: def.js
hello
world
&lt;/pre&gt;

&lt;p&gt;The output shows that the code in &lt;tt&gt;sayer.js&lt;/tt&gt; is only executed
once, like with Python modules; subsequent imports just return the module
reference which was built during the first import.&lt;/p&gt;

&lt;p&gt;The source for the Java code to run this is available here:
&lt;a href="http://muellerware.org/hg/org.muellerware.jsml/"&gt;http://muellerware.org/hg/org.muellerware.jsml/&lt;/a&gt;;
it's an Eclipse project stored in an hg repository.&lt;/p&gt;
 
&lt;p&gt;There are really only two Java files used for this, if you just want to peek at the code:
&lt;a href="http://muellerware.org/hg/org.muellerware.jsml/raw-file/6fa8b9268386/src/org/muellerware/jsml/Main.java"&gt;&lt;tt&gt;Main.java&lt;/tt&gt;&lt;/a&gt;
and
&lt;a href="http://muellerware.org/hg/org.muellerware.jsml/raw-file/6fa8b9268386/src/org/muellerware/jsml/ModuleLoader.java"&gt;&lt;tt&gt;ModuleLoader.java&lt;/tt&gt;&lt;/a&gt;.
&lt;/p&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;Why don't we have something like this in the browser?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Frankly, after spending a very small amount of time implementing the
basic functionality, I have to wonder why we don't have something like this
in the web browsers today?  We have 
&lt;a href="http://www.w3.org/TR/XMLHttpRequest/"&gt;XMLHttpRequest&lt;/a&gt;
to programmatically fetch data, why don't we have a way of programmatically
fetching and executing code?  &lt;tt&gt;&amp;lt;script&amp;nbsp;src=""&amp;gt;&lt;/tt&gt; is a sorry excuse of
a version of this.  Let me code it, dammit!&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-4226987403281345781?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/FTvjmx9UzeQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/4226987403281345781/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=4226987403281345781" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4226987403281345781?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4226987403281345781?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/FTvjmx9UzeQ/javascript-modules.html" title="JavaScript modules" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/01/javascript-modules.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4NRXg8cCp7ImA9WxVSEk8.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-4327568302878261942</id><published>2009-01-06T01:30:00.002-05:00</published><updated>2009-01-06T01:56:34.678-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-06T01:56:34.678-05:00</app:edited><title>gpx and exif</title><content type="html">&lt;div&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;Using a GPS&lt;/b&gt;&lt;/p&gt;
 
&lt;p&gt;We got our first GPS last Christmas, in preparation for our trip to Ireland
in the spring (awesome trip, BTW).  That was a Garmin n&amp;uuml;vi 270, which is the basic hardware
device preloaded with maps of the US and Europe.  Buying a device without the
Europe maps, and then adding them back would have been a little more expensive.
The device was quite useful on the trip.  
&lt;/p&gt;

&lt;p&gt;As I'm a man, I've had more need for the device than my wife, and I had
been leaving it in my car.  So for my birthday this year, my wife got me a
basic device, the Garmin n&amp;uuml;vi 205.  She wanted 'hers' back.
When I started hiking a bit more this
fall, I took it with me on the hikes, because it sucks to get lost.  I could
also kinda figure out where I was based on the shape of the track the 
device was generating,
compared to maps showing trails.&lt;/p&gt;

&lt;p&gt;The big problem with taking a n&amp;uuml;vi hiking is that the battery only
lasts 4-5 hours.  It never ran out, but came close a few times.  Another 
problem people may have with older devices is that they don't seem to have the
nice tracking function that is really what you want in the device, to show
you visibly where you've been on the map.  Our one year old n&amp;uuml;vi 270
doesn't do the tracking thing, near as I can tell.  Lastly, it's not terribly
convenient to slip into your pocket; it has a very sensitive touch screen and
a easily switched on/off switch at the top.  I found an old Palm Pilot
leather case, with a hard 'front side' to prevent accidental
touches through the case, that ended up being a perfect fit
(saving $20 or on the Garmin case; I'm a pack-rat), but still a tight
fit for the pocket, and you have to slip it in and out the case just so.&lt;/p&gt;

&lt;p&gt;For Christmas, my wife ended up getting me a Garmin eTrex Venture
HC, which is the basic GPS hiking model.  The maps, compared to the 
n&amp;uuml;vi suck, but that's ok, even the default Garmin maps don't
include enough detail for hiking.  This device handles track data
much better than the n&amp;uuml;vi, in that you can pre-load a bunch
of tracks into the device and then display them while you're hiking.
I've got a bit of a long-winded procedure to generate tracks from
existing trail maps and Google Earth (see below), which then shows
me something close to the actual trails while I'm hiking.
&lt;/p&gt;

&lt;p&gt;Besides being used for live tracking, the other thing I've been wanting
to do is to correlate the pictures I've been taking while hiking with the
GPS, so that I can associate a fairly precise location with the pictures.
So that's how I spent a bit of my xmas break; writing that program.&lt;/p&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;What is GPX?&lt;/b&gt;&lt;/p&gt;
 
&lt;p&gt;GPX is a XML file that your Garmin device will poop out giving you a 
braindump of what it knows; "favorites" you've set up, track logs for where
you've been, etc.  The file format is described pretty well on 
&lt;a href="http://www.topografix.com/gpx.asp"&gt;this site&lt;/a&gt;.
The only thing I couldn't quickly figure out was the units for 
the elevation; meters.&lt;/p&gt;

&lt;p&gt;The GPX file will contain a list of points, where each
point has the following properties - latitude,
longitude, elevation, and time - which it collects every so often
(you can configure how often this happens).  Here's the GPX file from
my most recent hike to 
&lt;a href="http://www.triangleland.org/lands/tlc/white_pines_np_access.shtml"&gt;White Plains Nature Preserve&lt;/a&gt; -
&lt;a href="http://muellerware.org/kml/White-Pines-Nature-Preserve.gpx"&gt;http://muellerware.org/kml/White-Pines-Nature-Preserve.gpx&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Actually, getting that GPX file can be a little tricky.  You'll need to
connect your GPS device to your computer, and for Garmin use the software
they provide on a CD to pull the GPX file out, or for the Mac use
&lt;a href="http://www8.garmin.com/macosx/"&gt;RoadTrip&lt;/a&gt;.  For RoadTrip,
I always create a new folder for each GPX file I want to create, copy just
the stuff I want from the "most recent import" (or whatever), and then 
export that folder, which exports it to a GPX file with the same name as
the folder.  A bit non-intuitive, but you'll figure it out.&lt;/p&gt;

&lt;p&gt;Once you have the GPX file, you can open it directly in Google Earth.
Google Maps doesn't appear to directly eat GPX files, but will eat
KML files, and you can easily convert a GPX file to a KML file using the
&lt;a href="http://www.gpsbabel.org/"&gt;&lt;tt&gt;gpsbabel&lt;/tt&gt;&lt;/a&gt; program.&lt;/p&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;What is EXIF?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;EXIF is a standard for metadata embedded in image files.  The site
&lt;a href="http://www.exif.org/"&gt;http://www.exif.org/&lt;/a&gt; explains all, 
I guess.  The spec is a bit dry.  All sorts of metadata can get added
to images by your camera, including all the camera settings used
when the picture was takem, model information, and for this purpose,
GPS information.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.flickr.com/photos/pmuellr/3164787237/meta/"&gt;Here&lt;/a&gt; 
is an example of the sorts of information that gets stored as EXIF data
for a photo.&lt;/p&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;Two great tastes ...&lt;/b&gt;&lt;/p&gt;
 
&lt;p&gt;So, now that we have a bunch of images, and a GPX file, it's a 
&lt;a href="http://en.wikipedia.org/wiki/Small_matter_of_programming"&gt;SMOP&lt;/a&gt;
to get the time of the photo, calculate the GPS coordinates given
that time, and then stamp them back into the photo.&lt;/p&gt;

&lt;p&gt;It looked to be a difficult slog to deal with the EXIF data myself, so some
reading quickly led me to the
&lt;a href="http://www.sno.phy.queensu.ca/~phil/exiftool/"&gt;&lt;tt&gt;exiftool&lt;/tt&gt;&lt;/a&gt;
program which can do all manner of slicing and dicing of EXIF data for
your images.&lt;/p&gt;

&lt;p&gt;The program I wrote reads in the GPX file, and then for every image
pulls out the time the photo was taken with &lt;tt&gt;exiftool&lt;/tt&gt;, and calculates the GPS coordinates
for that photo, stamping that data back into the image with &lt;tt&gt;exiftool&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;The program, &lt;tt&gt;gpx2exif&lt;/tt&gt;, is housed here: 
&lt;a href="http://muellerware.org/hg/gpx2exif/"&gt;http://muellerware.org/hg/gpx2exif/&lt;/a&gt;,
is written in Python, may required version 2.5 or above, and also requires that you
have &lt;tt&gt;exiftool&lt;/tt&gt; installed.&lt;/p&gt;

&lt;p&gt;In addition to stamping the images with GPS data (actually, creating new copies of the
images with the GPS EXIF data), it also creates a KML file you can load into
Google Earth to 'test' the locations that got stamped.  In case your camera's
clock is not synchronized to the GPS (hint, hint).  If your times are off,
read the &lt;tt&gt;exiftool&lt;/tt&gt; help, there's a way to adjust the times of your photos in
one swell foop.&lt;/p&gt;

&lt;p&gt;Once you've got the GPS data stamped in your images, sites like Flickr
and Picasa will show you "map" versions of your sets, and do other stuff
with the geo data.  The map view for my White Pines set at Flickr is
&lt;a href="http://www.flickr.com/photos/pmuellr/sets/72157612129287858/map/"&gt;here&lt;/a&gt;
and the map view for the same set at Picasa is
&lt;a href="http://picasaweb.google.com/pmuellr/200812WhitePines/photo#map"&gt;here&lt;/a&gt;.
&lt;/p&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;What's next&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Turns out you can do all sorts of interesting analysis of the data
in the GPX file, like:

&lt;ul&gt;
&lt;li&gt;calculate distance travelled&lt;/li&gt;
&lt;li&gt;calculate speed&lt;/li&gt;
&lt;li&gt;figure out when you stopped for a break&lt;/li&gt;
&lt;li&gt;plot data onto Google Maps or Google Earth&lt;/li&gt;
&lt;li&gt;generate elevation maps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should be able to do all this stuff in a web browser, in fact,
by writing the analysis code in JavaScript.  Given that you can access
Flickr cross-site via their 
&lt;a href="http://www.flickr.com/services/api/response.json.html"&gt;'JSONP'-ish support&lt;/a&gt;,
associating photos with the GPS data is something you can also probably
do in the browser.  We'll see.  I'm a little worried that the number of
data points and expensive math required will be a bit much for normal
JavaScript processing; I may need to use a Google Gears worker to
offload some of that processing.
&lt;/p&gt;

&lt;!-- ===================================================================== --&gt;
&lt;p&gt;&lt;b&gt;Notes&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;tt&gt;exiftool&lt;/tt&gt; rocks; I was was happy to not have to deal with reading/writing
EXIF data myself.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;My camera stores times in "local" format.  Would have been nice
if it used UTC.  Do any cameras do this?  I made an assumption that
the camera, and computer you are running &lt;tt&gt;gpx2exif&lt;/tt&gt; on, are running
at the same local time.  Again, use &lt;tt&gt;exiftool&lt;/tt&gt; to "fix"
this, if it's wrong.&lt;/p&gt;

&lt;li&gt;&lt;p&gt;I still can't figure out the secret to the &lt;tt&gt;findall()&lt;/tt&gt; method
&lt;a href="http://docs.python.org/library/xml.etree.elementtree.html"&gt;ElementTree&lt;/a&gt;.  bugger.
Seems like a great API, I just can't use it.  The XML processing wasn't that
complex, so 
&lt;a href="http://docs.python.org/library/xml.dom.minidom.html"&gt;minidom&lt;/a&gt;, 
which I'm very familiar with, was fine.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Neither Flickr nor Picasa will do anything with your EXIF GPS data unless
you specifically tell them to; presumably for privacy reasons.  For
Flickr, the setting is 
&lt;a href="http://www.flickr.com/account/?tab=privacy"&gt;here&lt;/a&gt;;
for Picasa, the setting is 
&lt;a href="http://picasaweb.google.com/lh/settings"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The resulting map views from Flickr and Picasa aren't terribly pleasing
to me; in fact, the KML "test" file I produce from &lt;tt&gt;gpx2exif&lt;/tt&gt; is
way more interesting.  I think because you can see the actual trail,
but also the markers I used (default ones) work better than thumbnails
that Picasa uses, and the markers used by Flickr can't be disambiguated
when they're too close, like they can in Google Earth.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;On the Garmin eTrex device, if you "save" a track that
you've made (hiked), it will strip the time values out.  Make
sure you export the track off the device before saving; the 
time values are (obviously) critical to determining the
locations for your photos.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;To pre-load a set of trails for a park onto the device, I do
the following.  Get a version of the trail maps (prolly from a PDF
from the park site) and convert to a JPG file.  Bring up Google Earth,
find the park, and add an image overlay for the image file you created;
set the transparency down so you can see the trails and Google Earth
detail.  Hopefully there's enough detail in the image, and Google Earth
so that you can move/resize the image overlay close enough.  Then
create some new line segments in Google Earth, tracing over the trails.
I couldn't figure out how to export those line segments directly out
of Google Earth, but if you "mail" the folder they are in to yourself,
you will get a KMZ file, which is just a zip file containing a KML file.
Garmin tools like RoadMap don't eat KML, but you can convert the 
KML to a GPX using &lt;tt&gt;gpsbabel&lt;/tt&gt;, and then import that.
Voil&amp;agrave;; trails to follow on my device.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;
When traveling long distances now, I've become completely dependent
on the GPS, and it's very nice to have when you're not on the
interstate.  In fact, I've been actively avoiding interstates as much
as I can now; traveling back roads through small towns is much more fun.
You basically don't have to keep track of where you are,
what roads you're on, where to turn, etc.  As long as you got
the destination plugged in right. And then I find myself racing against
the ETA the GPS displays prominently.
I called my wife at one point when I was coming home from hiking trip and
the conversation went something like this:&lt;/p&gt;

&lt;table&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;wife&lt;/b&gt;:&lt;/td&gt; &lt;td&gt;So, where are you?&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;me&lt;/b&gt;:&lt;/td&gt;   &lt;td&gt;I have no idea.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;wife&lt;/b&gt;:&lt;/td&gt; &lt;td&gt;Well, which way are you coming home?&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;me&lt;/b&gt;:&lt;/td&gt;   &lt;td&gt;I have no idea.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;wife&lt;/b&gt;:&lt;/td&gt; &lt;td&gt;I don't suppose you know when you'll be getting home?&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;b&gt;me&lt;/b&gt;:&lt;/td&gt;   &lt;td&gt;4:37&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/p&gt;&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/22367266-4327568302878261942?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/tNV_pwjnn2U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/4327568302878261942/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=4327568302878261942" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4327568302878261942?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4327568302878261942?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/tNV_pwjnn2U/gpx-and-exif.html" title="gpx and exif" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/01/gpx-and-exif.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkQBQ3s_fCp7ImA9WxRbEkU.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-2998624753316652508</id><published>2008-12-02T23:58:00.000-05:00</published><updated>2008-12-02T23:59:12.544-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-02T23:59:12.544-05:00</app:edited><title>more android thoughts</title><content type="html">&lt;div&gt;

&lt;p&gt;I remember right when Android came out, I downloaded the SDK and tried
playing with it, and there was some kind of silly show-stopping problem with
it on the Mac.  
&lt;a href="http://pmuellr.blogspot.com/2007/11/initial-android-thoughts.html"&gt;Thoughts from then&lt;/a&gt;, 
just a little under a year ago.
IIRC, the bug got fixed fairly quickly, but not quick enough for me
to get a chance to get back to looking at it in any depth.  A long time goes by, and right before
this Thanksgiving, I got the urge to look at it again, so I did.  Here are some 
unorganized thoughts.&lt;/p&gt;

&lt;p&gt;Note that I still didn't really spend a lot of time with it; the time I spent
probably raised more questions than it answered, in a good way.
I did the obligatory HelloWorld demo, the
&lt;a href="http://code.google.com/android/intro/tutorial.html"&gt;Notepad tutorial&lt;/a&gt;,
and lots of browsing and reading in between.&lt;/p&gt;

&lt;p&gt;Please comment if I misspeak about something; lots of guessing and
incomplete research on my part here (this thing is big!).&lt;/p&gt;

&lt;!-- ================================================ --&gt;
&lt;p&gt;&lt;b&gt;Wow.  Lots of stuff here.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Hats off to the team.  This thing is huge, and seems fairly well put
together, especially considering the size.  The 
&lt;a href="http://source.android.com/"&gt;source&lt;/a&gt; takes up 1.4GB on disk; Linux
and WebKit and on and on and on.  It's fun just to 
&lt;a href="http://android.git.kernel.org/"&gt;troll around the source directories&lt;/a&gt; 
to see what's there.  But I recommend 
&lt;a href="http://source.android.com/download"&gt;downloading the wad&lt;/a&gt; 
and browsing with your usual editors/tools.&lt;/p&gt;

&lt;!-- ================================================ --&gt;
&lt;p&gt;&lt;b&gt;Rev 1&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;So sure, maybe it's not as sexy and polished as the iPhone, and
sure the devices got shipped with a 
&lt;a href="http://www.linuxdevices.com/news/NS2714843045.html"&gt;silly little bug&lt;/a&gt;,
but I'm willing to forgive early releases.  Given the scope
of the effort, again, I think they've done a great job.  It's early
days.&lt;/p&gt;

&lt;p&gt;But I'm also not willing to shell
out my own pocket money for a rev 1 device or o/s.
Just like I (no longer) buy rev 1 Apple products or immediately
install new versions of OS X.
Tired of playing pioneer.&lt;/p&gt;

&lt;p&gt;I guess I'm most worried about the potential immaturity of the
application and UI frameworks.  Usually good frameworks require evolution,
and I've used lots of "intelligently designed" frameworks over the years, so I'm a bit
of a doubter when I see a new one pop up overnight.  Might be interesting
to get some background on them, kinda like 
&lt;a href="http://research.google.com/pubs/papers.html"&gt;Google has done with BigTable&lt;/a&gt;
and some of their other technologies.&lt;/p&gt;

&lt;p&gt;Here's an example worry: the 
&lt;a href="http://android-developers.blogspot.com/2008/12/touch-mode.html"&gt;Touch Mode&lt;/a&gt;
blog post has me a bit confused.  Touching the screen causes selection
and focus to be lost?  eh?  I've been using my finger on PDA touch screens
since the Palm.  I'm used to touching the screen causing selection and focus
events &lt;b&gt;to&lt;/b&gt; occur, not to be lost.  I'm either not understanding what's going on here, or 
this seems wrong.  And here's a funny little note:  
&lt;i&gt;"This is why some developers are confused when they create a custom view and start 
receiving key events only after moving the trackball once: their application is in touch mode, 
and they need to use the trackball to exit touch mode and resurrect the focus."&lt;/i&gt;
Um, developers are confused?  I think users will be confused by this also,
won't they?  I'll give them the benefit of the doubt here, I'd like to 
see how well this works on an actual device before passing judgement.
Lastly, I'm glad to see that the
&lt;a href="http://dev.eclipse.org/newslists/news.eclipse.platform.swt/msg18842.html"&gt;wiggly mouse&lt;/a&gt;
is back - it's been years!  The referenced mail doesn't go into details,
but I've been dealing with self-inflicted wiggly mouse problems since the
Smalltalk days.  Those were due to bugs though, not design.&lt;/p&gt;

&lt;!-- ================================================ --&gt;
&lt;p&gt;&lt;b&gt;Devices other than the T-Mobile G1?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I kinda hate to even provide the link the
aurally offensive 
&lt;a href="http://www.t-mobileg1.com/"&gt;T-Mobile G1 site&lt;/a&gt;,
but I'll let you feel my pain.&lt;/p&gt;

&lt;p&gt;So what other devices are going to be available?  More phones, I guess,
but I wonder if anyone will do a non-phone version, like Apple's iPod Touch?
I'm currently not willing to pay the data charges for presumably light 
bandwidth usage (over cell); I'm too much of a cheapskate and live fine
with my cheapo phone.  But I'm more than willing to carry a device I can
connect to wifi.&lt;/p&gt;

&lt;p&gt;I didn't see much (any?) information on any newer devices coming out,
which is a bit worrisome.  Before spending a significant amount of time 
playing with this, I'd like to know this thing has a future.  It 
&lt;i&gt;seems&lt;/i&gt; like a no-brainer to me that device manufacturers would take
advantage of Android (many caveats apply), but I'm not willing to bet on
common sense.&lt;/p&gt;

&lt;!-- ================================================ --&gt;
&lt;p&gt;&lt;b&gt;How would you do a port something like the Nokia N800?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;In lieu of new devices, what about porting to existing devices, like
(my) 
&lt;a href="http://www.nseries.com/products/n800/"&gt;Nokia N800&lt;/a&gt;?  Or say, a 
netbook?&lt;/p&gt;

&lt;p&gt;Turns out folks &lt;b&gt;have&lt;/b&gt; ported Android to the N800; see
&lt;a href="http://elinux.org/Android_on_OMAP"&gt;here&lt;/a&gt; and
&lt;a href="http://moblog.net/view/847397/android-on-the-n800-now-with-apps-and-keyboard"&gt;here&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;It appears what these folks have done is ported the entire stack to the
device, starting with Linux.  Youch.  More what I was thinking was porting
the minimum number of things to be able to run Android apps on it somehow.
Basically, get something like the emulator running as a native app on the
device, as an application container.  I don't really feel the need to either blow away my existing
device, or run another Linux on top of (beside?) it.  And I'd be willing to
live with having to run Android apps in a container, instead of as native
apps themselves.&lt;/p&gt;

&lt;p&gt;We did this sort of thing back when we were working on embedded Java;
we had a MIDP environment that could run on the native operating system,
with the UI layer (for instance) implemented in SWT.  In fact, I assumed
this was probably how the emulator that ships with the 
&lt;a href="http://code.google.com/android/documentation.html"&gt;Android SDK&lt;/a&gt;
was implemented, but it slowly dawned on me that it's actually running
the entire stack, from Linux up, in a virtualization environment of some
kind.  Wowsa.  That's why it takes 23 seconds for the emulator to start
up.&lt;/p&gt;

&lt;p&gt;To implement an emulator for Android, you need to decide how low-level
access you want to support.  And the answer is obviously: the "Java" code
that you use to write applications.  All I'd want to do is run existing
apps, which can only (?) access "Java" APIs, so &lt;i&gt;all&lt;/i&gt; you have to do
is have a matching set of Java APIs that do the right thing on the
platform (note the 'all' is italicized).&lt;/p&gt;

&lt;p&gt;In terms of implementation, since this is, really, Java source, you
could (?) just run the apps in plain old Java.  Alternatively, if you didn't
have a Java available, you could port the Dalvik VM, and run it that way.
&lt;/p&gt;

&lt;p&gt;For the N800, there is a Java available (I've not tried it); it's a
J2ME flavor, so may not be enough anyway.  Might be better off porting
the Dalvik VM, then porting the UI bits to Hildon/GTK/whatever; the N800 is
already running Linux, so presumably other natively accessed things
would have a bit of hope of running out of the box (but not camera,
GPS, etc).  Webkit's got me nervous.&lt;/p&gt;

&lt;p&gt;Lots and lots of caveats here, and it's entirely possible that for some
reason or another, you really, really need that Linux kernel to even run
the plain ole "Java" applications.&lt;/p&gt;

&lt;!-- ================================================ --&gt;
&lt;p&gt;&lt;b&gt;Java&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;So I'll admit Java isn't my first choice for a language on a device
like this.  I like the option of 
&lt;a href="http://pymaemo.garage.maemo.org/"&gt;Python on Maemo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But I can live with Java on a constrained device like this; I wasn't
unhappy doing embedded Java years ago.  One of my pain points 
with Java is the sheer bulk of crap needed to get anything done, 
pulling in, eventually, loads of Apache and Eclipse projects to do some 
heavy lifting for you.  The nice thing here, everything is included, or 
seems to be.  But even we if end up needing more stuff (why do I even
bother saying "if"), we're talking about a constrained device here, where
you'll get laughed at if you want to install a 1MB library to pull in some
function.  People will have to learn how to write small code.  Forced sanity.&lt;/p&gt;

&lt;!-- ================================================ --&gt;
&lt;p&gt;&lt;b&gt;Scripting?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Mark Murphy's blog post on 
&lt;a href="http://androidguys.com/?p=647"&gt;using Java-based scripting languages on Android&lt;/a&gt;
sums up the major points, especially as to language implementations that generate Java byte
code directly; those will be a problem, and I think that affects a number of the interesting
scripting languages.  Presumably, someday you'll be able to generate and load Dalvik
bytecode in Android.  Maybe there will be a way to load Java bytecode and have it
internally generate creamy Dalvik output automagically.  Many possibilities.&lt;/p&gt;

&lt;p&gt;But I wonder how appropriate scripting languages would be anyway?  I've
written about
&lt;a href="http://pmuellr.blogspot.com/2006/08/scripting-languages-in-java.html"&gt;this&lt;/a&gt;
&lt;a href="http://pmuellr.blogspot.com/2007/01/interop-not.html"&gt;before&lt;/a&gt;.
If my option is to write Java code, or to write Java code in a Python dialect,
I'll just stick to Java.
&lt;/p&gt;

&lt;!-- ================================================ --&gt;
&lt;p&gt;&lt;b&gt;JavaScripting&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Of course there's always JavaScript available, either in the native
browser via web applications, or in some other way through the use of the
&lt;tt&gt;&lt;a href="http://code.google.com/android/reference/android/webkit/WebView.html"&gt;WebView&lt;/a&gt;&lt;/tt&gt;
UI View class.  And check out this interesting looking method, in that class:
&lt;tt&gt;&lt;a href="http://code.google.com/android/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object,%20java.lang.String)"&gt;WebView.addJavascriptInterface()&lt;/a&gt;&lt;/tt&gt;.
hmmm ...&lt;/p&gt;
 
&lt;!-- ================================================ --&gt;
&lt;p&gt;&lt;b&gt;Dalvik docs&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Some Dalvik docs like bytecode descriptions, file shapes, etc are available
&lt;a href="http://android.git.kernel.org/?p=platform/dalvik.git;a=tree;f=docs;h=f2fb051b2c110fc536a21d8c43f1cd0726294e27;hb=release-1.0"&gt;here&lt;/a&gt;.
Of course, almost no one needs this info, but in case you just had
to know ...&lt;/p&gt;

&lt;p&gt;I was a little surprised the Java-ness of Dalvik went so far as to support
JNI, but I guess that really makes a lot of sense.&lt;/p&gt;

&lt;!-- ================================================ --&gt;
&lt;p&gt;&lt;b&gt;Proprietary stuff&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;The 
&lt;a href="http://code.google.com/android/maps-api-signup.html"&gt;licensing situation with maps&lt;/a&gt;
is a little disconcerting, and at 
&lt;a href="http://code.google.com/android/maps-api-tos.pdf"&gt;11 pages&lt;/a&gt;, a bit long.  
But this feels a lot more like an application-level service than, say,
core infrastructure, and I'm fine with people setting limits on application services
like this.
Of course, the core infrastructure / application service line is a bit
fuzzy.  I use Google Maps a lot; it's starting to feel like core infrastructure.
Google's got us right where they want us!&lt;/p&gt;

&lt;!-- ================================================ --&gt;
&lt;p&gt;&lt;b&gt;How about a native desktop version?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Imagine something similar to Apple's Dashboard, only running Android applications.
You know I just want to start using that 
&lt;tt&gt;WebView.addJavascriptInterface()&lt;/tt&gt;
API on the desktop ...&lt;/p&gt;

&lt;p&gt;I had the same thoughts on MIDP, back in the day, 
of using it as a container for little useful desktop apps.  But that was
pretty silly, given the lameness of MIDP.&lt;/p&gt;

&lt;p&gt;Again, I think the nice way to do this
would be to run the apps "native" instead of in a virtualized Linux box.  
I think if you looked at some of the common componentry used in Android
and Chrome, you might end up thinking that being able to run Android apps in
Chrome would be an interesting idea.  
&lt;/p&gt;

&lt;p&gt;Now, you might say "the UI capabilities of Android are too lame to
be useful on a desktop!"
Thing is, I hear that
&lt;a href="http://daringfireball.net/linked/2008/12/01/fahey-bulk-rename-utility"&gt;complicated GUIs are on the outs&lt;/a&gt;.
Even &lt;a href="http://tomayko.com/writings/administrative-debris"&gt;on the internets&lt;/a&gt;!
I generally agree with those thoughts, and I have to admit, 
one of the most interesting UI's I've seen recently was 
&lt;a href="http://flickr.com/photos/marklarson/2687633368/"&gt;Muxtape&lt;/a&gt;
&lt;a href="http://en.wikipedia.org/wiki/Muxtape"&gt;(R.I.P.)&lt;/a&gt;; 
simple.&lt;/p&gt;

&lt;p&gt;Speaking of simple UIs, after watching 
&lt;a href="http://www.youtube.com/watch?v=YULCa3CUquM"&gt;this video discussing ListView&lt;/a&gt;,
I couldn't help but to think of our old, dear friend
&lt;a href="http://en.wikipedia.org/wiki/Gopher_(protocol)"&gt;Gopher&lt;/a&gt;
(&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=388195"&gt;R.I.P.&lt;/a&gt;?).
Once upon a time, I imagined having Gopher server interfaces on everything, so I 
could have a simple universal client that could talk to anything.  
Good times.&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-2998624753316652508?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/sqSav7Ewq_Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/2998624753316652508/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=2998624753316652508" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2998624753316652508?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2998624753316652508?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/sqSav7Ewq_Q/more-android-thoughts.html" title="more android thoughts" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2008/12/more-android-thoughts.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0ABSXs-cCp7ImA9WxRVFko.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-135708029757707757</id><published>2008-11-14T11:20:00.001-05:00</published><updated>2008-11-14T11:22:38.558-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-14T11:22:38.558-05:00</app:edited><title>javascript service frameworks</title><content type="html">&lt;div&gt;
 
&lt;p&gt;In my &lt;a href="http://pmuellr.blogspot.com/2008/11/brainwashed.html"&gt;&lt;i&gt;"brainwashed"&lt;/i&gt;&lt;/a&gt; post, I 
managed to get a diss in for 
&lt;a href="http://browserplus.yahoo.com/"&gt;Yahoo!'s BrowserPlus&amp;trade;&lt;/a&gt;,
calling it a band-aid.  However, I carefully, pro-actively covered my 
arse with an earlier Twitter message
&lt;i&gt;"Y! BrowserPlus&amp;trade; looks interesting; maybe the service framework moreso than the function provided"&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;The 
&lt;a href="http://browserplus.yahoo.com/developer/services/"&gt;existing services&lt;/a&gt; 
provided by BrowserPlus&amp;trade; seem like eye-candy.  Not sure I really need an IRC client in my web apps,
nor text to speech.  And I'm worried about the &lt;a href="http://browserplus.yahoo.com/support/#securityUpdates"&gt;kill switch&lt;/a&gt;.
Mainly because the implication is that I'm somehow always tethered in an uncacheable way to Yahoo!.  
&lt;i&gt;shiver&lt;/i&gt;
&lt;/p&gt;

&lt;p&gt;But I do like the
&lt;a href="http://browserplus.yahoo.com/developer/api/"&gt;service framework stuff&lt;/a&gt;.
At this point, don't really care how useful it is, glad to see people
playing in the space.  Why?&lt;/p&gt;

&lt;p&gt;The level of functionality we have today, provided by the browsers,
for components/modularity of javascript code is 
&lt;tt&gt;&lt;b&gt;&amp;lt;script&amp;nbsp;src=&amp;quot;&amp;quot;&amp;gt;&lt;/b&gt;&lt;/tt&gt;.  Basically,
all the power, flexibility, and functionality of the C preprocessor's
&lt;tt&gt;&lt;b&gt;#include&lt;/b&gt;&lt;/tt&gt; statement (good and bad).  But I'm looking at 
my calendar to see what year this is again.  Doh!&lt;/p&gt;

&lt;p&gt;The big JavaScript frameworks build their component stories on top of this,
and the whole thing just gives me the willies looking at it.
While I often wonder if JavaScript actually needs real structuring
capabilities in the language, like a &lt;b&gt;&lt;tt&gt;class&lt;/tt&gt;&lt;/b&gt; statement,
et al., I'm happy to try living without it, and try playing with
some other mechanisms.&lt;/p&gt;

&lt;p&gt;Java likewise has a crap component/modularity capabilities out of the box.
Jar files and class loaders.  OSGi plugs that hole.  JavaScript likewise
needs it's &lt;a href="http://www.theonion.com/content/node/90029"&gt;hole filled&lt;/a&gt;
(that link is sfw, I swear).
&lt;/p&gt;

&lt;p&gt;So let's start experimenting! Go, go Yahoo! BrowserPlus&amp;trade;!&lt;/p&gt;

&lt;b&gt;Could we do this with Google Gears WorkerPools?&lt;/b&gt;

&lt;p&gt;In my &lt;a href="http://pmuellr.blogspot.com/2008/09/fun-with-workerpools.html"&gt;&lt;i&gt;"fun with WorkerPools"&lt;/i&gt;&lt;/a&gt;
blog post from a while back, I wondered about building a service framework on top
of the 
&lt;a href="http://code.google.com/apis/gears/api_workerpool.html"&gt;WorkerPool bits&lt;/a&gt; 
from Google Gears.  Seems like building something similar to what BrowserPlus&amp;trade;
provides is pretty do-able.&lt;/p&gt;

&lt;p&gt;The great thing about the WorkerPool stuff is that it brings another
dimension to the JavaScript story - separate environments / contexts / spaces.
The ability to have a bunch of code running, separated into protected 
object spaces, with very explicit communication channels open between
these spaces.  The best you can do with 
&lt;tt&gt;&lt;b&gt;&amp;lt;script&amp;nbsp;src=&amp;quot;&amp;quot;&amp;gt;&lt;/b&gt;&lt;/tt&gt;
is namespacing via fixed name objects.  Ugly and unsafe.
I assume BrowserPlus&amp;trade; is doing the multi-context thing as well,
but I haven't looked close enough.
&lt;/p&gt;

&lt;p&gt;The other neat thing about Google Gears is that something like it
has leaked into the 
&lt;a href="http://www.whatwg.org/"&gt;WHATWG&lt;/a&gt; 
work, via a draft recommendation called
&lt;a href="http://www.whatwg.org/specs/web-workers/current-work/"&gt;Web Workers&lt;/a&gt;.
Meaning we may be able to do this in a browser-independent way
sometime around
&lt;a href="http://wiki.whatwg.org/wiki/FAQ#When_will_HTML_5_be_finished.3F"&gt;2022&lt;/a&gt;.
Or, our 
&lt;a href="http://www.google.com/chrome"&gt;Chrome&lt;/a&gt;
Overlords will render it moot, since Chrome already ships Google Gears.  Or all the
browsers 
&lt;a href="http://cruzapp.com/"&gt;will start shipping Gears&lt;/a&gt;.
Whatever.  Workers FTW!
&lt;/p&gt;

&lt;p&gt;So let's start experimenting! Go, go Google Gears WorkerPool-based service frameworks!&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-135708029757707757?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/sEVPhquy6ck" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/135708029757707757/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=135708029757707757" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/135708029757707757?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/135708029757707757?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/sEVPhquy6ck/javascript-service-frameworks.html" title="javascript service frameworks" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2008/11/javascript-service-frameworks.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4DRXg-eCp7ImA9WxRVFUg.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-6587499489741775836</id><published>2008-11-13T00:42:00.001-05:00</published><updated>2008-11-13T00:42:54.650-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-13T00:42:54.650-05:00</app:edited><title>hiking in the triangle</title><content type="html">&lt;div&gt;

 &lt;div style='width:240; float:right; text-align:right; font-size:small; border-width:1px; border-color:#444444; border-style:solid; padding:3px; margin-bottom:30px; margin-left:30px;'&gt;
 &lt;img width='240' height='180' alt='Stone Mountain State Park' src='http://farm4.static.flickr.com/3180/3008660851_739b59aeba_m.jpg'&gt;
 &lt;br/&gt;
 &lt;a href='http://flickr.com/photos/pmuellr/3008660851/'&gt;Stone Mountain State Park&lt;/a&gt;
 &lt;br/&gt;&amp;copy;
 &lt;a href='http://flickr.com/people/pmuellr'&gt;Patrick Mueller&lt;/a&gt;
 &lt;br/&gt;&lt;a href='http://creativecommons.org/licenses/by-nc-sa/2.0/'&gt;&lt;img src='http://i.creativecommons.org/l/by-nc-sa/2.0/80x15.png' title='used under a Creative Commons Attribution-NonCommercial-ShareAlike License' width='80' height='15' border='0'/&gt;&lt;/a&gt;
 &lt;/div&gt;

&lt;p&gt;I've been doing a fair amount of hiking around the area lately, for some reason.
Since it seems like there are a lot of folk unfamiliar with the fantastic parks available
in the triangle area, and North Carolina in general, thought I'd dump some information 
here.&lt;/p&gt;  

&lt;p&gt;&lt;b&gt;Local Hikes&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;For the hikes listed below, you won't need any special equipment to take a hike.
Outdoors-y clothes, something you'll be comfortable walking in
for a couple of miles (you're hiking!).  And sweating in.
Some kind of tennis shoes /sneakers.  Bug spray if it's a buggy season.  Sunscreen.
A hat?
And a bottle of water.  You'll be outside, walking around for an hour or two; use your head.&lt;/p&gt;

&lt;ul&gt;
 
&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.townofcary.org/depts/prdept/parks/hemlock.htm"&gt;Hemlock Bluffs Nature Preserve&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;This park is maintained by the Town of Cary, and is a little bit of forest in the southern end of the city,
right off of Kildaire Farm Road.  Just a couple of short paths through the woods, along side Swift Creek, with
some unexpected bluffs to overlook.  I don't
think any of the individual trails in the park are more than two miles.&lt;/p&gt;

&lt;p&gt;The Stevens Nature Center is co-located here which has some information on the park available in one of
the buildings at the park entrance.  They also hold 
&lt;a href="http://www.townofcary.org/depts/prdept/programs.htm"&gt;occasional classes&lt;/a&gt; 
on various topics, through the Town of Cary.
&lt;/p&gt;

&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.tlc-nc.org/lands/tlc/swift_creek_np.shtml"&gt;Swift Creek bluffs&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;A small park maintained by the Triangle Land Conservancy, off Holly Springs Road, between
Cary Parkway and Penney Road.  Admit it, you had no idea there was a park in 
that swampy-looking land, did you? 
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.ncparks.gov/Visit/parks/wium/main.php"&gt;William B. Umstead State Park&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Oddly enough, I haven't been there in years.  It's odd, because I drive by this park every day 
I drive to work; it's directly to the south of the airport, filling the area between I-40 on the west,
and US-70 on the east.  Joe Miller (see below) frequently writes about hiking, running, and biking
in the park.  Sounds great, and I feel like an idiot for not having visited in so long.
&lt;/p&gt;

&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.ncparks.gov/Visit/parks/raro/main.php"&gt;Raven Rock State Park&lt;/a&gt;&lt;/b&gt;
&lt;a href="http://www.flickr.com/photos/pmuellr/sets/72157600829495651/"&gt;[pix]&lt;/a&gt;
&lt;a href="http://www.flickr.com/photos/pmuellr/sets/72157607771976543/"&gt;[pix]&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;This is one of the family favorites.  The main attraction is Raven Rock itself, which is a rocky 
outcrop on the banks of the Cape Fear river.  Fairly simple hike to the river, then a set of stair
steps down &lt;b&gt;to&lt;/b&gt; the river.  Lots of rocks to climb on, for the kids.  The Raven Rock Loop Trail
is 2.6 miles.
&lt;/p&gt;

&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.ncparks.gov/Visit/parks/ocmo/main.php"&gt;Occoneechee Mountain State Natural Area&lt;/a&gt;&lt;/b&gt;
&lt;a href="http://www.flickr.com/photos/pmuellr/sets/72157608088823240/"&gt;[pix]&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;A small park in Hillsborough, bordering the Eno River.  While you can't get to the summit itself,
you can walk up to the second highest point, and around an old abandoned quarry with some resultant
man-made cliffs.  You can both look out over the cliffs, from above, then walk down to the Eno
River and get a view from below.  The eastern section of the Loop Trail is about two miles.
&lt;/p&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Less Local Hikes&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Listed here a couple of parks that aren't really local to the triangle, but close enough to
make a day trip.  I'm totally geared up when I go to one of these; boots, pack with bunch of crap
in it, staff, GPS, etc.  Though I've done some of the shorter hikes with the kids with just a 
bottle of water.&lt;/p&gt;  

&lt;p&gt;The paths marked on the trails as "strenuous" generally mean - lots of climbing - which usually
also means great views.  There will be lots of sweat.&lt;/p&gt;

&lt;p&gt;Do some research before you go.&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.ncparks.gov/Visit/parks/haro/main.php"&gt;Hanging Rock State Park&lt;/a&gt;&lt;/b&gt;
&lt;a href="http://www.flickr.com/photos/pmuellr/sets/72157607461576884/"&gt;[pix]&lt;/a&gt;
&lt;a href="http://www.flickr.com/photos/pmuellr/sets/72057594075755631/"&gt;[pix]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hanging Rock is the main draw here, a fairly easy hike with great views and some rock scrambling
when you get to the top.  Lots of people.
&lt;/p&gt;

&lt;p&gt;Moore's Wall Loop Trail takes you up a different mountain.  At the top is an observation deck with
fantastic views.  You can do a bit of rock scrambling at the top, and some points along the ridge.
Not many people.
&lt;/p&gt;

&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.ncparks.gov/Visit/parks/stmo/main.php"&gt;Stone Mountain State Park&lt;/a&gt;&lt;/b&gt; 
&lt;a href="http://www.flickr.com/photos/pmuellr/sets/72157608715790246/"&gt;[pix]&lt;/a&gt;
&lt;a href="http://www.flickr.com/photos/pmuellr/sets/998703/"&gt;[pix]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A big mound of granite that's pretty breath taking.  To see the view of the mountain, you'll have
to venture on the trail to Hutchinson Homestead, which is a pretty easy hike.  The hike up the
mountain is a different story.  There will be sweat.  They now have steps that take you almost the entire way up
the side of the mountain; not as fun as before they had the steps, but certainly a lot safer.
&lt;/p&gt;

&lt;p&gt;When I was up there last week, I met a 70 year old couple from Charlotte who hit the
mountain every year.  I can only hope to be so lucky.&lt;/p&gt;

&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.ncparks.gov/Visit/parks/crmo/main.php"&gt;Crowders Mountain State Park&lt;/a&gt;&lt;/b&gt; 
&lt;a href="http://www.flickr.com/photos/pmuellr/sets/72157608464845693/"&gt;[pix]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The main draw is Crowders Mountain; lots of people.  King's Pinnacle is just as nice, with much
fewer people.
&lt;/p&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Web Sites&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
 
&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.ncparks.gov/"&gt;North Carolina State Parks&lt;/a&gt; by NC Division of Parks and Recreation&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;This is a site maintained by the same folks who actually maintain the fantastic North Carolina state park system.
Information on all the parks and natural areas (what's the difference?) is provided, including maps
to the parks, maps of the facilities and trails in the parks, and other general information.
The maps are quite detailed, and are PDF versions of the slightly better quality print versions
of the maps available at the parks themselves.  You'll want to use the maps provided at the park,
while you're hiking,
because they are a bit larger than the print version, printed on nice heavy paper, pre-folded, and
have additional park information available on the flip side of the map.  But print one of the
PDF maps before you go, just in case they're out, or if you happen to go to part of a park
which doesn't have a maps kiosk or park station nearby.&lt;/p&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.tlc-nc.org/"&gt;Triangle Land Conservancy&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;You can read all about what the conservancy is about on their web site, but for purposes
of this blog post, their web site contains links to a couple of hikable areas that they 
provide access to.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.townofcary.org/tupage/recreation.htm"&gt;The Town Of Cary Cary Parks, Recreation &amp;amp; Cultural Resources Department&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Contains links to Cary's parks, trails and greenways.  
&lt;/p&gt;&lt;/li&gt;
 
&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://maps.google.com/maps?q=http://www.muellerware.org/projects/ncParksMap/ncParksMap.kml"&gt;North Carolina Parks - Google Maps&lt;/a&gt; by me&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;This is a crude "mashup" I wrote a while back, recently refurbished to fix some broken links.
It's a view of North Carolina in Google Maps, with a marker placed at all the state parks,
and a few other random parks I've added.
Clicking on a marker gives you a popup with a link to the park's web site, and the
current weather and coupla day forecast, with links to more detailed weather information.
A right click (if you're a righty) might bring up a context menu that offers to get
directions to the park from somewhere else, like your house.&lt;/p&gt;

&lt;p&gt;You can also load the park data into Google Earth, by using the &lt;i&gt;Add&lt;/i&gt; / &lt;i&gt;Network Link&lt;/i&gt;
menu item (on the Mac version anyway), and pasting the URL to the
&lt;tt&gt;KML&lt;/tt&gt; file into the &lt;i&gt;Link&lt;/i&gt; field: 
&lt;a href="http://www.muellerware.org/projects/ncParksMap/ncParksMap.kml"&gt;&lt;tt&gt;http://www.muellerware.org/projects/ncParksMap/ncParksMap.kml&lt;/tt&gt;&lt;/a&gt;.
Once you've added it to your &lt;i&gt;My Places&lt;/i&gt; list, you can use the context menu on the 
entry for the parks to refresh the data from the KML file (basically, the weather).  Of course,
Google Earth can show you the weather itself.  It can also show you pictures taken from within
the parks, links to Wikipedia entries, and so on.  Google Earth is a great way to get familiar with
the layout of the hilly parks, especially if you set "Elevation Exaggeration" to the maximum value of 3.
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Blogs&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
 
&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://blogs.newsobserver.com/joemiller/home"&gt;Get Out!  Get Fit!&lt;/a&gt; by Joe Miller&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Joe works for the Raleigh's 
&lt;a href="http://www.newsobserver.com/"&gt;News and Observer&lt;/a&gt; 
newspaper.  He authors a print column 
&lt;a href="http://www.newsobserver.com/437/index.html"&gt;"Take It Outside"&lt;/a&gt;,
which is also republished to the web.  He usually references his print columns
in his blog, so there's not much need to watch for the print columns.  Just
follow his blog instead.&lt;/p&gt;

&lt;p&gt;Joe covers all manner of outdoor activities, not just hiking, but he spends
quite a bit of time covering hiking and biking in North Carolina.  He has also
written a few books, which I'll reference below.
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Books&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
 
&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.amazon.com/100-Classic-Hikes-North-Carolina/dp/1594850542"&gt;100 Classic Hikes in North Carolina&lt;/a&gt; by Joe Miller&lt;/b&gt; - $16&lt;/p&gt;
&lt;p&gt;This is Joe's most recent book, and covers, as it claims, 100 hikes in North Carolina - east, west, north, south and in between.
He covers a lot of the state parks, so provides addition information over what's available on the state park's web site.  
In the Introduction, he discusses clothing and gear, though as I mention above, for 
short hikes, you won't need much.  It's a good introduction to other gear you might want to get though.
&lt;/p&gt;&lt;/li&gt;
 
&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="https://miva.nando.com/mm5/merchant.mvc?Screen=PROD&amp;amp;Store_Code=TNOS&amp;amp;Product_Code=BTIOM&amp;amp;Category_Code=B"&gt;Take It Outside: Hiking in the the Triangle&lt;/a&gt; by Joe Miller&lt;/b&gt; - $13&lt;/p&gt;
&lt;p&gt;This is Joe's earlier book, which covers hikes in the Triangle area of North Carolina.  Ten years old
but still relevant.  Simple hikes, places you should definitely check out because they're right
in your backyard, if you live here.
&lt;/p&gt;&lt;/li&gt;
 
&lt;/ul&gt;
&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-6587499489741775836?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/G3b5xNo1Hf4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/6587499489741775836/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=6587499489741775836" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/6587499489741775836?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/6587499489741775836?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/G3b5xNo1Hf4/hiking-in-triangle.html" title="hiking in the triangle" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2008/11/hiking-in-triangle.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcBRHYyfip7ImA9WxRVFUk.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-7728391921086502447</id><published>2008-11-12T22:20:00.001-05:00</published><updated>2008-11-12T22:30:55.896-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-12T22:30:55.896-05:00</app:edited><title>brainwashed</title><content type="html">&lt;div&gt;

&lt;p&gt;I remember reading 
Michael Lewis's
&lt;a href="http://en.wikipedia.org/wiki/Liar%27s_Poker"&gt;&lt;i&gt;"Liar's Poker"&lt;/i&gt;&lt;/a&gt;
back in the day, and enjoying it, so it's not a big surprise that I also enjoyed
reading 
his recent article on our financial crisis,
&lt;a href="http://www.portfolio.com/news-markets/national-news/portfolio/2008/11/11/The-End-of-Wall-Streets-Boom"&gt;&lt;i&gt;"The End"&lt;/i&gt;&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;But my reaction to the article is a little different than 
Tim Bray's 
&lt;a href="http://www.tbray.org/ongoing/When/200x/2008/11/11/Angry"&gt;&lt;i&gt;"Angry"&lt;/i&gt; blog post&lt;/a&gt;.
Anger is an understandable reaction; we've essentially been fleeced.  But when you get fleeced,
you have to realize that often &lt;b&gt;you&lt;/b&gt; walked right into the scam.  One of the people to be
angry at, is yourself.
&lt;/p&gt;

&lt;p style="font-size:large"&gt;&lt;b&gt;How did this happen?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;One word: brainwashing.  We all wanted to believe there really was a lot of
money to be made, that level of wealth building going on was somehow
sustainable, and that we could all be a part of it.
&lt;/p&gt;

&lt;div style='width:240; float:right; text-align:right; font-size:small; padding:3px; margin-bottom:30px; margin-left:30px;'&gt;
&lt;img border="0" src="http://farm4.static.flickr.com/3048/3025398461_1de783eb1f_m.jpg"&gt;&lt;br/&gt;
&lt;i&gt;DJIA from 1930 to today - &lt;a href="http://finance.yahoo.com/echarts?s=^DJI#chart2:symbol=^dji;range=my;indicator=volume;charttype=line;crosshair=on;ohlcvalues=0;logscale=off;source=undefined"&gt;link to live chart&lt;/a&gt;&lt;/i&gt;
&lt;/div&gt;

&lt;p&gt;But honestly, did you really believe your realtor when they told you the 
property prices in the neighborhood you bought into were appreciating 10% a
year, with no end in sight?  Does it really seem ok to spend $30,000 on
an automobile?  Can you really look at the historical record of the Dow Jones
Industrial Average from the 1930's to today, and say: &lt;i&gt;"I don't see anything abnormal"&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;We all wanted to believe, so ignored the signs, if we saw them at all.
Were there some bad apples out there?  Sure.  But far more folks
who weren't really bad apples, really just duped like we were.  Deluded
by fantasies of riches. Brainwashed.&lt;/p&gt;

&lt;p style="font-size:large"&gt;&lt;b&gt;Relating this to computer tech&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I couldn't help but to extrapolate from my take on Lewis's article,
to some of the
goings on in the computer tech field today, because I think there's a fair
amount of brainwashing going on in tech also.  What do you think about the
following ideas:&lt;/p&gt;

&lt;ul&gt;
 
&lt;li&gt;&lt;p&gt;Using &lt;a href="http://www.latex-project.org/"&gt;LaTeX&lt;/a&gt; files or Microsoft Word
.doc files as serialization formats for structured data.&lt;/p&gt;&lt;/li&gt;
 
&lt;li&gt;&lt;p&gt;Using C or C++ to build your next web-based application.&lt;/p&gt;&lt;/li&gt;
 
&lt;/ul&gt;

&lt;p&gt;To me, these sound crazy.  Why would you 
use a word processing system as the basis for a data serialization format?  
Nuts, right?  &lt;b&gt;But we are&lt;/b&gt;.  XML traces it's roots back to 
&lt;a href="http://en.wikipedia.org/wiki/IBM_Generalized_Markup_Language"&gt;IBM's Generalized Markup Language&lt;/a&gt;,
a text markup language not like LaTeX or &lt;a href="http://en.wikipedia.org/wiki/Nroff"&gt;nroff&lt;/a&gt;
(good times, good times).  XML is frankly not all that different from GML, I'd say
easier on the eyes (brackets are easier to visually parse than colons), and more regularized
syntax.  But it's fundamentally a language to apply bits of text formatting
to large amounts of raw text.  A typical BookMaster document was mainly plain
old text, with occasional tags to mark paragraph boundaries, etc.
&lt;/p&gt;

&lt;p&gt;Same sort of nutso thinking with Java.  A potentially decent systems-level programming language,
it could have been a successor to C and C++ had things worked out a bit
differently.  But as an application programming language?  Sure, some people
can do it.  But there's a level of complexity there, over and above 
application programming languages we've used in the past - COBOL and
BASIC, for instance - that really renders it unsuitable for a large potential segment
of the programmer market.&lt;/p&gt;

&lt;p&gt;How did these modern-day accidents occur?  Hype.  Being in the right place at the
right time.  They more or less worked for simple cases.  We all wanted to
believe.   We brainwashed ourselves.&lt;/p&gt;

&lt;p&gt;Luckily, evolution is taking it's toll on these two languages.  XML isn't
the only game in town now for structured data; JSON and YAML are often used where it makes sense;
Roy Fielding notes that 
&lt;a href="http://roy.gbiv.com/untangled/2008/paper-tigers-and-hidden-dragons"&gt;perhaps GIF images are an interesting way to
represent sparse bit arrays&lt;/a&gt; (ok, that's a random mutation in evolutionary terms).  We're seeing an upswing in 
alternative languages where Java used to be king: Ruby, Python, Groovy, etc
(with many of these languages having implementations &lt;b&gt;in&lt;/b&gt; Java - perfect!).
&lt;/p&gt;

&lt;p&gt;Reality is setting in; do what makes sense; think different; the hype curve doesn't always
point to the right answer.&lt;/p&gt;

&lt;p style="font-size:large"&gt;&lt;b&gt;My new favorite example of tech brainwashing&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;So while I can't complain so much about XML and Java as I used to,
it's kicking a dead horse at this point, I do have a new whipping boy in the tech
world for where we've been brainwashed - "web applications".  Those
things that run in our web browser, giving us the power, beauty and
flexibility of desktop apps.  Web 2.0.  RIAs.  GMail and Google Maps.&lt;/p&gt;

&lt;p&gt;I don't have to explain to anyone who's ever tried putting together
a "Web 2.0 application" the utter pain in doing this.  Ignoring server-side
issues, you have to deal with three different languages: HTML, CSS, and JavaScript;
typically interspersed betwixt themselves.  That behave differently in the
three to five popular browsers you might hope to support.  And the
iPhone.  Server side programming throws more wrenches in the gears, as
in our simpler web 1.0 world, we frequently mixed HTML, CSS, and JavaScript
with whatever programming language(s) we used on the server.  And
we still do, at times, in this new world also, only there's lots more
HTML, CSS and JavaScript, so it's even messier.&lt;/p&gt;

&lt;p&gt;Or maybe you're using Flex or Silverlight or some other more constrained
environment for your web app.  But then you have different problems; your users might expect
to be able to bookmark in the middle of the app - it's running on the web
after all.  Or cut and paste some of the content.  
Etc.  
And you're probably
still deploying in a web browser anyway!  There is no escape!&lt;/p&gt;

&lt;p&gt;What really frustrates me about the situation we're in, is that we've
painted ourselves into a corner.  We started with a very useful, mainly
read-only, networked hypertext viewer, and over the years bolted new 
geegaws on the sides.  Blink tags.  Tables.  JavaScript. Frames.  DHTML.  
File uploads.  XmlHTTPRequest.  SVG.  HTML Canvas. (stop me, my head's about to explode!)
All great stuff to add to a mainly read-only, networked hypertext viewer.
Can you use it to build a word processor?  Yes, 
&lt;a href="http://docs.google.com/"&gt;you can&lt;/a&gt;.  Well, a team of software developers
at Google can.  Not sure that &lt;b&gt;I&lt;/b&gt; can.&lt;/p&gt;

&lt;p&gt;But I &lt;b&gt;used&lt;/b&gt; to be able to build GUI apps without a lot of difficulty.
High function, richly formatting text editors even.
In C, for gawd's sake, though life got a lot easier in Smalltalk.&lt;/p&gt;

&lt;p&gt;It's time to stop thinking we can 
&lt;a href="http://browserplus.yahoo.com/"&gt;apply bandages&lt;/a&gt;
to the status quo
and make everything better.  
We want to believe.  Just another gadget or framework is going to
make everything better!  We've brainwashed ourselves.&lt;/p&gt;

&lt;p&gt;Wake up!
We fundamentally have the wrong tools to do the job.
We're using a spoon where we should be using a backhoe.
Look down!  You're using a spoon for *bleep*'s sake!
Don't you realize it?  Slap yourself around a little and clear the
fog from your eyes.  Expect better.
&lt;/p&gt;
 
&lt;p&gt;To be a little more concrete, I actually do think that the 
fundamentals of our web tech economy are sound.  I'm not unhappy with
HTTP, HTML, CSS, and JavaScript when viewed as separate technologies.
I don't think we've fit them together in the best way, to make it
easy to build applications with.  And they're wrapped in a shell
optimized around mainly read-only, history-enabled, page-by-page navigation, 
which doesn't seem like the best base
on which to build an application.
It's time for some new thinking here.
Can we take some of the basic building blocks we already have and build
a better application runtime platform than what we've got in front of us?
I have to believe the answer is: &lt;b&gt;Yes we can&lt;/b&gt;.
&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-7728391921086502447?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/D6Yedd_aVM8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/7728391921086502447/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=7728391921086502447" title="21 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7728391921086502447?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7728391921086502447?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/D6Yedd_aVM8/brainwashed.html" title="brainwashed" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">21</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2008/11/brainwashed.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08FQ349eSp7ImA9WxRXE0U.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-2368884441026802636</id><published>2008-10-18T23:06:00.001-04:00</published><updated>2008-10-19T00:16:52.061-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-19T00:16:52.061-04:00</app:edited><title>webimidi</title><content type="html">&lt;div&gt;
 
&lt;p&gt;As a reader of the great blog
&lt;a href="http://createdigitalmusic.com/"&gt;&lt;i&gt;create digital music&lt;/i&gt;&lt;/a&gt;,
I've been reading about and playing a bit with all the great
&lt;a href="http://createdigitalmusic.com/tag/ds/"&gt;Nintendo DS music software&lt;/a&gt;,
and just reading about the 
&lt;a href="http://createdigitalmusic.com/tag/ipod-touch/"&gt;iPhone/touch software&lt;/a&gt;
(I am currently iPhone/iTouch challenged).  Fun stuff.&lt;/p&gt;

&lt;p&gt;Of most interest to me are MIDI
controllers; hardware or software that you can use to control some other 
software via the enduring MIDI protocol.  Having a MIDI controller on
a portable device is a great idea; the more devices you have
available, the better.  But one of the problems with 
MIDI controllers is that there's never one that fits your needs
exactly.  Most of the existing handheld software is fairly fixed function.&lt;/p&gt;

&lt;p&gt;So what I really want is some software that easily lets me construct
a MIDI controller that does exactly what I want.  That I can use on
one of my portable devices: a
&lt;a href="http://www.nseries.com/n800"&gt;Nokia N800&lt;/a&gt; 
and a Nintendo DS.&lt;/p&gt;

&lt;p&gt;There are two general problems to solve: making it easy to construct a
new controller, and getting input from handheld into a MIDI device on 
my desktop where my music software is running.
&lt;/p&gt;

&lt;p&gt;At some point it struck me that having the MIDI controllers
implemented as UIs that can run in a web browser solves some of
the general constraints.  Writing UIs in HTML, CSS, and JavaScript
is (to some extent) easier than writing to native GUI toolkits.
Plus, there's the hope of writing a UI once and being able to 
reuse it on several devices.  Writing code specific to an iPhone
doesn't help me if I later want to run it on a Nokia N800 or
Nintendo DS later.
&lt;/p&gt;

&lt;p&gt;On the MIDI side, providing an HTTP interface on the desktop to
MIDI devices make it easy to interface to them from other devices.
There are some existing ways to interface with MIDI over tcp/ip,
including Network MIDI
(&lt;a href="https://ietf.org/rfc/rfc4695.txt"&gt;RFC 4695&lt;/a&gt; and
&lt;a href="https://ietf.org/rfc/rfc4696.txt"&gt;RFC 4696&lt;/a&gt;; Apple
provides an implementation of these protocols, but doesn't 
document some of the control messaging bits) and 
&lt;a href="http://dsmidiwifi.tobw.net/"&gt;DSMI&lt;/a&gt;.  But none of
these actually flow over HTTP, and it just seems so appropriate
to actually surface the interface over HTTP.  Duh.
&lt;/p&gt;

&lt;p&gt;And thus,
&lt;a href="http://code.google.com/p/webimidi/"&gt;webimidi&lt;/a&gt;
is born.
&lt;/p&gt;

&lt;p&gt;Below is a movie of the single device that I've included
with the code, which is a simple two octave keyboard.&lt;/p&gt;

&lt;object width="425" height="344"&gt;
&lt;param name="movie" value="http://www.youtube.com/v/QwTYLdDugXo&amp;hl=en&amp;fs=1"&gt;&lt;/param&gt;
&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;
&lt;embed src="http://www.youtube.com/v/QwTYLdDugXo&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;
&lt;/embed&gt;
&lt;/object&gt;

&lt;p&gt;I wrote webimidi in Python, although I was tempted to use the Ruby MIDI interface
that Giles Bowkett's provides in
&lt;a href="http://github.com/gilesbowkett/archaeopteryx/wikis/home"&gt;Archaeopteryx&lt;/a&gt;,
but that would have been too easy.  ha ha.  Actually, I've been feeling more 
python-y lately than ruby-y, and this was a great excuse to learn two parts of
Python I haven't played with:&lt;/p&gt;

&lt;ul&gt;
 
&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://docs.python.org/lib/module-ctypes.html"&gt;ctypes&lt;/a&gt;&lt;/b&gt; -
a foreign function interface (FFI).  ctypes allows you to interface with
native shared libraries, the native data structures they use, etc.  The world
(of C) is your oyster.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;b&gt;&lt;a href="http://www.python.org/dev/peps/pep-0333/"&gt;wsgi&lt;/a&gt;&lt;/b&gt; -
Python's Web Server Gateway Interface.  For folks familiar with Java,
wsgi is the "servlet" of the Python world.    
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Currently, webimidi only runs on Mac OS X, and probably only 10.5.
Porting to Windows would really just be a matter of doing a ctypes
interface to Windows MIDI functions (I did this MANY years ago 
in Smalltalk; it's doable, I just have no interest in actually doing
it today).
 
&lt;p&gt;Up next, a controller for my
&lt;a href="http://line6.com/toneportux1/"&gt;Line6 TonePort UX1&lt;/a&gt;.
Also, seeing if I can get something useful to run on my Nintendo DS; not clear that it
supports XmlHTTTPRequest, which is currently a pre-req for controllers built like this.
&lt;/p&gt;



&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-2368884441026802636?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/SDXN1jpFICM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/2368884441026802636/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=2368884441026802636" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2368884441026802636?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2368884441026802636?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/SDXN1jpFICM/webimidi.html" title="webimidi" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2008/10/webimidi.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcGQX07eyp7ImA9WxRSGEk.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-7807369793572668384</id><published>2008-09-19T14:13:00.001-04:00</published><updated>2008-09-19T14:13:40.303-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-19T14:13:40.303-04:00</app:edited><title>fun with WorkerPools</title><content type="html">&lt;div&gt;
&lt;p&gt;Arrr&lt;/p&gt;
&lt;p&gt;I suspect I''e looked at  
&lt;a href="http://gears.google.com/"&gt;Google Gears&lt;/a&gt;
a half dozen or so times since it was originally released.
Always looked kinda intarstin', but hadn't mightily any use for it.
I took another look when
&lt;a href="http://www.google.com/chrome"&gt;Chrome&lt;/a&gt;
was announced, since, o' all the stuff in Chrome,
the fact that 
&lt;a href="http://www.google.com/support/chrome/bin/answer.py?hl=en&amp;amp;answer=97489"&gt;Gears was baked in&lt;/a&gt;
was the most intarstin' bit t' me.&lt;/p&gt;

&lt;p&gt;(Bein' a bit curmugdeonly har, as in, the flashy chrome bits don't excite me.
"When I was a kid" my web browser (OS/2's WebExplorer) could only remember 10
bookmarks.  The Nintendo DS Browser works for me, in a pinch.  Now 
&lt;b&gt;GET OFF MY YARD!&lt;/b&gt;)&lt;/p&gt;

&lt;p&gt;Aye&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Pirate-speak translation above provided by the
&lt;a href="http://www.talklikeapirateday.com/translate/"&gt;Pirate Speak Translator&lt;/a&gt;.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Gears is the most interesting bit in Chrome because it's the programmable bit.&lt;/p&gt;

&lt;p&gt;What I decided to look through the other day was the 
&lt;a href="http://code.google.com/apis/gears/api_workerpool.html"&gt;WorkerPool bits&lt;/a&gt;,
since I hadn't really looked into them much before.  What I realized
pretty quickly is that they should have actually called these
&lt;b&gt;&lt;a href="http://en.wikipedia.org/wiki/Actor_model"&gt;Actor&lt;/a&gt;&lt;/b&gt;Pools.
You may be familiar with the Actor paradigm via the recent
&lt;a href="http://www.pragmaticprogrammer.com/articles/erlang"&gt;Erlang hotness&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;In a nutshell, the WorkerPool facility provides the following capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the ability to run a hunk of JavaScript code in a new context&lt;/li&gt;
&lt;li&gt;that context does not share code or state with any other JavaScript context, 
including the context which 'launched' the code&lt;/li&gt;
&lt;li&gt;the only way to communicate with the code is via asynchronous one-way 
message sends of arbitrary JavaScript objects (basically, the same sorts of
objects describable in JSON; no functions or non-trivial objects allowed, for instance)&lt;/li&gt;
&lt;li&gt;the ability to run that code independently of other contexts.  Think
threads, though that's just an implementation detail.
&lt;/ul&gt;

&lt;p&gt;If that's all it was, wouldn't be terribly interesting.  You can get aspects
of this type of stuff with traditional JavaScript code, though it's often messy.
Gears provides, at least, a fairly clean way of providing these capabilities.&lt;/p&gt;

&lt;p&gt;But here's where it gets interesting.  That hunk of code that you've created
a worker for can be loaded from an arbitrary server, referenced via a URL.  And then that code 
follows the "same origin policy" rules for other Gears APIs available to workers,
for instance, the 
&lt;a href="http://code.google.com/apis/gears/api_database.html"&gt;Database APIs&lt;/a&gt; and
&lt;a href="http://code.google.com/apis/gears/api_httprequest.html"&gt;HttpRequest APIs&lt;/a&gt;.
In other words, your worker code can access HTTP-resources on the server it came
from, and have a 'protected' Database that it manages that is only visible to 
workers that also were loaded from that server.&lt;/p&gt;

&lt;p&gt;Very cool, because this means that you can build workers that act as self-contained
service modules to allow access to HTTP resources for other applications to use.  None of
the usual cross-site chicanery we've had to deal with.  In addition, these modules
can manage their own protected cache of data.  Also, such modules can be reused across
multiple web applications, with each one reusing the same code and database store.&lt;/p&gt;

&lt;p&gt;This seems like powerful mojo.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Building an RPC mechanism on top of the message send APIs&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;One of the downers, for most people, with the current WorkerPool APIs, is 
going to be the message sending paradigm.  It's pretty low-level and raw.
The great thing is that asynchronous message sends are a type of atomic building
block upon which other forms of IPC can easily be built.  The 
&lt;a href="http://www.qnx.com/"&gt;QNX operating system&lt;/a&gt; is famously built up on
this core concept, 
&lt;a href="http://www.qnx.com/developers/docs/qnx_4.25_docs/qnx4/sysarch/microkernel.html"&gt;slightly expanded&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I've taken a run at building a simple RPC mechanism built on top of the message
send API.  The proof of concept is available here:
&lt;a href="http://muellerware.org/ggw-services-poc/"&gt;http://muellerware.org/ggw-services-poc/&lt;/a&gt;.
Here's how it works:&lt;/p&gt;

&lt;p&gt;To build your RPC-styled worker, create a JavaScript file that includes the services you want to expose, implemented as plain
old functions, along with a list of the functions you want to expose.  Here's an example of
some math services:&lt;/p&gt;

&lt;pre&gt;
    //---------------------------------------------------------
    // service function to add a list of numbers
    //---------------------------------------------------------
    function add() {
        var result = 0
        for (var i=0; i&amp;lt;arguments.length; i++) {
            result += arguments[i]
        }
        return result
    }

    ...

    //---------------------------------------------------------
    // list of exported services
    //---------------------------------------------------------
    services = [
        add,
        ...
    ]
    
    //---------------------------------------------------------
    // boiler-plate from here to end
    //---------------------------------------------------------
    
    ...
&lt;/pre&gt;

&lt;p&gt;At the bottom of this file is some boiler-plate code that deals with the messaging
interface.  Basically, messages are received that are serialized versions of the
function invocation: function name, arguments, and an identifier to indicate
which invocation this was (needed to match up return values later).  The boiler-plate
code cracks open the message, reflectively calls the function, then sends back the
function result as a message to the original message sender.&lt;/p&gt;

&lt;p&gt;On the client end, in your main HTML / JavaScript code, you'll be using the
service like this:&lt;/p&gt;

&lt;pre&gt;
   math_service = new ggw_services_Service("math_services.js")

   ...

   // callback function to display the result of our service call
   function print_sum(sum) {
      ...
   }

   // handler that invokes our service call
   function do_sum() {
      math_service.services.add(print_sum, 1,2,3,4,5,6,7,8,9,10)
   }

   ...
&lt;/pre&gt;

&lt;p&gt;In this code, we instantiate the services with the &lt;tt&gt;ggw_services_Service&lt;/tt&gt;
constructor, passing it the URL of the JavaScript code we want to run as a 
worker - this would be the service implementation file described above.  The
resulting object will then expose proxies for the exposed functions in the service
in the &lt;tt&gt;services&lt;/tt&gt; field of the object.  You call these just like normal 
functions.  One trick: because the message sends are one-way, and you'll probably
want to get a result back, the first parameter can be a call-back function which
is invoked when the service method returns it's value.  In this case, that would
be the &lt;tt&gt;print_sum&lt;/tt&gt; function.&lt;/p&gt;

&lt;p&gt;Neat.  But crude.  To do this right, would require a bit more infrastructure, as well
as making sure you can catch all the sorts of error conditions that can happen.  The end
result won't be (shouldn't be) as transparent as the example above, but you can 
probably get pretty close.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Notes&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
 
&lt;li&gt;&lt;p&gt;Because there is no sharing of code or data in a worker, and anything else,
things like debugging get hard, because you can't access the DOM, you can't access
the &lt;tt&gt;document&lt;/tt&gt;, you can't access &lt;tt&gt;alert()&lt;/tt&gt;.  In FireBug, you can see
the message text from &lt;tt&gt;Error&lt;/tt&gt;s, which is useful, especially when you throw
them yourself.  But the code source isn't identified, just that the error occurred on 
"worker 0" or the like. 
&lt;/p&gt;&lt;li&gt;

&lt;li&gt;&lt;p&gt;Speaking of FireBug, I was able to pretty consistently lock up FireFox
while debugging my example.  Due to my browser coding naivet&amp;eacute;, don't know
if this was me, FireBug, Gears, or some combination of them.  But it got old fast.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;It's not clear what the best way is to handle security credentials for HTTP requests
from within workers.  My gut tells me that some Gears APIs to manage sensitive
data like passwords and keys would be useful.  Storing credentials in a server-specific
database doesn't sound great, but doesn't sound terrible either.  But it's not even
clear how a worker would go about prompting a user for credentials, and do it safely.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The current story for worker code is that all the worker code has to be in 
a single file.  Not great.  It would be nice to have an API like &lt;tt&gt;loadScript()&lt;/tt&gt;
or some such that would allow you to add additional JavaScript code to your context.
In lieu of that, you can always XHR GET your additional code, and &lt;tt&gt;eval()&lt;/tt&gt;
it into the context.  Icky, but should work.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;One of the nice things about the stark bleakness of the context in 
which the workers run is that it makes these workers applicable to other 
environments.  For instance, it's not a huge stretch to consider porting
the Gears APIs to &lt;a href="http://www.mozilla.org/rhino/"&gt;Rhino&lt;/a&gt;, allowing
reuse of the workers from within Java.  Very cool for Java, where loading
"live code" is typically not something that is done, for various reasons, but
this makes it relatively straight-forward.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;In terms of higher-level frameworks for this stuff, I think I'd start looking
at OSGi and it's 
&lt;a href="http://www.knopflerfish.org/osgi_service_tutorial.html"&gt;Bundle and Service concepts&lt;/a&gt;.  
I suspect there's a pretty good fit there.
Combined with the previous thought of reusing workers in Java itself, why not design it
&lt;b&gt;around&lt;/b&gt; OSGi, so that I could actually design a worker such that it could easily
be spun into OSGi bundle itself, and so directly consumable by OSGi-friendly code without
having to have them deal with "yucky" JavaScript.  Having access to JavaScript in Java
isn't always considered a "plus" by Java programmers, but they can be easily fooled.
&lt;/p&gt;&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/22367266-7807369793572668384?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/J8oepJNJoMY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/7807369793572668384/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=7807369793572668384" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7807369793572668384?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7807369793572668384?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/J8oepJNJoMY/fun-with-workerpools.html" title="fun with WorkerPools" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2008/09/fun-with-workerpools.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQMSX4-eyp7ImA9WxdaE04.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-7127590420102757366</id><published>2008-08-21T11:25:00.000-04:00</published><updated>2008-08-21T11:26:28.053-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-21T11:26:28.053-04:00</app:edited><title>better than json</title><content type="html">&lt;p&gt;Well, 
&lt;a href="http://bitworking.org/news/359/restful-json-followup-and-mailing-list"&gt;JSON is the new hotness&lt;/a&gt;. 
This week.  Again.
Thought I'd jot down some thoughts I had on JSON last summer,
in the area of improving on JSON.&lt;/p&gt;

&lt;p&gt;Before doing that, let me go over some of my core beliefs about JSON:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;It defines an ASCII serialization format for
a lowest common denominator of primitive and composite types used in
most common programming languages, so it can be used to
serialize natural data structures in many environments.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;JSON doesn't attempt to handle traditional OO mechanics, it's really
just plain old simple data and data structures, keeping things simpler.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The fact that JSON is legal JavaScript, and so can be
&lt;tt&gt;eval()&lt;/tt&gt;'d 
and
&lt;tt&gt;&amp;lt;script src=""&amp;gt;&lt;/tt&gt;'d in 
web browsers via 
&lt;a href="http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/"&gt;JSONP&lt;/a&gt;,
is not a benefit, it's a security nightmare waiting to happen.
JSON parsers are easy to write, and with JSONP you're giving up too
much control over your HTTP requests.&lt;/p&gt;&lt;/li&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The 'readability' and 'writeability' of JSON, by humans, isn't a big
priority for me.  But it does bug me that it could easily more readable
and writable, by humans.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Basically, I like what it can express, and I care less about the syntax.&lt;/p&gt;

&lt;p&gt;So, what would I change?  Turns out, not much, mainly syntax changes to
aid in human readability and writability.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Add some additional primitive data types / literal forms.&lt;/b&gt;
Some obvious ones would be
&lt;a href="http://intertwingly.net/blog/2008/07/11/Decimal-in-ECMAScript"&gt;decimal&lt;/a&gt;
and 
&lt;a href="http://www.ietf.org/rfc/rfc3339.txt"&gt;date&lt;/a&gt;.  Most languages
can support these, somehow.  Date gets dicey in terms of subsetting,
like date with no time, time with no date, etc.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Remove the idiotic &lt;tt&gt;"\/"&lt;/tt&gt; escaping rule.&lt;/b&gt;
&lt;a href="http://groups.google.com/group/opensocial-and-gadgets-spec/browse_thread/thread/1642ec0bed9b95ba/21956eed23f04e13"&gt;People think&lt;/a&gt; 
they have to encode &lt;tt&gt;"/"&lt;/tt&gt; character
because it shows up in the 'backslash escapeable character list'.
Section 8, Examples, of 
&lt;a href="http://www.ietf.org/rfc/rfc4627.txt"&gt;RFC 4627&lt;/a&gt; has
an example which clearly does not use escaped &lt;tt&gt;"/"&lt;/tt&gt; characters.
I assume this escaping rule had something to do with the way 
JavaScript is/was parsed in some web browsers.  feh.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Remove extraneous punctuation.&lt;/b&gt;
The &lt;tt&gt;","&lt;/tt&gt; separators used between elements in &lt;tt&gt;{}&lt;/tt&gt; and &lt;tt&gt;[]&lt;/tt&gt;
structures aren't needed.  Make them optional.  Same with the
&lt;tt&gt;":"&lt;/tt&gt; characters between key / value pairs in &lt;tt&gt;{}&lt;/tt&gt; 
structures.  For human readable output, I'd not use &lt;tt&gt;","&lt;/tt&gt; but would use
&lt;tt&gt;":"&lt;/tt&gt;, because I like the visual parsing you get between
key value pairs.  I would typically write key / value pairs 
on a single line anyway,
obviating the need for the &lt;tt&gt;","&lt;/tt&gt; separator. 
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Stop requiring quotes around strings unless required.&lt;/b&gt;
This is the biggest noise reducer.  There are only 3 keywords in
JSON - &lt;tt&gt;true&lt;/tt&gt;, &lt;tt&gt;false&lt;/tt&gt;, and &lt;tt&gt;null&lt;/tt&gt;.  For
property keys specifically, many times the key values aren't
one of these keywords, aren't another primitive literal value,
and don't include whitespace or other separator characters.
Their values are basically that of 'identifiers'.  That get used
unquoted in JavaScript itself, in 
&lt;a href="http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Operators/Member_Operators"&gt;JavaScript dot notation&lt;/a&gt;
and
&lt;a href="http://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Literals#Object_Literals"&gt;object literals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I assume this quoted property name rule exists is to keep
people from inadvertently using JavaScript keywords as
property keys, which would then screw up the parse-by-&lt;tt&gt;eval()&lt;/tt&gt; trick.
For program generated JSON, it's probably just easier to always
use quotes, but when JSON is being rendered for humans, I'd like
quotes removed if they could be.  When writing literal JSON,
I'd also not use quotes if I didn't have to.
&lt;/p&gt;

&lt;p&gt;The same rules apply for all string usage, not just property keys.
But I'd probably typically want to read and write strings as quoted
values everywhere but property keys, as that's just what I'm used to.&lt;/p&gt;

&lt;p&gt;Using 'bare strings' means that you might write out a property
name that in the future became a new JSON keyword.  Not good.
So perhaps something like the
Smalltalk/Ruby symbol syntax construct could be used.  Basically a
new character prefix, with no terminator, indicating the following
characters up to a separator are the string value.  If &lt;tt&gt;"#"&lt;/tt&gt; was the prefix,
then &lt;tt&gt;#abc&lt;/tt&gt; would be the same thing as &lt;tt&gt;"abc"&lt;/tt&gt;.

&lt;p&gt;Or perhaps we can find and set some rules that would allow
new keywords and operators to be introduced without breaking 
serializations that weren't aware of them.  The
&lt;a href="http://www-306.ibm.com/software/awdtools/netrexx/library/nrlkeys.html"&gt;NextREXX language&lt;/a&gt;
does this.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Provide single line and multi-line comments.&lt;/b&gt;
Duh.
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Examples&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Here are some examples of using some of these changes,
based on the following JSON object that I
&lt;a href="http://groups.google.com/group/restful-json/browse_thread/thread/c2850aa08fa08119"&gt;found on the web somewhere&lt;/a&gt;.
To be fair, since these examples are supposed to show readability enhancements, 
I did a reformatting in TextMate.  Here's the original, but reformatted, legal JSON.
&lt;/p&gt;

&lt;pre&gt;
{
    "members": [
        {
            "href": "34KJDCSKJN2HHF0DW20394",
            "etag": "0hf0239hf2hf9fds09sadfo90ua093j",
            "entity": {
                "id": "example.org:34KJDCSKJN2HHF0DW20394",
                "name": {
                    "unstructured": "Jane Doe"
                },
                "gender": {
                    "displayvalue": "&amp;#x5973;&amp;#x6027;",
                    "key":          "FEMALE"
                }
            }
        },
        {
            "href": "aaaaaaaaaaa11111",
            "etag": "alsjdfieflsajfajsfjadsljfalksjd",
            "entity": {
                "id": "example.org:aaaaaaaaaaa11111",
                "name": {
                    "unstructured": "Joe Gregorio"
                },
                "gender": {
                    "displayvalue": "Male",
                    "key":          "MALE"
                }
            }
        }
    ],
    "next": null
}
&lt;/pre&gt;

&lt;p&gt;Let's remove the comma's.  Comma removal doesn't help much
with the readability, but it's much easier to not have to
add the commons when you're writing JSON literals by hand.&lt;/p&gt;

&lt;pre&gt;
{
    "members": [
        {
            "href": "34KJDCSKJN2HHF0DW20394"
            "etag": "0hf0239hf2hf9fds09sadfo90ua093j"
            "entity": {
                "id": "example.org:34KJDCSKJN2HHF0DW20394"
                "name": {
                    "unstructured": "Jane Doe"
                }
                "gender": {
                    "displayvalue": "&amp;#x5973;&amp;#x6027;"
                    "key":          "FEMALE"
                }
            }
        }
        {
            "href": "aaaaaaaaaaa11111"
            "etag": "alsjdfieflsajfajsfjadsljfalksjd"
            "entity": {
                "id": "example.org:aaaaaaaaaaa11111"
                "name": {
                    "unstructured": "Joe Gregorio"
                }
                "gender": {
                    "displayvalue": "Male"
                    "key":          "MALE"
                }
            }
        }
    ]
    "next": null
}
&lt;/pre&gt;

&lt;p&gt;Now remove the quotes around property keys.  That's really nice,
but for compatibility with potential new keywords, it probably is best to not use 'bare strings'.&lt;/p&gt;

&lt;pre&gt;
{
    members: [
        {
            href: "34KJDCSKJN2HHF0DW20394"
            etag: "0hf0239hf2hf9fds09sadfo90ua093j"
            entity: {
                id: "example.org:34KJDCSKJN2HHF0DW20394"
                name: {
                    unstructured: "Jane Doe"
                }
                gender: {
                    displayvalue: "&amp;#x5973;&amp;#x6027;"
                    key:          "FEMALE"
                }
            }
        }
        {
            href: "aaaaaaaaaaa11111"
            etag: "alsjdfieflsajfajsfjadsljfalksjd"
            entity: {
                id: "example.org:aaaaaaaaaaa11111"
                name: {
                    unstructured: "Joe Gregorio"
                }
                gender: {
                    displayvalue: "Male"
                    key:          "MALE"
                }
            }
        }
    ]
    next: null
}
&lt;/pre&gt;

&lt;p&gt;Now try prefixing property keys with &lt;tt&gt;"#"&lt;/tt&gt; using a symbol-like construct, 
and not using &lt;tt&gt;":"&lt;/tt&gt; to 
separate key value pairs, to make up for having to put the quote in.  Add some comments.&lt;/p&gt;

&lt;pre&gt;
{
    // the list of entries in the list
    #members [
        // Jane Doe's entry
        {
            #href "34KJDCSKJN2HHF0DW20394"
            #etag "0hf0239hf2hf9fds09sadfo90ua093j"
            #entity {
                #id "example.org:34KJDCSKJN2HHF0DW20394"
                #name {
                    #unstructured "Jane Doe"
                }
                #gender {
                    // apparently this data is multi-byte encoded
                    #displayvalue "&amp;#x5973;&amp;#x6027;"
                    #key          "FEMALE"
                }
            }
        }
        // Joe Gregorio's entry
        {
            #href "aaaaaaaaaaa11111"
            #etag "alsjdfieflsajfajsfjadsljfalksjd"
            #entity {
                #id "example.org:aaaaaaaaaaa11111"
                #name {
                    #unstructured "Joe Gregorio"
                }
                #gender {
                    #displayvalue "Male"
                    #key          "MALE"
                }
            }
        }
    ]
    #next null
}
&lt;/pre&gt;

&lt;p&gt;To me, I see some readability enhancement with these changes.  I think the big bang 
for the buck is the writability enhancement.&lt;/p&gt;

&lt;p&gt;As I said above, the syntax isn't a really big deal for me.  It's only
a big deal when I have to read it with my eyes or type it at a keyboard.
Which we seem to be doing more of these days.  In fact, I had to fix two typos in
&lt;a href="http://groups.google.com/group/restful-json/browse_thread/thread/c2850aa08fa08119"&gt;Joe's original sample&lt;/a&gt;.  
Can you find them?&lt;/p&gt;

&lt;p&gt;It's funny that with all the whining I do about unreadable and overly verbose XML,
I find it easier to read and write XML than JSON.  That might well just be because I'm
typically reading and writing XML with syntax coloring viewers and editors, but not
doing that so much with JSON.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-7127590420102757366?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/OxkOsHYOQWw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/7127590420102757366/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=7127590420102757366" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7127590420102757366?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7127590420102757366?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/OxkOsHYOQWw/better-than-json.html" title="better than json" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2008/08/better-than-json.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkACSXkyeCp7ImA9WxdRGUk.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-7499194706624505142</id><published>2008-06-08T13:03:00.000-04:00</published><updated>2008-06-08T13:06:08.790-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-08T13:06:08.790-04:00</app:edited><title>hoping for the ide wars</title><content type="html">&lt;div&gt;

&lt;p&gt;Joe calls it
&lt;i&gt;"&lt;a href="http://bitworking.org/news/321/The-Professionalization-of-Scripting-Languages"&gt;The professionalization of scripting languages&lt;/a&gt;"&lt;/i&gt;;
I &lt;a title="twitter link" href="http://twitter.com/pmuellr/statuses/826510934"&gt;call it&lt;/a&gt;
&lt;i&gt;"the javascript wars"&lt;/i&gt;.
As it relates to 
&lt;a href="http://webkit.org/blog/189/announcing-squirrelfish/"&gt;SquirrelFish&lt;/a&gt;
anyway.  As for 
&lt;a href="http://www.infoq.com/news/2008/05/MagLevAtRailsConf"&gt;maglev&lt;/a&gt;, 
&lt;a href="http://twitter.com/pmuellr/statuses/824796819"&gt;I say&lt;/a&gt;
&lt;i&gt;"thank you for setting a new bar for 'dynlang' runtimes; it was desperately needed"&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;That's the big take away; as we see competing implementations of JavaScript and
Ruby, the upside for us consumers is great - all the implementors 
trying to out-do themselves, giving us better and better runtimes.
We saw the same with the web browsers and Java VMs in the 90's.
&lt;/p&gt;

&lt;p&gt;But all of that is just getting the runtimes to run faster, use less memory, and in
general just being better citizens on our computers.  
That doesn't change the way I work all that
much, just lets me develop (and test) faster.  What else can we take away from
the Smalltalk experience?&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Development environments&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;There were plenty of warts in the Smalltalk IDE story - you had to use the IDE's
text editor, your entire development environment was mixed in with your product
code, etc.  But of course there were lots of advantages to that also.  Smalltalk
was the last development environment where I actively took advantage of extending
the environment with my own code. Before Smalltalk I was using 
programmable text editors and commmand
lines; I was quite comfortable scripting both, even on mainframes. 
Since Smalltalk I've generally been using 
Eclipse for work stuff, but
the effort in extending the environment has just been too much work for me to
invest in, though I've tried a few times.  I settle for writing
ant scripts; that's how bad things have gotten - I'm programming in XML.&lt;/p&gt;

&lt;p&gt;What's on the horizon?  Eclipse has
&lt;a href="http://wiki.eclipse.org/E4"&gt;E4&lt;/a&gt;.  Which seems like it's largely a 
cleanup/sanitization of Eclipse, vs a complete re-think.  I suspect I will write
as many extensions for E4 as I have for the previous versions of Eclipse.
Perhaps I'll sit that out and wait for Steve Northover's 
&lt;a href="http://inside-swt.blogspot.com/2008/03/fake-steve-northover.html"&gt;E5&lt;/a&gt;.
Frankly, I think it's time we started fresh; let's call it &lt;b&gt;F1&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;Gilad Bracha has a recent blog
post on 
&lt;i&gt;"&lt;a href="http://gbracha.blogspot.com/2008/06/incremental-development-environments.html"&gt;Incremental Development Environments&lt;/a&gt;"&lt;/i&gt;
including a link to 
&lt;a href="http://bracha.org/hopscotch-wasdett.pdf"&gt;a paper on Hopscotch&lt;/a&gt;.
Frankly, the paper didn't do much for me, and the sole screenshot is of
something which appears to be a browser-based IDE.  Not terribly fascinating
at this point, in terms of the specifics.
I hope to hear more about Hopscotch after Vassilli Bykov's presentation
"Interfaces Without Tools" at 
&lt;a href="https://alanknight.dabbledb.com/page/sts2008/SmTvegzY"&gt;Smalltalk Solutions 2008&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It'll be terribly fascinating if people are actually getting interested in IDEs
again.  &lt;b&gt;Let the IDE Wars begin!&lt;/b&gt;&lt;/p&gt;

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-7499194706624505142?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/872XGTxQvsg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/7499194706624505142/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=7499194706624505142" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7499194706624505142?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7499194706624505142?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/872XGTxQvsg/hoping-for-ide-wars.html" title="hoping for the ide wars" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2008/06/hoping-for-ide-wars.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cAQ3Y-eCp7ImA9WxdTGEg.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-1209151893533983102</id><published>2008-05-15T09:42:00.001-04:00</published><updated>2008-05-15T09:44:02.850-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-15T09:44:02.850-04:00</app:edited><title>appropriateness</title><content type="html">&lt;p&gt;Bill de h&amp;#xD3;ra points out some 
&lt;a href="http://www.dehora.net/journal/2008/05/15/blubml/"&gt;seeming discrepancies in Jeff Atwood's views on XML&lt;/a&gt;.
Or my reading-between-the-lines, XML-ish markup languages, like HTML.  Here's my take:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XML is a great way to mark up text.&lt;/li&gt;
&lt;li&gt;XML is a terrible way to represent data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I see no discrepancies here.  My view of XML as a text markup language are biased given that
I used &lt;a href="http://en.wikipedia.org/wiki/IBM_Generalized_Markup_Language"&gt;GML&lt;/a&gt;
for many years, since 1983 or so, to produce documentation.&lt;/p&gt;
 
&lt;p&gt;Likewise, though I've often pooped all over 
Java, claiming it's a terrible language, I think there is (or was anyway) a place for it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java could have been a great replacement for C, in many cases.&lt;/li&gt;
&lt;li&gt;Java is a terrible language with which to build applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd no more want to build a web or desktop app with Java (read: C), than I would want to 
write a sound driver in JavaScript.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-1209151893533983102?l=pmuellr.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/bab1Zqr1IXo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/1209151893533983102/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22367266&amp;postID=1209151893533983102" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/1209151893533983102?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/1209151893533983102?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/bab1Zqr1IXo/appropriateness.html" title="appropriateness" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00305132796495191158" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2008/05/appropriateness.html</feedburner:origLink></entry></feed>
