<?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:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CEIMQ3o9fyp7ImA9WhBVFE0.&quot;"><id>tag:blogger.com,1999:blog-22367266</id><updated>2013-04-19T16:16:22.467-04:00</updated><title>pmuellr</title><subtitle type="html">Patrick Mueller</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><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>223</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/pmuellr" /><feedburner:info uri="pmuellr" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DUQDRHs5cCp7ImA9WhBTEkQ.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-3982767092563942998</id><published>2013-02-07T23:22:00.000-05:00</published><updated>2013-02-07T23:22:55.528-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-07T23:22:55.528-05:00</app:edited><title>dustup</title><content type="html">&lt;p&gt;A few months ago, I took a look at Nathan Marz's &lt;a href="http://storm-project.net/"&gt;Storm project&lt;/a&gt;.
As someone who has used and implemented &lt;a href="http://en.wikipedia.org/wiki/Actor_model"&gt;Actor-like&lt;/a&gt;
systems a few times over the years, always fun to see another take.  Although
Storm is aimed at the "cloud", it's easy to look at it and see how you
might be able to use it for local computation.  In fact, I have a problem area
I'm working in right now where something like Storm might be useful, but I just
need it to work in a single process.  In JavaScript.&lt;/p&gt;

&lt;p&gt;Another recent problem area I've been looking at is async, and
using Promises to help with that mess.  I've been looking at
Kris Kowal's &lt;a href="http://documentup.com/kriskowal/q/"&gt;&lt;code&gt;q&lt;/code&gt;&lt;/a&gt;
specifically.
It's a nice package, and there's a lot to love.
But as I was thinking about how I was going to end up using them, I imagined
building up these chained promises over and over again for some of my
processing.  As live objects.  Which, on the face of it, is insane.  If
I can build a static structure and have object flow through them instead.
Should be able to cut down on the amount of live objects created, and it will
probably be easier to debug.&lt;/p&gt;

&lt;p&gt;So, with that in mind, I finally sat down and reinterpreted Storm
this evening, with my
&lt;a href="https://github.com/pmuellr/dustup"&gt;dustup&lt;/a&gt; project.&lt;/p&gt;

