<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DkMCQ3k4fip7ImA9WhRUEU4.&quot;"><id>tag:blogger.com,1999:blog-22367266</id><updated>2012-01-21T03:27:42.736-05: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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>219</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;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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-2897338559158240774?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-64780419174178852?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-2976012419713345912?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-1383519842683429266?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-535450172561441953?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-8270567618462148909?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-1468710805033159283?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-5239431319589229225?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-7928235752351317533?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-7896201245717282494?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-5514008300139896619?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-478366542803312928?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-230674860359186161?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-2353235542752962308?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-3641721101876463661?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-7824900025739082065?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-6318675506367644427?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.jpg" /></author><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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-5677038977010307200?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-4373820045177904894?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-4981671497364566279?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.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;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-7306783706286079989?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.jpg" /></author><feedburner:origLink>http://pmuellr.blogspot.com/2010/02/prior-art.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8CQnc4cSp7ImA9WxBWF08.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-7164348780403963241</id><published>2010-02-09T10:19:00.001-05:00</published><updated>2010-02-09T10:21:03.939-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-09T10:21:03.939-05:00</app:edited><title>modjewel 0.2.0 - a CommonJS require() function for the browser</title><content type="html">&lt;p&gt;I decided to get off my butt and bring my "for the browser" CommonJS &lt;tt&gt;require()&lt;/tt&gt; implementation at &lt;a href="http://github.com/pmuellr/modjewel"&gt;http://github.com/pmuellr/modjewel&lt;/a&gt; into the 20-teens.
    
&lt;p&gt;&lt;b&gt;some background&lt;/b&gt;

&lt;p&gt;Just over a year ago the "ServerJS" group was formed based on the &lt;a href="http://www.blueskyonmars.com/2009/01/29/what-server-side-javascript-needs/"&gt;&lt;i&gt; "What Server Side JavaScript needs" &lt;/i&gt;&lt;/a&gt; blog post from Kevin Dangoor.  This effort was renamed "CommonJS" later in the year, and lives on the web here: &lt;a href="http://commonjs.org/"&gt;http://commonjs.org/&lt;/a&gt;.  Kris Kowal has a nice write up on CommonJS at Ars Technica in the article &lt;a href="http://arstechnica.com/web/news/2009/12/commonjs-effort-sets-javascript-on-path-for-world-domination.ars"&gt;&lt;i&gt;"CommonJS effort sets JavaScript on path for world domination"&lt;/i&gt;&lt;/a&gt;, if you don't know anything about it.  Note: I'm a sucker for &lt;a href="http://shop.cafepress.com/j9-world-domination"&gt;software-based world domination&lt;/a&gt;.

&lt;p&gt;One of the first items looked at by the CommonJS community was a "module" system, centered around a function named &lt;tt&gt;require()&lt;/tt&gt;. More information on modules and &lt;tt&gt;require()&lt;/tt&gt; is available here: &lt;a href="http://wiki.commonjs.org/wiki/Modules/1.1"&gt;http://wiki.commonjs.org/wiki/Modules/1.1&lt;/a&gt;.  While most of the folks in the group were playing with server-side JavaScript, I was interested in the browser, so cooked up a crude version of &lt;tt&gt;require()&lt;/tt&gt; in a github project just over a year ago; the crufty old hack is &lt;a href="http://github.com/pmuellr/modjewel/blob/6ec4af270cfc5c29e3ed51a9a1825dd0c01573f8/ModJewel_require_0_1.js"&gt;here&lt;/a&gt;.

&lt;p&gt;I figured someone else would do a proper version, but haven't really come across anything besides David Flanagan's efforts, documented in his blog posts &lt;a href="http://www.davidflanagan.com/2009/11/commonjs-module.html"&gt;&lt;i&gt;"CommonJS Modules implementation"&lt;/i&gt;&lt;/a&gt; and &lt;a href="http://www.davidflanagan.com/2009/11/a-module-loader.html"&gt;&lt;i&gt;"A module loader with simple dependency management"&lt;/i&gt;&lt;/a&gt;.  I have to admit I don't watch the CommonJS stuff all that closely, I probably missed some other implementations.

&lt;p&gt;David's code doesn't have any kind of a license associated with it, so I didn't really feel it was appropriate to use it for a real project.  And there were  some things I wanted to modify.  So, at the very least David shamed me into sprucing up &lt;tt&gt;modjewel&lt;/tt&gt; and I will admit to stealing bits of his design as well.

