Merge branch 'release-1.2.0'
diff --git a/weinre.build/build.properties b/weinre.build/build.properties
index 319717e..2b833f7 100644
--- a/weinre.build/build.properties
+++ b/weinre.build/build.properties
@@ -8,7 +8,7 @@
 #-----------------------------------------------------------
 # weinre version
 #-----------------------------------------------------------
-WEINRE_VERSION: 1.1.0
+WEINRE_VERSION: 1.2.0
 
 #-----------------------------------------------------------
 # some common locations used in the ant scripts
diff --git a/weinre.build/debug.sh b/weinre.build/debug.sh
index c63b146..4abc85c 100755
--- a/weinre.build/debug.sh
+++ b/weinre.build/debug.sh
@@ -9,4 +9,5 @@
 	-agentlib:$DEBUG \
 	-Dfile.encoding=UTF-8 \
 	-classpath $CP \
-	weinre.server.Main
\ No newline at end of file
+	weinre.server.Main \
+	--verbose true
\ No newline at end of file
diff --git a/weinre.doc/ChangeLog.body.html b/weinre.doc/ChangeLog.body.html
index 037a9f7..e1760e1 100644
--- a/weinre.doc/ChangeLog.body.html
+++ b/weinre.doc/ChangeLog.body.html
@@ -5,6 +5,20 @@
  * Copyright (c) 2011 IBM Corporation
 -->
 
+<!-- ======================================================================= -->
+<h2>2011/03/12 - version 1.2.0</h2>
+<ul>
+<li> DOM elements are now updated live as they change in the target
+<li> more console support; sprintf formatting and expandable object logging
+</ul>
+
+<p>issues closed:
+<ul>
+<li><a href="https://github.com/pmuellr/weinre/issues/27">issue 27</a> - edge case where programmatically created DOM is only picked up partially
+<li><a href="https://github.com/pmuellr/weinre/issues/37">issue 37</a> - console.log output doesn't do sprintf-style string interpolations
+</ul>
+
+<!-- ======================================================================= -->
 <h2>2011/03/02 - version 1.1.0</h2>
 <ul>
 <li>added Timeline panel; tracks timers, intervals, XHRs, some other events, and
@@ -18,19 +32,20 @@
 
 <p>issues closed:
 <ul>
-<li><a href='https://github.com/pmuellr/weinre/issues/10'>issue 10</a> enable Timeline panel, and provide some events
-<li><a href='https://github.com/pmuellr/weinre/issues/20'>issue 20</a> catch up to latest Web Inspector code base
-<li><a href='https://github.com/pmuellr/weinre/issues/23'>issue 23</a> mac app's web pages can't connect to server
-<li><a href='https://github.com/pmuellr/weinre/issues/24'>issue 24</a> weinre server runs slowly on windows
-<li><a href='https://github.com/pmuellr/weinre/issues/25'>issue 25</a> pay down technical debt
-<li><a href='https://github.com/pmuellr/weinre/issues/28'>issue 28</a> create a standalone Java launch
-<li><a href='https://github.com/pmuellr/weinre/issues/29'>issue 29</a> autoconnect does not always work
-<li><a href='https://github.com/pmuellr/weinre/issues/30'>issue 30</a> all-json-idls.js is a pig
-<li><a href='https://github.com/pmuellr/weinre/issues/31'>issue 31</a> redirect error/warn/info/debug messages from client and target to server
-<li><a href='https://github.com/pmuellr/weinre/issues/32'>issue 32</a> monospace font too small everywhere
-<li><a href='https://github.com/pmuellr/weinre/issues/33'>issue 33</a> update doc
+<li><a href='https://github.com/pmuellr/weinre/issues/10'>issue 10</a> - enable Timeline panel, and provide some events
+<li><a href='https://github.com/pmuellr/weinre/issues/20'>issue 20</a> - catch up to latest Web Inspector code base
+<li><a href='https://github.com/pmuellr/weinre/issues/23'>issue 23</a> - mac app's web pages can't connect to server
+<li><a href='https://github.com/pmuellr/weinre/issues/24'>issue 24</a> - weinre server runs slowly on windows
+<li><a href='https://github.com/pmuellr/weinre/issues/25'>issue 25</a> - pay down technical debt
+<li><a href='https://github.com/pmuellr/weinre/issues/28'>issue 28</a> - create a standalone Java launch
+<li><a href='https://github.com/pmuellr/weinre/issues/29'>issue 29</a> - autoconnect does not always work
+<li><a href='https://github.com/pmuellr/weinre/issues/30'>issue 30</a> - all-json-idls.js is a pig
+<li><a href='https://github.com/pmuellr/weinre/issues/31'>issue 31</a> - redirect error/warn/info/debug messages from client and target to server
+<li><a href='https://github.com/pmuellr/weinre/issues/32'>issue 32</a> - monospace font too small everywhere
+<li><a href='https://github.com/pmuellr/weinre/issues/33'>issue 33</a> - update doc
 </ul>
 