&lt;p&gt;Some differences from Storm, besides the super obvious ones (JavaScript vs
Java/Clojure, and local vs distributed):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One of the things that didn't seem right to me in Storm was differentiating
spouts from bolts.  So I only have bolts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I'm also a fan of the &lt;a href="http://puredata.info/"&gt;PureData&lt;/a&gt;
real-time graphical programming environment, and so borrowed some ideas
from there.  Namely, that bolts should have inlets where data comes in, and
outlets where they go out, and that to hook bolts together, that you'll connect
an inlet to an outlet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Designed with CoffeeScript in mind.  So you can do nice looking things like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;x = new Bolt
    outlets:
       stdout: "standard output"
       stderr: "standard error"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which generates the following JavaScript:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;x = new Bolt({
    outlets: {
       stdout: "standard output",
       stderr: "standard error"
    }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Bolt.connect a: boltA, b: boltB
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which generates the following JavaScript&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Bolt.connect({a: boltA, b: boltB})
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Even though I designed it for and with CoffeeScript, you can
of course use it in JavaScript, and it seems totally survivable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stopping there left me with something that seems useful, and still small.
I hope to play with it in anger over the next week or so.&lt;/p&gt;

&lt;p&gt;Here's an example of a topology that just passes data from one bolt to another,
in CoffeeScript:
&lt;br&gt;
(&lt;a href="https://github.com/pmuellr/dustup/blob/master/test/sample.js"&gt;here's the JavaScript&lt;/a&gt;
for you CoffeeScript haters)&lt;/p&gt;

&lt;script src="https://gist.github.com/pmuellr/4736380.js"&gt;&lt;/script&gt;

&lt;p&gt;In the lines 1-2, we get access to the &lt;code&gt;dustup&lt;/code&gt; package and
the &lt;code&gt;Bolt&lt;/code&gt; class that it exports.&lt;/p&gt;

&lt;p&gt;On lines 4-6, we're creating a new bolt that only has a single outlet, named
&lt;code&gt;"a"&lt;/code&gt;
(the string value associated with the property &lt;code&gt;a&lt;/code&gt; - &lt;code&gt;"outlet a"&lt;/code&gt; - is ignored).&lt;/p&gt;

&lt;p&gt;On lines 8-11, we're creating a new bolt that only has a single inlet, named
&lt;code&gt;"b"&lt;/code&gt;.  Inlets need to provide a function which will be invoked when the
inlet receives data from an outlet.  In this case, the inlet function will
write the data to "the console".&lt;/p&gt;

&lt;p&gt;On line 13, we connect the &lt;code&gt;a&lt;/code&gt; outlet from the first bolt to the &lt;code&gt;b&lt;/code&gt; inlet of
the second bolt.  So that when we send a message out the &lt;code&gt;a&lt;/code&gt; outlet, the
&lt;code&gt;b&lt;/code&gt; inlet will receive it.&lt;/p&gt;

&lt;p&gt;Which we test on line 15, by having the first bolt emit some data.  Guess what
happens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next obvious thing to look at, is to see how asynchronous functions,
timers, and intervals fit into this scheme.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/vaHFFrogxxs" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/3982767092563942998?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/3982767092563942998?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/vaHFFrogxxs/dustup.html" title="dustup" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2013/02/dustup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMHRH0zfSp7ImA9WhNXE00.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-6418238260655039909</id><published>2012-11-30T14:23:00.001-05:00</published><updated>2012-11-30T14:23:55.385-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-30T14:23:55.385-05:00</app:edited><title>weinre installable at heroku (and behind other proxy servers)</title><content type="html">&lt;p&gt;I finally resolved
&lt;a href="https://issues.apache.org/jira/browse/CB-1494"&gt;an issue with weinre relating to using it behind
proxy servers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Matti Paksula figured out what the problem was, but I wasn't happy with the
additional complexity involved, so I
&lt;a href="https://git-wip-us.apache.org/repos/asf?p=cordova-weinre.git;a=blobdiff;f=weinre.server/lib/channelManager.coffee;h=d55bb0130179e4b0e6c3f62d19ef99a92fa6e7e9;hp=48abca6ea13d86582632efca0adfc073b9b0614e;hb=19454cfe2cd3c4515f7fb615f35fa2c7b2565401;hpb=de980f8b0de7c6472576aef1e4ab0b07d54534f7"&gt;made a simpler and more drastic change&lt;/a&gt; (in the &lt;code&gt;getChannel()&lt;/code&gt; function).&lt;/p&gt;

&lt;p&gt;Used to be, subsequent weinre connections after the first were
checked to make sure they came from the same "computer"; that was just a
silly sort of security check that can be worked around, if need be.  So
why bother with it, if it just gets in the way.&lt;/p&gt;

&lt;p&gt;So, now weinre can run on &lt;a href="http://www.heroku.com/"&gt;heroku&lt;/a&gt;.
I have a wrapper project at GitHub you can use to create your own server:
&lt;a href="https://github.com/pmuellr/weinre-heroku"&gt;https://github.com/pmuellr/weinre-heroku&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since Heroku provides
&lt;a href="https://devcenter.heroku.com/articles/usage-and-billing"&gt;750 free dyno-hours per app per month&lt;/a&gt;,
and weinre is one app, and uses one dyno at a time, and 750 hours are in a
month, you can run a weinre server on the Intertubes for free.&lt;/p&gt;

&lt;p&gt;As usual, weinre has been updated on &lt;a href="https://npmjs.org/package/weinre"&gt;npm&lt;/a&gt;.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/-vWj1ff8xh8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/6418238260655039909?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/6418238260655039909?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/-vWj1ff8xh8/weinre-installable-at-heroku-and-behind.html" title="weinre installable at heroku (and behind other proxy servers)" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2012/11/weinre-installable-at-heroku-and-behind.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YCRnc4eip7ImA9WhVQEU8.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-6844169911433769025</id><published>2012-03-30T12:50:00.000-04:00</published><updated>2012-03-30T13:39:27.932-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-03-30T13:39:27.932-04:00</app:edited><title>unofficial weinre binary packages for your convenience at my apache home page</title><content type="html">&lt;p&gt;weinre is now getting ready to go for the brass ring at Apache:
an "official" release.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOT THERE YET - NO OFFICIAL RELEASES YET&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Until that time, I have &lt;strong&gt;unofficial&lt;/strong&gt; binary packages available for your convenience.&lt;/p&gt;

&lt;p&gt;I've gone ahead and created a little download site at my personal Apache
page, here: &lt;a href="http://people.apache.org/~pmuellr/"&gt;http://people.apache.org/~pmuellr/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The download site contains all the doc and binary packages for every weinre version
I've 'shipped', in the 1.x directories.  It also contains &lt;strong&gt;unofficial&lt;/strong&gt;
binary packages of recent cuts of weinre for your convenience, as the &lt;code&gt;bin&lt;/code&gt;, &lt;code&gt;doc&lt;/code&gt;, and &lt;code&gt;src&lt;/code&gt; directories
in the &lt;a href="http://people.apache.org/~pmuellr/weinre-builds/"&gt;weinre-builds&lt;/a&gt; directory, and the same version of the doc, unpacked,
in the &lt;code&gt;latest&lt;/code&gt; directory of &lt;a href="http://people.apache.org/~pmuellr/weinre-docs/"&gt;weinre-docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As with previous binary releases for your convenience, you can &lt;code&gt;npm install&lt;/code&gt; weinre.  Here's the recipe:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;npm install {base-url}apache-cordova-weinre-{version}-bin.tar.gz

{base-url} = http://people.apache.org/~pmuellr/weinre-builds/bin/
{version}  = 2.0.0-pre-H0FABA3W-incubating
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That version number will change, so I'm not providing an exact link.  Check
the directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;help me help you&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you'd like to accelerate the process of getting weinre to "official" status,
you can help!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;install it&lt;/li&gt;
&lt;li&gt;use it&lt;/li&gt;
&lt;li&gt;review it&lt;/li&gt;
&lt;li&gt;build it&lt;/li&gt;
&lt;li&gt;enhance it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to post to the cordova mailing list at Apache, the weinre google group,
clone the source from Apache or GitHub, etc.  All the links are here:
&lt;a href="http://people.apache.org/~pmuellr/weinre-docs/latest/"&gt;http://people.apache.org/~pmuellr/weinre-docs/latest/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One link I forgot to add, and feel free to open a bug about this, is the link
to open a bug. &lt;a href="https://issues.apache.org/jira/secure/CreateIssue.jspa?pid=12312420&amp;amp;issuetype=1&amp;amp;Create=Create"&gt;It's hideous&lt;/a&gt; (the URL).
Add component "weinre" and maybe a "[weinre]" prefix on the summary.&lt;/p&gt;

&lt;p&gt;Thank you for helping yourself!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;you f'ing moved the downloads again you f'er!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Chill.  And some bad news.  The official releases won't be here (I don't think).
But I will provide a link on that site to the official releases, when they become 
real.&lt;/p&gt;

&lt;p&gt;I intend to keep this page around until I can get all the weinre bits available
in more appropriate places at Apache.  Not there yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;personal home pages at Apache&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apache provides "home pages" for Apache committers.  That's what I'm using for
this archive site.  If you're a committer, and curious about how I did the directory indexing,
the source for the site (modulo actual archives), is here: 
&lt;a href="https://github.com/pmuellr/people.apache.org"&gt;https://github.com/pmuellr/people.apache.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2012/03/30 1pm update&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/#!/janl"&gt;Jan Lehnardt&lt;/a&gt; pointed out to me 
&lt;a href="https://twitter.com/#!/janl/status/185771996561420288"&gt;on twitter&lt;/a&gt;
that I should avoid the use of the world "release", so that word has been 
changed to things like "binary package for your convenience".&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/5VV64ZCEniM" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/6844169911433769025?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/6844169911433769025?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/5VV64ZCEniM/unofficial-weinre-builds-at-my-apache.html" title="unofficial weinre binary packages for your convenience at my apache home page" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2012/03/unofficial-weinre-builds-at-my-apache.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8BSXo4eip7ImA9WhRaFU0.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-2328403398570329898</id><published>2012-02-17T12:56:00.001-05:00</published><updated>2012-02-17T13:54:18.432-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-17T13:54:18.432-05:00</app:edited><title>npm installable version of weinre</title><content type="html">&lt;p&gt;As part of the 
&lt;a href="https://issues.apache.org/jira/browse/CB-83"&gt;port of weinre from Java to node.js&lt;/a&gt;
it seemed logical to make it, somehow, 
&lt;a href="https://issues.apache.org/jira/browse/CB-259"&gt;npm installable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Success.&lt;/p&gt;

&lt;p&gt;There is currently a tar.gz download of the weinre runtime
available at the
&lt;a href="https://github.com/pmuellr/incubator-cordova-weinre/downloads"&gt;pmuellr/incubator-cordova-weinre downloads page&lt;/a&gt;.
I may keep a 'recent' build here until I get the 
&lt;a href="https://issues.apache.org/jira/browse/INFRA-4343"&gt;continuous builds of weinre at Apache&lt;/a&gt;
working.  At which point, the tar.gz should be available
somewhere at apache.&lt;/p&gt;

&lt;p&gt;Of course, let me know if you have any issues.  Preferred place for discussion
is the 
&lt;a href="https://groups.google.com/forum/?fromgroups#!forum/weinre"&gt;weinre Google Group&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;install locally&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;npm install https://github.com/downloads/pmuellr/incubator-cordova-weinre/weinre-node-1.7.0-pre-2012-02-17--16-47-15.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After that install, you can run weinre via&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;./node_modules/.bin/weinre
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;install globally&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;sudo npm -g install https://github.com/downloads/pmuellr/incubator-cordova-weinre/weinre-node-1.7.0-pre-2012-02-17--16-47-15.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After that install, you can run weinre via&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;weinre
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;notes/caveats&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The command-line options have not changed, although the &lt;code&gt;--reuseAddr&lt;/code&gt; option
is no longer supported.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There is no longer a Mac 'app' version of weinre.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This is &lt;strong&gt;not&lt;/strong&gt; an 'official build' of weinre, in the Apache
sense.  I need to figure out what that even means first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;These 'unofficial' builds have a horrendous 
&lt;a href="http://semver.org/"&gt;semver&lt;/a&gt;
patch version names.  Deal.  If you have a better scheme, please
&lt;a href="https://issues.apache.org/jira/secure/CreateIssueDetails!init.jspa?pid=12312420&amp;amp;components=12316604&amp;amp;issuetype=1"&gt;let me know&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I don't have plans to ever put weinre up at 
&lt;a href="http://npmjs.org/"&gt;npmjs.org&lt;/a&gt;,
since I have no idea how this would work, in practice.
I don't want to &lt;strong&gt;own&lt;/strong&gt; the weinre package up there; ideally
it would be &lt;strong&gt;owned&lt;/strong&gt; by Apache.  Can't see how that would
work either.  If I ever do put a weinre package up at 
npm, I think it would be a placeholder with instructions on
how to get it from Apache.  Or maybe there's a way we can
auto-link the npmjs.org package to Apache mirrors somehow?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I need to look at whether I should continue to ship all my package's
pre-reqs (and their pre-reqs, recursively) or not.  And relatedly,
whether I should actually make fixed version pre-reqs of all the 
recursively pre-req'd modules.  An issue came up today that
I "refreshed" the node_modules, and got an unexpected update
to the &lt;code&gt;formidable&lt;/code&gt; package (a pre-req of &lt;code&gt;connect&lt;/code&gt; which is a pre-req
of &lt;code&gt;express&lt;/code&gt; which is a pre-req of &lt;code&gt;weinre&lt;/code&gt;).  That's not great.
And could be fixed by having explicit versioned dependencies of
all the recursively pre-req'd modules in &lt;code&gt;weinre&lt;/code&gt; itself.
Sigh.  What do other people do here?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prolly need to improve the user docs.  The remainder of this blog 
post is the shipped &lt;code&gt;README.md&lt;/code&gt; file.  So, to read the docs,
start the server, read the docs the server embeds, online.  Sorry.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;running&lt;/h2&gt;

&lt;p&gt;For more information about running weinre, you can start the server
and browse the documentation online.&lt;/p&gt;

&lt;p&gt;Start the server with the following command&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;node weinre
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will start the server, and display a message with the URL to the
server.  Browse to that URL in your web browser, and then click on 
'documentation' link, which will display weinre's online documentation.
From there click on the 'Running' page to get more information about 
running weinre.&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;Update: &lt;a href="https://twitter.com/#!/patrickkettner"&gt;Patrick Kettner&lt;/a&gt; posted a link to this blog post on Hacker News, so you can discuss there, since I'm one of those "disable comments on blog" people.  &lt;a href="http://news.ycombinator.com/item?id=3604291"&gt;http://news.ycombinator.com/item?id=3604291&lt;/a&gt;.&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/xArt2w3qT2I" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2328403398570329898?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2328403398570329898?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/xArt2w3qT2I/npm-installable-version-of-weinre.html" title="npm installable version of weinre" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2012/02/npm-installable-version-of-weinre.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MMQns7fCp7ImA9WhRVGUQ.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-2897338559158240774</id><published>2012-01-19T13:58:00.000-05:00</published><updated>2012-01-19T13:58:03.504-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-19T13:58:03.504-05:00</app:edited><title>AMD - the good parts</title><content type="html">&lt;!-- 
wr --exec "markdown AMD-the-good-parts.md &gt; AMD-the-good-parts.html" *.md
--&gt;

&lt;p&gt;Based my blog post yesterday
"&lt;a href="http://pmuellr.blogspot.com/2012/01/more-on-why-amd-is-not-answer.html"&gt;More on why AMD is Not the Answer&lt;/a&gt;", 
you might guess I'm an AMD-hater. I strive to
&lt;a href="http://jsconf.eu/2011/an_end_to_negativity.html"&gt;not be negative&lt;/a&gt;,
but sometimes I fail.  Mea culpa.&lt;/p&gt;

&lt;p&gt;I &lt;em&gt;do&lt;/em&gt; have a number of issues with AMD.  But I think it's also fair to 
point out "the good parts".  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;my background&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've only really played with a few AMD 
libraries/runtimes. I've been more fiddling around with ways of 
taking node/CommonJS-style modules, and making them 
consumable by AMD runtimes.  The AMD runtimes I've played with 
the most are 
&lt;a href="https://github.com/jrburke/almond"&gt;almond&lt;/a&gt; 
and (my own) 
&lt;a href="https://github.com/pmuellr/modjewel"&gt;modjewel&lt;/a&gt;.
My focus has been on just the raw &lt;code&gt;require()&lt;/code&gt; and &lt;code&gt;define()&lt;/code&gt; 
functions.&lt;/p&gt;

&lt;p&gt;But I follow a lot of the AMD chatter around the web, 
and have done at least reading and perusing through other 
AMD implementations.  To find implementations of AMD, look at
&lt;a href="http://www.commonjs.org/impl/"&gt;this list&lt;/a&gt;
and search for "async".  The ones I hear the most about are
&lt;a href="http://requirejs.org/"&gt;require.js&lt;/a&gt;,
&lt;a href="http://dojotoolkit.org/features/"&gt;Dojo&lt;/a&gt;,
&lt;a href="https://github.com/pinf/loader-js#readme"&gt;PINF&lt;/a&gt;,
and
&lt;a href="https://github.com/cujojs/curl#readme"&gt;curl&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And now, "the good parts".&lt;/p&gt;

&lt;h2&gt;the code&lt;/h2&gt;

&lt;p&gt;Browsing the source repositories and web sites, 
you'll note that folks have spent a 
lot of time on the libraries - the code itself, documentation, 
test suites, support, etc.  Great jobs, all.  I know a lot 
of these libraries have been battle-tested by folks in 
positions to do pretty good battle-testing with them.&lt;/p&gt;

&lt;h2&gt;the evangelism&lt;/h2&gt;

&lt;p&gt;Special mention here to 
&lt;a href="http://tagneto.blogspot.com/"&gt;James Burke&lt;/a&gt;
(not 
&lt;a href="http://en.wikipedia.org/wiki/James_Burke_(gangster)"&gt;this one&lt;/a&gt;),
who has done a spectacular job leading and evangelizing 
the AMD cause, both within the "JavaScript Module" 
community, and outside.  In particular, he's been 
trying to get AMD support into popular libraries like 
&lt;a href="http://bugs.jquery.com/ticket/7102"&gt;jQuery&lt;/a&gt;,
&lt;a href="https://github.com/documentcloud/backbone/issues/search?q=AMD"&gt;backbone&lt;/a&gt;,
&lt;a href="https://github.com/documentcloud/underscore/issues/search?q=AMD"&gt;underscore&lt;/a&gt; and
&lt;a href="https://github.com/joyent/node/issues/search?q=AMD"&gt;node.js&lt;/a&gt;.
Sometimes with success, sometimes not. James has been 
cool and collected when dealing with jerks like me, 
pestering him with complaints, questions, requests and bug reports. 
Some open source communities can be cold and bitter 
places, but the AMD community is not one of those, and I'm sure
that's in part due to James.&lt;/p&gt;

&lt;p&gt;Thanks for all your hard work James!&lt;/p&gt;

&lt;h2&gt;the async support&lt;/h2&gt;

&lt;p&gt;AMD is an acronym for 
&lt;a href="https://github.com/amdjs/amdjs-api/wiki/AMD"&gt;Asynchronous Module Definition&lt;/a&gt;.
That first word, &lt;em&gt;Asynchronous&lt;/em&gt;, is key.
For the most part, if you're using JavaScript, you're living in a world of 
single-threaded processing, where long-running functions are implemented as 
asynchronous calls that take 
callback functions as arguments.  It makes sense, at least in some cases,
to extend this to the function of loading JavaScript code.&lt;/p&gt;

&lt;p&gt;If you need to load JavaScript in an async fashion, AMD is designed for you, 
and uses existing async function patterns that
JavaScript programmers should already be familiar with.&lt;/p&gt;

&lt;h2&gt;support for CommonJS&lt;/h2&gt;

&lt;p&gt;This is a touchy subject, because when you ask 10 people what "CommonJS" is,
you'll get 15 different answers.  For the purposes here, and really whenever
I use the phrase "CommonJS", I'm technically referring to 
&lt;a href="http://www.commonjs.org/specs/"&gt;one of the Modules/1.x specifications&lt;/a&gt;,
and more specifically, the general definitions of the &lt;code&gt;require()&lt;/code&gt; function
and the &lt;code&gt;exports&lt;/code&gt; and &lt;code&gt;module&lt;/code&gt; variables used in the body of a module.
These general definitions are also applicable, with some differences, in 
&lt;a href="http://nodejs.org/docs/latest/api/modules.html"&gt;node.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When I use the phrase "CommonJS", I am &lt;strong&gt;NEVER&lt;/strong&gt; referring to 
the other specifications in the CommonJS specs stable (linked to above).&lt;/p&gt;

&lt;p&gt;AMD supports this general definition of "CommonJS", in my book.
Super double plus one good!&lt;/p&gt;

&lt;p&gt;Aside: I'm looking for another 'name' to call my simplistic notion
of CommonJS.  So far, things like &lt;em&gt;simple &lt;code&gt;require()&lt;/code&gt;y support&lt;/em&gt;,
seem to capture my intent.  But you know how 
&lt;a href="http://callback.github.com/callback-weinre/"&gt;bad I am with naming&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;the design for quick edit-debug cycles&lt;/h2&gt;

&lt;p&gt;One of the goals of AMD is to facilitate a quick
edit-debug cycle while you are working on your JavaScript.  To
do this, AMD specifies that you wrap the body of your module in
a specific type of function wrapper when you author it.
Because of the way it's designed, these JavaScript files can
be loaded directly with a &lt;code&gt;&amp;lt;script src=&amp;gt;&lt;/code&gt; element in your HTML
file, or via &lt;code&gt;&amp;lt;script src=&amp;gt;&lt;/code&gt; elements injected into your live web page
dynamically, by a library.  This means that as soon as you save the JavaScript you're
editing in your text editor/IDE, you can refresh the page in
your browser without an intervening "build step" or special
server processing - the same files you are editing are loaded
directly in the browser.&lt;/p&gt;

&lt;h2&gt;the resources&lt;/h2&gt;

&lt;p&gt;Beyond just loading JavaScript code, AMD supports the notion
of loading other &lt;em&gt;things&lt;/em&gt;.  The &lt;em&gt;things&lt;/em&gt; you can load
are determined by what 
&lt;a href="https://github.com/amdjs/amdjs-api/wiki/Loader-Plugins"&gt;Loader Plugins&lt;/a&gt;
you have available.  Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jrburke/requirejs/blob/master/text.js"&gt;the text of a file/resource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jrburke/requirejs/blob/master/i18n.js"&gt;i18n bundles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ZeeAgency/requirejs-tpl"&gt;templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Coming from the Java world, this is familiar territory; see:
&lt;a href="http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getResourceAsStream(java.lang.String)"&gt;Class.getResource*() methods&lt;/a&gt;.
For the most part, I consider this to be amongst the core bits of 
functionality that a programming library should provide.  It's a common
pattern to ship data with your code, and you need some way to access it.
And, of course, this resource loading is available in an async manner
with AMD.&lt;/p&gt;

&lt;p&gt;Aside: I'm not sure what the analog of this is in the node.js world. 
You can certainly do it by hand, making use of the 
&lt;a href="http://nodejs.org/docs/latest/api/globals.html#__dirname"&gt;&lt;tt&gt;__dirname&lt;/tt&gt;&lt;/a&gt;
global, and then performing i/o yourself.  I'm just not sure if 
someone has wrapped this up nicely in a library yet.&lt;/p&gt;

&lt;h2&gt;the build&lt;/h2&gt;

&lt;p&gt;At the end of the day, hopefully, your web application is going to be available
to some audience, who will be using it for realz.  It's unlikely that you will want to 
continue to load your JavaScript code (and resources) as individual pieces as you do 
in development; instead, you'll want to concatenate and minimize your wads of goo
to keep load time to a minimum for your customers.&lt;/p&gt;

&lt;p&gt;And it seems like most AMD implementations provide a mechanism to do this.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/WlpJWAYgEck" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2897338559158240774?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2897338559158240774?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/WlpJWAYgEck/amd-good-parts.html" title="AMD - the good parts" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2012/01/amd-good-parts.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UBSHs-fyp7ImA9WhRVGU0.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-64780419174178852</id><published>2012-01-18T10:38:00.000-05:00</published><updated>2012-01-18T10:40:59.557-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-18T10:40:59.557-05:00</app:edited><title>More on why AMD is Not the Answer</title><content type="html">&lt;!--
wr --exec "markdown More-on-why-AMD-is-Not-the-Answer.md &gt; More-on-why-AMD-is-Not-the-Answer.html" *.md
--&gt;

&lt;p&gt;Follow-on to Tom Dale's blog post "&lt;a href="http://tomdale.net/2012/01/amd-is-not-the-answer/"&gt;AMD is Not the Answer&lt;/a&gt;" and James Burke's response "&lt;a href="http://tagneto.blogspot.com/2012/01/reply-to-tom-on-amd.html"&gt;Reply to Tom on AMD&lt;/a&gt;".  I pretty much concur with everything Tom said.  Here are some points brought up by James:&lt;/p&gt;

&lt;h2&gt;need an alternative&lt;/h2&gt;

&lt;p&gt;James says:&lt;/p&gt;

&lt;blockquote&gt;&lt;i&gt;
  &lt;p&gt;what is missing is a solid alternative to AMD. In particular, "use build tools to wrap up CommonJS modules" is not a generic solution. It does not allow for generic dynamic loading of resources, particularly from CDNs. Dynamic loading is needed for big sites that still do builds but want to stage loading of the site as the user uses it.&lt;/p&gt;
&lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;I don't think using build tools precludes you from building wads of modules that can be loaded dynamically.  Generic solutions bother me.  See: J2EE.&lt;/p&gt;

&lt;h2&gt;ceremony&lt;/h2&gt;

&lt;p&gt;James says:&lt;/p&gt;

&lt;blockquote&gt;&lt;i&gt;
  &lt;p&gt;On his concern about too much ceremony -- this is the minimum amount of ceremony:&lt;/p&gt;
&lt;/i&gt;&lt;/blockquote&gt;

&lt;pre&gt;&lt;code&gt;    define(function(require) {
        //Module code in here
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On the other hand, here's some code pulled from &lt;a href="http://svn.dojotoolkit.org/src/dijit/trunk/Calendar.js"&gt;&lt;code&gt;dijit.Calendar.js&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    define([
        "dojo/_base/array", // array.map
        "dojo/date",
        "dojo/date/locale",
        "dojo/_base/declare", // declare
        "dojo/dom-attr", // domAttr.get
        "dojo/dom-class", // domClass.add domClass.contains domClass.remove domClass.toggle
        "dojo/_base/event", // event.stop
        "dojo/_base/kernel", // kernel.deprecated
        "dojo/keys", // keys
        "dojo/_base/lang", // lang.hitch
        "dojo/sniff", // has("ie")
        "./CalendarLite",
        "./_Widget",
        "./_CssStateMixin",
        "./_TemplatedMixin",
        "./form/DropDownButton"
    ], function(array, date, local, declare, domAttr, domClass, event, kernel, keys, lang, has,
                CalendarLite, _Widget, _CssStateMixin, _TemplatedMixin, DropDownButton){
        //Module code in here
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This isn't just ceremony.  It's ugly ceremony of the sort that's difficult to debug when you screw up.&lt;/p&gt;

&lt;h2&gt;module consumption&lt;/h2&gt;

&lt;p&gt;James says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;the alternative he mentions does not handle the breadth of JS module consumption&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The simple &lt;code&gt;require()&lt;/code&gt;y story of &lt;a href="http://npmjs.org"&gt;npm&lt;/a&gt; modules seems to handle the JS module consumption pretty well, for node.js.  For the browser, you can use npm modules with &lt;a href="https://github.com/substack/node-browserify"&gt;Browserify&lt;/a&gt; or other "build tools".  Where is the equivalent of npm for AMD?  Or maybe npm already contains AMD modules?  Or let's say I want to just use a single module out of Dojo in my app.  How do I do that?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/9xV5RCxHpto" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/64780419174178852?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/64780419174178852?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/9xV5RCxHpto/more-on-why-amd-is-not-answer.html" title="More on why AMD is Not the Answer" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2012/01/more-on-why-amd-is-not-answer.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYHQXg4cCp7ImA9WhRVFEw.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-2976012419713345912</id><published>2012-01-12T20:12:00.000-05:00</published><updated>2012-01-12T20:12:10.638-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-12T20:12:10.638-05:00</app:edited><title>making Web SQL easier to use</title><content type="html">&lt;!--
wr --exec "markdown WebSQLStepper.md &gt; WebSQLStepper.html" *.md
--&gt;

&lt;p&gt;One HTML5-ish area I've not yet played much with, but am starting to now, is Web SQL.  Web SQL is the W3 standard for "SQL in the browser", which has been orphaned by the W3C.  Here are some warnings from the &lt;a href="http://www.w3.org/TR/webdatabase/"&gt;Web SQL Database spec at w3.org&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;"Beware. This specification is no longer in active maintenance and the Web Applications Working Group does not intend to maintain  it further."&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;"This document was on the W3C Recommendation track but specification work has stopped. The specification reached an impasse: all interested implementors have used the same SQL backend (Sqlite), but we need multiple independent implementations to proceed along a standardisation path."&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite the fact that the W3C no longer endorses Web SQL and will never 'standardize' it, implementations of Web SQL are shipping in browsers, including &lt;a href="http://mobilehtml5.org/"&gt;some mobile platforms&lt;/a&gt;.  It's not dead yet.&lt;/p&gt;

&lt;h2&gt;what's the api like?&lt;/h2&gt;

&lt;p&gt;Here's an example right out of the spec, to count the number of rows in a table:&lt;/p&gt;

&lt;script src="https://gist.github.com/1603740.js?file=showDocCount.js"&gt;&lt;/script&gt;

&lt;p&gt;A function &lt;code&gt;showDocCount()&lt;/code&gt;that calls a function &lt;code&gt;db.readTransaction()&lt;/code&gt; that takes two anonymous functions as callbacks.  One of those callbacks calls &lt;code&gt;t.executeSql()&lt;/code&gt; passing it yet another callback, which finally, mercifully, gets the row count.&lt;/p&gt;

&lt;p&gt;It's executing &lt;strong&gt;a single SQL statement&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;But wait, it gets better.&lt;/p&gt;

&lt;p&gt;If you need to run multiple SQL statements within a single transaction, you'll have to chain those &lt;code&gt;executeSql()&lt;/code&gt; invocations within increasingly nested callbacks.&lt;/p&gt;

&lt;p&gt;It's basically a horror show.  At least as far as I'm concerned.  Nested callbacks are things I hate to have to write, and things I really hate seeing other people have to write.  The result is almost always unintelligible.&lt;/p&gt;

&lt;h2&gt;can we make this easier to understand?&lt;/h2&gt;

&lt;p&gt;For &lt;a href="http://callback.github.com/callback-weinre/"&gt;weinre&lt;/a&gt;, I implemented a &lt;a href="https://github.com/callback/callback-weinre/blob/master/weinre.web/modules/weinre/target/SqlStepper.coffee"&gt;stepper module&lt;/a&gt; used by the &lt;a href="https://github.com/callback/callback-weinre/blob/master/weinre.web/modules/weinre/target/WiDatabaseImpl.coffee"&gt;inspector's database interface&lt;/a&gt;.  Not very clear what's going on there though, sorry.&lt;/p&gt;

&lt;p&gt;The basic idea is that you provide an array of functions - the steps - that the stepper will arrange to run in order, by managing the callbacks itself.  Double bonus good - you get to linearize your database transaction steps &lt;strong&gt;and&lt;/strong&gt; you don't have to deal with callbacks!&lt;/p&gt;

&lt;p&gt;I found another instance of this kind of processing in Caolan McMahon's &lt;a href="https://github.com/caolan/async"&gt;async&lt;/a&gt; library - specifically the &lt;a href="https://github.com/caolan/async#waterfall"&gt;&lt;code&gt;waterfall()&lt;/code&gt;&lt;/a&gt; function.  Not really appropriate for Web SQL, but at least it seems to validate the approach.&lt;/p&gt;

&lt;p&gt;I decided to implement a clean implementation of the stepper, trying to make it easy to use and understand.  The result is available as &lt;a href="https://github.com/pmuellr/WebSQLStepper"&gt;WebSQLStepper at GitHub&lt;/a&gt;.  As a use case, I took the &lt;a href="http://documentcloud.github.com/backbone/#examples-todos"&gt;Todos sample&lt;/a&gt; from &lt;a href="http://documentcloud.github.com/backbone/"&gt;Backbone&lt;/a&gt;, and modified it to use this library to persist the data to a Web SQL database.  The complete sample is &lt;a href="https://github.com/pmuellr/WebSQLStepper/blob/master/samples/backbone-todos/todos-websql.coffee"&gt;included in the GitHub repo&lt;/a&gt;, and here are the steps used to read all the rows of a database:&lt;/p&gt;

&lt;script src="https://gist.github.com/1603847.js?file=some-steps.coffee"&gt;&lt;/script&gt;

&lt;h2&gt;references&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pmuellr/WebSQLStepper"&gt;WebSQLStepper at GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.w3.org/TR/webdatabase/"&gt;Web SQL Database spec at W3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sqlite.org/"&gt;SQLite documentation&lt;/a&gt; - SQLlite is used in the Web SQL implementation for WebKit-based browsers&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/Hxgn-U8rdRU" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2976012419713345912?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2976012419713345912?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/Hxgn-U8rdRU/making-web-sql-easier-to-use.html" title="making Web SQL easier to use" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2012/01/making-web-sql-easier-to-use.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcGQHo7eip7ImA9WhRVFE0.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-1383519842683429266</id><published>2012-01-12T13:20:00.000-05:00</published><updated>2012-01-12T15:27:01.402-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-12T15:27:01.402-05:00</app:edited><title>wr - an auto-build command for the command-line</title><content type="html">&lt;!-- wr command invocation
wr --exec "markdown wr.md &gt; wr.html" wr.md
--&gt;

&lt;p&gt;
For much of my programming career, I've been a user of "IDE"s, including &lt;a href="http://www.youtube.com/watch?v=JDnypVoQcPw"&gt;BASIC&lt;/a&gt;, &lt;a href="http://www.youtube.com/watch?v=0ZQCXXhXq6Q"&gt;Turbo Pascal&lt;/a&gt;, various Smalltalks, IBM's VisualAge products and Eclipse.

&lt;p&gt;
Lately, I've been spending most of my time working without any IDEs.  My tools are text editors, terminal windows, a boat load of unix commands built-in to my OS, some additional command-line tools from various open source locales, and web browsers.  I think of this loosely organized/integrated set of tools as my IDE, they're just not packaged up in a nice single app.

&lt;p&gt;
But there's one thing I dearly love and really depend on in most IDE's that's missing from this command-line-based environment: an "auto-build" capability.  Specifically, when I save a file I'm editing, I want a "build" to happen automagically.  Without an "auto-build" capability, I'm left in a world where I save a change in my text editor, jump over to the terminal, run &lt;code&gt;make&lt;/code&gt;, then jump to my browser to test the build.  The jump to the terminal is not desired.  Using some existing editor's capability of running shell commands doesn't work either, because I use a wide variety of tools to "edit" things - all the tools would need this capability.

&lt;p&gt;
&lt;em&gt;(Quick aside about "builds".  A lot of people see "build" and think "30 minutes of waiting for the compiles to be done".  Yes, those builds are long and painful.  I'm looking at you WebKit.  But in all the IDEs I used to use, builds were &lt;strong&gt;insanely&lt;/strong&gt; fast.  Sub-second fast.  If you're living the "big C++ project" lifestyle, I feel your pain, and "auto-build" is probably not applicable for you.&lt;/em&gt;

&lt;p&gt;
&lt;em&gt;So, I'm talking about quick builds here.  As an example, once you've done at least one build of &lt;a href="http://callback.github.com/callback-weinre/"&gt;weinre&lt;/a&gt;, subsequent builds take on the order of 6 seconds or so - I consider that slow, but it's doing a lot of work, and I could probably cut the time in half if I needed to - I just haven't felt the need to.&lt;/em&gt;)

&lt;h2&gt;
a command to run something when a file changes&lt;/h2&gt;

&lt;p&gt;
A few years ago, I wasn't aware of a tool that could watch for arbitrary file changes and run a command for me, so I wrote one - &lt;a href="https://gist.github.com/240922"&gt;&lt;code&gt;run-when-changed&lt;/code&gt;&lt;/a&gt;.  This script served me well for a long time, but there were always little thingees I wanted to add to it.  And since &lt;code&gt;run-when-changed&lt;/code&gt; polled the file system to see when files changed, I was always interested in finding a better story than polling and the inevitable waiting for the polling cycle to hit - even waiting 3 seconds for &lt;code&gt;run-when-changed&lt;/code&gt; to realize a file changed was bothersome.

&lt;p&gt;
A port to &lt;a href="http://nodejs.org"&gt;node.js&lt;/a&gt; seemed like it might be in order, especially since it has a non-polling file watch function &lt;a href="http://nodejs.org/docs/latest/api/fs.html#fs.watch"&gt;&lt;code&gt;fs.watch()&lt;/code&gt;&lt;/a&gt;.

&lt;p&gt;
Earlier this week, I spent a few hours and now I have a replacement for &lt;code&gt;run-when-changed&lt;/code&gt;, called &lt;code&gt;wr&lt;/code&gt;, &lt;a href="https://github.com/pmuellr/wr"&gt;available at GitHub&lt;/a&gt;, written using node.js.  The name &lt;code&gt;wr&lt;/code&gt; comes from "&lt;strong&gt;w&lt;/strong&gt;atch and &lt;strong&gt;r&lt;/strong&gt;un".

&lt;p&gt;
Some features:

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;
installable via &lt;a href="http://search.npmjs.org/#/wr"&gt;npm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;
colorized stdout and stderr
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;
reversed video status messages
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;
when run with no arguments, will look for a &lt;code&gt;.wr&lt;/code&gt; file in the current directory to use as arguments
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Here's what it looks like, using it with one of my current projects:

&lt;p&gt;
&lt;a href="http://4.bp.blogspot.com/-5M0PsRQ0gC4/Tw5mzNVj39I/AAAAAAAAArA/XF0Pta31sPU/s1600/wr-screen-shot.jpg"&gt;
&lt;img src="http://1.bp.blogspot.com/-k7bmbZoGF2o/Tw8OhYH--EI/AAAAAAAAAsI/4X5KAJRK0uk/s1600/wr-screen-shot-3.jpg" border=0&gt;
&lt;/a&gt;

&lt;p&gt;
&lt;em&gt;Click the image for a slightly larger version.&lt;/em&gt;

&lt;p&gt;
Legend:

&lt;ul&gt;
&lt;li&gt;the reverse video blue lines are status messages&lt;/li&gt;
&lt;li&gt;the reverse video green lines are command success messages&lt;/li&gt;
&lt;li&gt;the reverse video red lines are command failure messages&lt;/li&gt;
&lt;li&gt;the blue text is stdout&lt;/li&gt;
&lt;li&gt;the red text is stderr&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
As another example, I'm generating this blog post by running the following command:

&lt;pre&gt;&lt;code&gt;    wr --exec "markdown wr.md &amp;gt; wr.html" wr.md
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
Breaking this command down, we have:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wr&lt;/code&gt; - the command&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--exec&lt;/code&gt; - a command-line option (see below in &lt;strong&gt;gotchas&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"markdown wr.md &amp;gt; wr.html"&lt;/code&gt; - the command to run&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wr.md&lt;/code&gt; - the file to watch for changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
The arguments to &lt;code&gt;wr&lt;/code&gt; are options, the command to run, and the names of files or directories to watch.  When the &lt;code&gt;wr&lt;/code&gt; command is run, it waits for one of the specified files to change, runs the specified command, reports the results of running the command, and then starts waiting for a file to change again.  Exit the program by pressing &lt;code&gt;^C&lt;/code&gt;.

&lt;p&gt;
The ability to store a &lt;code&gt;.wr&lt;/code&gt; file in a project directory makes life even easier.  I used to create a target in my &lt;code&gt;make&lt;/code&gt; files to invoke &lt;code&gt;run-which-changed&lt;/code&gt; ; now I just put the wr invocation for a project in the &lt;code&gt;.wr&lt;/code&gt; file, and run &lt;code&gt;wr&lt;/code&gt; with no arguments.

&lt;p&gt;
My work-flow for using &lt;code&gt;wr&lt;/code&gt; goes something like this:

&lt;ul&gt;
&lt;li&gt;open a terminal window&lt;/li&gt;
&lt;li&gt;cd into my project's home directory&lt;/li&gt;
&lt;li&gt;launch an editor, returning control to the command-line&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;wr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;move the terminal window where I will always be able to see the last few lines of the window, to see the live status&lt;/li&gt;
&lt;li&gt;switch between text editor and browser, for my edit-save-reload-test cycle, all day long, keeping an eye out for red stuff in the &lt;code&gt;wr&lt;/code&gt; output&lt;/li&gt;
&lt;li&gt;when the day is done, &lt;code&gt;^C&lt;/code&gt; out of &lt;code&gt;wr&lt;/code&gt;, and then commit work to my SCM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
This can all be yours, with a simple command-line incantation:

&lt;pre&gt;&lt;code&gt;    sudo npm -g install wr
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;
current gotchas&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;wr&lt;/code&gt; has two ways of invoking the command to run, determined by the command-line option &lt;code&gt;--exec&lt;/code&gt;; see the &lt;a href="https://github.com/pmuellr/wr"&gt;README&lt;/a&gt;, in the &lt;strong&gt;ENVIRONMENT&lt;/strong&gt; section, for more information on the differences.

&lt;p&gt;
The big gotcha though is the non-polling file watching.  This is an awesome feature, as it means as soon as you save a file, &lt;code&gt;wr&lt;/code&gt; will wake up and run a command.  The problem, on the Mac anyway, is that there is a relatively small limit on the number of files that can be watched this way.  Like, 200 or so.  If you go over the limit, you'll see some error messages from &lt;code&gt;wr&lt;/code&gt;, and you'll have to resort to using the &lt;code&gt;--poll&lt;/code&gt; option, which uses a polling file watcher.&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/9pMo_Snp7X0" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/1383519842683429266?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/1383519842683429266?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/9pMo_Snp7X0/wr-auto-build-command-for-command-line.html" title="wr - an auto-build command for the command-line" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-k7bmbZoGF2o/Tw8OhYH--EI/AAAAAAAAAsI/4X5KAJRK0uk/s72-c/wr-screen-shot-3.jpg" height="72" width="72" /><feedburner:origLink>http://pmuellr.blogspot.com/2012/01/wr-auto-build-command-for-command-line.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UDSHY8eCp7ImA9WhRXEEg.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-535450172561441953</id><published>2011-12-16T12:00:00.003-05:00</published><updated>2011-12-16T12:07:59.870-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-16T12:07:59.870-05:00</app:edited><title>accessible backed up git repos for transient work-related projects</title><content type="html">&lt;p&gt;&lt;b&gt;preface:&lt;/b&gt; &lt;i&gt;this is basically a "note to self", but thought others might find it useful&lt;/i&gt;

&lt;p&gt;I tend to create a lot of "projects" at work.  A "project" is a directory in my "&lt;tt&gt;~/Projects&lt;/tt&gt;" directory.  Who knows what might be in it; probably code, or maybe just documentation.  Many times, it's a "project" that I think may be useful to other people, and I may eventually "publish" to an either a public SCM repo farm like GitHub or an internal IBM SCM repo farm.  I currently have 317 projects in my "&lt;tt&gt;~/Projects&lt;/tt&gt;" directory.
    
&lt;p&gt;Before "publishing" it though, I'll usually want to crank on it for a bit, see if I can get the crap to work, and figure out if it's actually useful.  So there's a window where my project isn't being "backed up" or available to anyone else, because it's sitting on my laptop's spinning disk of rust.  That's not great.

&lt;p&gt;In the past, I've used Subversion and/or Mercurial to help manage this "back up" process for personal, non-work-related projects.  What I'd do is set up a repo on my shared server, and then just use it like any other remote SCM.

&lt;p&gt;Problems:

&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;What about work-related stuff?  I don't want to publish something that's work-related on a non-IBM site.
    
&lt;li&gt;&lt;p&gt;I made it sound like "&lt;i&gt;set up a repo on my shared server&lt;/i&gt;" was easy.  It isn't.  Depending on the capabilities of your server, it might be impossible.
    
&lt;li&gt;&lt;p&gt;Yeah, we do have various internal-only SCM repo farms in IBM, but those still require some "setup" and "maintenance", just a different flavor than shared hosting, and even that can be too much sometimes. Especially for a project which may only be useful for a couple of days.
    
&lt;/ul&gt;

&lt;p&gt;Bummer.
    
&lt;p&gt;&lt;b style="font-size:120%"&gt;a new hope&lt;/b&gt;
    
&lt;p&gt;What I'm doing now is using Git, and storing my Git repos on IBM's internal, backed up, rsync-/smb-/http-accessible cloud file store.  Even if you don't have rsync or smb access, there are likely ways you can do something similar, with different tools, on your own server.
    
&lt;p&gt;Here's how it works:
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;mount the file store on my local machine, create a directory for the new repo in my "&lt;tt&gt;git-repos&lt;/tt&gt;" directory, which is in a part of my cloud file store that is publically accessible via http, unmount the file store.
    
&lt;li&gt;&lt;p&gt;initialize the project on my local machine with git (eg, "&lt;tt&gt;git init&lt;/tt&gt;")
    
&lt;li&gt;&lt;p&gt;write a "&lt;tt&gt;backup&lt;/tt&gt;" script, which looks like this:
    
&lt;pre&gt;
#!/bin/sh

#--------------------------
# make the git repo accessible via:
#   git clone http://{host-name}/~pmuellr/git-repos/{project-name}/.git
#--------------------------

cd `dirname $0`

git update-server-info
rsync -av . {host-name}:{path-to}/git-repos/{project-name}
&lt;/pre&gt;
    
&lt;li&gt;&lt;p&gt;Instead of using a "&lt;tt&gt;git add/commit/push&lt;/tt&gt;" workflow, I use a "&lt;tt&gt;git add/commit;  ./backup&lt;/tt&gt;" workflow.
    
&lt;li&gt;&lt;p&gt;As the comment in the script notes, the git repo is accessible via http, to anyone who has access to that URL.  For the general case for me, that's anyone in IBM.

&lt;li&gt;&lt;p&gt;The "&lt;tt&gt;backup&lt;/tt&gt;" script, as written, also backs up my working directory.  Which is a win as far as I'm concerned.  Now I can also point folks to web-accessible/-renderable resources in my working directory.
    
&lt;/ul&gt;

&lt;p&gt;I've found this to be a very useful, very lightweight process to keep my immature projects backed up.  I don't doubt there are ways to do similar things with SVN or Mercurial or whatever as well, I just never tried.
    
&lt;p&gt;I can, but haven't yet, set up a similar story for personal projects, using my shared server, but that should be pretty easy; it supports rsync, but not smb.  Instead of "mount and create project directory", I can "ssh and create project directory".  Even that's probably not needed; rsync can likely create that project directory for me, but I'm an rsync n00b and I kind of like having to make that step explicit.&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/t57wL-4uDa8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/535450172561441953?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/535450172561441953?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/t57wL-4uDa8/accessible-backed-up-git-repos-for.html" title="accessible backed up git repos for transient work-related projects" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2011/12/accessible-backed-up-git-repos-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIHRXgyfyp7ImA9WhRSFEg.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-8270567618462148909</id><published>2011-11-16T10:31:00.000-05:00</published><updated>2011-11-16T10:32:14.697-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-16T10:32:14.697-05:00</app:edited><title>debugging concatenated JavaScript files</title><content type="html">&lt;p&gt;In James Burke's blog post "&lt;a href="http://tagneto.blogspot.com/2011/11/why-not-amd.html"&gt;Why not AMD?&lt;/a&gt;", 
the subject of debugging briefly came up. In response to the claim that AMD is "Inefficient by default", James responds: (bold emphasis applied by me)

&lt;blockquote&gt;&lt;i&gt;
&lt;p&gt;I assume this means that it allows separate modules to be loaded async. FWIW, the current state of ES harmony modules will allow separate file loading for each module. &lt;b&gt;This works better for debugging.&lt;/b&gt;
&lt;p&gt;For AMD, you can get the "one script file at the bottom of the page" loading with the 750 byte almond AMD shim and runtime http loading.
&lt;p&gt;I cannot see a better solution to this issue. If you have ideas I would like to hear them.
&lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;I'd like to point out some futures/options for making concatenated scripts easier to debug.  None of solutions deal with mangled names, they're just ways of letting the debugger show a concatenated script as the set of individual scripts that make up the concatenated script.  Baby steps!
    
&lt;!-- ====================================================================== --&gt;
&lt;p&gt;&lt;b style='font-size:150%'&gt;Source Map support in the web debuggers&lt;/b&gt;

&lt;p&gt;Werner Schuster's blog post "&lt;a href="http://www.infoq.com/news/2011/08/debug-languages-on-javascript-vm"&gt;Mozilla, WebKit To Support Debugging Minified JS As Well As CoffeeScript and other JS Languages&lt;/a&gt;" covers most of the ground for the Source Map work that's ongoing.  Chris Heilmann's recent presentation from Velocity "&lt;a href="http://velocityconf.com/velocityeu/public/schedule/detail/21787"&gt;Firefox Performance&lt;/a&gt;" mentions some work going on at Mozilla.
    
&lt;p&gt;Of course, we need both ends working here; minizer's are going to have to be able to spit out Source Maps, as well as language translators like CoffeeScript.  The CoffeeScript bug for Source Map work is &lt;a href="https://github.com/jashkenas/coffee-script/issues/558"&gt;here&lt;/a&gt; (I think).
    
&lt;!-- ====================================================================== --&gt;
&lt;p&gt;&lt;b style='font-size:150%'&gt;cheating with &lt;tt&gt;eval()&lt;/tt&gt; and &lt;tt&gt;//@ sourceurl&lt;/tt&gt;&lt;/b&gt;
    
&lt;p&gt;Back in the day, a feature in Firebug that I copied into Web Inspector was "sourceURL" support,
described in "&lt;a href="http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/"&gt;Give your eval a name with &lt;tt&gt;//@ sourceURL&lt;/tt&gt;&lt;/a&gt;".  I recently made use of this in my "unminified" version of the injected target weinre script.  &lt;a href="http://callback.github.com/callback-weinre/"&gt;weinre&lt;/a&gt; ships with two versions of the code that gets injected into the target: &lt;tt&gt;target-script.js&lt;/tt&gt; and &lt;tt&gt;target-script-min.js&lt;/tt&gt;.  The "min" version is what you should be using for typical weinre debugging, the non-"min" version is what I use when debugging the debugger.  

&lt;p&gt;The file &lt;tt&gt;target-script-min.js&lt;/tt&gt; contains gently minized JS files, just concatenated together.  The &lt;tt&gt;target-script.js&lt;/tt&gt; file is a bit different.  For every JS file, it adds a "&lt;tt&gt;//@ sourceurl&lt;/tt&gt;" comment to the bottom of the file, converts the script content to a string with &lt;tt&gt;JSON.stringify()&lt;/tt&gt;, and then writes an &lt;tt&gt;eval(&lt;i&gt;[that string here]&lt;/i&gt;)&lt;/tt&gt; to the concatenated file.  
    
&lt;p&gt;The difference between debugging these in a browser which supports &lt;tt&gt;sourceurl&lt;/tt&gt; is night and day.  Try it: after visiting these pages, open your web debugger and look at the scripts which are loaded.  Note, this works on Google Chrome 16.0.912.36 beta on a Mac (and likely other versions).
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://dl.dropbox.com/u/2192156/blog/sourceURL/target-script-min.html"&gt;&lt;tt&gt;target-script-min&lt;/tt&gt;&lt;/a&gt;
&lt;li&gt;&lt;a href="http://dl.dropbox.com/u/2192156/blog/sourceURL/target-script.html"&gt;&lt;tt&gt;target-script&lt;/tt&gt;&lt;/a&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/vSWaK4p3ctA" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/8270567618462148909?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/8270567618462148909?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/vSWaK4p3ctA/debugging-concatenated-javascript-files.html" title="debugging concatenated JavaScript files" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2011/11/debugging-concatenated-javascript-files.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQCRHYyfyp7ImA9WhRTEE0.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-1468710805033159283</id><published>2011-10-30T15:43:00.001-04:00</published><updated>2011-10-30T16:42:45.897-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-30T16:42:45.897-04:00</app:edited><title>what's new in weinre 1.6.0</title><content type="html">&lt;p&gt;Notable changes in &lt;a href="https://github.com/callback/callback-weinre/downloads"&gt;weinre 1.6&lt;/a&gt;, which was &lt;a href="http://callback.github.com/callback-weinre/ChangeLog.html"&gt;released last week&lt;/a&gt;.  More weinre links &lt;a href="http://callback.github.com/callback-weinre/Home.html"&gt;here&lt;/a&gt;.
    
&lt;!-- ====================================================================== --&gt;
&lt;p&gt;&lt;b style='font-size:150%'&gt;Element Highlighter Color Changes&lt;/b&gt;

&lt;p&gt;The "element highlighter" is the coloring you get on your web page when you hover over DOM elements in weinre's Elements panel.  Previously, the colors were very muddled.

&lt;p&gt;Below are the new colors, with the orange-ish margin, turquoise-ish padding, and purple-ish body.  Not shown is the border (this element has none), which is a bright yellow.

&lt;p&gt;&lt;img src="http://2.bp.blogspot.com/-0aKuphlThrA/Tq2OMTmlBDI/AAAAAAAAAqo/3tTOW_AvGZ4/s1600/weinre-1.6-highlighter.png"&gt;
    
&lt;p&gt;There are still some issues with this highlighter, which was about the 6th different one I had tried.  As a result of all those attempts, the element highlighter is now fairly pluggable, and it should be straight-forward for you to create a better one.  I dare ya.

&lt;!-- ====================================================================== --&gt;
&lt;p&gt;&lt;b style='font-size:150%'&gt;JavaScript Callback Error Diagnostics&lt;/b&gt;

&lt;p&gt;I often hear people talk about debugging their JavaScript with weinre, but weinre really just provides a &lt;a href="http://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop"&gt;REPL&lt;/a&gt; and console logging.  New in 1.6 is an attempt to provide some additional JavaScript diagnostics.
    
&lt;p&gt;For a set of built-in functions in JavaScript that have callbacks as parameters, weinre overrides those functions to run an instrumented version of the callback instead.  The instrumented version just runs the specified callback within a &lt;tt&gt;try/catch&lt;/tt&gt; statement and reports if an exception occurred.  The functions that weinre overrides are:
    
&lt;ul&gt;
&lt;li&gt;&lt;tt&gt;window.setTimeout()&lt;/tt&gt;
&lt;li&gt;&lt;tt&gt;window.setInterval()&lt;/tt&gt;
&lt;li&gt;&lt;tt&gt;window.addEventListener()&lt;/tt&gt;
&lt;li&gt;&lt;tt&gt;Node.prototype.addEventListener()&lt;/tt&gt;
&lt;li&gt;&lt;tt&gt;XMLHttpRequest.prototype.addEventListener()&lt;/tt&gt;
&lt;/ul&gt;
    
&lt;p&gt;The &lt;tt&gt;Node.prototype.addEventListener()&lt;/tt&gt; override should handle &lt;tt&gt;document&lt;/tt&gt; and all DOM elements in your document. The &lt;tt&gt;XMLHttpRequest.prototype.addEventListener()&lt;/tt&gt; will handle your XHR's.  Unfortunately, I'm not quite sure how to override the &lt;tt&gt;on&lt;/tt&gt;-family of event properties, because browser host objects suck.

&lt;p&gt;As an example of what you'll see in the Console window when an exception occurs, here's some JavaScript code which will generate a runtime error when the specified button is clicked:
    
&lt;script src="https://gist.github.com/1326232.js?file=error-in-click.js"&gt;&lt;/script&gt;
    
&lt;p&gt;Below is what you see in the console when the button is clicked.
    
&lt;p&gt;&lt;img src="http://1.bp.blogspot.com/-4Jkks3tudJk/Tq2OAkIvc-I/AAAAAAAAAps/vtaXQjeEeAU/s1600/weinre-1.6-error-info-a.png"&gt;
    
&lt;p&gt;Description of the five error messages in the console:
    
&lt;ol&gt;
&lt;li&gt;This is the toString() of the exception that was caught when the callback was invoked.
&lt;li&gt;The callsite is an informational description of the call which registered the callback.  In this case, it tells us the callback was registed to an &lt;tt&gt;&amp;lt;input&amp;gt;&lt;/tt&gt; element's click handler, and that the callback registered was a function named &lt;tt&gt;buttonClicked()&lt;/tt&gt;.
&lt;li&gt;If the caught exception has a &lt;tt&gt;stack&lt;/tt&gt; property, the stack will be dumped following this line.  Otherwise, you won't see this line or the stack.
&lt;li&gt;This is the stack at the time the runtime exception occurred, if available.  Note that the last two lines (&lt;tt&gt;at &amp;lt;error: TypeError: ...&lt;/tt&gt;) seem to be bugs of some kind in the browser (couldn't be in &lt;i&gt;my&lt;/i&gt; code!).
&lt;li&gt;This is actually a line from the new &lt;tt&gt;onerror&lt;/tt&gt; handler that weinre registers, unrelated to the new callback exception logging described here.
&lt;/ol&gt;
    
&lt;p&gt;Not all browser's JavaScript engines support the &lt;tt&gt;error.stack&lt;/tt&gt; property (eg, WebKit's JavaScriptCore), so this is what you'll see if you're running on one of those lame engines:
    
&lt;p&gt;&lt;img src="http://1.bp.blogspot.com/-pCWTsQGhA_A/Tq2OA0ti3ZI/AAAAAAAAAp8/BwpStcbiaLs/s1600/weinre-1.6-error-info-b.png"&gt;
    
&lt;p&gt;Also note the third line is, again, from the new &lt;tt&gt;onerror&lt;/tt&gt; handler, which seems to like to not contain useful information.  Why not?  See &lt;a href="http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2011-September/033252.html"&gt;here&lt;/a&gt;, &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=568564"&gt;here&lt;/a&gt;, &lt;a href="http://www.w3.org/Bugs/Public/show_bug.cgi?id=14177"&gt;here&lt;/a&gt;, and &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=70574"&gt;here&lt;/a&gt;.

&lt;!-- ====================================================================== --&gt;
&lt;p&gt;&lt;b style='font-size:150%'&gt;The New Resources Panel&lt;/b&gt;

&lt;p&gt;The Resources panel is brand new for version 1.6.  It provides diagnostics for all the XHRs that you code issues.  Below is an example of a web page that has issued five XHR's.
    
&lt;p&gt;&lt;img src="http://4.bp.blogspot.com/-K5SaICuSYCU/Tq2OBcJvJoI/AAAAAAAAAqE/NxhFXvYxC5Q/s1600/weinre-1.6-resources-a.png"&gt;

&lt;p&gt;Clicking on one of those rows will display additional information in the right hand side of the window, as shown below.

&lt;p&gt;&lt;img src="http://4.bp.blogspot.com/-jN4Bc-yc5C4/Tq2OBXxvqYI/AAAAAAAAAqQ/3ZuwMAHFTaI/s1600/weinre-1.6-resources-b.png"&gt;
    
&lt;p&gt;There are two tabs here, one to show "header" information, the other to show the "content".  The content for the XHR is shown below.
    
&lt;p&gt;&lt;img src="http://1.bp.blogspot.com/-gTNtlNnMgvU/Tq2OB0TeWWI/AAAAAAAAAqc/egXCk3JmioM/s1600/weinre-1.6-resources-c.png"&gt;

&lt;p&gt;To dismiss the detail view and get back to the table view, click the circled X button to the left of the Headers/Content tabs.

&lt;!--
&lt;p&gt;&lt;img src="https://lh4.googleusercontent.com/-KC-sTJuoMEI/Tq17-qIAOiI/AAAAAAAAAoc/29RPARrVMes/weinre-1.6-highlighter.png"&gt;
&lt;p&gt;&lt;img src="https://lh3.googleusercontent.com/-rWoBbCEhS24/Tq17-idj0KI/AAAAAAAAAog/EXITPblqN2o/weinre-1.6-error-info-a.png"&gt;
&lt;p&gt;&lt;img src="https://lh3.googleusercontent.com/-CvmPXcYuMl4/Tq17-YkgeUI/AAAAAAAAAoU/_Z2Etwh55MA/weinre-1.6-error-info-b.png"&gt;
&lt;p&gt;&lt;img src="https://lh3.googleusercontent.com/-jZmm46yptjQ/Tq17_Fohd-I/AAAAAAAAAos/zpB6UHXiYOU/weinre-1.6-resources-a.png"&gt;
&lt;p&gt;&lt;img src="https://lh6.googleusercontent.com/-4SW41FmODQo/Tq17_ZMjTTI/AAAAAAAAAo0/qvji1lSx2s4/weinre-1.6-resources-b.png"&gt;
&lt;p&gt;&lt;img src="https://lh4.googleusercontent.com/-l7fwm7DbSio/Tq17_lSg8EI/AAAAAAAAAo8/4K5Yv8bNxs0/weinre-1.6-resources-c.png"&gt;
--&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/MfwQsHO4MkQ" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/1468710805033159283?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/1468710805033159283?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/MfwQsHO4MkQ/whats-new-in-weinre-160.html" title="what's new in weinre 1.6.0" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-0aKuphlThrA/Tq2OMTmlBDI/AAAAAAAAAqo/3tTOW_AvGZ4/s72-c/weinre-1.6-highlighter.png" height="72" width="72" /><feedburner:origLink>http://pmuellr.blogspot.com/2011/10/whats-new-in-weinre-160.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0INSH48fip7ImA9WhdSE0k.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-5239431319589229225</id><published>2011-07-22T11:46:00.001-04:00</published><updated>2011-07-22T11:46:39.076-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-22T11:46:39.076-04:00</app:edited><title>weinre 1.5.0 is now available</title><content type="html">&lt;p&gt;weinre 1.5.0 is now available at &lt;a href="https://github.com/phonegap/weinre/downloads"&gt;https://github.com/phonegap/weinre/downloads&lt;/a&gt;.
    
&lt;p&gt;ChangeLog: &lt;a href="http://phonegap.github.com/weinre/ChangeLog.html"&gt;http://phonegap.github.com/weinre/ChangeLog.html&lt;/a&gt;
    
&lt;p&gt;I also went through and neutered the bits at the old "pmuellr/weinre" site.  Everything should now, somehow, point you to the "phonegap/weinre" site/repo.  Let me know if you see dangling pointers.  (note, I'm not going to change links in my old blog posts)&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/zA_4XLEIQfI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/5239431319589229225/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=5239431319589229225" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5239431319589229225?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5239431319589229225?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/zA_4XLEIQfI/weinre-150-is-now-available.html" title="weinre 1.5.0 is now available" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2011/07/weinre-150-is-now-available.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQDRHs7cSp7ImA9WhZVFE8.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-7928235752351317533</id><published>2011-05-26T12:11:00.001-04:00</published><updated>2011-05-26T12:12:55.509-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-26T12:12:55.509-04:00</app:edited><title>public weinre server hosted on the intertubes</title><content type="html">&lt;p&gt;Although I knew it was coming, the &lt;a href="https://twitter.com/#!/alunny/status/73451203698245632"&gt;twitter post from Andrew Lunny&lt;/a&gt; yesterday made me very happy: 

&lt;blockquote&gt;&lt;i&gt;
hosted weinre for PhoneGap Build is now live at &lt;a href="http://debug.phonegap.com"&gt;http://debug.phonegap.com&lt;/a&gt;
&lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;Awesome!  The fine folks at &lt;a href="http://www.nitobi.com/"&gt;Nitobi&lt;/a&gt; are running this server, not me.  Thank you so much!  I owe everyone involved a cool beverage of your choice, next time we meet (OSCON?).
    
&lt;p&gt;Of course, if you have any questions about using weinre, including this new public debug server, don't hesitate to ask:
    
&lt;ul&gt;
&lt;li&gt;Google Groups: &lt;a href="https://groups.google.com/group/weinre"&gt;https://groups.google.com/group/weinre&lt;/a&gt;
&lt;li&gt;IRC: #phonegap @ irc.freenode.net
&lt;li&gt;GitHub issues - &lt;a href="https://github.com/pmuellr/weinre/issues"&gt;https://github.com/pmuellr/weinre/issues&lt;/a&gt;, for bug reports, feature requests, etc
&lt;/ul&gt;


&lt;p&gt;&lt;b&gt;some additional things to do for multi-user weinre servers&lt;/b&gt;
    
&lt;p&gt;There's always more work to do, isn't there?  
    
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;make the front page easier to use and understand, if required
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/pmuellr/weinre/issues/55"&gt;optimize client and target resources&lt;/a&gt; - ok, this is kinda embarrassing, but the weinre server is not making use of some of the well-known best practices to optimize HTTP resource access
&lt;li&gt;&lt;p&gt;provide some hints / tips / best practices for folks wanting to run their own multi-user weinre server
&lt;/ul&gt;

&lt;p&gt;In case you're wondering why someone would want to run another multi-user weinre server, now that we have one "in the cloud":
    
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;um, you're going to depend on the cloud?
&lt;li&gt;&lt;p&gt;there's not much security around the current weinre client/server interaction patterns, and there is at least the problem that the current debug packets are flowing across the internet in plain text.  That includes, at a minimum, any serialized versions of DOM nodes that you are seeing in the DOM elements panel.
&lt;/ul&gt;

&lt;p&gt;Given that, seems like it would make sense for organizations to run their own in-house weinre servers.

&lt;p&gt;I'm planning on setting up a weinre server inside the IBM firewall for IBMers to use.  I'll post news on that subject to the new weinre "Community" I set up on the IBM internal "Connections" page.  To find that community, search for weinre, mobile, debug, etc.&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/oIMelG3SnQM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/7928235752351317533/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=7928235752351317533" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7928235752351317533?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7928235752351317533?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/oIMelG3SnQM/public-weinre-server-hosted-on.html" title="public weinre server hosted on the intertubes" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2011/05/public-weinre-server-hosted-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0AEQHk4eyp7ImA9WhZWGEQ.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-7896201245717282494</id><published>2011-05-20T07:23:00.000-04:00</published><updated>2011-05-20T07:41:41.733-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-20T07:41:41.733-04:00</app:edited><title>callback debugging - better mobile error diagnostics</title><content type="html">&lt;p&gt;One of the common issues that comes up regarding debugging mobile web apps, is that the error diagnostics for JavaScript are terrible.  Sometimes non-existent.  Current state of the art is to turn on the &lt;a href="http://developer.apple.com/library/safari/#documentation/appleapplications/Conceptual/Safari_Developer_Guide/2SafariDeveloperTools/SafariDeveloperTools.html"&gt;"Debug Console" switch in Mobile Safari&lt;/a&gt;, which is kinda horrifying, but does provide some information.  Or use low-level debug tools like &lt;a href="http://developer.android.com/guide/developing/tools/logcat.html"&gt;Android's &lt;tt&gt;logcat&lt;/tt&gt;&lt;/a&gt;.  These tools provide additional clues about JavaScript errors that have occurred.
    
&lt;p&gt;But I've wanted to add something to &lt;a href="http://pmuellr.github.com/weinre/"&gt;weinre&lt;/a&gt;, and a while back opened &lt;a href="https://github.com/pmuellr/weinre/issues/38"&gt;issue 38 - "provide better error handling - by hook or by crook"&lt;/a&gt;.  My first attempt was to try overriding some &lt;tt&gt;addEventListener()&lt;/tt&gt; functions, which would instrument the callback methods passed to them.  The instrumentation was to wrap the invocation of the original callback in a try/catch, and if something was caught, report it.  The reason this is a good avenue to go down is that after the top-level JavaScript code in your HTML and JavaScript files runs, everything else is run because of a callback somewhere.  If you can control the callbacks, you control JavaScript.
    
&lt;p&gt;Aside, there's a number of interesting links in that bug report:
    
&lt;ul&gt;
&lt;li&gt;v8's &lt;a href="http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi"&gt;stack trace API&lt;/a&gt;, callable from JavaScript
&lt;li&gt;what happens when you &lt;a href="https://groups.google.com/forum/#!msg/phonegap/DUYhZg-QAO4/jwanwtQzJCkJ"&gt;override &lt;tt&gt;Function.prototype.call()&lt;/tt&gt; in JavaScriptCore&lt;/a&gt; (Holy Shit Really?!)
&lt;/ul&gt;
    
&lt;p&gt;I decided to spend some time on the error diagnostics issue this week, but first did a cursory Google search, and found &lt;a href="http://blog.tlrobinson.net/post/336825719/automagically-wrapping-javascript-callback-functions"&gt;an article by Tom Robinson&lt;/a&gt; on the subject.  Basically describes the approach I was heading down, so things still sounded promising.
    
&lt;p&gt;Since I didn't see any kind of existing library to do this kinda stuff, I wrote one - &lt;a href="https://github.com/pmuellr/CBWrapper#readme"&gt;CBWrapper&lt;/a&gt;.  Putting it in a separate GitHub repository for now, because it's kind of a general purpose callback diagnostic tool.  Could be useful in Node, perhaps.  If it turns out to be useful and safe for weinre, I'll add it, but for now you can use it as a separate set of script files.

&lt;p&gt;Here's what it can do.  Keep in mind that the normal amount of JavaScript error handling you get in weinre is - nothing.  Add the CBWrapper scripts as indicated on it's page, and you'll instead see the following output in the weinre console.  Note that the information displayed is different depending on your web browser's JavaScript engine.  I only tested under Mobile Safari and Android's Browser.

&lt;p&gt;&lt;b&gt;under JSC&lt;/b&gt; - all Apple devices and older Android devices

&lt;pre&gt;
exception: TypeError: Result of expression 'xScript' [null] is not an object.
location:  https://[[url-elided]]/CBWrapper/tests/script-runtime-error-function.js:8
callback:  window.setTimeout(aScript(), 2000)
&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;under V8&lt;/b&gt; - newer Android devices

&lt;pre&gt;
exception: TypeError: Cannot call method 'doSomething' of null
callback:  window.setTimeout(aScript(), 2000)
           [http://[[url-elided]]/CBWrapper/tests/test-weinre-runtime-function-script.html:10]
stack:
TypeError: Cannot call method 'doSomething' of null
    at bScript (http://[[url-elided]]/CBWrapper/tests/script-runtime-error-function.js:8:11)
    at aScript (http://[[url-elided]]/CBWrapper/tests/script-runtime-error-function.js:3:5)
    at cbWrapper (http://[[url-elided]]/CBWrapper/CBWrapper.js:253:27)
    at http://[[url-elided]]/target/target-script-min.js#test:3674:14
&lt;/pre&gt;

&lt;p&gt;Curiously, the exception messages are wildly different here.  The line that threw the exception was:

&lt;pre&gt;
    xScript.doSomething() // where xScript == null
&lt;/pre&gt;

&lt;p&gt;Note that besides the other information provided, there's a line labelled "callback", which gives you some information about the function that registered the callback that just threw the error.  In this case, it was a &lt;tt&gt;window.setTimeout()&lt;/tt&gt; call, and the message provides some contextual information on the call itself.  The registration function is no longer on the stack, but I keep a reference to it in case you want it.  Like in this case.
    
&lt;p&gt;CBWrapper can do a lot more than log errors.  It provides before/after callbacks before every callback that it wraps, so you can do things like get the elapsed time of all the callbacks, log callback events on the Web Inspector timeline, etc.  In theory.
    
&lt;p&gt;Practice, however, is a different story.  Playing with it a bit, under weinre, led me to some issues.  See, weinre itself uses some of the same callbacks that CBWrapper wraps, so it's pretty easy to fall into a trap where you do something in a CBWrapper callback (write to the console), which causes weinre code to set a timer or do an XHR, and you've just created an endless chain of console logs / CBWrapper callbacks that will never end.  The callback-based async version of infinite recursion.  

&lt;p&gt;Finally, Kent Beck posted &lt;a href="https://twitter.com/#!/KentBeck/status/71321449599733760"&gt;the following message&lt;/a&gt; on Twitter today:
    
&lt;blockquote&gt;
the problem with callbacks triggering callbacks triggering callbacks is that when something goes wrong, reading the code doesn't help much
&lt;/blockquote&gt;
    
&lt;p&gt;Seems like maybe you could whip something up with CBWrapper that could show you callbacks registered from other callbacks, and then show a trail of those callbacks when an error is thrown. Would that help?  Only one way to find out and I'll leave that as an exercise for the reader.&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/3V5BvuF-_Gs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/7896201245717282494/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=7896201245717282494" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7896201245717282494?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7896201245717282494?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/3V5BvuF-_Gs/callback-debugging-better-mobile-error.html" title="callback debugging - better mobile error diagnostics" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2011/05/callback-debugging-better-mobile-error.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0AEQng8fSp7ImA9WhZXGUs.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-5514008300139896619</id><published>2011-05-09T13:20:00.000-04:00</published><updated>2011-05-09T13:21:43.675-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-09T13:21:43.675-04:00</app:edited><title>weinre 1.4.0 available</title><content type="html">&lt;p&gt;weinre 1.4.0 is now available in the usual place: &lt;a href="https://github.com/pmuellr/weinre/downloads"&gt;https://github.com/pmuellr/weinre/downloads&lt;/a&gt;.  Changelog is available here: &lt;a href="http://pmuellr.github.com/weinre/ChangeLog.html"&gt;http://pmuellr.github.com/weinre/ChangeLog.html&lt;/a&gt;.
    
&lt;p&gt;Major changes for this release:
    
&lt;ul&gt;
&lt;li&gt;Google Groups mailing list
&lt;li&gt;extensions
&lt;li&gt;multi-user support
&lt;/ul&gt;

&lt;p&gt;As always, for bugs or feature requests, &lt;a href="https://github.com/pmuellr/weinre/issues"&gt;create an an issue&lt;/a&gt;.  Or use the new Google Group (see below).
    
&lt;!-- =================== --&gt;
&lt;p&gt;&lt;b&gt;Google Groups mailing list&lt;/b&gt;
    
&lt;p&gt;I've created a Google Group for weinre, here: &lt;a href="http://groups.google.com/group/weinre"&gt;http://groups.google.com/group/weinre&lt;/a&gt;.  Usual stuff applies, the group is set to moderate messages for "new" members.
   
&lt;!-- =================== --&gt;
&lt;p&gt;&lt;b&gt;extensions&lt;/b&gt;
    
&lt;p&gt;Like all great platforms, Web Inspector has an extension mechanism allowing users to write code to extend the capabilities of the tool.  The extension support for real Web Inspector (used in Safari/Chrome/etc) is not currently enabled, but I went ahead and enabled it in weinre.
    
&lt;p&gt;I've written two extensions so far.
    
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pmuellr/weinre-ext-dom-monster"&gt;https://github.com/pmuellr/weinre-ext-dom-monster&lt;/a&gt; - runs &lt;a href="http://mir.aculo.us/dom-monster/"&gt;DOM Monster&lt;/a&gt; on your device, displaying the results in weinre
&lt;li&gt;&lt;a href="https://github.com/pmuellr/weinre-ext-sample"&gt;https://github.com/pmuellr/weinre-ext-sample&lt;/a&gt; - an example extension you can use to base a new extension on.
&lt;/ul&gt;

&lt;p&gt;Here's a screen-shot of DOM Monster running in weinre - click the image to see a larger version.  Isn't that panel icon so cute!
&lt;p&gt;&lt;a href="http://farm6.static.flickr.com/5143/5692972464_7bf49ddf9e_o.jpg"&gt;&lt;img src="http://farm6.static.flickr.com/5143/5692972464_65a5a842c0.jpg"&gt;&lt;/a&gt;

&lt;p&gt;The extension support is best-effort at present.  Definitely open an issue for bugs or feature requests.  If it's API related, I may forward them to the &lt;a href="http://webkit.org/new-inspector-bug"&gt;WebKit bugzilla component for Web Inspector&lt;/a&gt;.
    
&lt;p&gt;I presume in real Web Inspector, all the various &lt;tt&gt;.html&lt;/tt&gt; files that are loaded will be sandboxed, like Chrome and Safari extensions, but for weinre they're running as &lt;tt&gt;iframe&lt;/tt&gt;s of the main inspector window.  As such, they have full access to everything in Web Inspector.  Powerful.  Dangerous.  Have fun.
    
&lt;p&gt;I decided to use a deployment structure that is easily mapped to a VCS, like Git/GitHub.  This makes it easy to install and update extensions.  To install the DOM Monster extension, run the following shell commands:
    
&lt;pre&gt;
mkdir ~/.weinre
mkdir ~/.weinre/extensions
cd ~/.weinre/extensions    
git clone git@github.com:pmuellr/weinre-ext-dom-monster.git
&lt;/pre&gt;

&lt;p&gt;To update the extension, after I make and publish changes, just run:

&lt;pre&gt;
cd ~/.weinre/extensions/weinre-ext-dom-monster
git pull
&lt;/pre&gt;

&lt;!-- =================== --&gt;
&lt;p&gt;&lt;b&gt;multi-user support&lt;/b&gt;
    
&lt;p&gt;This support will only be useful to folks who want to host a weinre server for multiple people to use simultaneously.  For more information, see: &lt;a href="http://pmuellr.github.com/weinre/MultiUser.html"&gt;http://pmuellr.github.com/weinre/MultiUser.html&lt;/a&gt;.

&lt;p&gt;Although it's noted in the doc, I will mention here also.  There is no real security here.  Your client and target need to know a "shared secret" to connect to each other.  On the bright side, there's never any information persisted on the weinre server, everything is transient, so if you aren't connected to a weinre server, there's nothing for anyone to steal.

&lt;p&gt;There's likely more work to be done here, but looking for feedback.&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/ImSMTl_h8TA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/5514008300139896619/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=5514008300139896619" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5514008300139896619?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5514008300139896619?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/ImSMTl_h8TA/weinre-140-available.html" title="weinre 1.4.0 available" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://farm6.static.flickr.com/5143/5692972464_65a5a842c0_t.jpg" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2011/05/weinre-140-available.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkANSHw_cSp7ImA9WhZREEw.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-478366542803312928</id><published>2011-04-05T09:39:00.001-04:00</published><updated>2011-04-05T09:39:59.249-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-05T09:39:59.249-04:00</app:edited><title>weinre 1.3.0 available</title><content type="html">&lt;p&gt;weinre 1.3.0 is now available in the usual place: &lt;a href="https://github.com/pmuellr/weinre/downloads"&gt;https://github.com/pmuellr/weinre/downloads&lt;/a&gt;.  Changelog is available here: &lt;a href="http://pmuellr.github.com/weinre/ChangeLog.html"&gt;http://pmuellr.github.com/weinre/ChangeLog.html&lt;/a&gt;.
    
&lt;p&gt;Major changes for this release:
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;CSS style editing now available.  I'm surprised more people haven't complained about this - I think this is one of my favorite features of big Web Inspector.  If you're not familiar with it, there's some documentation on &lt;a href="http://code.google.com/chrome/devtools/docs/elements-styles.html#styles_edit"&gt;Chrome's DevTools documentation site about style editing&lt;/a&gt;.
    
&lt;li&gt;&lt;p&gt;The Resources panel has been enabled, but currently only the localStorage and sessionStorage entries contain values.  I couldn't resist adding localStorage support after seeing Steve Souder's blog post "&lt;a href="http://www.stevesouders.com/blog/2011/03/28/storager-case-study-bing-google/"&gt;&lt;i&gt;Storager case study: Bing, Google&lt;/i&gt;&lt;/a&gt;".
    
&lt;/ul&gt;

&lt;p&gt;A few notes on the style editing:
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;Those little yellow warning icons to the left of the property names are error indicators; either the property name or value is incorrect.  Unfortunately, for weinre, we can only catch such errors for properties you edit.  We can't catch errors that are present in your CSS that the browser originally sees.  The CSSOM doesn't provide access to error-ish stuff.
    
&lt;li&gt;&lt;p&gt;Adding new style rules &lt;a href="https://github.com/pmuellr/weinre/issues/47"&gt;doesn't work yet&lt;/a&gt;.  Vote on this issue if you really need it; pretty low priority for me.
    
&lt;li&gt;&lt;p&gt;If the Matched CSS Rules section is empty for most of the elements you click on, it may be because of same origin restrictions for accessing CSS rules via the CSSOM.  In other words, weinre may not be able to see the CSS rules for CSS files that you import from a different origin than the original document.  Still investigating.
    
&lt;/ul&gt;

&lt;p&gt;As always, for bugs or feature requests, &lt;a href="https://github.com/pmuellr/weinre/issues"&gt;create an an issue&lt;/a&gt;.&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/zYLSRFeFc5o" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/478366542803312928/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=478366542803312928" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/478366542803312928?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/478366542803312928?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/zYLSRFeFc5o/weinre-130-available.html" title="weinre 1.3.0 available" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2011/04/weinre-130-available.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkQEQ34-cSp7ImA9WhZTE08.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-230674860359186161</id><published>2011-03-16T20:03:00.001-04:00</published><updated>2011-03-16T20:05:02.059-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-16T20:05:02.059-04:00</app:edited><title>WTF are these scoop files?</title><content type="html">&lt;p&gt;At some point, someone's going to look at the &lt;a href="https://github.com/pmuellr/weinre/tree/master/weinre.web/modules/weinre/target"&gt;weinre source code&lt;/a&gt; and ask, &lt;i&gt;"WTF are all these .scoop files?"&lt;/i&gt;
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;They're almost JavaScript files, intended to preprocessed into legal JavaScript files.  The lines of the file which are &lt;b&gt;not&lt;/b&gt; indented are "directives" that indicate how the following indented bits are to processed.  The indented lines are plain old JavaScript which isn't touched by the preprocessor except to deal with "super" calls.

&lt;li&gt;&lt;p&gt;They're my response to wanting to use &lt;a href="http://en.wikipedia.org/wiki/Object-oriented_programming"&gt;classical OOP&lt;/a&gt; in JavaScript, without dealing with the crufty the way it's typically done in JavaScript.  I like JavaScript, but I hate cruft.
    
&lt;li&gt;&lt;p&gt;Since I'm also playing with &lt;a href="http://www.commonjs.org/"&gt;CommonJS&lt;/a&gt;, I ended up folding some goodies for that in too.
    
&lt;/ul&gt;

&lt;p&gt;Assuming you know JavaScript, and have some familiarity with classical OOP, I suspect you will get the gist of what's going on if you look at one of the weinre &lt;tt&gt;.scoop&lt;/tt&gt; files.

&lt;p&gt;I knew I'd be writing a lot of JavaScript for &lt;a href="http://pmuellr.github.com/weinre/"&gt;weinre&lt;/a&gt;, so I wrote &lt;b&gt;scoop&lt;/b&gt; first to make it a pleasant experience.  
    
&lt;p&gt;The &lt;a href="https://github.com/pmuellr/scooj"&gt;source for &lt;b&gt;scoop&lt;/b&gt; is at GitHub&lt;/a&gt;.  The doc is spartan, but my existing user base hasn't complained too much about that (existing user base ==  me).
    
&lt;p&gt;Here's what I learned in the process of using &lt;b&gt;scoop&lt;/b&gt; to build weinre:
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;I like it.  It's become second nature to author scoop files.
    
&lt;li&gt;&lt;p&gt;The preprocessor runs fast enough that it doesn't impact my build in any significant fashion.  In practice, all software I create has some kind of automated build that runs when I touch a source file.  Including web sites.  Adding one second to that process, if that, doesn't impact me. (weinre builds take 5 seconds, which includes compiling Java source - I could optimize that build more, but haven't needed to)

&lt;li&gt;&lt;p&gt;There's no &lt;a href="https://github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS"&gt;new language to learn&lt;/a&gt;.  It's just JavaScript with some structuring.  Just a few directives to learn, and rules to follow (indent your code).  No offense to the altJS crowd - I love all that stuff, but really don't want to invest in learning another language, figure out how to debug it, etc.

&lt;li&gt;&lt;p&gt;&lt;b&gt;scoop&lt;/b&gt; and the CommonJS module runtime I use (&lt;a href="https://github.com/pmuellr/modjewel"&gt;modjewel&lt;/a&gt;) both take turns processing the source, but don't change the line or column numbers of the original source.  When the JavaScript runtime complains about a syntax or runtime error with a line number, no mental mapping is required to find the line in the &lt;b&gt;scoop&lt;/b&gt; source.  The meat of code I step through in the debugger, function bodies, is the same as the &lt;b&gt;scoop&lt;/b&gt; code I write.

&lt;li&gt;&lt;p&gt;Exposing classes as modules seems to work fine, but requires the module system to support overriding the exports value that the module ends up populating.  In practice, this works with node.js and modjewel, so, works for me.  Specifically, the first class defined in a &lt;b&gt;scoop&lt;/b&gt; file is assigned to &lt;tt&gt;module.exports&lt;/tt&gt;, and thus any code which does a &lt;tt&gt;require()&lt;/tt&gt; on that module will get the class as a result.
    
&lt;li&gt;&lt;p&gt;The big downside of overriding module.exports is that recursively &lt;tt&gt;require()&lt;/tt&gt;'d modules don't work right.  I added a &lt;tt&gt;requireClass&lt;/tt&gt; directive which will identify this condition at runtime, and fails fast with a decent diagnostic.  Fixing these situations typically isn't difficult.

&lt;li&gt;Syntax-coloring text editors generally do the right thing for &lt;b&gt;scoop&lt;/b&gt; files, once you lie to them and tell them that a &lt;b&gt;scoop&lt;/b&gt; file is just a JavaScript file.  The directives are usually colored oddly, but that's not a big problem.  The actual JavaScript code is always colored correctly, for the text editors I use.

&lt;/ul&gt;

&lt;p&gt;Part of my rationalization of doing this is based on Smalltalk's class structuring story.  The Smalltalk language doesn't define any class structuring features like a "class statement" - all that is handled by the tooling and runtime.  And it has a great classical OOP story.  If Smalltalk can do it, then so can JavaScript.

&lt;p&gt;I have a long laundry list of things I'd like to do with &lt;b&gt;scoop&lt;/b&gt;, especially since I consider it just a stepping stone to having a nice, dynamic, live development environment for JavaScript, just like Smalltalk.  The current incarnation is the ascii, text-file version of where I want to go.  The thing I want to work on first is some read-only browsers for the module system and the class structure, that you can run right in your browser (or debugger).  Next would come live editing, etc, etc.  Probably would have worked on some of that stuff had &lt;a href="http://2011.jsconf.us/#/proposal/eff575eed3ae974073b61c61647085ac"&gt;my JSConf 2011 proposal for &lt;b&gt;scoop&lt;/b&gt;&lt;/a&gt; been accepted.  The pressure is off on that front though.&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/9aFDZEW48K0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/230674860359186161/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=230674860359186161" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/230674860359186161?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/230674860359186161?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/9aFDZEW48K0/wtf-are-these-scoop-files.html" title="WTF are these scoop files?" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2011/03/wtf-are-these-scoop-files.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUINQnk_eip7ImA9Wx9aEUs.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-2353235542752962308</id><published>2011-03-03T10:51:00.001-05:00</published><updated>2011-03-03T10:53:13.742-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-03T10:53:13.742-05:00</app:edited><title>mobile debugging updates</title><content type="html">&lt;p&gt;Yesterday, mobile web developers got some refreshed debug tools to play with.
I released a new version of &lt;a href="http://pmuellr.github.com/weinre/"&gt;weinre&lt;/a&gt;, and &lt;a href="http://twitter.com/#!/rem"&gt;Remy Sharp&lt;/a&gt; released some &lt;a href="http://www.youtube.com/watch?v=Y219Ziuipvc"&gt;YouTube&lt;/a&gt; &lt;a href="http://www.youtube.com/watch?v=DSH392Gxaho"&gt;movies&lt;/a&gt; showing off his &lt;a href="http://jsconsole.com/"&gt;JS Console tool&lt;/a&gt;.

&lt;p&gt;The big new feature for weinre is the Timeline.  The Chrome Dev Tools version of Timeline is documented &lt;a href="http://code.google.com/chrome/devtools/docs/timeline.html"&gt;here&lt;/a&gt;, and weinre implements some of it.  A little of it.  Timers, intervals, XHRs, some global events.  It handles &lt;a href="https://developer.mozilla.org/en/DOM/window.onerror"&gt;onerror&lt;/a&gt;, but I haven't seen onerror available on any mobile WebKit browsers, since it's a relatively &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=8519"&gt;new addition to WebKit&lt;/a&gt;.

&lt;p&gt;Aside, if you're not familiar with WebKit Web Inspector / Chrome Dev Tools (same thing, different names), the &lt;a href="http://code.google.com/chrome/devtools/"&gt;Google Chrome Developer Tools&lt;/a&gt; site seems to be the best source of information.

&lt;p&gt;With both jsconsole and weinre, there are limits to what you can do.  Specifically, since they are both written in user-land JavaScript, and there are no user-land JavaScript APIs that deal with breakpoints, there's no way to do breakpoints (well, ...).  Even just getting error information / stack traces is difficult-to-impossible.

&lt;p&gt;What we really need is the &lt;i&gt;real&lt;/i&gt; Web Inspector to work on mobile platforms.  There's some code in WebKit to handle the remote-y-ness, as shown by &lt;a href="http://www.screencast.com/users/pavelfeldman/folders/Jing/media/6cc3af04-1826-494f-9e5f-e0329de95227"&gt;this movie&lt;/a&gt;.  Not shipping yet, though, AFAIK. Maybe on iOS 4.3 or already in Honeycomb but hidden?  Would be a nice surprise for sure, but would make weinre - my baby - obsolete.  That's fine with me, I've been developing software long enough I know that sometimes your creations need to die.  There's plenty of other stuff to do in this arena.

&lt;p&gt;What's next for weinre?  &lt;a href="https://github.com/pmuellr/weinre/issues"&gt;You tell me&lt;/a&gt;.  Or post a message on Twitter mentioning weinre, and I'll probably see it.

&lt;p&gt;Here's the new movie for weinre:

&lt;p&gt;&lt;iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/gaAI29UkVCc?rel=0" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/mGvElRjnz-Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/2353235542752962308/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=2353235542752962308" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2353235542752962308?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/2353235542752962308?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/mGvElRjnz-Y/mobile-debugging-updates.html" title="mobile debugging updates" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://img.youtube.com/vi/gaAI29UkVCc/default.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2011/03/mobile-debugging-updates.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MDQHw6fSp7ImA9Wx9VF0o.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-3641721101876463661</id><published>2011-02-03T19:30:00.001-05:00</published><updated>2011-02-03T19:31:11.215-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-03T19:31:11.215-05:00</app:edited><title>Mobile, Debugging, Challenges, Hacks</title><content type="html">&lt;p&gt;Alex Russell has a great post today on software performance, titled &lt;a href="http://infrequently.org/2011/02/on-performance-innumeracy-false-positives/"&gt;Performance Innumeracy &amp;amp; False Positives&lt;/a&gt;.  Having worked in the embedded/mobile space for the last decade (on and off), I certainly feel his pain.  On the other hand, this is one of the reasons why I love the mobile space: it's challenging.
    
&lt;p&gt;Performance is just one of the challenges that we face in the mobile space.  Other issues are program and data size, RAM usage, and network speed.  All constrained compared to desktop-class machines.

&lt;p&gt;For some of these challenges, we need tools, because it's often not obvious where the problems really are.  Sometimes the only tools you have is your eyes staring at the code and intuition.  Performance, in particular, is an area that needs tools.  If there's one thing I've learned about performance problems over the years, it's this: your intuition is almost always wrong.  
    
&lt;p&gt;Alex showed a stack trace from WebKit in his blog post, without any kind of time numbers in it - a pretty crude tool. But most people don't even have &lt;b&gt;that&lt;/b&gt; luxury (instrumenting WebKit), for applications running in a browser.  On some mobile platforms, recompiling parts of the OS isn't even a possibility for most developers. 
    
&lt;p&gt;In lieu of actual tools, I'm always up for crazy hacks.  That's basically what &lt;a href="http://pmuellr.github.com/weinre/"&gt;weinre&lt;/a&gt; is - a crazy hack.  Take the Web Inspector user interface, and plug in a fake runtime behind it running on the target browser - just enough to get the user interface to display something interesting.  Until we have the real Web Inspector showing us the browser innards running on a mobile platform, maybe this cheat will be useful to folks.  

&lt;p&gt;On a slightly related note, an interesting bug got entered against Web Inspector the other day: &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=53659"&gt;Bug 53659 - Web Inspector: Better support for finding "leaked" DOM&lt;/a&gt;.  The summary describes a debugging scenario for which some new tooling could help.  Here's the sad part: if this were Smalltalk, there's a chance you could write a specialized tool to collect the desired information with user-land code.  The ability to enumerate all the live objects in a running image was an especially helpful feature.  How useful would it be, if you could do that in JavaScript?  In a special debugging mode, of course - not exactly a function you want to expose to &lt;i&gt;everyone&lt;/i&gt;.  But it would be nice to not have to wait for the platform developers to write tools for us, if we could write our own.
    
&lt;p&gt;Could you help diagnose the scenario described in Bug 53659 with a crazy hack?  If not, what's the bare minimum additional runtime functionality you'd need in JavaScript to do it?&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/cldp3gZFsCo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/3641721101876463661/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=3641721101876463661" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/3641721101876463661?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/3641721101876463661?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/cldp3gZFsCo/mobile-debugging-challenges-hacks.html" title="Mobile, Debugging, Challenges, Hacks" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2011/02/mobile-debugging-challenges-hacks.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcBR305eCp7ImA9Wx9RFk0.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-7824900025739082065</id><published>2010-12-17T11:07:00.001-05:00</published><updated>2010-12-17T11:07:36.320-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-17T11:07:36.320-05:00</app:edited><title>weinre at GitHub</title><content type="html">&lt;p&gt;I finally pushed my weinre project up to GitHub last night:

&lt;blockquote&gt;
weinre - &lt;b&gt;we&lt;/b&gt;b &lt;b&gt;in&lt;/b&gt;spector &lt;b&gt;re&lt;/b&gt;mote - pronounced "winery"
&lt;br&gt;&lt;a href="http://pmuellr.github.com/weinre/"&gt;http://pmuellr.github.com/weinre/&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's a debugger for mobile web apps.  Uses the Web Inspector debug front-end from WebKit (implemented in HTML/CSS/JS), plugged up to some plain old JavaScript running in your web page.  There's an HTTP server in there somewhere.

&lt;p&gt;It's early days - it may not be the easiest thing to set up and run - and there's a lot of function not implemented (showing all the CSS style info, for instance).  But it's something.  

&lt;p&gt;I intend to continue enhancing it over the next while.  First order of business will be to get it back, function-wise, to where my earlier prototype was, as shown in &lt;a href="http://www.youtube.com/watch?v=MxmFrFEGInU"&gt;this video&lt;/a&gt;.  I've been spending more time on infrastructure stuff than adding debug function lately - it'll be fun to dive back into the innards of Web Inspector again.

&lt;p&gt;My intention is for this work to eventually be folded into the &lt;a href="http://www.phonegap.com/"&gt;PhoneGap&lt;/a&gt; project.  PhoneGap (wisely IMO) requires a &lt;a href="http://www.phonegap.com/contributor-agreement"&gt;Contributor Agreement&lt;/a&gt; in place before accepting contributions, so I won't be able to accept any contributions into my repo unless you've signed up.

&lt;p&gt;If you have questions, feature requests, etc, create an &lt;a href="https://github.com/pmuellr/weinre/issues"&gt;issue at GitHub&lt;/a&gt;.  I also hang out on &lt;tt&gt;#phonegap&lt;/tt&gt; on freenode during business hours (US east).

&lt;p&gt;&lt;b&gt;Tasty Innards Too!&lt;/b&gt;

&lt;p&gt;Besides this project's subject matter being a fun thing to work on (building a working debugger), I've had a lot of fun building and using smaller thingees.  If I can get my blogging going again, hopefully I'll write more about some of these goodies, soon:
    
&lt;ul&gt;

&lt;li&gt;&lt;p&gt;All my JavaScript code is structured as CommonJS modules, using &lt;a href="https://github.com/pmuellr/modjewel"&gt;modjewel&lt;/a&gt;.

&lt;li&gt;&lt;p&gt;All my JavaScript is written in a pidgin dialect of JavaScript called
&lt;a href="https://github.com/pmuellr/scooj"&gt;scoop&lt;/a&gt;.  Basically just a lexically simpler way to define classes, methods, etc in JavaScript (if you didn't know already, I'm an &lt;a href="http://www.google.com/search?q=old+smalltalk+dude"&gt;old Smalltalk dude&lt;/a&gt;).  Here's an example - the implementation of the &lt;a href="https://github.com/pmuellr/weinre/blob/master/weinre.web/modules/weinre/target/Console.scoop"&gt;Console class&lt;/a&gt; used by the debug target.

&lt;li&gt;&lt;p&gt;The interface between the large grained components of weinre is specified in a subset-but-extended bastardization of WebIDL.  The Web Inspector code already does this itself (because WebKit in general does this also), and it worked out well for me.  I wrote a WebIDL-to-JSON compiler, and the runtime makes use of the JSON to create proxies, etc.  Lots more interesting stuff can be done here, I'm sure.

&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/8kc6MrlU3IM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/7824900025739082065/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=7824900025739082065" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7824900025739082065?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7824900025739082065?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/8kc6MrlU3IM/weinre-at-github.html" title="weinre at GitHub" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2010/12/weinre-at-github.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkAAR34yeCp7ImA9Wx9RE0g.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-6318675506367644427</id><published>2010-12-14T09:11:00.001-05:00</published><updated>2010-12-14T13:19:06.090-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-14T13:19:06.090-05:00</app:edited><title>tech books on the Kindle</title><content type="html">&lt;p&gt;Three images from David Flanagan's 
&lt;a href="http://oreilly.com/catalog/0636920016182"&gt;JQuery Pocket Reference&lt;/a&gt;,
as they look on my 3rd generation (latest) 6" (not the big one) Kindle.

&lt;p&gt;The first image below is from the PDF version of the book.
    
&lt;p&gt;The font size is a little too small for me, and I would assume, most
people.  It also wastes a lot of space on the left and right margins in
general, on the indentation of the code sample, and the footer information.

&lt;p&gt;Note that PDFs are not "resizable" in the same way a web page is; you can't
make the font larger.  What you see is what you get.

&lt;!--
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/pmuellr/5260294769"&gt;
&lt;img src="http://farm6.static.flickr.com/5005/5260294769_bf1c104c21_b.jpg"&gt;
&lt;/a&gt;
--&gt;

&lt;p&gt;&lt;img src="http://dl.dropbox.com/u/2192156/blog-images/kindle/kindle-pdf.jpg"&gt;

&lt;p&gt;The next image below is from the Mobi version of the book.  Mobi is a
publishing format that has been used by various reader software over the
years, and is the "native" format for the Kindle.

&lt;p&gt;What I'm showing here is the text at the smallest font size supported.  I
typically read at one font size up from that.  There are 8 font sizes
available when you're reading Mobi files, along with being able to tweak the
line spacing a bit, etc.

&lt;p&gt;I'm showing the smallest font size because it shows one of the biggest 
problems with using Mobi for tech documents - the code sample is too big 
for this font size (the smallest!) and it wraps.  It just looks terrible.

&lt;p&gt;I have some experience with the Mobi format, converting HTML documents to
Mobi using &lt;a href="http://calibre-ebook.com/"&gt;Calibre&lt;/a&gt;.  It appears the
Mobi format is pretty limited.  
I've tried all sorts of styling of &lt;tt&gt;&amp;lt;pre&amp;gt;&lt;/tt&gt; elements,
and the best you can do is force some vertical whitespace (not the default!)
in front of your code samples.  It's just awful.

&lt;!--
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/pmuellr/5260901514/"&gt;
&lt;img src="http://farm6.static.flickr.com/5241/5260901514_16f9b9aba2_b.jpg"&gt;
&lt;/a&gt;
--&gt;

&lt;p&gt;&lt;img src="http://dl.dropbox.com/u/2192156/blog-images/kindle/kindle-mobi.jpg"&gt;

&lt;p&gt;What's a boy to do?  Turns out O'Reilly also offers an ePub version of
their eBooks.  You can easily turn your ePub into a Mobi with Calibre, but
you're not going to be able to do much better than the image above.

&lt;p&gt;So I did something different:
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;unzip the ePub - ePub files are zip files with an 
&lt;tt&gt;.epub&lt;/tt&gt; file extension

&lt;li&gt;&lt;p&gt;concatenate all the &lt;tt&gt;.html&lt;/tt&gt; files in the epub together, into
one file - ePub files are XHTML files for their main text content

&lt;pre&gt;
cat ch*.html &gt; combined.html
&lt;/pre&gt;

&lt;li&gt;&lt;p&gt;remove the &lt;tt&gt;&amp;lt;head&amp;gt;&lt;/tt&gt; sections with a find/replace regex
pattern, etc

&lt;li&gt;&lt;p&gt;add a simple &lt;tt&gt;&amp;lt;style&amp;gt;&lt;/tt&gt; section:
&lt;pre&gt;
    h1.title {
        page-break-before:  always;
    }

    body {
        font-size:          200%;
        font-family:        Georgia;
    }

    pre {
        font-size:          70%;
        background-color:   #EEE;
        padding:            0.5em;
        overflow:           hidden;
        border-radius:      0.5em;
        -moz-border-radius: 0.5em;
    }

    .sidebar {
        padding:            0.0em 0.5em;
        overflow:           hidden;
        border-radius:      0.5em;
        -moz-border-radius: 0.5em;
        background-color:   #EEE;
    }

    .sidebar p.title {
        font-weight:        bold;
    }
&lt;/pre&gt;

&lt;li&gt;&lt;p&gt;bring the resulting file up in FireFox
    
&lt;li&gt;&lt;p&gt;print, but save to PDF instead of actually print (I'm on a Mac)
    
&lt;li&gt;&lt;p&gt;copy the PDF to the Kindle
&lt;/ul&gt;

&lt;p&gt;Here's the result.  Not perfect, but much better than the other two 
files.  The font is larger, and the code sample is readable and well separated
from the other text.

&lt;!--
&lt;p&gt;&lt;a href="http://www.flickr.com/photos/pmuellr/5260901742/"&gt;
&lt;img src="http://farm6.static.flickr.com/5082/5260901742_6b2db0dca1_b.jpg"&gt;
&lt;/a&gt;
--&gt;

&lt;p&gt;&lt;img src="http://dl.dropbox.com/u/2192156/blog-images/kindle/kindle-pdf-from-epub-via-html.jpg"&gt;

&lt;p&gt;Note: FireFox is not my day-to-day web browser, but is the only browser that
produces usable PDF files for files like this.  PDFs produced from both 
Safari and Chrome only last about 30 pages or so before the text disappears,
when viewed on the Kindle.  Who knows.

&lt;p&gt;Update on 2010/12/14 at 1:20pm - the images aren't working from flickr, so put on dropbox&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/ChfAwLSgSNI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/6318675506367644427/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=6318675506367644427" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/6318675506367644427?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/6318675506367644427?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/ChfAwLSgSNI/tech-books-on-kindle.html" title="tech books on the Kindle" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://farm6.static.flickr.com/5005/5260294769_bf1c104c21_t.jpg" height="72" width="72" /><thr:total>9</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2010/12/tech-books-on-kindle.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4NRHc-eCp7ImA9WxFWFks.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-5677038977010307200</id><published>2010-06-04T12:12:00.000-04:00</published><updated>2010-06-04T12:13:15.950-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-04T12:13:15.950-04:00</app:edited><title>bind() considered harmful</title><content type="html">&lt;p&gt;A recent passive-aggressive &lt;a href="http://twitter.com/pmuellr/status/15321492890"&gt;twitter message from me&lt;/a&gt;:

&lt;blockquote&gt;&lt;i&gt;
Oh yeah. Keep on bind()'ing folks, because bind() rocks. &lt;a href="http://bit.ly/aPyfuV"&gt;http://bit.ly/aPyfuV&lt;/a&gt;
&lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;In case you can't tell, the message is facetious.  &lt;code&gt;bind()&lt;/code&gt; does not actually rock.

&lt;!-- ============================================================= --&gt;
&lt;p&gt;&lt;b style="border-bottom:solid"&gt;what is &lt;code&gt;bind()&lt;/code&gt;?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bind()&lt;/code&gt; is a JavaScript function implemented by many JavaScript libraries and included in &lt;a href="http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/"&gt;ECMAScript 5&lt;/a&gt;.  If you aren't already familiar with &lt;code&gt;bind()&lt;/code&gt;, this post isn't going to make much sense, but if you're curious anyway, see &lt;a href="http://www.prototypejs.org/api/function/bind"&gt;Prototype's documentation for their &lt;code&gt;bind()&lt;/code&gt;&lt;/a&gt;.  

&lt;p&gt;Let's look at what &lt;code&gt;bind()&lt;/code&gt; is actually doing: 
&lt;ul&gt;
&lt;li&gt;associates an object to use as &lt;code&gt;this&lt;/code&gt; (aka the receiver) when the function is invoked
&lt;li&gt;associates additional parameters to be passed to the function when the function is invoked  (aka &lt;a href="http://api.prototypejs.org/language/function/prototype/bind/"&gt;currying&lt;/a&gt;).
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;bind()&lt;/code&gt; does this by returning a new function, which when invoked, arranges for the object you want as the receiver and the additional parameters to be passed to the original function.  It hides these values in the newly created function, associated with the closure the function was returned from.
    
&lt;p&gt;&lt;code&gt;bind()&lt;/code&gt; is frequently used for callbacks and event handlers, which typically allow you to pass a function as the callback, but don't provide a way to specify the receiver or additional parameters for the actual call to the callback.

&lt;!-- ============================================================= --&gt;
&lt;p&gt;&lt;b style="border-bottom:solid"&gt;why does &lt;code&gt;bind()&lt;/code&gt; not rock?&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
    
&lt;!-- =============================== --&gt;
&lt;li&gt;&lt;p&gt;gets in the way of debugging
    
&lt;p&gt;Take a look at the bug I linked to in the Twitter message above: &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=40080"&gt;Bug 40080: Web Inspector: better Function.prototype.bind for the internal code&lt;/a&gt;
    
&lt;p&gt;The bug concerns providing a better debug story around functions that have been &lt;code&gt;bind()&lt;/code&gt;'d.  Because the current story isn't very pretty.  When you stumble upon a &lt;code&gt;bind()&lt;/code&gt;'d function in the debugger, you see the source for the &lt;code&gt;bind()&lt;/code&gt; function itself, which isn't what you want to see.  In addition the resulting bound function is usually anonymous, which means your stack traces, profile reports, etc, will be filled with &lt;i&gt;(anonymous function)&lt;/i&gt; entries.

&lt;!-- =============================== --&gt;
&lt;li&gt;&lt;p&gt;garbage
    
&lt;p&gt;Calling &lt;code&gt;bind()&lt;/code&gt; creates a new function object every time it's called.  Not just a string, or empty object, or array.  A function.  Which I'm guessing is more expensive than simpler objects.  [yes, I should do some measurements.] A closure is also created and associated with the function (which is where the receiver and curried arguments are stored).  More garbage.  
        
&lt;p&gt;Now imagine that, for whatever reason, you need to add and then remove
a callback frequently, over and over again, for some reason.  Or set a timer over and over again.  And you're using &lt;code&gt;bind()&lt;/code&gt;.  Think of the garbage you're creating.

&lt;!-- =============================== --&gt;
&lt;li&gt;&lt;p&gt;Alex Russell posted some thoughts on &lt;code&gt;bind()&lt;/code&gt; in &lt;a href="https://mail.mozilla.org/pipermail/es-discuss/2010-April/011004.html"&gt;a post to the es-discuss mailing list&lt;/a&gt; (item 3).  
   
&lt;blockquote&gt;&lt;i&gt;
So why does this [using &lt;code&gt;bind()&lt;/code&gt;] suck? Two reasons: it's long-ish to type, and it doesn't do what the dot operator does -- i.e., return the same   function object every time.    
&lt;/i&gt;&lt;/blockquote&gt; 

&lt;p&gt;It is longer, and therefore yuckier.  It's also often not DRY (&lt;code&gt;obj&lt;/code&gt; referenced twice):
&lt;pre&gt;
    setTimeout( obj.method.bind(obj, "John"), 100 );
&lt;/pre&gt;

&lt;p&gt;The second point is explained by Alex in his post:

&lt;blockquote&gt;&lt;i&gt;
Many functions, both in the DOM and in the library, accept functions  
as arguments. ES5 provides a bind() method that can ease the use of  
these functions when the passed method comes from an object. This is,  
however, inconvenient. E.g.:

&lt;pre&gt;
   node.addEventListener("click", obj.method.bind(obj, ...));
&lt;/pre&gt;

Also, insufficient. Event listeners can't be detached when using  
Function.prototype.bind:

&lt;pre&gt;
   // doesn't do what it looks like it should
   node.removeEventListener("click", obj.method.bind(obj, ...));
&lt;/pre&gt;
&lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;So the trick here, if you want to use &lt;code&gt;removeEventListener()&lt;/code&gt;, is that you have to store the result of a single call to &lt;code&gt;bind()&lt;/code&gt; and then use that value in subsequent  &lt;code&gt;addEventListener()&lt;/code&gt; / &lt;code&gt;removeEventListener()&lt;/code&gt; paired calls.  Alex's post suggests a new language feature to work around this (btw, I'm not in favor of his proposed language feature).

&lt;/ul&gt;

&lt;!-- ============================================================= --&gt;
&lt;p&gt;&lt;b style="border-bottom:solid"&gt;why are we in a bind with &lt;code&gt;bind()&lt;/code&gt; today?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;It's pretty obvious to see how we got to the point where you need to use &lt;code&gt;bind()&lt;/code&gt; in your code today.
    
&lt;p&gt;Historically, JavaScript was a glue language that let you do a light amount of programmatic processing against stuff in your page.  When specifying a callback/listener, you didn't have to worry so much about the receiver of the function you passed in; you were probably using global variables instead of creating your own little objects.
    
&lt;p&gt;And so the places that take callbacks, like &lt;code&gt;setTimeout()&lt;/code&gt;,
&lt;code&gt;onload&lt;/code&gt; handlers, etc, didn't really have a need for you to specify the receiver of of the callback when it was invoked.  The receiver was always ... well, whatever it was for your callback.

&lt;p&gt;Fast-forward a decade, and now we have people building huge systems out of JavaScript, using some sort of "class" story, or living the hippy prototype lifestyle, or who knows what kids are doing today.  In any case, there's often an "object" in the picture, and you'd often like to arrange to have that object be the receiver of the callback.  Quite often, you'd like for the callback function to be a method of an object, and have the receiver of the callback be that object.
    
&lt;p&gt;The problem is, there's no where to put the receiver; all the pre-existing callback patterns just allowed the use of a function parameter.  The trick with &lt;code&gt;bind()&lt;/code&gt; is that it attaches the receiver, and possibly curry'd arguments, to an invisible bag wrapped around a newly created function which is a delegated version of your callback function.  Nature will find a way.

&lt;!-- ============================================================= --&gt;
&lt;p&gt;&lt;b style="border-bottom:solid"&gt;how can we fix the evils of &lt;code&gt;bind()&lt;/code&gt;?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;For me, the root of the problem is that we're passing the method receiver in a secondary channel, the bound function.  So, stop doing that.  Pass it explicitly.  
    
&lt;p&gt;Let's play with changing  &lt;a href="https://developer.mozilla.org/en/DOM/element.addEventListener"&gt;the &lt;code&gt;addEventListener()&lt;/code&gt; function&lt;/a&gt; to accommodate a new &lt;code&gt;receiver&lt;/code&gt; parameter.  Here's the current function signature:

&lt;pre&gt;
    target.addEventListener(type, listener, useCapture)
&lt;/pre&gt;

&lt;p&gt;We can add the &lt;code&gt;receiver&lt;/code&gt; parameter to the end of the function:

&lt;pre&gt;
    target.addEventListener(type, listener, useCapture, receiver)
&lt;/pre&gt;

&lt;p&gt;or we could allow &lt;code&gt;listener&lt;/code&gt; and &lt;code&gt;receiver&lt;/code&gt; to be combined together in an array and used where the existing &lt;code&gt;listener&lt;/code&gt; value is today:

&lt;pre&gt;
    target.addEventListener(type, [receiver, listener], useCapture)
&lt;/pre&gt;

&lt;p&gt;This second flavor tastes better to me.

&lt;!-- ============================================================= --&gt;
&lt;p&gt;&lt;b style="border-bottom:solid"&gt;what does the fix smell like?&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Let's compare the code.  For the examples below, &lt;code&gt;obj&lt;/code&gt; is the receiver of the callback, &lt;code&gt;callback()&lt;/code&gt; is a method available on the &lt;code&gt;obj&lt;/code&gt; object.  

&lt;p&gt;Using ECMAScript 5's &lt;code&gt;bind()&lt;/code&gt; method:

&lt;pre&gt;
    node.addEventListener("click", obj.callback.bind(obj))
&lt;/pre&gt;

&lt;p&gt;Here's the four-arg &lt;code&gt;addEventListener()&lt;/code&gt;:

&lt;pre&gt;
    node.addEventListener("click", obj.callback, false, obj)
&lt;/pre&gt;

&lt;p&gt;Here's the two-element-array-listener &lt;code&gt;addEventListener()&lt;/code&gt;:

&lt;pre&gt;
    node.addEventListener("click", [obj, obj.callback])
&lt;/pre&gt;

&lt;p&gt;These examples could be made even DRYer, if instead of passing a function reference, you pass a string, which will be used as a property  name to obtain the function from the receiver object:

&lt;pre&gt;
    node.addEventListener("click", "callback", false, obj)
    node.addEventListener("click", [obj, "callback"])
&lt;/pre&gt;

&lt;p&gt;In terms of being able to handle the &lt;code&gt;removeEventListener()&lt;/code&gt; case as well, when using the ECMAScript 5 version of &lt;code&gt;bind()&lt;/code&gt; you would have to arrange to store a copy of the bound function, so you can send the exact same function both &lt;code&gt;addEventListener()&lt;/code&gt; and &lt;code&gt;removeEventListener()&lt;/code&gt;.  My proposed versions could do a compare against the parameters or array elements, allowing you to use the exact same parameters on &lt;code&gt;addEventListener()&lt;/code&gt; and &lt;code&gt;removeEventListener()&lt;/code&gt;.
    
&lt;p&gt;In other words, here's how you do it in ECMAScript 5:
    
&lt;pre&gt;
    var boundFunction = obj.callback.bind(obj)
    
    node.addEventListener("click", boundFunction)
    ...
    node.removeEventListener("click", boundFunction)
&lt;/pre&gt;

&lt;p&gt;And here's how you do it with my proposal:
    
&lt;pre&gt;
    node.addEventListener("click", [obj, "callback"])
    ...
    node.removeEventListener("click", [obj, "callback"])
&lt;/pre&gt;
    
&lt;p&gt;This invocation pattern works the same for the other form of call that I proposed.
    
&lt;p&gt;Curried arguments can be handled the same way the &lt;code&gt;receiver&lt;/code&gt; parameter is handled; passed as additional arguments to &lt;code&gt;addEventListener()&lt;/code&gt; (not needed for &lt;code&gt;removeEventListener()&lt;/code&gt;?), or an additional element in the array where the &lt;code&gt;listener&lt;/code&gt; argument was previously used.  One simplification would be to allow a single curried argument - other callback systems typically refer to this as &lt;code&gt;userData&lt;/code&gt; or &lt;code&gt;clientData&lt;/code&gt; - rather than deal with a variadic list.  It's simple enough to combine multiple curried arguments into an object or array for use as a &lt;code&gt;userData&lt;/code&gt; argument.

&lt;!-- ============================================================= --&gt;
&lt;p&gt;&lt;b style="border-bottom:solid"&gt;actually, &lt;code&gt;bind()&lt;/code&gt; isn't always evil&lt;/b&gt;
    
&lt;p&gt;Although I've spent this entire post complaining about &lt;code&gt;bind()&lt;/code&gt;, I will acknowledge it's power and usefulness.  Particularly in meta-programming and function programming.
    
&lt;p&gt;My primary complaint is having to use &lt;code&gt;bind()&lt;/code&gt; is something pedestrian as callbacks.  That's too much.

&lt;!-- ============================================================= --&gt;
&lt;p&gt;&lt;b style="border-bottom:solid"&gt;the obligatory Smalltalk reference&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;My views on this subject are biased by my exposure to OTI/IBM Smalltalk.  Read up on the &lt;b&gt;Callbacks&lt;/b&gt; section on page 150 of &lt;a href="http://www-01.ibm.com/support/docview.wss?uid=swg27000344"&gt;"IBM Smalltalk: Programmer's Reference"&lt;/a&gt;. 
    
&lt;p&gt;You'll note that my suggestion here is no different than the  &lt;code&gt;addCallback:receiver:selector:clientData:&lt;/code&gt; method described in that manual, just a shorter name.&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/IuPhWW0hx-s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/5677038977010307200/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=5677038977010307200" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5677038977010307200?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5677038977010307200?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/IuPhWW0hx-s/bind-considered-harmful.html" title="bind() considered harmful" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><thr:total>8</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2010/06/bind-considered-harmful.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UGRX86fSp7ImA9WxFWFEQ.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-4373820045177904894</id><published>2010-06-02T11:05:00.001-04:00</published><updated>2010-06-02T11:07:04.115-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-02T11:07:04.115-04:00</app:edited><title>coopitition</title><content type="html">&lt;p&gt;A neat thing happened last month.  I entered a feature request against the Web Inspector debugger shipped with WebKit, to get some new function added.  Two weeks later, that function was implemented in the FireBug debugger for FireFox.  Coincidence?

&lt;p&gt;The feature request was this one: &lt;i&gt;&lt;a href="https://bugs.webkit.org/show_bug.cgi?id=38664"&gt;Bug 38664: Web Inspector: add a "table" method to console, to allow output of tabular data&lt;/a&gt;&lt;/i&gt;.  I got the idea for this from looking at another Web Inspector bug: &lt;i&gt;&lt;a href="https://bugs.webkit.org/show_bug.cgi?id=30897"&gt;Bug 30897: Web Inspector: Support Debugging via HTTP Headers like FirePHP and FireLogger&lt;/a&gt;&lt;/i&gt;.  Turns out that &lt;a href="http://www.firephp.org/"&gt;FirePHP&lt;/a&gt; (&lt;b&gt;another&lt;/b&gt; interesting project) has had support for tabular console output for a while.  I immediately felt left out.

&lt;p&gt;So how did the FireBug folks beat the Web Inspector folks (me included) to the implementation?  Turns out that IBM employs folks who work on both Web Inspector and FireBug.  My primary contact for FireBug stuff in IBM is John J Barton, and I thought this new function would be interesting enough they'd want it too.  I guess I was right.  John and I trade notes on stuff like this from time to time.

&lt;p&gt;Once Jan Odvarko (aka "Honza") posted his blog entry &lt;i&gt;&lt;a href="http://www.softwareishard.com/blog/firebug/tabular-logs-in-firebug/"&gt;Tabular logs in Firebug&lt;/a&gt;&lt;/i&gt;, my interest in this bug grew, for some reason  &lt;tt&gt;:-)&lt;/tt&gt;  So, had some conversation with Jan, on the bug, last Friday.  It was great for Jan to provide additional feedback in WebKit's Bugzilla.  And then I was totally surprised yesterday morning to find that a bunch of additional great ideas around the feature request got posted back to the bug over the weekend, from Jan and other Web Inspector developers.

&lt;p&gt;I decided to try to summarize where we were, provide some examples, and ended up writing a little &lt;code&gt;console.table()&lt;/code&gt; simulator to play with, all of which is currently available in this file: &lt;i&gt;&lt;a href="http://muellerware.org/papers/console-table.html"&gt;console.table() proposal&lt;/a&gt;&lt;/i&gt;.  Please post comments on that file back to the bug, for now.

&lt;p&gt;I love friendly competition!&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/yq5DRAkmUIs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/4373820045177904894/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=4373820045177904894" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4373820045177904894?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4373820045177904894?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/yq5DRAkmUIs/coopitition.html" title="coopitition" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2010/06/coopitition.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UBQHw4cCp7ImA9WxFRFEo.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-4981671497364566279</id><published>2010-04-28T13:18:00.001-04:00</published><updated>2010-04-28T13:20:51.238-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-28T13:20:51.238-04:00</app:edited><title>the weinre experiment - WEb INspector REmote</title><content type="html">&lt;p&gt;For the last few months, one of the things I've been working on is an experiment called &lt;code&gt;weinre&lt;/code&gt;, which stands for &lt;b&gt;WE&lt;/b&gt;b &lt;b&gt;IN&lt;/b&gt;spector &lt;b&gt;RE&lt;/b&gt;mote.
The basic ideas are:

&lt;ul&gt;
&lt;li&gt;reuse the existing Web Inspector UI code, implemented in HTML, CSS, and JS
&lt;li&gt;get that Web Inspector code to run as a plain old web page
&lt;li&gt;have that Web Inspector code debug a web page running in another browser window, perhaps on another machine
&lt;/ul&gt;

&lt;p&gt;You might ask - "Why?"  The answer is, largely: mobile.  How am I supposed to debug mobile web apps on an iPhone, Android device, or similar?  Today the answer is: painfully.  Tomorrow the answer should be: via a nice debug user interface like Web Inspector.
    
&lt;p&gt;The source and an executable demo are available on WebKit's wiki, currently at the bottom of the Web Inspector page: 

&lt;p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://trac.webkit.org/wiki/WebInspector"&gt;https://trac.webkit.org/wiki/WebInspector&lt;/a&gt; &lt;/ul&gt;

&lt;p&gt;I have an introductory write-up of the experiment at my web site, and it's also included with the source and executable demo: 

&lt;p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://muellerware.org/papers/weinre/manual.html"&gt;http://muellerware.org/papers/weinre/manual.html&lt;/a&gt;&lt;/ul&gt;
    
&lt;p&gt;If you are truly lazy and don't want to bother with those, but can afford 3 minutes for a demo movie, you can watch it on YouTube.  Best viewed in 720p (HD) in full screen mode, if your browser supports that.
    
&lt;p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=MxmFrFEGInU"&gt;http://www.youtube.com/watch?v=MxmFrFEGInU&lt;/a&gt;&lt;/ul&gt;

&lt;p&gt;Let me emphasize that this is an &lt;b&gt;experiment&lt;/b&gt;.  Although parts of it do work, as shown in the movie, it's a bit unwieldy and insecure to use as a production tool.  I was at a good place to stop, and so thought I'd archive the wad up for other people to experiment with.
    
&lt;p&gt;So, what's next?
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;Security, as noted in the write-up, is a big concern of mine.  Must do something there.
    
&lt;li&gt;&lt;p&gt;Remove the requirement for the separate agent/server.  Meaning that one of the debug client or the debug target should act as a server to it's peer.  Or perhaps both debug client and debug target should be able to act as the server.  Or use some other whacky IPC mechanism.
    
&lt;li&gt;&lt;p&gt;Formalize some structure around the messages sent between the target and client.  Today the messages sent between the debug target and debug client are very specific to the Web Inspector implementation.  It would be nice to have something less specific.  One of them things called an A-P-I.
    
&lt;li&gt;&lt;p&gt;Not sure where my time is going to be spent over the next year, but it might not be here, so the answer to "What's next?" might be: "nothing, from me".  But the tea leaves seem to be reading: "remote web debug".
    
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/7Ha9CAVxj0I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/4981671497364566279/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=4981671497364566279" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4981671497364566279?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/4981671497364566279?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/7Ha9CAVxj0I/weinre-experiment-web-inspector-remote.html" title="the weinre experiment - WEb INspector REmote" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2010/04/weinre-experiment-web-inspector-remote.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4GRHk8fip7ImA9WxBUEk0.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-7306783706286079989</id><published>2010-02-26T10:59:00.001-05:00</published><updated>2010-02-26T11:15:25.776-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-26T11:15:25.776-05:00</app:edited><title>prior art</title><content type="html">&lt;p&gt;A few caveats before starting:
    
&lt;ul&gt;
&lt;li&gt;I am not a lawyer, just an old country programmer, currently working at IBM.
&lt;li&gt;This blog post is my own and does not necessarily represent IBM’s positions, strategies or opinions.
&lt;li&gt;The patent infringement suit I mention below does not involve IBM as a litigant.  It does involve me as a fact witness.
&lt;li&gt;No need to go into details on the patent infringement suit, as they are irrelevant to this blog post.
&lt;/ul&gt;

&lt;p&gt;Tim Bray recently wrote a blog post, &lt;a href="http://www.tbray.org/ongoing/When/201x/2010/02/22/Patent-Fail"&gt;"Giving Up On Patents"&lt;/a&gt;, providing his opinion on the state of patents and linking to a number of interesting patent-related texts on the web.  My thoughts are currently roughly aligned with Tim's, so there's no need to restate them.  
    
&lt;p&gt;Since I was recently involved as a &lt;a href="http://definitions.uslegal.com/f/fact-witness/"&gt;fact witness&lt;/a&gt; in a &lt;a href="http://en.wikipedia.org/wiki/Patent_infringement"&gt;patent infringement&lt;/a&gt; suit, I thought I'd provide some tips if the following are true for you:
    
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You believe that there are a lot of patents granted for which there already exists &lt;a href="http://en.wikipedia.org/wiki/Prior_art"&gt;prior art&lt;/a&gt;, and so those patents really shouldn't be granted in the first place.
&lt;li&gt;&lt;p&gt;You make things.
&lt;/ul&gt;

&lt;p&gt;The tips:
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;b&gt;Document the crap out of the things that you make.&lt;/b&gt;
&lt;li&gt;&lt;p&gt;&lt;b&gt;Put your documentation on the web, and make sure search engines can find it 20 years from now.&lt;/b&gt;
&lt;/ul&gt;

&lt;p&gt;For the suit I was involved with, an attorney of one of the defendants did a Google search on a term relevant to the suit, and found a paper I had written 13 years ago, on my personal web site.  The paper they found lead them to believe I had information relevant to the suit; they thought I had evidence of prior art.  Eventually, a lot more documentation was excavated from various people and places.
    
&lt;p&gt;I found it interesting that a couple of movies were added to the pile of evidence I was asked about during my deposition, all of which appeared to be digitized versions of tape.  They were all also around 13 years old.  I suspect video will become even more popular as evidence in the future, given the ease in creating and disseminating it, and the amount of information it provides.  Lawyers love information.  Think screencasts, or perhaps &lt;a href="http://asciicasts.com/"&gt;ASCIIcasts&lt;/a&gt; are more relevant for the thing you made.
    
&lt;p&gt;In case you're morbidly curious, I don't believe the statements I provided during my deposition actually helped the defendant in any way.  Based on the questions I was asked, I have my guesses as to whether I helped anyone, but I have no way of knowing.  I didn't study the patent in question, so I don't know what claims the plaintiff is making, nor do I know how the defense is planning to defend against those claims.  All that is irrelevant for a fact witness; I was there to objectively answer questions that were asked of me.  Just the facts, ma'am.

&lt;p&gt;A couple of slightly humorous notes:
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;During the deposition, the court's Windows machine could not be coaxed to play the videos (missing codecs).  One of the younger attorneys saved the day with his MacBook.
    
&lt;li&gt;&lt;p&gt;Making some small talk (heh) with my counsel during a break, I mentioned that I might claim "software patents are against my religion" if I was ever asked to do something I really didn't want to do.  He had a good laugh, and said he'd never heard that before.  Note taken.
    
&lt;li&gt;&lt;p&gt;The paper that the attorney found on the web had a self-referential link in it.  I always do that, never know what might happen to an HTML file.  The link, however, was to a web site long since gone, which today renders as a parked 404 page somewhere.  Of course, the paper had moved somewhere else, and of course, Google knew where it was.  But it was still funny to see that old link.
    
&lt;li&gt;&lt;p&gt;Being a fact witness doesn't pay well.  I received a $55 check for my time; the deposition was an all-day event.
    
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/IhrMb8llGok" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7306783706286079989?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7306783706286079989?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/IhrMb8llGok/prior-art.html" title="prior art" /><author><name>Patrick Mueller</name><uri>http://www.blogger.com/profile/04900886008475308281</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-0rfovvACxRY/T9k0ksA3l4I/AAAAAAAAAtQ/OmEN4ZaNsk8/s220/2010-03-12-bw-500x500-orton.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2010/02/prior-art.html</feedburner:origLink></entry></feed>