&lt;p&gt;One thing I learned from David's blog post was that compliance tests exist.  Loves having tests.  They currently live here: &lt;a href="http://github.com/kriskowal/commonjs"&gt;http://github.com/kriskowal/commonjs&lt;/a&gt;.  Note that David's blog post points to an older version of the tests.

&lt;p&gt;Onto the goodies in the newly improved &lt;tt&gt;modjewel&lt;/tt&gt; ...

&lt;!-- ==================================================================== --&gt;
&lt;p&gt;&lt;b&gt;nice ui for the compliance tests&lt;/b&gt;
    
&lt;p&gt;As I mentioned above, there's a set of test cases for the &lt;tt&gt;require()&lt;/tt&gt; function. Problem is, they're built for command-line invocation; remember, this CommonJS stuff is more server-side than client-side JavaScript.  I was recently pawing through the source for the &lt;a href="http://www2.webkit.org/perf/sunspider-0.9/sunspider.html"&gt;SunSpider JavaScript benchmarks&lt;/a&gt;, and realized I could use the same "run the tests serially in IFrames" technique here, so I lifted that design.  I now have a single page that will load and run all the tests serially, and produce a green/red report card when done.  It's not perfect, but it's very handy.
    
&lt;p&gt;One weird thing to note was that I couldn't find any kind of license on the tests; I ended up importing them directly into my project, which is kind of silly.  I should probably run them right out of the github repo.

&lt;!-- ==================================================================== --&gt;
&lt;p&gt;&lt;b&gt;support for &lt;tt&gt;module.setExports()&lt;/tt&gt;&lt;/b&gt;

&lt;p&gt;The existing facilities with modules make it easy to provide access to a number of objects within a particular module.  However, for those times you only have a single object in a module, things get verbose.  Here's an example: say you want to build and use a  module called &lt;tt&gt;WebDav&lt;/tt&gt; (so the file is named &lt;tt&gt;WebDav.js&lt;/tt&gt;) which exports a single function, &lt;tt&gt;WebDav&lt;/tt&gt;.
    
&lt;p&gt;In the file &lt;tt&gt;WebDav.js&lt;/tt&gt;, you would define the &lt;tt&gt;WebDav&lt;/tt&gt; class as:

&lt;pre&gt;
   exports.WebDav = function WebDav() {
       // the function is 'named' for debug purposes
   ...
   }
&lt;/pre&gt;

&lt;p&gt;You can then use the &lt;tt&gt;WebDav&lt;/tt&gt; class in another file as:
    
&lt;pre&gt;
   var WebDav = require("WebDav").WebDav
&lt;/pre&gt;

&lt;p&gt;All the RY of Java. The &lt;tt&gt;"WebDav"&lt;/tt&gt; passed to &lt;tt&gt;require()&lt;/tt&gt; specifies the module, and the next &lt;tt&gt;WebDav&lt;/tt&gt; selects the function as a property of the &lt;tt&gt;exports&lt;/tt&gt; object the module populated.
    
&lt;p&gt;Alternatively, with the &lt;tt&gt;module.setExports()&lt;/tt&gt; support you can define the class in &lt;tt&gt;WebDav.js&lt;/tt&gt; as:

&lt;pre&gt;
   module.setExports(function WebDav() {
   ...
   })
&lt;/pre&gt;
  
&lt;p&gt;and then use it in another file as:

&lt;pre&gt;
   var WebDav = require("WebDav")
&lt;/pre&gt;
          
&lt;p&gt;Better! Very convenient if you have a 1-1 correspondence between classes and modules.

&lt;p&gt;&lt;tt&gt;module.setExports()&lt;/tt&gt; isn't official yet; see the wiki page for more information: &lt;a href="http://wiki.commonjs.org/wiki/Modules/SetExports"&gt;http://wiki.commonjs.org/wiki/Modules/SetExports&lt;/a&gt;.

&lt;!-- ==================================================================== --&gt;
&lt;p&gt;&lt;b&gt;preloading modules via &lt;tt&gt;&amp;lt;script src=""&amp;gt;&lt;/tt&gt;&lt;/b&gt;