+<!-- ======================================================================= -->
 <h2>2011/01/25 - version 1.0.0</h2>
 <ul>
 <li> Don't display "not implemented" messages. Closes <a href="https://github.com/pmuellr/weinre/issues/1">issue 19</a>.
@@ -45,6 +60,7 @@
 <li> Get metrics working in Elements panel.  Closes <a href="https://github.com/pmuellr/weinre/issues/1">issue 1</a>.
 </ul>
 
+<!-- ======================================================================= -->
 <h2>2010/12/16 - version 0.9.9</h2>
 
 <ul>
diff --git a/weinre.web/demo/weinre-demo-min.html b/weinre.web/demo/weinre-demo-min.html
index 978b170..3170577 100644
--- a/weinre.web/demo/weinre-demo-min.html
+++ b/weinre.web/demo/weinre-demo-min.html
@@ -21,7 +21,7 @@
 </head>
 
 <body onload="onLoad()">
-<input id="button" type="button" value="start stuff">
+<input id="button-start-stuff" type="button" value="start stuff">
 
 <h1>this is a green h1</h1>
 <h1 class="blue">this is a blue h1</h1>
@@ -29,6 +29,9 @@
 <p>Some text, <i>some italic text</i>, and <b>some bold text</b>.
 
 <div id="metrics">a div</div>
+
+<input id="button-clear-output" type="button" value="clear output">
+<div id="output"></div>
 </body>
 
 </html>
diff --git a/weinre.web/demo/weinre-demo-pieces.html b/weinre.web/demo/weinre-demo-pieces.html
index e88f0c5..2ef3573 100644
--- a/weinre.web/demo/weinre-demo-pieces.html
+++ b/weinre.web/demo/weinre-demo-pieces.html
@@ -52,7 +52,7 @@
 </head>
 
 <body onload="onLoad()">
-<input id="button" type="button" value="start stuff">
+<input id="button-start-stuff" type="button" value="start stuff">
 
 <h1>this is a green h1</h1>
 <h1 class="blue">this is a blue h1</h1>
@@ -60,6 +60,9 @@
 <p>Some text, <i>some italic text</i>, and <b>some bold text</b>.
 
 <div id="metrics">a div</div>
+
+<input id="button-clear-output" type="button" value="clear output">
+<div id="output"></div>
 </body>
 
 </html>
diff --git a/weinre.web/demo/weinre-demo.html b/weinre.web/demo/weinre-demo.html
index 150c9cb..9300102 100644
--- a/weinre.web/demo/weinre-demo.html
+++ b/weinre.web/demo/weinre-demo.html
@@ -21,7 +21,7 @@
 </head>
 
 <body onload="onLoad()">
-<input id="button" type="button" value="start stuff">
+<input id="button-start-stuff" type="button" value="start stuff">
 
 <h1>this is a green h1</h1>
 <h1 class="blue">this is a blue h1</h1>
@@ -29,6 +29,9 @@
 <p>Some text, <i>some italic text</i>, and <b>some bold text</b>.
 
 <div id="metrics">a div</div>
+
+<input id="button-clear-output" type="button" value="clear output">
+<div id="output"></div>
 </body>
 
 </html>