&lt;p&gt;The way &lt;tt&gt;modjewel&lt;/tt&gt;'s version of &lt;tt&gt;require()&lt;/tt&gt; works is like every other browser-based one: it use synchronous XHR.  Which is ok for development-time, but completely unacceptable at deployment-time.  So they say.  Flanagan came up a preload story for his &lt;a href="http://www.davidflanagan.com/2009/11/a-module-loader.html"&gt;require2.js&lt;/a&gt; file, but the mechanism seemed a little crude.  

&lt;p&gt;Instead, I created a command-line utility which will convert a module into a file which can be embedded with &amp;lt;script&amp;nbsp;src=""&amp;gt;.  So then the story would be that you run this utility as part of a build step, perhaps minize or whatever you kids do to your JavaScript afterwards.  In the end, you have a "plain old" JavaScript file to "include".  All the utility really does is wrap your code in a function.  When this code is executed, it registers the module and the function, such that the first time &lt;tt&gt;require()&lt;/tt&gt; is called to load the module, the function is executed and the module is loaded.
    
&lt;p&gt;A nice aspect of this is that the order in which the &amp;lt;script&amp;nbsp;src=""&amp;gt; are placed doesn't need to be in some kind of special pre-req order.  Including the modules doesn't really load them, it just pre-loads them.

&lt;p&gt;Anyway, it's one answer to the "you can't use synchronous XHR!" argument.

&lt;!-- ==================================================================== --&gt;
&lt;p&gt;&lt;b&gt;portability&lt;/b&gt;
    
&lt;p&gt;I've run the tests successfully on Mac Chrome, Mac Safari, Mac Opera 10, the IPhone Simulator, Windows Chrome, and Windows FireFox 3.0.  IE 7.0 was a no-go.  

&lt;p&gt;There is an issue with Chrome, where some tests fail when running against a &lt;tt&gt;file://&lt;/tt&gt; URL.  See &lt;a href="http://github.com/pmuellr/modjewel/issues#issue/1"&gt;issue 1&lt;/a&gt; for more info.

&lt;p&gt;There are some jiggly issues with Windows - of course those being path separator issues (\ instead of /) and new-line issues (CR LF instead of LF).  Should be easy to fix.  Not sure what to do about IE 7, do I use FireBug Lite to debug that?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-7164348780403963241?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/VVtabicdEUs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/7164348780403963241/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=7164348780403963241" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7164348780403963241?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/7164348780403963241?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/VVtabicdEUs/modjewel-020-commonjs-require-function.html" title="modjewel 0.2.0 - a CommonJS require() function for the browser" /><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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2010/02/modjewel-020-commonjs-require-function.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMDQH8_eCp7ImA9WxBWEEg.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-242613326910615427</id><published>2010-02-01T15:31:00.001-05:00</published><updated>2010-02-01T15:34:31.140-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-01T15:34:31.140-05:00</app:edited><title>remote web inspector - baby steps</title><content type="html">&lt;p&gt;Last week, I did a little work getting a remote debug story between an iPhone and WebKit's Web Inspector limping.  Barely limping.  More like crawling.  Anyhoo, the write-up is here:

&lt;p&gt;&lt;a href="http://muellerware.org/papers/remote-web-inspector-baby-steps.html"&gt;http://muellerware.org/papers/remote-web-inspector-baby-steps.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-242613326910615427?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/heYAIcmaPZo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/242613326910615427/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=242613326910615427" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/242613326910615427?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/242613326910615427?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/heYAIcmaPZo/remote-web-inspector-baby-steps.html" title="remote web inspector - baby steps" /><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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2010/02/remote-web-inspector-baby-steps.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EDRH89fSp7ImA9WxNaGE8.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-8569569942161607394</id><published>2009-12-02T20:59:00.003-05:00</published><updated>2009-12-03T02:34:35.165-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-03T02:34:35.165-05:00</app:edited><title>who called that function?</title><content type="html">&lt;p&gt;A question came up today in Web Inspector land - someone wanted to know why &lt;code&gt;setTimeout()&lt;/code&gt; was being called so often in some web application.  The suggestion was that a capability could be added to &lt;a href="http://www.chromium.org/devtools/google-chrome-developer-tools-tutorial#timeline"&gt;Web Inspector's timeline panel&lt;/a&gt; to show a function's  invocations (&lt;code&gt;setTimeout()&lt;/code&gt; in this case) as well as the stack traces for those calls, to figure out who was actually calling the function.
    
&lt;p&gt;My immediate thought was - can't you do this with user-land code?  If you can do it with plain old JavaScript, then I see less of a need to add the function to the debugger.  Especially since:
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;The timeline already collects a LOT of information, keeping track of stack traces just adds more.  The UI will get even busier, and Web Inspector will eat even more memory.
    
&lt;li&gt;&lt;p&gt;Some new gestures would be required to manage the list of functions that you wanted to see on the timeline, and whether you wanted the stack traces or not (if optional).  Note that it's not possible to use the existing breakpoint gestures for this, as you can't set a breakpoint on built-in function (like &lt;code&gt;setTimeout()&lt;/code&gt;).
    
&lt;/ul&gt;

&lt;p&gt;I wasn't &lt;i&gt;sure&lt;/i&gt; you could do this with user-land code, so I felt the need to figure out if you could or not.  I got close, maybe close enough, and the result is up at GitHub as a gist with a  &lt;a href="http://gist.github.com/247514#file_wrap_with_back_trace.js"&gt;&lt;code&gt;wrapWithBackTrace()&lt;/code&gt;&lt;/a&gt; function.  The idea is that you pass the function you want traced and back traces displayed for, into the &lt;code&gt;wrapWithBackTrace()&lt;/code&gt; function, which returns a new function to use in place of the original.  Invoking that function will dump information on the console, including a back trace of functions that called this function.  I think there are enough comments in the code to figure out what's going on, but here are a few caveats:
    
&lt;ul&gt;
    
&lt;li&gt;&lt;p&gt;The existing code makes use of &lt;code&gt;Array&lt;/code&gt;'s new methods &lt;code&gt;indexOf()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, and &lt;code&gt;forEach()&lt;/code&gt;.  How nice to have these!  If you don't have them, there's a link in the code to a site to get portable versions of them.  Note that all the browsers I tested with (listed below) seemed to have them already.  Wonderful!
    
&lt;li&gt;&lt;p&gt;The whole functionality revolves around the bizarre &lt;code&gt;caller&lt;/code&gt; property of &lt;code&gt;Function&lt;/code&gt; instances.  Look it up in your favorite JavaScript reference.  Supposedly this property will disappear in future implementations of JavaScript engines, and is already not available in some (IE, I think).
    
&lt;/ul&gt;

&lt;p&gt;Some sample code that uses the &lt;code&gt;wrapWithBackTrace()&lt;/code&gt; function is available in the same gist.  Here's a bit of it:
    
&lt;pre&gt;
function legend(message) {
    var dashes = new Array(60).join("-")
    console.log(dashes)
    console.log(message)
    console.log(dashes)
    console.log("")
}

// tests with user-land function

function factorial(n) {
    if (n &amp;lt;= 0) return 1
    return n * factorial(n-1)
}

function printFactorial(n) {
    console.log(n + "! == " + factorial(n))
    console.log("")
}

function a() { b() }
function b() { c() }
function c() { 
    printFactorial(0)
    printFactorial(5)
}

legend("calling factorial() before wrapping")
a()

&lt;b&gt;// install the replacement function
factorial = wrapWithBackTrace(factorial)&lt;/b&gt;

legend("calling factorial() after wrapping")
a()

legend("calling factorial() at top level")
factorial(0)    
&lt;/pre&gt;

&lt;p&gt;This code exercises some of the edge cases for the function - recursive functions, and functions run at the top level of a script (no back trace available).  The output of running the code above, in the console, is:
    
&lt;pre&gt;
-----------------------------------------------------------
calling factorial() before wrapping
-----------------------------------------------------------

0! == 1

5! == 120

-----------------------------------------------------------
calling factorial() after wrapping
-----------------------------------------------------------

&lt;b&gt;&lt;i&gt;backtrace for factorial()
   - printFactorial()
   - c()
   - b()
   - a()&lt;/i&gt;&lt;/b&gt;

0! == 1

&lt;b&gt;&lt;i&gt;backtrace for factorial()
   - factorial()
   - wrappedWithBackTrace()
   - ... recursion on factorial()

&lt;/i&gt;&lt;/b&gt;(... repeated invocations elided ...)&lt;b&gt;&lt;i&gt;

backtrace for factorial()
   - factorial()
   - wrappedWithBackTrace()
   - ... recursion on factorial()