diff --git a/weinre.web/demo/weinre-demo.js b/weinre.web/demo/weinre-demo.js
index ddec2b9..5e3be85 100644
--- a/weinre.web/demo/weinre-demo.js
+++ b/weinre.web/demo/weinre-demo.js
@@ -7,23 +7,33 @@
 
 //------------------------------------------------------------------------------
 var started = false
-var button
+
+var buttonStartStuff
+var buttonClearOutput
+var outputElement 
 
 //------------------------------------------------------------------------------
 function onLoad() {
-    if (!button) button = document.getElementById("button")
+    if (!buttonStartStuff)  buttonStartStuff  = document.getElementById("button-start-stuff")
+    if (!buttonClearOutput) buttonClearOutput = document.getElementById("button-clear-output")
+    if (!outputElement)     outputElement     = document.getElementById("output")
     
-    button.addEventListener("click", function() {
+    buttonStartStuff.addEventListener("click", function() {
         if (!started) {
-            button.value = "stop stuff"
+            buttonStartStuff.value = "stop stuff"
             startStuff()
         }
         else {
-            button.value = "start stuff"
+            buttonStartStuff.value = "start stuff"
             stopStuff()      
         }
         started = !started
     })
+    
+    buttonClearOutput.addEventListener("click", function() {
+        outputElement.innerHTML = ""
+    })
+    
 }
 
 //------------------------------------------------------------------------------
@@ -39,11 +49,17 @@
 
 //------------------------------------------------------------------------------
 function intervalStuff() {
+
+    var message = "doing interval stuff at " + new Date()
+    
     // add a timeout
-    setTimeout(function() { console.log("doing interval stuff")}, 333)
+    setTimeout(function() { console.log(message)}, 333)
     
     // add a timeline marker
-    console.markTimeline("doing interval Stuff")
+    console.markTimeline(message)
+    
+    // write the message to the page
+    output(message)
     
     // do an XHR
     var xhr = new XMLHttpRequest()
@@ -58,6 +74,13 @@
 }
 
 //------------------------------------------------------------------------------
+function output(string) {
+    var element = document.createElement("div")
+    element.innerHTML = string
+    outputElement.appendChild(element)
+}
+
+//------------------------------------------------------------------------------
 function logXhr(xhr) {
     console.log("xhr: readyState: " + xhr.readyState)
 }
diff --git a/weinre.web/modules/weinre/target/Console.scoop b/weinre.web/modules/weinre/target/Console.scoop
index e796a02..b528b4d 100644
--- a/weinre.web/modules/weinre/target/Console.scoop
+++ b/weinre.web/modules/weinre/target/Console.scoop
@@ -52,6 +52,10 @@
     }
 
 //-----------------------------------------------------------------------------
+static getter original
+    return OriginalConsole
+
+//-----------------------------------------------------------------------------
 static method useRemote(value)
     if (arguments.length == 0) return UsingRemote
     
@@ -69,13 +73,21 @@
 //-----------------------------------------------------------------------------
 method _generic(level, messageParts)
     
-    var message = messageParts.join(" ")
+    var message = messageParts[0]
+    
+    var parameters = []
+    for (var i=0; i<messageParts.length; i++) {
+        parameters.push(
+            Weinre.injectedScript.wrapObjectForConsole(messageParts[i], true)
+        )
+    }
     
     var payload = {
         source:      MessageSource.JS,
         type:        MessageType.Log,
         level:       level,
-        message:     message
+        message:     message,
+        parameters:  parameters
     }
     
     Weinre.wi.ConsoleNotify.addConsoleMessage(payload)
diff --git a/weinre.web/modules/weinre/target/NodeStore.scoop b/weinre.web/modules/weinre/target/NodeStore.scoop
index 2ddd83a..3c77093 100644
--- a/weinre.web/modules/weinre/target/NodeStore.scoop
+++ b/weinre.web/modules/weinre/target/NodeStore.scoop
@@ -6,13 +6,20 @@
  * Copyright (c) 2010, 2011 IBM Corporation
  */
 
+requireClass ../common/Weinre
+requireClass ../common/IDGenerator
+
 //-----------------------------------------------------------------------------
 class NodeStore
     this.__nodeMap      = {}
     this.__nodeDataMap  = {}
-    this.__nextId       = 0
     this.inspectedNodes = []
-
+    
+    document.addEventListener("DOMSubtreeModified",       handleDOMSubtreeModified, false)
+    document.addEventListener("DOMNodeInserted",          handleDOMNodeInserted, false)
+    document.addEventListener("DOMNodeRemoved",           handleDOMNodeRemoved, false)
+    document.addEventListener("DOMAttrModified",          handleDOMAttrModified, false)
+    document.addEventListener("DOMCharacterDataModified", handleDOMCharacterDataModified, false)
 
 //-----------------------------------------------------------------------------
 method addInspectedNode(nodeId)
@@ -30,6 +37,10 @@
     return this.__nodeMap[nodeId]
 
 //-----------------------------------------------------------------------------
+method checkNodeId(node)
+    return node.__weinre_id
+
+//-----------------------------------------------------------------------------
 method getNodeId(node)
     if (node.__weinre_id) { 
         return node.__weinre_id
@@ -45,8 +56,20 @@
     return this.serializeNode(this.getNode(nodeId), depth)
 
 //-----------------------------------------------------------------------------
+method getPreviousSiblingId(node)
+    while (true) {
+        var sib = node.previousSibling
+        if (!sib) return 0
+        
+        var id = this.checkNodeId(sib)
+        if (id) return id
+        
+        node = sib
+    }
+
+//-----------------------------------------------------------------------------
 method nextNodeId()
-    return "" + (++this.__nextId)
+    return "" + IDGenerator.next()
 
 //-----------------------------------------------------------------------------
 method serializeNode(node, depth)
@@ -158,3 +181,57 @@
     if (node.__weinreHighlighter) return true 
     if (node.nodeType != Node.TEXT_NODE) return false
     return !!node.nodeValue.match(/^\s*$/) 
+
+//-----------------------------------------------------------------------------
+function handleDOMSubtreeModified(event)
+    if (!event.attrChange) return
+    
+    NodeStore.handleDOMAttrModified(event)
+
+//-----------------------------------------------------------------------------
+function handleDOMNodeInserted(event)
+    var targetId = Weinre.nodeStore.checkNodeId(event.target)
+    var parentId = Weinre.nodeStore.checkNodeId(event.relatedNode)
+    
+    if (!parentId) return
+    
+    var child = Weinre.nodeStore.serializeNode(event.target, 0)
+    var previous = Weinre.nodeStore.getPreviousSiblingId(event.target)
+    Weinre.wi.DOMNotify.childNodeInserted(parentId, previous, child)
+
+//-----------------------------------------------------------------------------
+function handleDOMNodeRemoved(event)
+    var targetId = Weinre.nodeStore.checkNodeId(event.target)
+    var parentId = Weinre.nodeStore.checkNodeId(event.relatedNode)
+    
+    if (!parentId) return
+    
+    if (targetId) {
+        Weinre.wi.DOMNotify.childNodeRemoved(parentId, targetId)
+    }
+    else {
+        var childCount = Weinre.nodeStore.childNodeCount(event.relatedNode)
+        Weinre.wi.DOMNotify.childNodeCountUpdated(parentId, childCount)
+    }
+
+//-----------------------------------------------------------------------------
+// This event is not actually fired in WebKit, but DOMSubtreeModified may
+// be fired for attribute changes.  Doesn't seem to be at the moment.
+function handleDOMAttrModified(event)
+    var targetId = Weinre.nodeStore.checkNodeId(event.target)
+    if (!targetId) return
+    
+    attrs = []
+    for (var i=0; i<event.target.attributes.length; i++) {
+        attrs.push(event.target.attributes[i].name)
+        attrs.push(event.target.attributes[i].value)
+    }
+    
+    Weinre.wi.DOMNotify.attributesUpdated(targetId, attrs)
+
+//-----------------------------------------------------------------------------
+function handleDOMCharacterDataModified(event)
+    var targetId = Weinre.nodeStore.checkNodeId(event.target)
+    if (!targetId) return
+    
+    Weinre.wi.DOMNotify.characterDataModified(targetId, event.newValue)