backtrace for factorial()
   - printFactorial()
   - c()
   - b()
   - a()&lt;/i&gt;&lt;/b&gt;

5! == 120

-----------------------------------------------------------
calling factorial() at top level
-----------------------------------------------------------

&lt;b&gt;&lt;i&gt;backtrace for factorial()
   - {top level call}&lt;/i&gt;&lt;/b&gt;
&lt;/pre&gt;

&lt;p&gt;Sample code is also provided that wraps &lt;code&gt;setTimeout()&lt;/code&gt;, which worked the same way.  Just wanted to make sure it worked with built-in functions as well as user-land functions.
    
&lt;p&gt;The code works in the latest WebKit nightly, Safari 4.0.4, Firefox 3.5.5, Chrome 4.0.249.12, and Opera 10.10, all on Mac OS X 10.6.  Note that Opera does not have &lt;code&gt;console.log()&lt;/code&gt;, so I gave it one:
    
&lt;pre&gt;
console = {log: opera.postError}
&lt;/pre&gt;

&lt;p&gt;The code also works &lt;code&gt;&lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt;&lt;/code&gt;.  The &lt;code&gt;node&lt;/code&gt; system also doesn't have a &lt;code&gt;console.log()&lt;/code&gt; function, so I gave it one:
    
&lt;pre&gt;
console = {log: require('sys').puts}
&lt;/pre&gt;

&lt;p&gt;Actually, there's one &lt;i&gt;tiny&lt;/i&gt; little WIBNI with &lt;code&gt;node&lt;/code&gt; that shows up in the output - can you spot it? (you'll need to install node and try it yourself)

&lt;p&gt;In the end, I kinda doubt the usefulness of this - the problem being that so much of JavaScript these days is anonymous functions.  Without being able to get the "file name" and line number a function is defined on, and without a name for the function itself, having your backtrace be a list of &lt;code&gt;{anonymous}&lt;/code&gt; is less that helpful.  Seems like it would be handy to have a &lt;code&gt;getStackTrace()&lt;/code&gt; method on &lt;code&gt;Arguments&lt;/code&gt; to give you this information.  This still wouldn't help with &lt;a href="http://pmuellr.blogspot.com/2009/11/evil-eval.html"&gt;&lt;code&gt;eval()&lt;/code&gt;'d code&lt;/a&gt; though, as it doesn't even have a "file name" associated with it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-8569569942161607394?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/AmamCemr_Kk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/8569569942161607394/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=8569569942161607394" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/8569569942161607394?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/8569569942161607394?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/AmamCemr_Kk/who-called-that-function.html" title="who called that function?" /><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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/12/who-called-that-function.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU8MQX4-eCp7ImA9WxNUEkU.&quot;"><id>tag:blogger.com,1999:blog-22367266.post-5190405905448441818</id><published>2009-11-03T16:27:00.001-05:00</published><updated>2009-11-03T16:31:20.050-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-03T16:31:20.050-05:00</app:edited><title>evil eval</title><content type="html">&lt;p&gt;With all the nascent alt-JS things people are playing with, 
talked about on 
&lt;a href="http://www.infoq.com/news/2009/09/javascript-compilation-target"&gt;this InfoQ  blog post&lt;/a&gt;,
I got to thinking a while back how we could make debugging a little better
for these folks in 
&lt;a href="http://developer.apple.com/safari/library/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/UsingtheWebInspector/UsingtheWebInspector.html"&gt;WebKit's Web Inspector&lt;/a&gt;.

&lt;p&gt;With my familiarity of Java's innards, I happened to think about
supporting a mode of using an alternative source file, and line number mappings
between the original source and the generated source, to allow folks to have
some level of source-level debugging in their original language.  That would
be for systems which actually generate JavaScript from the original language.

&lt;p&gt;Java supports meta-data in it's .class files for this sort of information,
and I've seen it used for things like debugging Groovy in Eclipse using the
stock Java debugger.  Not a perfect story, but useful.

&lt;p&gt;So I opened up
&lt;a href="https://bugs.webkit.org/show_bug.cgi?id=30933"&gt;Bug 30933 - Web Inspector: support for debugging alt-JS files which generate JS&lt;/a&gt;.
Feel free to drop ideas there.

&lt;p&gt;Anyhoo ...
    
&lt;p&gt;While chatting with someone who could make use of this, they noted that
their biggest problem was that &lt;code&gt;eval()&lt;/code&gt; doesn't do a very good 
job of providing information about syntax errors in the &lt;code&gt;eval()&lt;/code&gt;'d
code.  Really?  Time for some experiments.

&lt;p&gt;First, why care about &lt;code&gt;eval()&lt;/code&gt; in the first place?  Since 
&lt;a href="http://www.google.com/search?q=evil+eval"&gt;it's evil&lt;/a&gt;.  If code is
being generated from some alternate source, don't you end up with JavaScript
code you can just use in the browser with a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;
element?  Sure, you can do it that way.  But
why do an off-line compile if you could do the compile in the browser?

&lt;p&gt;It's also the case that some 'traditional' JavaScript libraries like 
&lt;a href="http://www.dojotoolkit.org/"&gt;Dojo&lt;/a&gt; may end up (depending on
your configuration), downloading your source via XHR and then running it
via &lt;code&gt;eval()&lt;/code&gt; instead of using &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;
elements.

&lt;p&gt;Getting good diagnostic information from &lt;code&gt;eval()&lt;/code&gt; would be good for lots of
people.

&lt;p&gt;On to the experiment:
    
&lt;p&gt;Here's the source of an HTML file to try out with different browsers.  There's a link in 
the HTML which, when clicked, will run the &lt;code&gt;clickMe()&lt;/code&gt; JavaScript
function.  That function builds a string which will be passed into &lt;code&gt;eval()&lt;/code&gt;.
I added 100 or so newline's in the source before a string that all the
browsers would actually choke on (took me a minute; my first guesses at
things that would cause syntax errors didn't).  The 100 empty lines are to see
what kind of line numbers JavaScript will tell us about, if at all; if line numbers
with syntax errors are reported, we want to see a line number like 100, not
13 (the line in the source that invokes &lt;code&gt;eval()&lt;/code&gt;).

&lt;p&gt;The page is also available 
&lt;a href="http://muellerware.org/exception-in-eval.html"&gt;on my web site&lt;/a&gt;.

&lt;p&gt;Below the source are the results you see in the browser after clicking;
these are the properties of the exception object generated by &lt;code&gt;eval()&lt;/code&gt;,
one per line. 

&lt;p&gt;HTML source for test:
&lt;pre&gt;
     1  &amp;lt;html&amp;gt;
     2  &amp;lt;head&amp;gt;
     3  &amp;lt;/head&amp;gt;
     4  &amp;lt;body&amp;gt;
     5  &amp;lt;a href=&amp;quot;javascript:clickMe();&amp;quot;&amp;gt;click me!&amp;lt;/a&amp;gt;
     6  &amp;lt;p&amp;gt;
     7  &amp;lt;div id=&amp;quot;output&amp;quot; style=&amp;quot;font-family: monospace&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
     8  &amp;lt;script&amp;gt;
     9  function clickMe() {
    10      var lines99 = new Array(100).join(&amp;quot;\n&amp;quot;);
    11      evalString = lines99 + &amp;quot;for ]](x does not compute)]]\n&amp;quot;; 
    12      try {
    13          eval(evalString); // this is line 13 of the source file
    14      }
    15      catch(e) {
    16          dumpException(e);
    17      }
    18  }
    19  
    20  function dumpException(obj) {
    21      var result = &amp;quot;Exception:&amp;lt;br&amp;gt;\n&amp;quot;;
    22      for (var key in obj) {
    23          result += &amp;quot;   &amp;quot; + key + &amp;quot;: &amp;quot; + obj[key] + &amp;quot;&amp;lt;br&amp;gt;\n&amp;quot;;
    24      }
    25      document.getElementById(&amp;quot;output&amp;quot;).innerHTML = result;
    26  }
    27  &amp;lt;/script&amp;gt;
    28  &amp;lt;/body&amp;gt;
    29  &amp;lt;/html&amp;gt;
&lt;/pre&gt;

&lt;hr&gt;

&lt;p&gt;&lt;b&gt;WebKit nightly r50423 on Mac (basically, Safari):&lt;/b&gt;
&lt;pre&gt;
Exception:
   message: Parse error
   line: 100
   sourceId: 4837249224
   name: SyntaxError
&lt;/pre&gt;
    
&lt;hr&gt;

&lt;p&gt;&lt;b&gt;Opera 10.00 Build 6652 on Mac:&lt;/b&gt;
&lt;pre&gt;
Exception:
   message: Statement on line 6: Syntax error stacktrace: n/a; see opera:config#UserPrefs|Exceptions Have Stacktrace
   opera#sourceloc: 6
   stacktrace: false
&lt;/pre&gt;
    
&lt;hr&gt;

&lt;p&gt;&lt;b&gt;Google Chrome 4.0.223.11 on Mac:&lt;/b&gt;
&lt;pre&gt;
Exception:
   message: Unexpected token ]
   stack: SyntaxError: Unexpected token ]
    at clickMe (http://muellerware.org/exception-in-eval.html:12:8)
    at unknown source
   type: unexpected_token
   arguments: ]
   name: SyntaxError
&lt;/pre&gt;
    
&lt;hr&gt;

&lt;p&gt;&lt;b&gt;Firefox 3.5.4 on Mac:&lt;/b&gt;
&lt;pre&gt;
Exception:
   message: missing ( after for
   fileName: http://muellerware.org/exception-in-eval.html
   lineNumber: 112
   stack: eval("[100 \n's elided]for ]](x does not compute)]]\n")@:0 clickMe()@http://muellerware.org/exception-in-eval.html:13 @javascript:clickMe();:1
   name: SyntaxError
&lt;/pre&gt;
    
&lt;hr&gt;

&lt;p&gt;&lt;b&gt;IE 8.0.7100.0 on Windows 7 RC:&lt;/b&gt;
&lt;pre&gt;
Exception:
   name: SyntaxError
   message: Expected '('
   number: -2146827283
   description: Expected '('
&lt;/pre&gt;

&lt;hr&gt;

&lt;p&gt;&lt;b&gt;Google Chrome 3.0.195.27 on Windows 7 RC:&lt;/b&gt;
&lt;pre&gt;
Exception:
   message: Unexpected token ]
   stack: SyntaxError: Unexpected token ] at clickMe (http://muellerware.org/exception-in-eval.html:13:8) at unknown source
   type: unexpected_token
   arguments: ]
   name: SyntaxError    
&lt;/pre&gt;

&lt;hr&gt;

&lt;p&gt;Yikes, not a pretty picture!  WebKit was the only one that got the 
line number I wanted.  But it gave a pretty crappy "message". 
Nice seeing the "stack" entries for some of the implementations.

&lt;p&gt;To be honest, things like the "message" - the reason &lt;b&gt;why&lt;/b&gt; you got
the syntax error - I expect to be somewhat implementation dependent.  Although
I expect &lt;b&gt;something&lt;/b&gt; (looking at you, JavaScriptCore!).  

&lt;p&gt;There's a question of semantics, of course.  The exception generated
from WebKit, with the line number of the &lt;code&gt;eval()&lt;/code&gt;'d source,
would be confusing had I not caught the exception (though perhaps I'd see
something different in the debugger had I &lt;b&gt;not&lt;/b&gt; caught the exception).
In reality, what you may really want
to see, structurally, is something like Java's nestable
&lt;code&gt;&lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/InvocationTargetException.html"&gt;InvocationTargetException&lt;/a&gt;&lt;/code&gt;,
for &lt;code&gt;eval()&lt;/code&gt;, because there are multiple levels of things going 
on here; for the ultimate evil, &lt;code&gt;eval()&lt;/code&gt; may end up doing some of it's
own &lt;code&gt;eval()&lt;/code&gt;'s.

&lt;p&gt;In any case, it would be nice to see some of this stuff standardized.  In
ECMAScript 6, I guess.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22367266-5190405905448441818?l=pmuellr.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/pmuellr/~4/sK-MZhZjmoE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://pmuellr.blogspot.com/feeds/5190405905448441818/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=22367266&amp;postID=5190405905448441818" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5190405905448441818?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22367266/posts/default/5190405905448441818?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/pmuellr/~3/sK-MZhZjmoE/evil-eval.html" title="evil eval" /><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://3.bp.blogspot.com/_oM1f-qZM0zM/TAZy-WKN8DI/AAAAAAAAAfk/eeHVkwM37v4/S220/2010-03-12-bw-115x115.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://pmuellr.blogspot.com/2009/11/evil-eval.html</feedburner:origLink></entry></feed>

