diff --git a/dist/renderjs-0.10.0.js b/dist/renderjs-0.10.0.js
new file mode 100644
index 0000000000000000000000000000000000000000..06dee4707220cd396e14f8469f22dd8634bbca30
--- /dev/null
+++ b/dist/renderjs-0.10.0.js
@@ -0,0 +1,2138 @@
+/*
+ * js_channel is a very lightweight abstraction on top of
+ * postMessage which defines message formats and semantics
+ * to support interactions more rich than just message passing
+ * js_channel supports:
+ *  + query/response - traditional rpc
+ *  + query/update/response - incremental async return of results
+ *    to a query
+ *  + notifications - fire and forget
+ *  + error handling
+ *
+ * js_channel is based heavily on json-rpc, but is focused at the
+ * problem of inter-iframe RPC.
+ *
+ * Message types:
+ *  There are 5 types of messages that can flow over this channel,
+ *  and you may determine what type of message an object is by
+ *  examining its parameters:
+ *  1. Requests
+ *    + integer id
+ *    + string method
+ *    + (optional) any params
+ *  2. Callback Invocations (or just "Callbacks")
+ *    + integer id
+ *    + string callback
+ *    + (optional) params
+ *  3. Error Responses (or just "Errors)
+ *    + integer id
+ *    + string error
+ *    + (optional) string message
+ *  4. Responses
+ *    + integer id
+ *    + (optional) any result
+ *  5. Notifications
+ *    + string method
+ *    + (optional) any params
+ */
+
+;var Channel = (function() {
+    "use strict";
+
+    // current transaction id, start out at a random *odd* number between 1 and a million
+    // There is one current transaction counter id per page, and it's shared between
+    // channel instances.  That means of all messages posted from a single javascript
+    // evaluation context, we'll never have two with the same id.
+    var s_curTranId = Math.floor(Math.random()*1000001);
+
+    // no two bound channels in the same javascript evaluation context may have the same origin, scope, and window.
+    // futher if two bound channels have the same window and scope, they may not have *overlapping* origins
+    // (either one or both support '*').  This restriction allows a single onMessage handler to efficiently
+    // route messages based on origin and scope.  The s_boundChans maps origins to scopes, to message
+    // handlers.  Request and Notification messages are routed using this table.
+    // Finally, channels are inserted into this table when built, and removed when destroyed.
+    var s_boundChans = { };
+
+    // add a channel to s_boundChans, throwing if a dup exists
+    function s_addBoundChan(win, origin, scope, handler) {
+        function hasWin(arr) {
+            for (var i = 0; i < arr.length; i++) if (arr[i].win === win) return true;
+            return false;
+        }
+
+        // does she exist?
+        var exists = false;
+
+
+        if (origin === '*') {
+            // we must check all other origins, sadly.
+            for (var k in s_boundChans) {
+                if (!s_boundChans.hasOwnProperty(k)) continue;
+                if (k === '*') continue;
+                if (typeof s_boundChans[k][scope] === 'object') {
+                    exists = hasWin(s_boundChans[k][scope]);
+                    if (exists) break;
+                }
+            }
+        } else {
+            // we must check only '*'
+            if ((s_boundChans['*'] && s_boundChans['*'][scope])) {
+                exists = hasWin(s_boundChans['*'][scope]);
+            }
+            if (!exists && s_boundChans[origin] && s_boundChans[origin][scope])
+            {
+                exists = hasWin(s_boundChans[origin][scope]);
+            }
+        }
+        if (exists) throw "A channel is already bound to the same window which overlaps with origin '"+ origin +"' and has scope '"+scope+"'";
+
+        if (typeof s_boundChans[origin] != 'object') s_boundChans[origin] = { };
+        if (typeof s_boundChans[origin][scope] != 'object') s_boundChans[origin][scope] = [ ];
+        s_boundChans[origin][scope].push({win: win, handler: handler});
+    }
+
+    function s_removeBoundChan(win, origin, scope) {
+        var arr = s_boundChans[origin][scope];
+        for (var i = 0; i < arr.length; i++) {
+            if (arr[i].win === win) {
+                arr.splice(i,1);
+            }
+        }
+        if (s_boundChans[origin][scope].length === 0) {
+            delete s_boundChans[origin][scope];
+        }
+    }
+
+    function s_isArray(obj) {
+        if (Array.isArray) return Array.isArray(obj);
+        else {
+            return (obj.constructor.toString().indexOf("Array") != -1);
+        }
+    }
+
+    // No two outstanding outbound messages may have the same id, period.  Given that, a single table
+    // mapping "transaction ids" to message handlers, allows efficient routing of Callback, Error, and
+    // Response messages.  Entries are added to this table when requests are sent, and removed when
+    // responses are received.
+    var s_transIds = { };
+
+    // class singleton onMessage handler
+    // this function is registered once and all incoming messages route through here.  This
+    // arrangement allows certain efficiencies, message data is only parsed once and dispatch
+    // is more efficient, especially for large numbers of simultaneous channels.
+    var s_onMessage = function(e) {
+        try {
+          var m = JSON.parse(e.data);
+          if (typeof m !== 'object' || m === null) throw "malformed";
+        } catch(e) {
+          // just ignore any posted messages that do not consist of valid JSON
+          return;
+        }
+
+        var w = e.source;
+        var o = e.origin;
+        var s, i, meth;
+
+        if (typeof m.method === 'string') {
+            var ar = m.method.split('::');
+            if (ar.length == 2) {
+                s = ar[0];
+                meth = ar[1];
+            } else {
+                meth = m.method;
+            }
+        }
+
+        if (typeof m.id !== 'undefined') i = m.id;
+
+        // w is message source window
+        // o is message origin
+        // m is parsed message
+        // s is message scope
+        // i is message id (or undefined)
+        // meth is unscoped method name
+        // ^^ based on these factors we can route the message
+
+        // if it has a method it's either a notification or a request,
+        // route using s_boundChans
+        if (typeof meth === 'string') {
+            var delivered = false;
+            if (s_boundChans[o] && s_boundChans[o][s]) {
+                for (var j = 0; j < s_boundChans[o][s].length; j++) {
+                    if (s_boundChans[o][s][j].win === w) {
+                        s_boundChans[o][s][j].handler(o, meth, m);
+                        delivered = true;
+                        break;
+                    }
+                }
+            }
+
+            if (!delivered && s_boundChans['*'] && s_boundChans['*'][s]) {
+                for (var j = 0; j < s_boundChans['*'][s].length; j++) {
+                    if (s_boundChans['*'][s][j].win === w) {
+                        s_boundChans['*'][s][j].handler(o, meth, m);
+                        break;
+                    }
+                }
+            }
+        }
+        // otherwise it must have an id (or be poorly formed
+        else if (typeof i != 'undefined') {
+            if (s_transIds[i]) s_transIds[i](o, meth, m);
+        }
+    };
+
+    // Setup postMessage event listeners
+    if (window.addEventListener) window.addEventListener('message', s_onMessage, false);
+    else if(window.attachEvent) window.attachEvent('onmessage', s_onMessage);
+
+    /* a messaging channel is constructed from a window and an origin.
+     * the channel will assert that all messages received over the
+     * channel match the origin
+     *
+     * Arguments to Channel.build(cfg):
+     *
+     *   cfg.window - the remote window with which we'll communicate
+     *   cfg.origin - the expected origin of the remote window, may be '*'
+     *                which matches any origin
+     *   cfg.scope  - the 'scope' of messages.  a scope string that is
+     *                prepended to message names.  local and remote endpoints
+     *                of a single channel must agree upon scope. Scope may
+     *                not contain double colons ('::').
+     *   cfg.debugOutput - A boolean value.  If true and window.console.log is
+     *                a function, then debug strings will be emitted to that
+     *                function.
+     *   cfg.debugOutput - A boolean value.  If true and window.console.log is
+     *                a function, then debug strings will be emitted to that
+     *                function.
+     *   cfg.postMessageObserver - A function that will be passed two arguments,
+     *                an origin and a message.  It will be passed these immediately
+     *                before messages are posted.
+     *   cfg.gotMessageObserver - A function that will be passed two arguments,
+     *                an origin and a message.  It will be passed these arguments
+     *                immediately after they pass scope and origin checks, but before
+     *                they are processed.
+     *   cfg.onReady - A function that will be invoked when a channel becomes "ready",
+     *                this occurs once both sides of the channel have been
+     *                instantiated and an application level handshake is exchanged.
+     *                the onReady function will be passed a single argument which is
+     *                the channel object that was returned from build().
+     */
+    return {
+        build: function(cfg) {
+            var debug = function(m) {
+                if (cfg.debugOutput && window.console && window.console.log) {
+                    // try to stringify, if it doesn't work we'll let javascript's built in toString do its magic
+                    try { if (typeof m !== 'string') m = JSON.stringify(m); } catch(e) { }
+                    console.log("["+chanId+"] " + m);
+                }
+            };
+
+            /* browser capabilities check */
+            if (!window.postMessage) throw("jschannel cannot run this browser, no postMessage");
+            if (!window.JSON || !window.JSON.stringify || ! window.JSON.parse) {
+                throw("jschannel cannot run this browser, no JSON parsing/serialization");
+            }
+
+            /* basic argument validation */
+            if (typeof cfg != 'object') throw("Channel build invoked without a proper object argument");
+
+            if (!cfg.window || !cfg.window.postMessage) throw("Channel.build() called without a valid window argument");
+
+            /* we'd have to do a little more work to be able to run multiple channels that intercommunicate the same
+             * window...  Not sure if we care to support that */
+            if (window === cfg.window) throw("target window is same as present window -- not allowed");
+
+            // let's require that the client specify an origin.  if we just assume '*' we'll be
+            // propagating unsafe practices.  that would be lame.
+            var validOrigin = false;
+            if (typeof cfg.origin === 'string') {
+                var oMatch;
+                if (cfg.origin === "*") validOrigin = true;
+                // allow valid domains under http and https.  Also, trim paths off otherwise valid origins.
+                else if (null !== (oMatch = cfg.origin.match(/^https?:\/\/(?:[-a-zA-Z0-9_\.])+(?::\d+)?/))) {
+                    cfg.origin = oMatch[0].toLowerCase();
+                    validOrigin = true;
+                }
+            }
+
+            if (!validOrigin) throw ("Channel.build() called with an invalid origin");
+
+            if (typeof cfg.scope !== 'undefined') {
+                if (typeof cfg.scope !== 'string') throw 'scope, when specified, must be a string';
+                if (cfg.scope.split('::').length > 1) throw "scope may not contain double colons: '::'";
+            }
+
+            /* private variables */
+            // generate a random and psuedo unique id for this channel
+            var chanId = (function () {
+                var text = "";
+                var alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+                for(var i=0; i < 5; i++) text += alpha.charAt(Math.floor(Math.random() * alpha.length));
+                return text;
+            })();
+
+            // registrations: mapping method names to call objects
+            var regTbl = { };
+            // current oustanding sent requests
+            var outTbl = { };
+            // current oustanding received requests
+            var inTbl = { };
+            // are we ready yet?  when false we will block outbound messages.
+            var ready = false;
+            var pendingQueue = [ ];
+
+            var createTransaction = function(id,origin,callbacks) {
+                var shouldDelayReturn = false;
+                var completed = false;
+
+                return {
+                    origin: origin,
+                    invoke: function(cbName, v) {
+                        // verify in table
+                        if (!inTbl[id]) throw "attempting to invoke a callback of a nonexistent transaction: " + id;
+                        // verify that the callback name is valid
+                        var valid = false;
+                        for (var i = 0; i < callbacks.length; i++) if (cbName === callbacks[i]) { valid = true; break; }
+                        if (!valid) throw "request supports no such callback '" + cbName + "'";
+
+                        // send callback invocation
+                        postMessage({ id: id, callback: cbName, params: v});
+                    },
+                    error: function(error, message) {
+                        completed = true;
+                        // verify in table
+                        if (!inTbl[id]) throw "error called for nonexistent message: " + id;
+
+                        // remove transaction from table
+                        delete inTbl[id];
+
+                        // send error
+                        postMessage({ id: id, error: error, message: message });
+                    },
+                    complete: function(v) {
+                        completed = true;
+                        // verify in table
+                        if (!inTbl[id]) throw "complete called for nonexistent message: " + id;
+                        // remove transaction from table
+                        delete inTbl[id];
+                        // send complete
+                        postMessage({ id: id, result: v });
+                    },
+                    delayReturn: function(delay) {
+                        if (typeof delay === 'boolean') {
+                            shouldDelayReturn = (delay === true);
+                        }
+                        return shouldDelayReturn;
+                    },
+                    completed: function() {
+                        return completed;
+                    }
+                };
+            };
+
+            var setTransactionTimeout = function(transId, timeout, method) {
+              return window.setTimeout(function() {
+                if (outTbl[transId]) {
+                  // XXX: what if client code raises an exception here?
+                  var msg = "timeout (" + timeout + "ms) exceeded on method '" + method + "'";
+                  (1,outTbl[transId].error)("timeout_error", msg);
+                  delete outTbl[transId];
+                  delete s_transIds[transId];
+                }
+              }, timeout);
+            };
+
+            var onMessage = function(origin, method, m) {
+                // if an observer was specified at allocation time, invoke it
+                if (typeof cfg.gotMessageObserver === 'function') {
+                    // pass observer a clone of the object so that our
+                    // manipulations are not visible (i.e. method unscoping).
+                    // This is not particularly efficient, but then we expect
+                    // that message observers are primarily for debugging anyway.
+                    try {
+                        cfg.gotMessageObserver(origin, m);
+                    } catch (e) {
+                        debug("gotMessageObserver() raised an exception: " + e.toString());
+                    }
+                }
+
+                // now, what type of message is this?
+                if (m.id && method) {
+                    // a request!  do we have a registered handler for this request?
+                    if (regTbl[method]) {
+                        var trans = createTransaction(m.id, origin, m.callbacks ? m.callbacks : [ ]);
+                        inTbl[m.id] = { };
+                        try {
+                            // callback handling.  we'll magically create functions inside the parameter list for each
+                            // callback
+                            if (m.callbacks && s_isArray(m.callbacks) && m.callbacks.length > 0) {
+                                for (var i = 0; i < m.callbacks.length; i++) {
+                                    var path = m.callbacks[i];
+                                    var obj = m.params;
+                                    var pathItems = path.split('/');
+                                    for (var j = 0; j < pathItems.length - 1; j++) {
+                                        var cp = pathItems[j];
+                                        if (typeof obj[cp] !== 'object') obj[cp] = { };
+                                        obj = obj[cp];
+                                    }
+                                    obj[pathItems[pathItems.length - 1]] = (function() {
+                                        var cbName = path;
+                                        return function(params) {
+                                            return trans.invoke(cbName, params);
+                                        };
+                                    })();
+                                }
+                            }
+                            var resp = regTbl[method](trans, m.params);
+                            if (!trans.delayReturn() && !trans.completed()) trans.complete(resp);
+                        } catch(e) {
+                            // automagic handling of exceptions:
+                            var error = "runtime_error";
+                            var message = null;
+                            // * if it's a string then it gets an error code of 'runtime_error' and string is the message
+                            if (typeof e === 'string') {
+                                message = e;
+                            } else if (typeof e === 'object') {
+                                // either an array or an object
+                                // * if it's an array of length two, then  array[0] is the code, array[1] is the error message
+                                if (e && s_isArray(e) && e.length == 2) {
+                                    error = e[0];
+                                    message = e[1];
+                                }
+                                // * if it's an object then we'll look form error and message parameters
+                                else if (typeof e.error === 'string') {
+                                    error = e.error;
+                                    if (!e.message) message = "";
+                                    else if (typeof e.message === 'string') message = e.message;
+                                    else e = e.message; // let the stringify/toString message give us a reasonable verbose error string
+                                }
+                            }
+
+                            // message is *still* null, let's try harder
+                            if (message === null) {
+                                try {
+                                    message = JSON.stringify(e);
+                                    /* On MSIE8, this can result in 'out of memory', which
+                                     * leaves message undefined. */
+                                    if (typeof(message) == 'undefined')
+                                      message = e.toString();
+                                } catch (e2) {
+                                    message = e.toString();
+                                }
+                            }
+
+                            trans.error(error,message);
+                        }
+                    }
+                } else if (m.id && m.callback) {
+                    if (!outTbl[m.id] ||!outTbl[m.id].callbacks || !outTbl[m.id].callbacks[m.callback])
+                    {
+                        debug("ignoring invalid callback, id:"+m.id+ " (" + m.callback +")");
+                    } else {
+                        // XXX: what if client code raises an exception here?
+                        outTbl[m.id].callbacks[m.callback](m.params);
+                    }
+                } else if (m.id) {
+                    if (!outTbl[m.id]) {
+                        debug("ignoring invalid response: " + m.id);
+                    } else {
+                        // XXX: what if client code raises an exception here?
+                        if (m.error) {
+                            (1,outTbl[m.id].error)(m.error, m.message);
+                        } else {
+                            if (m.result !== undefined) (1,outTbl[m.id].success)(m.result);
+                            else (1,outTbl[m.id].success)();
+                        }
+                        delete outTbl[m.id];
+                        delete s_transIds[m.id];
+                    }
+                } else if (method) {
+                    // tis a notification.
+                    if (regTbl[method]) {
+                        // yep, there's a handler for that.
+                        // transaction has only origin for notifications.
+                        regTbl[method]({ origin: origin }, m.params);
+                        // if the client throws, we'll just let it bubble out
+                        // what can we do?  Also, here we'll ignore return values
+                    }
+                }
+            };
+
+            // now register our bound channel for msg routing
+            s_addBoundChan(cfg.window, cfg.origin, ((typeof cfg.scope === 'string') ? cfg.scope : ''), onMessage);
+
+            // scope method names based on cfg.scope specified when the Channel was instantiated
+            var scopeMethod = function(m) {
+                if (typeof cfg.scope === 'string' && cfg.scope.length) m = [cfg.scope, m].join("::");
+                return m;
+            };
+
+            // a small wrapper around postmessage whose primary function is to handle the
+            // case that clients start sending messages before the other end is "ready"
+            var postMessage = function(msg, force) {
+                if (!msg) throw "postMessage called with null message";
+
+                // delay posting if we're not ready yet.
+                var verb = (ready ? "post  " : "queue ");
+                debug(verb + " message: " + JSON.stringify(msg));
+                if (!force && !ready) {
+                    pendingQueue.push(msg);
+                } else {
+                    if (typeof cfg.postMessageObserver === 'function') {
+                        try {
+                            cfg.postMessageObserver(cfg.origin, msg);
+                        } catch (e) {
+                            debug("postMessageObserver() raised an exception: " + e.toString());
+                        }
+                    }
+
+                    cfg.window.postMessage(JSON.stringify(msg), cfg.origin);
+                }
+            };
+
+            var onReady = function(trans, type) {
+                debug('ready msg received');
+                if (ready) throw "received ready message while in ready state.  help!";
+
+                if (type === 'ping') {
+                    chanId += '-R';
+                } else {
+                    chanId += '-L';
+                }
+
+                obj.unbind('__ready'); // now this handler isn't needed any more.
+                ready = true;
+                debug('ready msg accepted.');
+
+                if (type === 'ping') {
+                    obj.notify({ method: '__ready', params: 'pong' });
+                }
+
+                // flush queue
+                while (pendingQueue.length) {
+                    postMessage(pendingQueue.pop());
+                }
+
+                // invoke onReady observer if provided
+                if (typeof cfg.onReady === 'function') cfg.onReady(obj);
+            };
+
+            var obj = {
+                // tries to unbind a bound message handler.  returns false if not possible
+                unbind: function (method) {
+                    if (regTbl[method]) {
+                        if (!(delete regTbl[method])) throw ("can't delete method: " + method);
+                        return true;
+                    }
+                    return false;
+                },
+                bind: function (method, cb) {
+                    if (!method || typeof method !== 'string') throw "'method' argument to bind must be string";
+                    if (!cb || typeof cb !== 'function') throw "callback missing from bind params";
+
+                    if (regTbl[method]) throw "method '"+method+"' is already bound!";
+                    regTbl[method] = cb;
+                    return this;
+                },
+                call: function(m) {
+                    if (!m) throw 'missing arguments to call function';
+                    if (!m.method || typeof m.method !== 'string') throw "'method' argument to call must be string";
+                    if (!m.success || typeof m.success !== 'function') throw "'success' callback missing from call";
+
+                    // now it's time to support the 'callback' feature of jschannel.  We'll traverse the argument
+                    // object and pick out all of the functions that were passed as arguments.
+                    var callbacks = { };
+                    var callbackNames = [ ];
+
+                    var pruneFunctions = function (path, obj) {
+                        if (typeof obj === 'object') {
+                            for (var k in obj) {
+                                if (!obj.hasOwnProperty(k)) continue;
+                                var np = path + (path.length ? '/' : '') + k;
+                                if (typeof obj[k] === 'function') {
+                                    callbacks[np] = obj[k];
+                                    callbackNames.push(np);
+                                    delete obj[k];
+                                } else if (typeof obj[k] === 'object') {
+                                    pruneFunctions(np, obj[k]);
+                                }
+                            }
+                        }
+                    };
+                    pruneFunctions("", m.params);
+
+                    // build a 'request' message and send it
+                    var msg = { id: s_curTranId, method: scopeMethod(m.method), params: m.params };
+                    if (callbackNames.length) msg.callbacks = callbackNames;
+
+                    if (m.timeout)
+                      // XXX: This function returns a timeout ID, but we don't do anything with it.
+                      // We might want to keep track of it so we can cancel it using clearTimeout()
+                      // when the transaction completes.
+                      setTransactionTimeout(s_curTranId, m.timeout, scopeMethod(m.method));
+
+                    // insert into the transaction table
+                    outTbl[s_curTranId] = { callbacks: callbacks, error: m.error, success: m.success };
+                    s_transIds[s_curTranId] = onMessage;
+
+                    // increment current id
+                    s_curTranId++;
+
+                    postMessage(msg);
+                },
+                notify: function(m) {
+                    if (!m) throw 'missing arguments to notify function';
+                    if (!m.method || typeof m.method !== 'string') throw "'method' argument to notify must be string";
+
+                    // no need to go into any transaction table
+                    postMessage({ method: scopeMethod(m.method), params: m.params });
+                },
+                destroy: function () {
+                    s_removeBoundChan(cfg.window, cfg.origin, ((typeof cfg.scope === 'string') ? cfg.scope : ''));
+                    if (window.removeEventListener) window.removeEventListener('message', onMessage, false);
+                    else if(window.detachEvent) window.detachEvent('onmessage', onMessage);
+                    ready = false;
+                    regTbl = { };
+                    inTbl = { };
+                    outTbl = { };
+                    cfg.origin = null;
+                    pendingQueue = [ ];
+                    debug("channel destroyed");
+                    chanId = "";
+                }
+            };
+
+            obj.bind('__ready', onReady);
+            setTimeout(function() {
+                postMessage({ method: scopeMethod('__ready'), params: "ping" }, true);
+            }, 0);
+
+            return obj;
+        }
+    };
+})();
+;/*
+ * DOMParser HTML extension
+ * 2012-09-04
+ *
+ * By Eli Grey, http://eligrey.com
+ * Public domain.
+ * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+ */
+/*! @source https://gist.github.com/1129031 */
+(function (DOMParser) {
+  "use strict";
+  var DOMParser_proto = DOMParser.prototype,
+    real_parseFromString = DOMParser_proto.parseFromString;
+
+  // Firefox/Opera/IE throw errors on unsupported types
+  try {
+    // WebKit returns null on unsupported types
+    if ((new DOMParser()).parseFromString("", "text/html")) {
+      // text/html parsing is natively supported
+      return;
+    }
+  } catch (ignore) {}
+
+  DOMParser_proto.parseFromString = function (markup, type) {
+    var result, doc, doc_elt, first_elt;
+    if (/^\s*text\/html\s*(?:;|$)/i.test(type)) {
+      doc = document.implementation.createHTMLDocument("");
+      doc_elt = doc.documentElement;
+
+      doc_elt.innerHTML = markup;
+      first_elt = doc_elt.firstElementChild;
+
+      if (doc_elt.childElementCount === 1
+          && first_elt.localName.toLowerCase() === "html") {
+        doc.replaceChild(first_elt, doc_elt);
+      }
+
+      result = doc;
+    } else {
+      result = real_parseFromString.apply(this, arguments);
+    }
+    return result;
+  };
+}(DOMParser));
+
+;// IE does not support have Document.prototype.contains.
+if (typeof document.contains !== 'function') {
+  Document.prototype.contains = function(node) {
+    if (node === this || node.parentNode === this)
+      return true;
+    return this.documentElement.contains(node);
+ }
+}
+;/*! RenderJs */
+/*jslint nomen: true*/
+
+/*
+ * renderJs - Generic Gadget library renderer.
+ * http://www.renderjs.org/documentation
+ */
+(function (document, window, RSVP, DOMParser, Channel, MutationObserver,
+           Node, FileReader, Blob, navigator, Event) {
+  "use strict";
+
+  function readBlobAsDataURL(blob) {
+    var fr = new FileReader();
+    return new RSVP.Promise(function (resolve, reject) {
+      fr.addEventListener("load", function (evt) {
+        resolve(evt.target.result);
+      });
+      fr.addEventListener("error", reject);
+      fr.readAsDataURL(blob);
+    }, function () {
+      fr.abort();
+    });
+  }
+
+  function ajax(url) {
+    var xhr;
+    function resolver(resolve, reject) {
+      function handler() {
+        try {
+          if (xhr.readyState === 0) {
+            // UNSENT
+            reject(xhr);
+          } else if (xhr.readyState === 4) {
+            // DONE
+            if ((xhr.status < 200) || (xhr.status >= 300) ||
+                (!/^text\/html[;]?/.test(
+                  xhr.getResponseHeader("Content-Type") || ""
+                ))) {
+              reject(xhr);
+            } else {
+              resolve(xhr);
+            }
+          }
+        } catch (e) {
+          reject(e);
+        }
+      }
+
+      xhr = new XMLHttpRequest();
+      xhr.open("GET", url);
+      xhr.onreadystatechange = handler;
+      xhr.setRequestHeader('Accept', 'text/html');
+      xhr.withCredentials = true;
+      xhr.send();
+    }
+
+    function canceller() {
+      if ((xhr !== undefined) && (xhr.readyState !== xhr.DONE)) {
+        xhr.abort();
+      }
+    }
+    return new RSVP.Promise(resolver, canceller);
+  }
+
+  var gadget_model_dict = {},
+    javascript_registration_dict = {},
+    stylesheet_registration_dict = {},
+    gadget_loading_klass,
+    loading_klass_promise,
+    renderJS,
+    Monitor,
+    scope_increment = 0,
+    isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i'),
+    is_page_unloaded = false,
+    error_list = [];
+
+  window.addEventListener('error', function (error) {
+    error_list.push(error);
+  });
+
+  window.addEventListener('beforeunload', function () {
+    // XXX If another listener cancel the page unload,
+    // it will not restore renderJS crash report
+    is_page_unloaded = true;
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // Helper functions
+  /////////////////////////////////////////////////////////////////
+  function removeHash(url) {
+    var index = url.indexOf('#');
+    if (index > 0) {
+      url = url.substring(0, index);
+    }
+    return url;
+  }
+
+  function letsCrash(e) {
+    var i,
+      body,
+      container,
+      paragraph,
+      link,
+      error;
+    if (is_page_unloaded) {
+      /*global console*/
+      console.info('-- Error dropped, as page is unloaded');
+      console.info(e);
+      return;
+    }
+
+    error_list.push(e);
+    // Add error handling stack
+    error_list.push(new Error('stopping renderJS'));
+
+    body = document.getElementsByTagName('body')[0];
+    while (body.firstChild) {
+      body.removeChild(body.firstChild);
+    }
+
+    container = document.createElement("section");
+    paragraph = document.createElement("h1");
+    paragraph.textContent = 'Unhandled Error';
+    container.appendChild(paragraph);
+
+    paragraph = document.createElement("p");
+    paragraph.textContent = 'Please report this error to the support team';
+    container.appendChild(paragraph);
+
+    paragraph = document.createElement("p");
+    paragraph.textContent = 'Location: ';
+    link = document.createElement("a");
+    link.href = link.textContent = window.location.toString();
+    paragraph.appendChild(link);
+    container.appendChild(paragraph);
+
+    paragraph = document.createElement("p");
+    paragraph.textContent = 'User-agent: ' + navigator.userAgent;
+    container.appendChild(paragraph);
+
+    body.appendChild(container);
+
+    for (i = 0; i < error_list.length; i += 1) {
+      error = error_list[i];
+
+      if (error instanceof Event) {
+        error = {
+          string: error.toString(),
+          message: error.message,
+          type: error.type,
+          target: error.target
+        };
+        if (error.target !== undefined) {
+          error_list.splice(i + 1, 0, error.target);
+        }
+      }
+
+      if (error instanceof XMLHttpRequest) {
+        error = {
+          message: error.toString(),
+          readyState: error.readyState,
+          status: error.status,
+          statusText: error.statusText,
+          response: error.response,
+          responseUrl: error.responseUrl,
+          response_headers: error.getAllResponseHeaders()
+        };
+      }
+      if (error.constructor === Array ||
+          error.constructor === String ||
+          error.constructor === Object) {
+        try {
+          error = JSON.stringify(error);
+        } catch (ignore) {
+        }
+      }
+
+      container = document.createElement("section");
+
+      paragraph = document.createElement("h2");
+      paragraph.textContent = error.message || error;
+      container.appendChild(paragraph);
+
+      if (error.fileName !== undefined) {
+        paragraph = document.createElement("p");
+        paragraph.textContent = 'File: ' +
+          error.fileName +
+          ': ' + error.lineNumber;
+        container.appendChild(paragraph);
+      }
+
+      if (error.stack !== undefined) {
+        paragraph = document.createElement("pre");
+        paragraph.textContent = 'Stack: ' + error.stack;
+        container.appendChild(paragraph);
+      }
+
+      body.appendChild(container);
+    }
+    // XXX Do not crash the application if it fails
+    // Where to write the error?
+    /*global console*/
+    console.error(e.stack);
+    console.error(e);
+  }
+
+  /////////////////////////////////////////////////////////////////
+  // Service Monitor promise
+  /////////////////////////////////////////////////////////////////
+  function ResolvedMonitorError(message) {
+    this.name = "resolved";
+    if ((message !== undefined) && (typeof message !== "string")) {
+      throw new TypeError('You must pass a string.');
+    }
+    this.message = message || "Default Message";
+  }
+  ResolvedMonitorError.prototype = new Error();
+  ResolvedMonitorError.prototype.constructor = ResolvedMonitorError;
+
+  Monitor = function () {
+    var monitor = this,
+      promise_list = [],
+      promise,
+      reject,
+      notify,
+      resolved;
+
+    if (!(this instanceof Monitor)) {
+      return new Monitor();
+    }
+
+    function canceller() {
+      var len = promise_list.length,
+        i;
+      for (i = 0; i < len; i += 1) {
+        promise_list[i].cancel();
+      }
+      // Clean it to speed up other canceller run
+      promise_list = [];
+    }
+
+    promise = new RSVP.Promise(function (done, fail, progress) {
+      reject = function (rejectedReason) {
+        if (resolved) {
+          return;
+        }
+        monitor.isRejected = true;
+        monitor.rejectedReason = rejectedReason;
+        resolved = true;
+        canceller();
+        return fail(rejectedReason);
+      };
+      notify = progress;
+    }, canceller);
+
+    monitor.cancel = function () {
+      if (resolved) {
+        return;
+      }
+      resolved = true;
+      promise.cancel();
+      promise.fail(function (rejectedReason) {
+        monitor.isRejected = true;
+        monitor.rejectedReason = rejectedReason;
+      });
+    };
+    monitor.then = function () {
+      return promise.then.apply(promise, arguments);
+    };
+    monitor.fail = function () {
+      return promise.fail.apply(promise, arguments);
+    };
+
+    monitor.monitor = function (promise_to_monitor) {
+      if (resolved) {
+        throw new ResolvedMonitorError();
+      }
+      var queue = new RSVP.Queue()
+        .push(function () {
+          return promise_to_monitor;
+        })
+        .push(function (fulfillmentValue) {
+          // Promise to monitor is fullfilled, remove it from the list
+          var len = promise_list.length,
+            sub_promise_to_monitor,
+            new_promise_list = [],
+            i;
+          for (i = 0; i < len; i += 1) {
+            sub_promise_to_monitor = promise_list[i];
+            if (!(sub_promise_to_monitor.isFulfilled ||
+                sub_promise_to_monitor.isRejected)) {
+              new_promise_list.push(sub_promise_to_monitor);
+            }
+          }
+          promise_list = new_promise_list;
+        }, function (rejectedReason) {
+          if (rejectedReason instanceof RSVP.CancellationError) {
+            if (!(promise_to_monitor.isFulfilled &&
+                  promise_to_monitor.isRejected)) {
+              // The queue could be cancelled before the first push is run
+              promise_to_monitor.cancel();
+            }
+          }
+          reject(rejectedReason);
+          throw rejectedReason;
+        }, function (notificationValue) {
+          notify(notificationValue);
+          return notificationValue;
+        });
+
+      promise_list.push(queue);
+
+      return this;
+    };
+  };
+
+  Monitor.prototype = Object.create(RSVP.Promise.prototype);
+  Monitor.prototype.constructor = Monitor;
+
+  /////////////////////////////////////////////////////////////////
+  // RenderJSGadget
+  /////////////////////////////////////////////////////////////////
+  function RenderJSGadget() {
+    if (!(this instanceof RenderJSGadget)) {
+      return new RenderJSGadget();
+    }
+  }
+  RenderJSGadget.prototype.__title = "";
+  RenderJSGadget.prototype.__interface_list = [];
+  RenderJSGadget.prototype.__path = "";
+  RenderJSGadget.prototype.__html = "";
+  RenderJSGadget.prototype.__required_css_list = [];
+  RenderJSGadget.prototype.__required_js_list = [];
+
+  function createMonitor(g) {
+    if (g.__monitor !== undefined) {
+      g.__monitor.cancel();
+    }
+    g.__monitor = new Monitor();
+    g.__monitor.fail(function (error) {
+      if (!(error instanceof RSVP.CancellationError)) {
+        return g.aq_reportServiceError(error);
+      }
+    }).fail(function (error) {
+      // Crash the application if the acquisition generates an error.
+      return letsCrash(error);
+    });
+  }
+
+  function clearGadgetInternalParameters(g) {
+    g.__sub_gadget_dict = {};
+    createMonitor(g);
+  }
+
+  function loadSubGadgetDOMDeclaration(g) {
+    var element_list = g.__element.querySelectorAll('[data-gadget-url]'),
+      element,
+      promise_list = [],
+      scope,
+      url,
+      sandbox,
+      i;
+
+    for (i = 0; i < element_list.length; i += 1) {
+      element = element_list[i];
+      scope = element.getAttribute("data-gadget-scope");
+      url = element.getAttribute("data-gadget-url");
+      sandbox = element.getAttribute("data-gadget-sandbox");
+      if (url !== null) {
+        promise_list.push(g.declareGadget(url, {
+          element: element,
+          scope: scope || undefined,
+          sandbox: sandbox || undefined
+        }));
+      }
+    }
+
+    return RSVP.all(promise_list);
+  }
+
+  RenderJSGadget.__ready_list = [clearGadgetInternalParameters,
+                                 loadSubGadgetDOMDeclaration];
+  RenderJSGadget.ready = function (callback) {
+    this.__ready_list.push(callback);
+    return this;
+  };
+
+  RenderJSGadget.__service_list = [];
+  RenderJSGadget.declareService = function (callback) {
+    this.__service_list.push(callback);
+    return this;
+  };
+
+  function startService(gadget) {
+    gadget.__monitor.monitor(new RSVP.Queue()
+      .push(function () {
+        var i,
+          service_list = gadget.constructor.__service_list;
+        for (i = 0; i < service_list.length; i += 1) {
+          gadget.__monitor.monitor(service_list[i].apply(gadget));
+        }
+      })
+      );
+  }
+
+  /////////////////////////////////////////////////////////////////
+  // RenderJSGadget.declareMethod
+  /////////////////////////////////////////////////////////////////
+  RenderJSGadget.declareMethod = function (name, callback) {
+    this.prototype[name] = function () {
+      var context = this,
+        argument_list = arguments;
+
+      return new RSVP.Queue()
+        .push(function () {
+          return callback.apply(context, argument_list);
+        });
+    };
+    // Allow chain
+    return this;
+  };
+
+  RenderJSGadget
+    .declareMethod('getInterfaceList', function () {
+      // Returns the list of gadget prototype
+      return this.__interface_list;
+    })
+    .declareMethod('getRequiredCSSList', function () {
+      // Returns a list of CSS required by the gadget
+      return this.__required_css_list;
+    })
+    .declareMethod('getRequiredJSList', function () {
+      // Returns a list of JS required by the gadget
+      return this.__required_js_list;
+    })
+    .declareMethod('getPath', function () {
+      // Returns the path of the code of a gadget
+      return this.__path;
+    })
+    .declareMethod('getTitle', function () {
+      // Returns the title of a gadget
+      return this.__title;
+    })
+    .declareMethod('getElement', function () {
+      // Returns the DOM Element of a gadget
+      if (this.__element === undefined) {
+        throw new Error("No element defined");
+      }
+      return this.__element;
+    });
+
+  /////////////////////////////////////////////////////////////////
+  // RenderJSGadget.declareAcquiredMethod
+  /////////////////////////////////////////////////////////////////
+  function acquire(child_gadget, method_name, argument_list) {
+    var gadget = this,
+      key,
+      gadget_scope;
+
+    for (key in gadget.__sub_gadget_dict) {
+      if (gadget.__sub_gadget_dict.hasOwnProperty(key)) {
+        if (gadget.__sub_gadget_dict[key] === child_gadget) {
+          gadget_scope = key;
+        }
+      }
+    }
+    return new RSVP.Queue()
+      .push(function () {
+        // Do not specify default __acquired_method_dict on prototype
+        // to prevent modifying this default value (with
+        // allowPublicAcquiredMethod for example)
+        var aq_dict = gadget.__acquired_method_dict || {};
+        if (aq_dict.hasOwnProperty(method_name)) {
+          return aq_dict[method_name].apply(gadget,
+                                            [argument_list, gadget_scope]);
+        }
+        throw new renderJS.AcquisitionError("aq_dynamic is not defined");
+      })
+      .push(undefined, function (error) {
+        if (error instanceof renderJS.AcquisitionError) {
+          return gadget.__aq_parent(method_name, argument_list);
+        }
+        throw error;
+      });
+  }
+
+  RenderJSGadget.declareAcquiredMethod =
+    function (name, method_name_to_acquire) {
+      this.prototype[name] = function () {
+        var argument_list = Array.prototype.slice.call(arguments, 0),
+          gadget = this;
+        return new RSVP.Queue()
+          .push(function () {
+            return gadget.__aq_parent(method_name_to_acquire, argument_list);
+          });
+      };
+
+      // Allow chain
+      return this;
+    };
+  RenderJSGadget.declareAcquiredMethod("aq_reportServiceError",
+                                       "reportServiceError");
+
+  /////////////////////////////////////////////////////////////////
+  // RenderJSGadget.allowPublicAcquisition
+  /////////////////////////////////////////////////////////////////
+  RenderJSGadget.allowPublicAcquisition =
+    function (method_name, callback) {
+      this.prototype.__acquired_method_dict[method_name] = callback;
+
+      // Allow chain
+      return this;
+    };
+
+  // Set aq_parent on gadget_instance which call acquire on parent_gadget
+  function setAqParent(gadget_instance, parent_gadget) {
+    gadget_instance.__aq_parent = function (method_name, argument_list) {
+      return acquire.apply(parent_gadget, [gadget_instance, method_name,
+                                           argument_list]);
+    };
+  }
+
+  /////////////////////////////////////////////////////////////////
+  // RenderJSEmbeddedGadget
+  /////////////////////////////////////////////////////////////////
+  // Class inheritance
+  function RenderJSEmbeddedGadget() {
+    if (!(this instanceof RenderJSEmbeddedGadget)) {
+      return new RenderJSEmbeddedGadget();
+    }
+    RenderJSGadget.call(this);
+  }
+  RenderJSEmbeddedGadget.__ready_list = RenderJSGadget.__ready_list.slice();
+  RenderJSEmbeddedGadget.__service_list =
+    RenderJSGadget.__service_list.slice();
+  RenderJSEmbeddedGadget.ready =
+    RenderJSGadget.ready;
+  RenderJSEmbeddedGadget.declareService =
+    RenderJSGadget.declareService;
+  RenderJSEmbeddedGadget.prototype = new RenderJSGadget();
+  RenderJSEmbeddedGadget.prototype.constructor = RenderJSEmbeddedGadget;
+
+  /////////////////////////////////////////////////////////////////
+  // privateDeclarePublicGadget
+  /////////////////////////////////////////////////////////////////
+  function privateDeclarePublicGadget(url, options, parent_gadget) {
+    var gadget_instance;
+    if (options.element === undefined) {
+      options.element = document.createElement("div");
+    }
+
+    function loadDependency(method, url) {
+      return function () {
+        return method(url);
+      };
+    }
+
+    return new RSVP.Queue()
+      .push(function () {
+        return renderJS.declareGadgetKlass(url);
+      })
+      // Get the gadget class and instanciate it
+      .push(function (Klass) {
+        var i,
+          template_node_list = Klass.__template_element.body.childNodes;
+        gadget_loading_klass = Klass;
+        gadget_instance = new Klass();
+        gadget_instance.__element = options.element;
+        for (i = 0; i < template_node_list.length; i += 1) {
+          gadget_instance.__element.appendChild(
+            template_node_list[i].cloneNode(true)
+          );
+        }
+        setAqParent(gadget_instance, parent_gadget);
+        // Load dependencies if needed
+        return RSVP.all([
+          gadget_instance.getRequiredJSList(),
+          gadget_instance.getRequiredCSSList()
+        ]);
+      })
+      // Load all JS/CSS
+      .push(function (all_list) {
+        var q = new RSVP.Queue(),
+          i;
+        // Load JS
+        for (i = 0; i < all_list[0].length; i += 1) {
+          q.push(loadDependency(renderJS.declareJS, all_list[0][i]));
+        }
+        // Load CSS
+        for (i = 0; i < all_list[1].length; i += 1) {
+          q.push(loadDependency(renderJS.declareCSS, all_list[1][i]));
+        }
+        return q;
+      })
+      .push(function () {
+        return gadget_instance;
+      });
+  }
+
+  /////////////////////////////////////////////////////////////////
+  // RenderJSIframeGadget
+  /////////////////////////////////////////////////////////////////
+  function RenderJSIframeGadget() {
+    if (!(this instanceof RenderJSIframeGadget)) {
+      return new RenderJSIframeGadget();
+    }
+    RenderJSGadget.call(this);
+  }
+  RenderJSIframeGadget.__ready_list = RenderJSGadget.__ready_list.slice();
+  RenderJSIframeGadget.ready =
+    RenderJSGadget.ready;
+  RenderJSIframeGadget.__service_list = RenderJSGadget.__service_list.slice();
+  RenderJSIframeGadget.declareService =
+    RenderJSGadget.declareService;
+  RenderJSIframeGadget.prototype = new RenderJSGadget();
+  RenderJSIframeGadget.prototype.constructor = RenderJSIframeGadget;
+
+  /////////////////////////////////////////////////////////////////
+  // privateDeclareIframeGadget
+  /////////////////////////////////////////////////////////////////
+  function privateDeclareIframeGadget(url, options, parent_gadget) {
+    var gadget_instance,
+      iframe,
+      iframe_loading_deferred = RSVP.defer();
+    if (options.element === undefined) {
+      throw new Error("DOM element is required to create Iframe Gadget " +
+                      url);
+    }
+
+    // Check if the element is attached to the DOM
+    if (!document.contains(options.element)) {
+      throw new Error("The parent element is not attached to the DOM for " +
+                      url);
+    }
+
+    gadget_instance = new RenderJSIframeGadget();
+    setAqParent(gadget_instance, parent_gadget);
+    iframe = document.createElement("iframe");
+//    gadget_instance.element.setAttribute("seamless", "seamless");
+    iframe.setAttribute("src", url);
+    gadget_instance.__path = url;
+    gadget_instance.__element = options.element;
+    // Attach it to the DOM
+    options.element.appendChild(iframe);
+
+    // XXX Manage unbind when deleting the gadget
+
+    // Create the communication channel with the iframe
+    gadget_instance.__chan = Channel.build({
+      window: iframe.contentWindow,
+      origin: "*",
+      scope: "renderJS"
+    });
+
+    // Create new method from the declareMethod call inside the iframe
+    gadget_instance.__chan.bind("declareMethod",
+                                function (trans, method_name) {
+        gadget_instance[method_name] = function () {
+          var argument_list = arguments,
+            wait_promise = new RSVP.Promise(function (resolve, reject) {
+              gadget_instance.__chan.call({
+                method: "methodCall",
+                params: [
+                  method_name,
+                  Array.prototype.slice.call(argument_list, 0)],
+                success: function (s) {
+                  resolve(s);
+                },
+                error: function (e) {
+                  reject(e);
+                }
+              });
+            });
+          return new RSVP.Queue()
+            .push(function () {
+              return wait_promise;
+            });
+        };
+        return "OK";
+      });
+
+    // Wait for the iframe to be loaded before continuing
+    gadget_instance.__chan.bind("ready", function (trans) {
+      iframe_loading_deferred.resolve(gadget_instance);
+      return "OK";
+    });
+    gadget_instance.__chan.bind("failed", function (trans, params) {
+      iframe_loading_deferred.reject(params);
+      return "OK";
+    });
+    gadget_instance.__chan.bind("acquire", function (trans, params) {
+      gadget_instance.__aq_parent.apply(gadget_instance, params)
+        .then(function (g) {
+          trans.complete(g);
+        }).fail(function (e) {
+          trans.error(e.toString());
+        });
+      trans.delayReturn(true);
+    });
+
+    return RSVP.any([
+      iframe_loading_deferred.promise,
+      // Timeout to prevent non renderJS embeddable gadget
+      // XXX Maybe using iframe.onload/onerror would be safer?
+      new RSVP.Queue()
+        .push(function () {
+          return RSVP.timeout(5000);
+        })
+        .push(undefined, function () {
+          throw new Error('Timeout while loading: ' + url);
+        })
+    ]);
+  }
+
+  /////////////////////////////////////////////////////////////////
+  // privateDeclareDataUrlGadget
+  /////////////////////////////////////////////////////////////////
+  function privateDeclareDataUrlGadget(url, options, parent_gadget) {
+
+    return new RSVP.Queue()
+      .push(function () {
+        return ajax(url);
+      })
+      .push(function (xhr) {
+        // Insert a "base" element, in order to resolve all relative links
+        // which could get broken with a data url
+        var doc = (new DOMParser()).parseFromString(xhr.responseText,
+                                                    'text/html'),
+          base = doc.createElement('base'),
+          blob;
+        base.href = url;
+        doc.head.insertBefore(base, doc.head.firstChild);
+        blob = new Blob([doc.documentElement.outerHTML],
+                        {type: "text/html;charset=UTF-8"});
+        return readBlobAsDataURL(blob);
+      })
+      .push(function (data_url) {
+        return privateDeclareIframeGadget(data_url, options, parent_gadget);
+      });
+  }
+
+  /////////////////////////////////////////////////////////////////
+  // RenderJSGadget.declareGadget
+  /////////////////////////////////////////////////////////////////
+  RenderJSGadget
+    .declareMethod('declareGadget', function (url, options) {
+      var queue,
+        parent_gadget = this,
+        local_loading_klass_promise,
+        previous_loading_klass_promise = loading_klass_promise;
+
+      if (options === undefined) {
+        options = {};
+      }
+      if (options.sandbox === undefined) {
+        options.sandbox = "public";
+      }
+
+      // transform url to absolute url if it is relative
+      url = renderJS.getAbsoluteURL(url, this.__path);
+      // Change the global variable to update the loading queue
+      loading_klass_promise = new RSVP.Queue()
+        // Wait for previous gadget loading to finish first
+        .push(function () {
+          return previous_loading_klass_promise;
+        })
+        .push(undefined, function () {
+          // Forget previous declareGadget error
+          return;
+        })
+        .push(function () {
+          var method;
+          if (options.sandbox === "public") {
+            method = privateDeclarePublicGadget;
+          } else if (options.sandbox === "iframe") {
+            method = privateDeclareIframeGadget;
+          } else if (options.sandbox === "dataurl") {
+            method = privateDeclareDataUrlGadget;
+          } else {
+            throw new Error("Unsupported sandbox options '" +
+                            options.sandbox + "'");
+          }
+          return method(url, options, parent_gadget);
+        })
+        // Set the HTML context
+        .push(function (gadget_instance) {
+          // Drop the current loading klass info used by selector
+          gadget_loading_klass = undefined;
+          return gadget_instance;
+        })
+        .push(undefined, function (e) {
+          // Drop the current loading klass info used by selector
+          // even in case of error
+          gadget_loading_klass = undefined;
+          throw e;
+        });
+      local_loading_klass_promise = loading_klass_promise;
+
+      queue = new RSVP.Queue()
+        .push(function () {
+          return local_loading_klass_promise;
+        })
+        // Set the HTML context
+        .push(function (gadget_instance) {
+          var i,
+            scope;
+          // Trigger calling of all ready callback
+          function ready_wrapper() {
+            return gadget_instance;
+          }
+          for (i = 0; i < gadget_instance.constructor.__ready_list.length;
+               i += 1) {
+            // Put a timeout?
+            queue.push(gadget_instance.constructor.__ready_list[i]);
+            // Always return the gadget instance after ready function
+            queue.push(ready_wrapper);
+          }
+
+          // Store local reference to the gadget instance
+          scope = options.scope;
+          if (scope === undefined) {
+            scope = 'RJS_' + scope_increment;
+            scope_increment += 1;
+            while (parent_gadget.__sub_gadget_dict.hasOwnProperty(scope)) {
+              scope = 'RJS_' + scope_increment;
+              scope_increment += 1;
+            }
+          }
+          parent_gadget.__sub_gadget_dict[scope] = gadget_instance;
+          gadget_instance.__element.setAttribute("data-gadget-scope",
+                                                 scope);
+
+          // Put some attribute to ease page layout comprehension
+          gadget_instance.__element.setAttribute("data-gadget-url", url);
+          gadget_instance.__element.setAttribute("data-gadget-sandbox",
+                                                 options.sandbox);
+          gadget_instance.__element._gadget = gadget_instance;
+
+          if (document.contains(gadget_instance.__element)) {
+            // Put a timeout
+            queue.push(startService);
+          }
+          // Always return the gadget instance after ready function
+          queue.push(ready_wrapper);
+
+          return gadget_instance;
+        });
+      return queue;
+    })
+    .declareMethod('getDeclaredGadget', function (gadget_scope) {
+      if (!this.__sub_gadget_dict.hasOwnProperty(gadget_scope)) {
+        throw new Error("Gadget scope '" + gadget_scope + "' is not known.");
+      }
+      return this.__sub_gadget_dict[gadget_scope];
+    })
+    .declareMethod('dropGadget', function (gadget_scope) {
+      if (!this.__sub_gadget_dict.hasOwnProperty(gadget_scope)) {
+        throw new Error("Gadget scope '" + gadget_scope + "' is not known.");
+      }
+      // http://perfectionkills.com/understanding-delete/
+      delete this.__sub_gadget_dict[gadget_scope];
+    });
+
+  /////////////////////////////////////////////////////////////////
+  // renderJS selector
+  /////////////////////////////////////////////////////////////////
+  renderJS = function (selector) {
+    var result;
+    if (selector === window) {
+      // window is the 'this' value when loading a javascript file
+      // In this case, use the current loading gadget constructor
+      result = gadget_loading_klass;
+    }
+    if (result === undefined) {
+      throw new Error("Unknown selector '" + selector + "'");
+    }
+    return result;
+  };
+
+  /////////////////////////////////////////////////////////////////
+  // renderJS.AcquisitionError
+  /////////////////////////////////////////////////////////////////
+  renderJS.AcquisitionError = function (message) {
+    this.name = "AcquisitionError";
+    if ((message !== undefined) && (typeof message !== "string")) {
+      throw new TypeError('You must pass a string.');
+    }
+    this.message = message || "Acquisition failed";
+  };
+  renderJS.AcquisitionError.prototype = new Error();
+  renderJS.AcquisitionError.prototype.constructor =
+    renderJS.AcquisitionError;
+
+  /////////////////////////////////////////////////////////////////
+  // renderJS.getAbsoluteURL
+  /////////////////////////////////////////////////////////////////
+  renderJS.getAbsoluteURL = function (url, base_url) {
+    var doc, base, link,
+      html = "<!doctype><html><head></head></html>";
+
+    if (url && base_url && !isAbsoluteOrDataURL.test(url)) {
+      doc = (new DOMParser()).parseFromString(html, 'text/html');
+      base = doc.createElement('base');
+      link = doc.createElement('link');
+      doc.head.appendChild(base);
+      doc.head.appendChild(link);
+      base.href = base_url;
+      link.href = url;
+      return link.href;
+    }
+    return url;
+  };
+
+  /////////////////////////////////////////////////////////////////
+  // renderJS.declareJS
+  /////////////////////////////////////////////////////////////////
+  renderJS.declareJS = function (url) {
+    // Prevent infinite recursion if loading render.js
+    // more than once
+    var result;
+    if (javascript_registration_dict.hasOwnProperty(url)) {
+      result = RSVP.resolve();
+    } else {
+      result = new RSVP.Promise(function (resolve, reject) {
+        var newScript;
+        newScript = document.createElement('script');
+        newScript.type = 'text/javascript';
+        newScript.src = url;
+        newScript.onload = function () {
+          javascript_registration_dict[url] = null;
+          resolve();
+        };
+        newScript.onerror = function (e) {
+          reject(e);
+        };
+        document.head.appendChild(newScript);
+      });
+    }
+    return result;
+  };
+
+  /////////////////////////////////////////////////////////////////
+  // renderJS.declareCSS
+  /////////////////////////////////////////////////////////////////
+  renderJS.declareCSS = function (url) {
+    // https://github.com/furf/jquery-getCSS/blob/master/jquery.getCSS.js
+    // No way to cleanly check if a css has been loaded
+    // So, always resolve the promise...
+    // http://requirejs.org/docs/faq-advanced.html#css
+    var result;
+    if (stylesheet_registration_dict.hasOwnProperty(url)) {
+      result = RSVP.resolve();
+    } else {
+      result = new RSVP.Promise(function (resolve, reject) {
+        var link;
+        link = document.createElement('link');
+        link.rel = 'stylesheet';
+        link.type = 'text/css';
+        link.href = url;
+        link.onload = function () {
+          stylesheet_registration_dict[url] = null;
+          resolve();
+        };
+        link.onerror = function (e) {
+          reject(e);
+        };
+        document.head.appendChild(link);
+      });
+    }
+    return result;
+  };
+
+  /////////////////////////////////////////////////////////////////
+  // renderJS.declareGadgetKlass
+  /////////////////////////////////////////////////////////////////
+  renderJS.declareGadgetKlass = function (url) {
+    var result;
+
+    function parse(xhr) {
+      var tmp_constructor,
+        key,
+        parsed_html;
+      if (!gadget_model_dict.hasOwnProperty(url)) {
+        // Class inheritance
+        tmp_constructor = function () {
+          RenderJSGadget.call(this);
+        };
+        tmp_constructor.__ready_list = RenderJSGadget.__ready_list.slice();
+        tmp_constructor.__service_list = RenderJSGadget.__service_list.slice();
+        tmp_constructor.declareMethod =
+          RenderJSGadget.declareMethod;
+        tmp_constructor.declareAcquiredMethod =
+          RenderJSGadget.declareAcquiredMethod;
+        tmp_constructor.allowPublicAcquisition =
+          RenderJSGadget.allowPublicAcquisition;
+        tmp_constructor.ready =
+          RenderJSGadget.ready;
+        tmp_constructor.declareService =
+          RenderJSGadget.declareService;
+        tmp_constructor.prototype = new RenderJSGadget();
+        tmp_constructor.prototype.constructor = tmp_constructor;
+        tmp_constructor.prototype.__path = url;
+        tmp_constructor.prototype.__acquired_method_dict = {};
+        // https://developer.mozilla.org/en-US/docs/HTML_in_XMLHttpRequest
+        // https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
+        // https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM
+        tmp_constructor.__template_element =
+          (new DOMParser()).parseFromString(xhr.responseText, "text/html");
+        parsed_html = renderJS.parseGadgetHTMLDocument(
+          tmp_constructor.__template_element,
+          url
+        );
+        for (key in parsed_html) {
+          if (parsed_html.hasOwnProperty(key)) {
+            tmp_constructor.prototype['__' + key] = parsed_html[key];
+          }
+        }
+
+        gadget_model_dict[url] = tmp_constructor;
+      }
+
+      return gadget_model_dict[url];
+    }
+
+    if (gadget_model_dict.hasOwnProperty(url)) {
+      // Return klass object if it already exists
+      result = RSVP.resolve(gadget_model_dict[url]);
+    } else {
+      // Fetch the HTML page and parse it
+      result = new RSVP.Queue()
+        .push(function () {
+          return ajax(url);
+        })
+        .push(function (xhr) {
+          return parse(xhr);
+        });
+    }
+    return result;
+  };
+
+  /////////////////////////////////////////////////////////////////
+  // renderJS.clearGadgetKlassList
+  /////////////////////////////////////////////////////////////////
+  // For test purpose only
+  renderJS.clearGadgetKlassList = function () {
+    gadget_model_dict = {};
+    javascript_registration_dict = {};
+    stylesheet_registration_dict = {};
+  };
+
+  /////////////////////////////////////////////////////////////////
+  // renderJS.parseGadgetHTMLDocument
+  /////////////////////////////////////////////////////////////////
+  renderJS.parseGadgetHTMLDocument = function (document_element, url) {
+    var settings = {
+        title: "",
+        interface_list: [],
+        required_css_list: [],
+        required_js_list: []
+      },
+      i,
+      element;
+
+    if (!url || !isAbsoluteOrDataURL.test(url)) {
+      throw new Error("The url should be absolute: " + url);
+    }
+
+    if (document_element.nodeType === 9) {
+      settings.title = document_element.title;
+
+      if (document_element.head !== null) {
+        for (i = 0; i < document_element.head.children.length; i += 1) {
+          element = document_element.head.children[i];
+          if (element.href !== null) {
+            // XXX Manage relative URL during extraction of URLs
+            // element.href returns absolute URL in firefox but "" in chrome;
+            if (element.rel === "stylesheet") {
+              settings.required_css_list.push(
+                renderJS.getAbsoluteURL(element.getAttribute("href"), url)
+              );
+            } else if (element.nodeName === "SCRIPT" &&
+                       (element.type === "text/javascript" ||
+                        !element.type)) {
+              settings.required_js_list.push(
+                renderJS.getAbsoluteURL(element.getAttribute("src"), url)
+              );
+            } else if (element.rel ===
+                       "http://www.renderjs.org/rel/interface") {
+              settings.interface_list.push(
+                renderJS.getAbsoluteURL(element.getAttribute("href"), url)
+              );
+            }
+          }
+        }
+      }
+    } else {
+      throw new Error("The first parameter should be an HTMLDocument");
+    }
+    return settings;
+  };
+
+  /////////////////////////////////////////////////////////////////
+  // global
+  /////////////////////////////////////////////////////////////////
+  window.rJS = window.renderJS = renderJS;
+  window.__RenderJSGadget = RenderJSGadget;
+  window.__RenderJSEmbeddedGadget = RenderJSEmbeddedGadget;
+  window.__RenderJSIframeGadget = RenderJSIframeGadget;
+
+  ///////////////////////////////////////////////////
+  // Bootstrap process. Register the self gadget.
+  ///////////////////////////////////////////////////
+
+  function bootstrap() {
+    var url = removeHash(window.location.href),
+      tmp_constructor,
+      root_gadget,
+      loading_gadget_promise = new RSVP.Queue(),
+      declare_method_count = 0,
+      embedded_channel,
+      notifyReady,
+      notifyDeclareMethod,
+      gadget_ready = false,
+      iframe_top_gadget,
+      last_acquisition_gadget,
+      declare_method_list_waiting = [],
+      gadget_failed = false,
+      gadget_error,
+      connection_ready = false;
+
+    // Create the gadget class for the current url
+    if (gadget_model_dict.hasOwnProperty(url)) {
+      throw new Error("bootstrap should not be called twice");
+    }
+    loading_klass_promise = new RSVP.Promise(function (resolve, reject) {
+
+      last_acquisition_gadget = new RenderJSGadget();
+      last_acquisition_gadget.__acquired_method_dict = {
+        reportServiceError: function (param_list) {
+          letsCrash(param_list[0]);
+        }
+      };
+      // Stop acquisition on the last acquisition gadget
+      // Do not put this on the klass, as their could be multiple instances
+      last_acquisition_gadget.__aq_parent = function (method_name) {
+        throw new renderJS.AcquisitionError(
+          "No gadget provides " + method_name
+        );
+      };
+
+      //we need to determine tmp_constructor's value before exit bootstrap
+      //because of function : renderJS
+      //but since the channel checking is async,
+      //we can't use code structure like:
+      // if channel communication is ok
+      //    tmp_constructor = RenderJSGadget
+      // else
+      //    tmp_constructor = RenderJSEmbeddedGadget
+      if (window.self === window.top) {
+        // XXX Copy/Paste from declareGadgetKlass
+        tmp_constructor = function () {
+          RenderJSGadget.call(this);
+        };
+        tmp_constructor.declareMethod = RenderJSGadget.declareMethod;
+        tmp_constructor.declareAcquiredMethod =
+          RenderJSGadget.declareAcquiredMethod;
+        tmp_constructor.allowPublicAcquisition =
+          RenderJSGadget.allowPublicAcquisition;
+        tmp_constructor.__ready_list = RenderJSGadget.__ready_list.slice();
+        tmp_constructor.ready = RenderJSGadget.ready;
+        tmp_constructor.__service_list = RenderJSGadget.__service_list.slice();
+        tmp_constructor.declareService =
+          RenderJSGadget.declareService;
+        tmp_constructor.prototype = new RenderJSGadget();
+        tmp_constructor.prototype.constructor = tmp_constructor;
+        tmp_constructor.prototype.__path = url;
+        gadget_model_dict[url] = tmp_constructor;
+
+        // Create the root gadget instance and put it in the loading stack
+        root_gadget = new gadget_model_dict[url]();
+
+        setAqParent(root_gadget, last_acquisition_gadget);
+
+      } else {
+        // Create the root gadget instance and put it in the loading stack
+        tmp_constructor = RenderJSEmbeddedGadget;
+        tmp_constructor.__ready_list = RenderJSGadget.__ready_list.slice();
+        tmp_constructor.__service_list = RenderJSGadget.__service_list.slice();
+        tmp_constructor.prototype.__path = url;
+        root_gadget = new RenderJSEmbeddedGadget();
+        setAqParent(root_gadget, last_acquisition_gadget);
+
+        // Create the communication channel
+        embedded_channel = Channel.build({
+          window: window.parent,
+          origin: "*",
+          scope: "renderJS",
+          onReady: function () {
+            var k;
+            iframe_top_gadget = false;
+            //Default: Define __aq_parent to inform parent window
+            root_gadget.__aq_parent =
+              tmp_constructor.prototype.__aq_parent = function (method_name,
+                argument_list, time_out) {
+                return new RSVP.Promise(function (resolve, reject) {
+                  embedded_channel.call({
+                    method: "acquire",
+                    params: [
+                      method_name,
+                      argument_list
+                    ],
+                    success: function (s) {
+                      resolve(s);
+                    },
+                    error: function (e) {
+                      reject(e);
+                    },
+                    timeout: time_out
+                  });
+                });
+              };
+
+            // Channel is ready, so now declare Function
+            notifyDeclareMethod = function (name) {
+              declare_method_count += 1;
+              embedded_channel.call({
+                method: "declareMethod",
+                params: name,
+                success: function () {
+                  declare_method_count -= 1;
+                  notifyReady();
+                },
+                error: function () {
+                  declare_method_count -= 1;
+                }
+              });
+            };
+            for (k = 0; k < declare_method_list_waiting.length; k += 1) {
+              notifyDeclareMethod(declare_method_list_waiting[k]);
+            }
+            declare_method_list_waiting = [];
+            // If Gadget Failed Notify Parent
+            if (gadget_failed) {
+              embedded_channel.notify({
+                method: "failed",
+                params: gadget_error
+              });
+              return;
+            }
+            connection_ready = true;
+            notifyReady();
+            //the channel is ok
+            //so bind calls to renderJS method on the instance
+            embedded_channel.bind("methodCall", function (trans, v) {
+              root_gadget[v[0]].apply(root_gadget, v[1])
+                .then(function (g) {
+                  trans.complete(g);
+                }).fail(function (e) {
+                  trans.error(e.toString());
+                });
+              trans.delayReturn(true);
+            });
+          }
+        });
+
+        // Notify parent about gadget instanciation
+        notifyReady = function () {
+          if ((declare_method_count === 0) && (gadget_ready === true)) {
+            embedded_channel.notify({method: "ready"});
+          }
+        };
+
+        // Inform parent gadget about declareMethod calls here.
+        notifyDeclareMethod = function (name) {
+          declare_method_list_waiting.push(name);
+        };
+
+        notifyDeclareMethod("getInterfaceList");
+        notifyDeclareMethod("getRequiredCSSList");
+        notifyDeclareMethod("getRequiredJSList");
+        notifyDeclareMethod("getPath");
+        notifyDeclareMethod("getTitle");
+
+        // Surcharge declareMethod to inform parent window
+        tmp_constructor.declareMethod = function (name, callback) {
+          var result = RenderJSGadget.declareMethod.apply(
+              this,
+              [name, callback]
+            );
+          notifyDeclareMethod(name);
+          return result;
+        };
+
+        tmp_constructor.declareService =
+          RenderJSGadget.declareService;
+        tmp_constructor.declareAcquiredMethod =
+          RenderJSGadget.declareAcquiredMethod;
+        tmp_constructor.allowPublicAcquisition =
+          RenderJSGadget.allowPublicAcquisition;
+
+        iframe_top_gadget = true;
+      }
+
+      tmp_constructor.prototype.__acquired_method_dict = {};
+      gadget_loading_klass = tmp_constructor;
+
+      function init() {
+        // XXX HTML properties can only be set when the DOM is fully loaded
+        var settings = renderJS.parseGadgetHTMLDocument(document, url),
+          j,
+          key;
+        for (key in settings) {
+          if (settings.hasOwnProperty(key)) {
+            tmp_constructor.prototype['__' + key] = settings[key];
+          }
+        }
+        tmp_constructor.__template_element = document.createElement("div");
+        root_gadget.__element = document.body;
+        for (j = 0; j < root_gadget.__element.childNodes.length; j += 1) {
+          tmp_constructor.__template_element.appendChild(
+            root_gadget.__element.childNodes[j].cloneNode(true)
+          );
+        }
+        RSVP.all([root_gadget.getRequiredJSList(),
+                  root_gadget.getRequiredCSSList()])
+          .then(function (all_list) {
+            var i,
+              js_list = all_list[0],
+              css_list = all_list[1];
+            for (i = 0; i < js_list.length; i += 1) {
+              javascript_registration_dict[js_list[i]] = null;
+            }
+            for (i = 0; i < css_list.length; i += 1) {
+              stylesheet_registration_dict[css_list[i]] = null;
+            }
+            gadget_loading_klass = undefined;
+          }).then(function () {
+
+            // select the target node
+            var target = document.querySelector('body'),
+              // create an observer instance
+              observer = new MutationObserver(function (mutations) {
+                var i, k, len, len2, node, added_list;
+                mutations.forEach(function (mutation) {
+                  if (mutation.type === 'childList') {
+
+                    len = mutation.removedNodes.length;
+                    for (i = 0; i < len; i += 1) {
+                      node = mutation.removedNodes[i];
+                      if (node.nodeType === Node.ELEMENT_NODE) {
+                        if (node.hasAttribute("data-gadget-url") &&
+                            (node._gadget !== undefined)) {
+                          createMonitor(node._gadget);
+                        }
+                        added_list =
+                          node.querySelectorAll("[data-gadget-url]");
+                        len2 = added_list.length;
+                        for (k = 0; k < len2; k += 1) {
+                          node = added_list[k];
+                          if (node._gadget !== undefined) {
+                            createMonitor(node._gadget);
+                          }
+                        }
+                      }
+                    }
+
+                    len = mutation.addedNodes.length;
+                    for (i = 0; i < len; i += 1) {
+                      node = mutation.addedNodes[i];
+                      if (node.nodeType === Node.ELEMENT_NODE) {
+                        if (node.hasAttribute("data-gadget-url") &&
+                            (node._gadget !== undefined)) {
+                          if (document.contains(node)) {
+                            startService(node._gadget);
+                          }
+                        }
+                        added_list =
+                          node.querySelectorAll("[data-gadget-url]");
+                        len2 = added_list.length;
+                        for (k = 0; k < len2; k += 1) {
+                          node = added_list[k];
+                          if (document.contains(node)) {
+                            if (node._gadget !== undefined) {
+                              startService(node._gadget);
+                            }
+                          }
+                        }
+                      }
+                    }
+
+                  }
+                });
+              }),
+              // configuration of the observer:
+              config = {
+                childList: true,
+                subtree: true,
+                attributes: false,
+                characterData: false
+              };
+
+            // pass in the target node, as well as the observer options
+            observer.observe(target, config);
+
+            return root_gadget;
+          }).then(resolve, function (e) {
+            reject(e);
+            console.error(e);
+            throw e;
+          });
+      }
+      document.addEventListener('DOMContentLoaded', init, false);
+    });
+
+    loading_gadget_promise
+      .push(function () {
+        return loading_klass_promise;
+      })
+      .push(function (root_gadget) {
+        var i;
+
+        function ready_wrapper() {
+          return root_gadget;
+        }
+
+        tmp_constructor.ready(function (g) {
+          return startService(g);
+        });
+
+        loading_gadget_promise.push(ready_wrapper);
+        for (i = 0; i < tmp_constructor.__ready_list.length; i += 1) {
+          // Put a timeout?
+          loading_gadget_promise
+            .push(tmp_constructor.__ready_list[i])
+            // Always return the gadget instance after ready function
+            .push(ready_wrapper);
+        }
+      });
+    if (window.self === window.top) {
+      loading_gadget_promise
+        .fail(function (e) {
+          letsCrash(e);
+          throw e;
+        });
+    } else {
+      // Inform parent window that gadget is correctly loaded
+      loading_gadget_promise
+        .then(function () {
+          gadget_ready = true;
+          if (connection_ready) {
+            notifyReady();
+          }
+        })
+        .fail(function (e) {
+          //top gadget in iframe
+          if (iframe_top_gadget) {
+            gadget_failed = true;
+            gadget_error = e.toString();
+            letsCrash(e);
+          } else {
+            embedded_channel.notify({method: "failed", params: e.toString()});
+          }
+          throw e;
+        });
+    }
+
+  }
+  bootstrap();
+
+}(document, window, RSVP, DOMParser, Channel, MutationObserver, Node,
+  FileReader, Blob, navigator, Event));
diff --git a/dist/renderjs-0.10.0.min.js b/dist/renderjs-0.10.0.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..c2881f4d178fbdf9f1b86014c22649a09c6c76f9
--- /dev/null
+++ b/dist/renderjs-0.10.0.min.js
@@ -0,0 +1 @@
+var Channel=function(){"use strict";function a(a,b,c,d){function f(b){for(var c=0;c<b.length;c++)if(b[c].win===a)return!0;return!1}var g=!1;if("*"===b){for(var h in e)if(e.hasOwnProperty(h)&&"*"!==h&&"object"==typeof e[h][c]&&(g=f(e[h][c])))break}else e["*"]&&e["*"][c]&&(g=f(e["*"][c])),!g&&e[b]&&e[b][c]&&(g=f(e[b][c]));if(g)throw"A channel is already bound to the same window which overlaps with origin '"+b+"' and has scope '"+c+"'";"object"!=typeof e[b]&&(e[b]={}),"object"!=typeof e[b][c]&&(e[b][c]=[]),e[b][c].push({win:a,handler:d})}function b(a,b,c){for(var d=e[b][c],f=0;f<d.length;f++)d[f].win===a&&d.splice(f,1);0===e[b][c].length&&delete e[b][c]}function c(a){return Array.isArray?Array.isArray(a):-1!=a.constructor.toString().indexOf("Array")}var d=Math.floor(1000001*Math.random()),e={},f={},g=function(a){try{var b=JSON.parse(a.data);if("object"!=typeof b||null===b)throw"malformed"}catch(a){return}var c,d,g,h=a.source,i=a.origin;if("string"==typeof b.method){var j=b.method.split("::");2==j.length?(c=j[0],g=j[1]):g=b.method}if("undefined"!=typeof b.id&&(d=b.id),"string"==typeof g){var k=!1;if(e[i]&&e[i][c])for(var l=0;l<e[i][c].length;l++)if(e[i][c][l].win===h){e[i][c][l].handler(i,g,b),k=!0;break}if(!k&&e["*"]&&e["*"][c])for(var l=0;l<e["*"][c].length;l++)if(e["*"][c][l].win===h){e["*"][c][l].handler(i,g,b);break}}else"undefined"!=typeof d&&f[d]&&f[d](i,g,b)};return window.addEventListener?window.addEventListener("message",g,!1):window.attachEvent&&window.attachEvent("onmessage",g),{build:function(e){var g=function(a){if(e.debugOutput&&window.console&&window.console.log){try{"string"!=typeof a&&(a=JSON.stringify(a))}catch(b){}console.log("["+j+"] "+a)}};if(!window.postMessage)throw"jschannel cannot run this browser, no postMessage";if(!window.JSON||!window.JSON.stringify||!window.JSON.parse)throw"jschannel cannot run this browser, no JSON parsing/serialization";if("object"!=typeof e)throw"Channel build invoked without a proper object argument";if(!e.window||!e.window.postMessage)throw"Channel.build() called without a valid window argument";if(window===e.window)throw"target window is same as present window -- not allowed";var h=!1;if("string"==typeof e.origin){var i;"*"===e.origin?h=!0:null!==(i=e.origin.match(/^https?:\/\/(?:[-a-zA-Z0-9_\.])+(?::\d+)?/))&&(e.origin=i[0].toLowerCase(),h=!0)}if(!h)throw"Channel.build() called with an invalid origin";if("undefined"!=typeof e.scope){if("string"!=typeof e.scope)throw"scope, when specified, must be a string";if(e.scope.split("::").length>1)throw"scope may not contain double colons: '::'"}var j=function(){for(var a="",b="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",c=0;5>c;c++)a+=b.charAt(Math.floor(Math.random()*b.length));return a}(),k={},l={},m={},n=!1,o=[],p=function(a,b,c){var d=!1,e=!1;return{origin:b,invoke:function(b,d){if(!m[a])throw"attempting to invoke a callback of a nonexistent transaction: "+a;for(var e=!1,f=0;f<c.length;f++)if(b===c[f]){e=!0;break}if(!e)throw"request supports no such callback '"+b+"'";t({id:a,callback:b,params:d})},error:function(b,c){if(e=!0,!m[a])throw"error called for nonexistent message: "+a;delete m[a],t({id:a,error:b,message:c})},complete:function(b){if(e=!0,!m[a])throw"complete called for nonexistent message: "+a;delete m[a],t({id:a,result:b})},delayReturn:function(a){return"boolean"==typeof a&&(d=a===!0),d},completed:function(){return e}}},q=function(a,b,c){return window.setTimeout(function(){if(l[a]){var d="timeout ("+b+"ms) exceeded on method '"+c+"'";l[a].error("timeout_error",d),delete l[a],delete f[a]}},b)},r=function(a,b,d){if("function"==typeof e.gotMessageObserver)try{e.gotMessageObserver(a,d)}catch(h){g("gotMessageObserver() raised an exception: "+h.toString())}if(d.id&&b){if(k[b]){var i=p(d.id,a,d.callbacks?d.callbacks:[]);m[d.id]={};try{if(d.callbacks&&c(d.callbacks)&&d.callbacks.length>0)for(var j=0;j<d.callbacks.length;j++){for(var n=d.callbacks[j],o=d.params,q=n.split("/"),r=0;r<q.length-1;r++){var s=q[r];"object"!=typeof o[s]&&(o[s]={}),o=o[s]}o[q[q.length-1]]=function(){var a=n;return function(b){return i.invoke(a,b)}}()}var t=k[b](i,d.params);i.delayReturn()||i.completed()||i.complete(t)}catch(h){var u="runtime_error",v=null;if("string"==typeof h?v=h:"object"==typeof h&&(h&&c(h)&&2==h.length?(u=h[0],v=h[1]):"string"==typeof h.error&&(u=h.error,h.message?"string"==typeof h.message?v=h.message:h=h.message:v="")),null===v)try{v=JSON.stringify(h),"undefined"==typeof v&&(v=h.toString())}catch(w){v=h.toString()}i.error(u,v)}}}else d.id&&d.callback?l[d.id]&&l[d.id].callbacks&&l[d.id].callbacks[d.callback]?l[d.id].callbacks[d.callback](d.params):g("ignoring invalid callback, id:"+d.id+" ("+d.callback+")"):d.id?l[d.id]?(d.error?l[d.id].error(d.error,d.message):void 0!==d.result?l[d.id].success(d.result):l[d.id].success(),delete l[d.id],delete f[d.id]):g("ignoring invalid response: "+d.id):b&&k[b]&&k[b]({origin:a},d.params)};a(e.window,e.origin,"string"==typeof e.scope?e.scope:"",r);var s=function(a){return"string"==typeof e.scope&&e.scope.length&&(a=[e.scope,a].join("::")),a},t=function(a,b){if(!a)throw"postMessage called with null message";var c=n?"post  ":"queue ";if(g(c+" message: "+JSON.stringify(a)),b||n){if("function"==typeof e.postMessageObserver)try{e.postMessageObserver(e.origin,a)}catch(d){g("postMessageObserver() raised an exception: "+d.toString())}e.window.postMessage(JSON.stringify(a),e.origin)}else o.push(a)},u=function(a,b){if(g("ready msg received"),n)throw"received ready message while in ready state.  help!";for(j+="ping"===b?"-R":"-L",v.unbind("__ready"),n=!0,g("ready msg accepted."),"ping"===b&&v.notify({method:"__ready",params:"pong"});o.length;)t(o.pop());"function"==typeof e.onReady&&e.onReady(v)},v={unbind:function(a){if(k[a]){if(!delete k[a])throw"can't delete method: "+a;return!0}return!1},bind:function(a,b){if(!a||"string"!=typeof a)throw"'method' argument to bind must be string";if(!b||"function"!=typeof b)throw"callback missing from bind params";if(k[a])throw"method '"+a+"' is already bound!";return k[a]=b,this},call:function(a){if(!a)throw"missing arguments to call function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to call must be string";if(!a.success||"function"!=typeof a.success)throw"'success' callback missing from call";var b={},c=[],e=function(a,d){if("object"==typeof d)for(var f in d)if(d.hasOwnProperty(f)){var g=a+(a.length?"/":"")+f;"function"==typeof d[f]?(b[g]=d[f],c.push(g),delete d[f]):"object"==typeof d[f]&&e(g,d[f])}};e("",a.params);var g={id:d,method:s(a.method),params:a.params};c.length&&(g.callbacks=c),a.timeout&&q(d,a.timeout,s(a.method)),l[d]={callbacks:b,error:a.error,success:a.success},f[d]=r,d++,t(g)},notify:function(a){if(!a)throw"missing arguments to notify function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to notify must be string";t({method:s(a.method),params:a.params})},destroy:function(){b(e.window,e.origin,"string"==typeof e.scope?e.scope:""),window.removeEventListener?window.removeEventListener("message",r,!1):window.detachEvent&&window.detachEvent("onmessage",r),n=!1,k={},m={},l={},e.origin=null,o=[],g("channel destroyed"),j=""}};return v.bind("__ready",u),setTimeout(function(){t({method:s("__ready"),params:"ping"},!0)},0),v}}}();!function(a){"use strict";var b=a.prototype,c=b.parseFromString;try{if((new a).parseFromString("","text/html"))return}catch(d){}b.parseFromString=function(a,b){var d,e,f,g;return/^\s*text\/html\s*(?:;|$)/i.test(b)?(e=document.implementation.createHTMLDocument(""),f=e.documentElement,f.innerHTML=a,g=f.firstElementChild,1===f.childElementCount&&"html"===g.localName.toLowerCase()&&e.replaceChild(g,f),d=e):d=c.apply(this,arguments),d}}(DOMParser),"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)}),function(a,b,c,d,e,f,g,h,i,j,k){"use strict";function l(a){var b=new h;return new c.Promise(function(c,d){b.addEventListener("load",function(a){c(a.target.result)}),b.addEventListener("error",d),b.readAsDataURL(a)},function(){b.abort()})}function m(a){function b(b,c){function d(){try{0===e.readyState?c(e):4===e.readyState&&(e.status<200||e.status>=300||!/^text\/html[;]?/.test(e.getResponseHeader("Content-Type")||"")?c(e):b(e))}catch(a){c(a)}}e=new XMLHttpRequest,e.open("GET",a),e.onreadystatechange=d,e.setRequestHeader("Accept","text/html"),e.withCredentials=!0,e.send()}function d(){void 0!==e&&e.readyState!==e.DONE&&e.abort()}var e;return new c.Promise(b,d)}function n(a){var b=a.indexOf("#");return b>0&&(a=a.substring(0,b)),a}function o(c){var d,e,f,g,h,i;if(M)return console.info("-- Error dropped, as page is unloaded"),void console.info(c);for(N.push(c),N.push(new Error("stopping renderJS")),e=a.getElementsByTagName("body")[0];e.firstChild;)e.removeChild(e.firstChild);for(f=a.createElement("section"),g=a.createElement("h1"),g.textContent="Unhandled Error",f.appendChild(g),g=a.createElement("p"),g.textContent="Please report this error to the support team",f.appendChild(g),g=a.createElement("p"),g.textContent="Location: ",h=a.createElement("a"),h.href=h.textContent=b.location.toString(),g.appendChild(h),f.appendChild(g),g=a.createElement("p"),g.textContent="User-agent: "+j.userAgent,f.appendChild(g),e.appendChild(f),d=0;d<N.length;d+=1){if(i=N[d],i instanceof k&&(i={string:i.toString(),message:i.message,type:i.type,target:i.target},void 0!==i.target&&N.splice(d+1,0,i.target)),i instanceof XMLHttpRequest&&(i={message:i.toString(),readyState:i.readyState,status:i.status,statusText:i.statusText,response:i.response,responseUrl:i.responseUrl,response_headers:i.getAllResponseHeaders()}),i.constructor===Array||i.constructor===String||i.constructor===Object)try{i=JSON.stringify(i)}catch(l){}f=a.createElement("section"),g=a.createElement("h2"),g.textContent=i.message||i,f.appendChild(g),void 0!==i.fileName&&(g=a.createElement("p"),g.textContent="File: "+i.fileName+": "+i.lineNumber,f.appendChild(g)),void 0!==i.stack&&(g=a.createElement("pre"),g.textContent="Stack: "+i.stack,f.appendChild(g)),e.appendChild(f)}console.error(c.stack),console.error(c)}function p(a){if(this.name="resolved",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Default Message"}function q(){return this instanceof q?void 0:new q}function r(a){void 0!==a.__monitor&&a.__monitor.cancel(),a.__monitor=new G,a.__monitor.fail(function(b){return b instanceof c.CancellationError?void 0:a.aq_reportServiceError(b)}).fail(function(a){return o(a)})}function s(a){a.__sub_gadget_dict={},r(a)}function t(a){var b,d,e,f,g,h=a.__element.querySelectorAll("[data-gadget-url]"),i=[];for(g=0;g<h.length;g+=1)b=h[g],d=b.getAttribute("data-gadget-scope"),e=b.getAttribute("data-gadget-url"),f=b.getAttribute("data-gadget-sandbox"),null!==e&&i.push(a.declareGadget(e,{element:b,scope:d||void 0,sandbox:f||void 0}));return c.all(i)}function u(a){a.__monitor.monitor((new c.Queue).push(function(){var b,c=a.constructor.__service_list;for(b=0;b<c.length;b+=1)a.__monitor.monitor(c[b].apply(a))}))}function v(a,b,d){var e,f,g=this;for(e in g.__sub_gadget_dict)g.__sub_gadget_dict.hasOwnProperty(e)&&g.__sub_gadget_dict[e]===a&&(f=e);return(new c.Queue).push(function(){var a=g.__acquired_method_dict||{};if(a.hasOwnProperty(b))return a[b].apply(g,[d,f]);throw new F.AcquisitionError("aq_dynamic is not defined")}).push(void 0,function(a){if(a instanceof F.AcquisitionError)return g.__aq_parent(b,d);throw a})}function w(a,b){a.__aq_parent=function(c,d){return v.apply(b,[a,c,d])}}function x(){return this instanceof x?void q.call(this):new x}function y(b,d,e){function f(a,b){return function(){return a(b)}}var g;return void 0===d.element&&(d.element=a.createElement("div")),(new c.Queue).push(function(){return F.declareGadgetKlass(b)}).push(function(a){var b,f=a.__template_element.body.childNodes;for(D=a,g=new a,g.__element=d.element,b=0;b<f.length;b+=1)g.__element.appendChild(f[b].cloneNode(!0));return w(g,e),c.all([g.getRequiredJSList(),g.getRequiredCSSList()])}).push(function(a){var b,d=new c.Queue;for(b=0;b<a[0].length;b+=1)d.push(f(F.declareJS,a[0][b]));for(b=0;b<a[1].length;b+=1)d.push(f(F.declareCSS,a[1][b]));return d}).push(function(){return g})}function z(){return this instanceof z?void q.call(this):new z}function A(b,d,f){var g,h,i=c.defer();if(void 0===d.element)throw new Error("DOM element is required to create Iframe Gadget "+b);if(!a.contains(d.element))throw new Error("The parent element is not attached to the DOM for "+b);return g=new z,w(g,f),h=a.createElement("iframe"),h.setAttribute("src",b),g.__path=b,g.__element=d.element,d.element.appendChild(h),g.__chan=e.build({window:h.contentWindow,origin:"*",scope:"renderJS"}),g.__chan.bind("declareMethod",function(a,b){return g[b]=function(){var a=arguments,d=new c.Promise(function(c,d){g.__chan.call({method:"methodCall",params:[b,Array.prototype.slice.call(a,0)],success:function(a){c(a)},error:function(a){d(a)}})});return(new c.Queue).push(function(){return d})},"OK"}),g.__chan.bind("ready",function(a){return i.resolve(g),"OK"}),g.__chan.bind("failed",function(a,b){return i.reject(b),"OK"}),g.__chan.bind("acquire",function(a,b){g.__aq_parent.apply(g,b).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}),c.any([i.promise,(new c.Queue).push(function(){return c.timeout(5e3)}).push(void 0,function(){throw new Error("Timeout while loading: "+b)})])}function B(a,b,e){return(new c.Queue).push(function(){return m(a)}).push(function(b){var c,e=(new d).parseFromString(b.responseText,"text/html"),f=e.createElement("base");return f.href=a,e.head.insertBefore(f,e.head.firstChild),c=new i([e.documentElement.outerHTML],{type:"text/html;charset=UTF-8"}),l(c)}).push(function(a){return A(a,b,e)})}function C(){var d,h,i,j,k,l,m,p,s=n(b.location.href),t=new c.Queue,v=0,y=!1,z=[],A=!1,B=!1;if(H.hasOwnProperty(s))throw new Error("bootstrap should not be called twice");E=new c.Promise(function(n,t){function C(){var b,e,i=F.parseGadgetHTMLDocument(a,s);for(e in i)i.hasOwnProperty(e)&&(d.prototype["__"+e]=i[e]);for(d.__template_element=a.createElement("div"),h.__element=a.body,b=0;b<h.__element.childNodes.length;b+=1)d.__template_element.appendChild(h.__element.childNodes[b].cloneNode(!0));c.all([h.getRequiredJSList(),h.getRequiredCSSList()]).then(function(a){var b,c=a[0],d=a[1];for(b=0;b<c.length;b+=1)I[c[b]]=null;for(b=0;b<d.length;b+=1)J[d[b]]=null;D=void 0}).then(function(){var b=a.querySelector("body"),c=new f(function(b){var c,d,e,f,h,i;b.forEach(function(b){if("childList"===b.type){for(e=b.removedNodes.length,c=0;e>c;c+=1)if(h=b.removedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&r(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],void 0!==h._gadget&&r(h._gadget);for(e=b.addedNodes.length,c=0;e>c;c+=1)if(h=b.addedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&a.contains(h)&&u(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],a.contains(h)&&void 0!==h._gadget&&u(h._gadget)}})}),d={childList:!0,subtree:!0,attributes:!1,characterData:!1};return c.observe(b,d),h}).then(n,function(a){throw t(a),console.error(a),a})}m=new q,m.__acquired_method_dict={reportServiceError:function(a){o(a[0])}},m.__aq_parent=function(a){throw new F.AcquisitionError("No gadget provides "+a)},b.self===b.top?(d=function(){q.call(this)},d.declareMethod=q.declareMethod,d.declareAcquiredMethod=q.declareAcquiredMethod,d.allowPublicAcquisition=q.allowPublicAcquisition,d.__ready_list=q.__ready_list.slice(),d.ready=q.ready,d.__service_list=q.__service_list.slice(),d.declareService=q.declareService,d.prototype=new q,d.prototype.constructor=d,d.prototype.__path=s,H[s]=d,h=new H[s],w(h,m)):(d=x,d.__ready_list=q.__ready_list.slice(),d.__service_list=q.__service_list.slice(),d.prototype.__path=s,h=new x,w(h,m),i=e.build({window:b.parent,origin:"*",scope:"renderJS",onReady:function(){var a;for(l=!1,h.__aq_parent=d.prototype.__aq_parent=function(a,b,d){return new c.Promise(function(c,e){i.call({method:"acquire",params:[a,b],success:function(a){c(a)},error:function(a){e(a)},timeout:d})})},k=function(a){v+=1,i.call({method:"declareMethod",params:a,success:function(){v-=1,j()},error:function(){v-=1}})},a=0;a<z.length;a+=1)k(z[a]);return z=[],A?void i.notify({method:"failed",params:p}):(B=!0,j(),void i.bind("methodCall",function(a,b){h[b[0]].apply(h,b[1]).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}))}}),j=function(){0===v&&y===!0&&i.notify({method:"ready"})},k=function(a){z.push(a)},k("getInterfaceList"),k("getRequiredCSSList"),k("getRequiredJSList"),k("getPath"),k("getTitle"),d.declareMethod=function(a,b){var c=q.declareMethod.apply(this,[a,b]);return k(a),c},d.declareService=q.declareService,d.declareAcquiredMethod=q.declareAcquiredMethod,d.allowPublicAcquisition=q.allowPublicAcquisition,l=!0),d.prototype.__acquired_method_dict={},D=d,a.addEventListener("DOMContentLoaded",C,!1)}),t.push(function(){return E}).push(function(a){function b(){return a}var c;for(d.ready(function(a){return u(a)}),t.push(b),c=0;c<d.__ready_list.length;c+=1)t.push(d.__ready_list[c]).push(b)}),b.self===b.top?t.fail(function(a){throw o(a),a}):t.then(function(){y=!0,B&&j()}).fail(function(a){throw l?(A=!0,p=a.toString(),o(a)):i.notify({method:"failed",params:a.toString()}),a})}var D,E,F,G,H={},I={},J={},K=0,L=new RegExp("^(?:[a-z]+:)?//|data:","i"),M=!1,N=[];b.addEventListener("error",function(a){N.push(a)}),b.addEventListener("beforeunload",function(){M=!0}),p.prototype=new Error,p.prototype.constructor=p,G=function(){function a(){var a,b=h.length;for(a=0;b>a;a+=1)h[a].cancel();h=[]}var b,d,e,f,g=this,h=[];return this instanceof G?(b=new c.Promise(function(b,c,h){d=function(b){return f?void 0:(g.isRejected=!0,g.rejectedReason=b,f=!0,a(),c(b))},e=h},a),g.cancel=function(){f||(f=!0,b.cancel(),b.fail(function(a){g.isRejected=!0,g.rejectedReason=a}))},g.then=function(){return b.then.apply(b,arguments)},g.fail=function(){return b.fail.apply(b,arguments)},void(g.monitor=function(a){if(f)throw new p;var b=(new c.Queue).push(function(){return a}).push(function(a){var b,c,d=h.length,e=[];for(c=0;d>c;c+=1)b=h[c],b.isFulfilled||b.isRejected||e.push(b);h=e},function(b){throw b instanceof c.CancellationError&&(a.isFulfilled&&a.isRejected||a.cancel()),d(b),b},function(a){return e(a),a});return h.push(b),this})):new G},G.prototype=Object.create(c.Promise.prototype),G.prototype.constructor=G,q.prototype.__title="",q.prototype.__interface_list=[],q.prototype.__path="",q.prototype.__html="",q.prototype.__required_css_list=[],q.prototype.__required_js_list=[],q.__ready_list=[s,t],q.ready=function(a){return this.__ready_list.push(a),this},q.__service_list=[],q.declareService=function(a){return this.__service_list.push(a),this},q.declareMethod=function(a,b){return this.prototype[a]=function(){var a=this,d=arguments;return(new c.Queue).push(function(){return b.apply(a,d)})},this},q.declareMethod("getInterfaceList",function(){return this.__interface_list}).declareMethod("getRequiredCSSList",function(){return this.__required_css_list}).declareMethod("getRequiredJSList",function(){return this.__required_js_list}).declareMethod("getPath",function(){return this.__path}).declareMethod("getTitle",function(){return this.__title}).declareMethod("getElement",function(){if(void 0===this.__element)throw new Error("No element defined");return this.__element}),q.declareAcquiredMethod=function(a,b){return this.prototype[a]=function(){var a=Array.prototype.slice.call(arguments,0),d=this;return(new c.Queue).push(function(){return d.__aq_parent(b,a)})},this},q.declareAcquiredMethod("aq_reportServiceError","reportServiceError"),q.allowPublicAcquisition=function(a,b){return this.prototype.__acquired_method_dict[a]=b,this},x.__ready_list=q.__ready_list.slice(),x.__service_list=q.__service_list.slice(),x.ready=q.ready,x.declareService=q.declareService,x.prototype=new q,x.prototype.constructor=x,z.__ready_list=q.__ready_list.slice(),z.ready=q.ready,z.__service_list=q.__service_list.slice(),z.declareService=q.declareService,z.prototype=new q,z.prototype.constructor=z,q.declareMethod("declareGadget",function(b,d){var e,f,g=this,h=E;return void 0===d&&(d={}),void 0===d.sandbox&&(d.sandbox="public"),b=F.getAbsoluteURL(b,this.__path),E=(new c.Queue).push(function(){return h}).push(void 0,function(){}).push(function(){var a;if("public"===d.sandbox)a=y;else if("iframe"===d.sandbox)a=A;else{if("dataurl"!==d.sandbox)throw new Error("Unsupported sandbox options '"+d.sandbox+"'");a=B}return a(b,d,g)}).push(function(a){return D=void 0,a}).push(void 0,function(a){throw D=void 0,a}),f=E,e=(new c.Queue).push(function(){return f}).push(function(c){function f(){return c}var h,i;for(h=0;h<c.constructor.__ready_list.length;h+=1)e.push(c.constructor.__ready_list[h]),e.push(f);if(i=d.scope,void 0===i)for(i="RJS_"+K,K+=1;g.__sub_gadget_dict.hasOwnProperty(i);)i="RJS_"+K,K+=1;return g.__sub_gadget_dict[i]=c,c.__element.setAttribute("data-gadget-scope",i),c.__element.setAttribute("data-gadget-url",b),c.__element.setAttribute("data-gadget-sandbox",d.sandbox),c.__element._gadget=c,a.contains(c.__element)&&e.push(u),e.push(f),c})}).declareMethod("getDeclaredGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");return this.__sub_gadget_dict[a]}).declareMethod("dropGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");delete this.__sub_gadget_dict[a]}),F=function(a){var c;if(a===b&&(c=D),void 0===c)throw new Error("Unknown selector '"+a+"'");return c},F.AcquisitionError=function(a){if(this.name="AcquisitionError",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Acquisition failed"},F.AcquisitionError.prototype=new Error,F.AcquisitionError.prototype.constructor=F.AcquisitionError,F.getAbsoluteURL=function(a,b){var c,e,f,g="<!doctype><html><head></head></html>";return a&&b&&!L.test(a)?(c=(new d).parseFromString(g,"text/html"),e=c.createElement("base"),f=c.createElement("link"),c.head.appendChild(e),c.head.appendChild(f),e.href=b,f.href=a,f.href):a},F.declareJS=function(b){var d;return d=I.hasOwnProperty(b)?c.resolve():new c.Promise(function(c,d){var e;e=a.createElement("script"),e.type="text/javascript",e.src=b,e.onload=function(){I[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},F.declareCSS=function(b){var d;return d=J.hasOwnProperty(b)?c.resolve():new c.Promise(function(c,d){var e;e=a.createElement("link"),e.rel="stylesheet",e.type="text/css",e.href=b,e.onload=function(){J[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},F.declareGadgetKlass=function(a){function b(b){var c,e,f;if(!H.hasOwnProperty(a)){c=function(){q.call(this)},c.__ready_list=q.__ready_list.slice(),c.__service_list=q.__service_list.slice(),c.declareMethod=q.declareMethod,c.declareAcquiredMethod=q.declareAcquiredMethod,c.allowPublicAcquisition=q.allowPublicAcquisition,c.ready=q.ready,c.declareService=q.declareService,c.prototype=new q,c.prototype.constructor=c,c.prototype.__path=a,c.prototype.__acquired_method_dict={},c.__template_element=(new d).parseFromString(b.responseText,"text/html"),f=F.parseGadgetHTMLDocument(c.__template_element,a);for(e in f)f.hasOwnProperty(e)&&(c.prototype["__"+e]=f[e]);H[a]=c}return H[a]}var e;return e=H.hasOwnProperty(a)?c.resolve(H[a]):(new c.Queue).push(function(){return m(a)}).push(function(a){return b(a)})},F.clearGadgetKlassList=function(){H={},I={},J={}},F.parseGadgetHTMLDocument=function(a,b){var c,d,e={title:"",interface_list:[],required_css_list:[],required_js_list:[]};if(!b||!L.test(b))throw new Error("The url should be absolute: "+b);if(9!==a.nodeType)throw new Error("The first parameter should be an HTMLDocument");if(e.title=a.title,null!==a.head)for(c=0;c<a.head.children.length;c+=1)d=a.head.children[c],null!==d.href&&("stylesheet"===d.rel?e.required_css_list.push(F.getAbsoluteURL(d.getAttribute("href"),b)):"SCRIPT"!==d.nodeName||"text/javascript"!==d.type&&d.type?"http://www.renderjs.org/rel/interface"===d.rel&&e.interface_list.push(F.getAbsoluteURL(d.getAttribute("href"),b)):e.required_js_list.push(F.getAbsoluteURL(d.getAttribute("src"),b)));return e},b.rJS=b.renderJS=F,b.__RenderJSGadget=q,b.__RenderJSEmbeddedGadget=x,b.__RenderJSIframeGadget=z,C()}(document,window,RSVP,DOMParser,Channel,MutationObserver,Node,FileReader,Blob,navigator,Event);
\ No newline at end of file
diff --git a/dist/renderjs-latest.js b/dist/renderjs-latest.js
index 556331c40404b54b8e905310e86b1d725b219623..06dee4707220cd396e14f8469f22dd8634bbca30 100644
--- a/dist/renderjs-latest.js
+++ b/dist/renderjs-latest.js
@@ -673,7 +673,7 @@ if (typeof document.contains !== 'function') {
  * http://www.renderjs.org/documentation
  */
 (function (document, window, RSVP, DOMParser, Channel, MutationObserver,
-           Node, FileReader, Blob) {
+           Node, FileReader, Blob, navigator, Event) {
   "use strict";
 
   function readBlobAsDataURL(blob) {
@@ -737,7 +737,19 @@ if (typeof document.contains !== 'function') {
     renderJS,
     Monitor,
     scope_increment = 0,
-    isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i');
+    isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i'),
+    is_page_unloaded = false,
+    error_list = [];
+
+  window.addEventListener('error', function (error) {
+    error_list.push(error);
+  });
+
+  window.addEventListener('beforeunload', function () {
+    // XXX If another listener cancel the page unload,
+    // it will not restore renderJS crash report
+    is_page_unloaded = true;
+  });
 
   /////////////////////////////////////////////////////////////////
   // Helper functions
@@ -751,23 +763,107 @@ if (typeof document.contains !== 'function') {
   }
 
   function letsCrash(e) {
-    if (e.constructor === XMLHttpRequest) {
-      e = {
-        readyState: e.readyState,
-        status: e.status,
-        statusText: e.statusText,
-        response_headers: e.getAllResponseHeaders()
-      };
+    var i,
+      body,
+      container,
+      paragraph,
+      link,
+      error;
+    if (is_page_unloaded) {
+      /*global console*/
+      console.info('-- Error dropped, as page is unloaded');
+      console.info(e);
+      return;
+    }
+
+    error_list.push(e);
+    // Add error handling stack
+    error_list.push(new Error('stopping renderJS'));
+
+    body = document.getElementsByTagName('body')[0];
+    while (body.firstChild) {
+      body.removeChild(body.firstChild);
     }
-    if (e.constructor === Array ||
-        e.constructor === String ||
-        e.constructor === Object) {
-      try {
-        e = JSON.stringify(e);
-      } catch (ignore) {
+
+    container = document.createElement("section");
+    paragraph = document.createElement("h1");
+    paragraph.textContent = 'Unhandled Error';
+    container.appendChild(paragraph);
+
+    paragraph = document.createElement("p");
+    paragraph.textContent = 'Please report this error to the support team';
+    container.appendChild(paragraph);
+
+    paragraph = document.createElement("p");
+    paragraph.textContent = 'Location: ';
+    link = document.createElement("a");
+    link.href = link.textContent = window.location.toString();
+    paragraph.appendChild(link);
+    container.appendChild(paragraph);
+
+    paragraph = document.createElement("p");
+    paragraph.textContent = 'User-agent: ' + navigator.userAgent;
+    container.appendChild(paragraph);
+
+    body.appendChild(container);
+
+    for (i = 0; i < error_list.length; i += 1) {
+      error = error_list[i];
+
+      if (error instanceof Event) {
+        error = {
+          string: error.toString(),
+          message: error.message,
+          type: error.type,
+          target: error.target
+        };
+        if (error.target !== undefined) {
+          error_list.splice(i + 1, 0, error.target);
+        }
       }
+
+      if (error instanceof XMLHttpRequest) {
+        error = {
+          message: error.toString(),
+          readyState: error.readyState,
+          status: error.status,
+          statusText: error.statusText,
+          response: error.response,
+          responseUrl: error.responseUrl,
+          response_headers: error.getAllResponseHeaders()
+        };
+      }
+      if (error.constructor === Array ||
+          error.constructor === String ||
+          error.constructor === Object) {
+        try {
+          error = JSON.stringify(error);
+        } catch (ignore) {
+        }
+      }
+
+      container = document.createElement("section");
+
+      paragraph = document.createElement("h2");
+      paragraph.textContent = error.message || error;
+      container.appendChild(paragraph);
+
+      if (error.fileName !== undefined) {
+        paragraph = document.createElement("p");
+        paragraph.textContent = 'File: ' +
+          error.fileName +
+          ': ' + error.lineNumber;
+        container.appendChild(paragraph);
+      }
+
+      if (error.stack !== undefined) {
+        paragraph = document.createElement("pre");
+        paragraph.textContent = 'Stack: ' + error.stack;
+        container.appendChild(paragraph);
+      }
+
+      body.appendChild(container);
     }
-    document.getElementsByTagName('body')[0].textContent = e;
     // XXX Do not crash the application if it fails
     // Where to write the error?
     /*global console*/
@@ -1273,7 +1369,13 @@ if (typeof document.contains !== 'function') {
       iframe_loading_deferred.promise,
       // Timeout to prevent non renderJS embeddable gadget
       // XXX Maybe using iframe.onload/onerror would be safer?
-      RSVP.timeout(5000)
+      new RSVP.Queue()
+        .push(function () {
+          return RSVP.timeout(5000);
+        })
+        .push(undefined, function () {
+          throw new Error('Timeout while loading: ' + url);
+        })
     ]);
   }
 
@@ -2033,4 +2135,4 @@ if (typeof document.contains !== 'function') {
   bootstrap();
 
 }(document, window, RSVP, DOMParser, Channel, MutationObserver, Node,
-  FileReader, Blob));
+  FileReader, Blob, navigator, Event));
diff --git a/dist/renderjs-latest.min.js b/dist/renderjs-latest.min.js
index 073cf158ff00dc7b96bd9da44d6269383dcb2129..c2881f4d178fbdf9f1b86014c22649a09c6c76f9 100644
--- a/dist/renderjs-latest.min.js
+++ b/dist/renderjs-latest.min.js
@@ -1 +1 @@
-var Channel=function(){"use strict";function a(a,b,c,d){function f(b){for(var c=0;c<b.length;c++)if(b[c].win===a)return!0;return!1}var g=!1;if("*"===b){for(var h in e)if(e.hasOwnProperty(h)&&"*"!==h&&"object"==typeof e[h][c]&&(g=f(e[h][c])))break}else e["*"]&&e["*"][c]&&(g=f(e["*"][c])),!g&&e[b]&&e[b][c]&&(g=f(e[b][c]));if(g)throw"A channel is already bound to the same window which overlaps with origin '"+b+"' and has scope '"+c+"'";"object"!=typeof e[b]&&(e[b]={}),"object"!=typeof e[b][c]&&(e[b][c]=[]),e[b][c].push({win:a,handler:d})}function b(a,b,c){for(var d=e[b][c],f=0;f<d.length;f++)d[f].win===a&&d.splice(f,1);0===e[b][c].length&&delete e[b][c]}function c(a){return Array.isArray?Array.isArray(a):-1!=a.constructor.toString().indexOf("Array")}var d=Math.floor(1000001*Math.random()),e={},f={},g=function(a){try{var b=JSON.parse(a.data);if("object"!=typeof b||null===b)throw"malformed"}catch(a){return}var c,d,g,h=a.source,i=a.origin;if("string"==typeof b.method){var j=b.method.split("::");2==j.length?(c=j[0],g=j[1]):g=b.method}if("undefined"!=typeof b.id&&(d=b.id),"string"==typeof g){var k=!1;if(e[i]&&e[i][c])for(var l=0;l<e[i][c].length;l++)if(e[i][c][l].win===h){e[i][c][l].handler(i,g,b),k=!0;break}if(!k&&e["*"]&&e["*"][c])for(var l=0;l<e["*"][c].length;l++)if(e["*"][c][l].win===h){e["*"][c][l].handler(i,g,b);break}}else"undefined"!=typeof d&&f[d]&&f[d](i,g,b)};return window.addEventListener?window.addEventListener("message",g,!1):window.attachEvent&&window.attachEvent("onmessage",g),{build:function(e){var g=function(a){if(e.debugOutput&&window.console&&window.console.log){try{"string"!=typeof a&&(a=JSON.stringify(a))}catch(b){}console.log("["+j+"] "+a)}};if(!window.postMessage)throw"jschannel cannot run this browser, no postMessage";if(!window.JSON||!window.JSON.stringify||!window.JSON.parse)throw"jschannel cannot run this browser, no JSON parsing/serialization";if("object"!=typeof e)throw"Channel build invoked without a proper object argument";if(!e.window||!e.window.postMessage)throw"Channel.build() called without a valid window argument";if(window===e.window)throw"target window is same as present window -- not allowed";var h=!1;if("string"==typeof e.origin){var i;"*"===e.origin?h=!0:null!==(i=e.origin.match(/^https?:\/\/(?:[-a-zA-Z0-9_\.])+(?::\d+)?/))&&(e.origin=i[0].toLowerCase(),h=!0)}if(!h)throw"Channel.build() called with an invalid origin";if("undefined"!=typeof e.scope){if("string"!=typeof e.scope)throw"scope, when specified, must be a string";if(e.scope.split("::").length>1)throw"scope may not contain double colons: '::'"}var j=function(){for(var a="",b="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",c=0;5>c;c++)a+=b.charAt(Math.floor(Math.random()*b.length));return a}(),k={},l={},m={},n=!1,o=[],p=function(a,b,c){var d=!1,e=!1;return{origin:b,invoke:function(b,d){if(!m[a])throw"attempting to invoke a callback of a nonexistent transaction: "+a;for(var e=!1,f=0;f<c.length;f++)if(b===c[f]){e=!0;break}if(!e)throw"request supports no such callback '"+b+"'";t({id:a,callback:b,params:d})},error:function(b,c){if(e=!0,!m[a])throw"error called for nonexistent message: "+a;delete m[a],t({id:a,error:b,message:c})},complete:function(b){if(e=!0,!m[a])throw"complete called for nonexistent message: "+a;delete m[a],t({id:a,result:b})},delayReturn:function(a){return"boolean"==typeof a&&(d=a===!0),d},completed:function(){return e}}},q=function(a,b,c){return window.setTimeout(function(){if(l[a]){var d="timeout ("+b+"ms) exceeded on method '"+c+"'";l[a].error("timeout_error",d),delete l[a],delete f[a]}},b)},r=function(a,b,d){if("function"==typeof e.gotMessageObserver)try{e.gotMessageObserver(a,d)}catch(h){g("gotMessageObserver() raised an exception: "+h.toString())}if(d.id&&b){if(k[b]){var i=p(d.id,a,d.callbacks?d.callbacks:[]);m[d.id]={};try{if(d.callbacks&&c(d.callbacks)&&d.callbacks.length>0)for(var j=0;j<d.callbacks.length;j++){for(var n=d.callbacks[j],o=d.params,q=n.split("/"),r=0;r<q.length-1;r++){var s=q[r];"object"!=typeof o[s]&&(o[s]={}),o=o[s]}o[q[q.length-1]]=function(){var a=n;return function(b){return i.invoke(a,b)}}()}var t=k[b](i,d.params);i.delayReturn()||i.completed()||i.complete(t)}catch(h){var u="runtime_error",v=null;if("string"==typeof h?v=h:"object"==typeof h&&(h&&c(h)&&2==h.length?(u=h[0],v=h[1]):"string"==typeof h.error&&(u=h.error,h.message?"string"==typeof h.message?v=h.message:h=h.message:v="")),null===v)try{v=JSON.stringify(h),"undefined"==typeof v&&(v=h.toString())}catch(w){v=h.toString()}i.error(u,v)}}}else d.id&&d.callback?l[d.id]&&l[d.id].callbacks&&l[d.id].callbacks[d.callback]?l[d.id].callbacks[d.callback](d.params):g("ignoring invalid callback, id:"+d.id+" ("+d.callback+")"):d.id?l[d.id]?(d.error?l[d.id].error(d.error,d.message):void 0!==d.result?l[d.id].success(d.result):l[d.id].success(),delete l[d.id],delete f[d.id]):g("ignoring invalid response: "+d.id):b&&k[b]&&k[b]({origin:a},d.params)};a(e.window,e.origin,"string"==typeof e.scope?e.scope:"",r);var s=function(a){return"string"==typeof e.scope&&e.scope.length&&(a=[e.scope,a].join("::")),a},t=function(a,b){if(!a)throw"postMessage called with null message";var c=n?"post  ":"queue ";if(g(c+" message: "+JSON.stringify(a)),b||n){if("function"==typeof e.postMessageObserver)try{e.postMessageObserver(e.origin,a)}catch(d){g("postMessageObserver() raised an exception: "+d.toString())}e.window.postMessage(JSON.stringify(a),e.origin)}else o.push(a)},u=function(a,b){if(g("ready msg received"),n)throw"received ready message while in ready state.  help!";for(j+="ping"===b?"-R":"-L",v.unbind("__ready"),n=!0,g("ready msg accepted."),"ping"===b&&v.notify({method:"__ready",params:"pong"});o.length;)t(o.pop());"function"==typeof e.onReady&&e.onReady(v)},v={unbind:function(a){if(k[a]){if(!delete k[a])throw"can't delete method: "+a;return!0}return!1},bind:function(a,b){if(!a||"string"!=typeof a)throw"'method' argument to bind must be string";if(!b||"function"!=typeof b)throw"callback missing from bind params";if(k[a])throw"method '"+a+"' is already bound!";return k[a]=b,this},call:function(a){if(!a)throw"missing arguments to call function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to call must be string";if(!a.success||"function"!=typeof a.success)throw"'success' callback missing from call";var b={},c=[],e=function(a,d){if("object"==typeof d)for(var f in d)if(d.hasOwnProperty(f)){var g=a+(a.length?"/":"")+f;"function"==typeof d[f]?(b[g]=d[f],c.push(g),delete d[f]):"object"==typeof d[f]&&e(g,d[f])}};e("",a.params);var g={id:d,method:s(a.method),params:a.params};c.length&&(g.callbacks=c),a.timeout&&q(d,a.timeout,s(a.method)),l[d]={callbacks:b,error:a.error,success:a.success},f[d]=r,d++,t(g)},notify:function(a){if(!a)throw"missing arguments to notify function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to notify must be string";t({method:s(a.method),params:a.params})},destroy:function(){b(e.window,e.origin,"string"==typeof e.scope?e.scope:""),window.removeEventListener?window.removeEventListener("message",r,!1):window.detachEvent&&window.detachEvent("onmessage",r),n=!1,k={},m={},l={},e.origin=null,o=[],g("channel destroyed"),j=""}};return v.bind("__ready",u),setTimeout(function(){t({method:s("__ready"),params:"ping"},!0)},0),v}}}();!function(a){"use strict";var b=a.prototype,c=b.parseFromString;try{if((new a).parseFromString("","text/html"))return}catch(d){}b.parseFromString=function(a,b){var d,e,f,g;return/^\s*text\/html\s*(?:;|$)/i.test(b)?(e=document.implementation.createHTMLDocument(""),f=e.documentElement,f.innerHTML=a,g=f.firstElementChild,1===f.childElementCount&&"html"===g.localName.toLowerCase()&&e.replaceChild(g,f),d=e):d=c.apply(this,arguments),d}}(DOMParser),"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)}),function(a,b,c,d,e,f,g,h,i){"use strict";function j(a){var b=new h;return new c.Promise(function(c,d){b.addEventListener("load",function(a){c(a.target.result)}),b.addEventListener("error",d),b.readAsDataURL(a)},function(){b.abort()})}function k(a){function b(b,c){function d(){try{0===e.readyState?c(e):4===e.readyState&&(e.status<200||e.status>=300||!/^text\/html[;]?/.test(e.getResponseHeader("Content-Type")||"")?c(e):b(e))}catch(a){c(a)}}e=new XMLHttpRequest,e.open("GET",a),e.onreadystatechange=d,e.setRequestHeader("Accept","text/html"),e.withCredentials=!0,e.send()}function d(){void 0!==e&&e.readyState!==e.DONE&&e.abort()}var e;return new c.Promise(b,d)}function l(a){var b=a.indexOf("#");return b>0&&(a=a.substring(0,b)),a}function m(b){if(b.constructor===XMLHttpRequest&&(b={readyState:b.readyState,status:b.status,statusText:b.statusText,response_headers:b.getAllResponseHeaders()}),b.constructor===Array||b.constructor===String||b.constructor===Object)try{b=JSON.stringify(b)}catch(c){}a.getElementsByTagName("body")[0].textContent=b,console.error(b.stack),console.error(b)}function n(a){if(this.name="resolved",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Default Message"}function o(){return this instanceof o?void 0:new o}function p(a){void 0!==a.__monitor&&a.__monitor.cancel(),a.__monitor=new E,a.__monitor.fail(function(b){return b instanceof c.CancellationError?void 0:a.aq_reportServiceError(b)}).fail(function(a){return m(a)})}function q(a){a.__sub_gadget_dict={},p(a)}function r(a){var b,d,e,f,g,h=a.__element.querySelectorAll("[data-gadget-url]"),i=[];for(g=0;g<h.length;g+=1)b=h[g],d=b.getAttribute("data-gadget-scope"),e=b.getAttribute("data-gadget-url"),f=b.getAttribute("data-gadget-sandbox"),null!==e&&i.push(a.declareGadget(e,{element:b,scope:d||void 0,sandbox:f||void 0}));return c.all(i)}function s(a){a.__monitor.monitor((new c.Queue).push(function(){var b,c=a.constructor.__service_list;for(b=0;b<c.length;b+=1)a.__monitor.monitor(c[b].apply(a))}))}function t(a,b,d){var e,f,g=this;for(e in g.__sub_gadget_dict)g.__sub_gadget_dict.hasOwnProperty(e)&&g.__sub_gadget_dict[e]===a&&(f=e);return(new c.Queue).push(function(){var a=g.__acquired_method_dict||{};if(a.hasOwnProperty(b))return a[b].apply(g,[d,f]);throw new D.AcquisitionError("aq_dynamic is not defined")}).push(void 0,function(a){if(a instanceof D.AcquisitionError)return g.__aq_parent(b,d);throw a})}function u(a,b){a.__aq_parent=function(c,d){return t.apply(b,[a,c,d])}}function v(){return this instanceof v?void o.call(this):new v}function w(b,d,e){function f(a,b){return function(){return a(b)}}var g;return void 0===d.element&&(d.element=a.createElement("div")),(new c.Queue).push(function(){return D.declareGadgetKlass(b)}).push(function(a){var b,f=a.__template_element.body.childNodes;for(B=a,g=new a,g.__element=d.element,b=0;b<f.length;b+=1)g.__element.appendChild(f[b].cloneNode(!0));return u(g,e),c.all([g.getRequiredJSList(),g.getRequiredCSSList()])}).push(function(a){var b,d=new c.Queue;for(b=0;b<a[0].length;b+=1)d.push(f(D.declareJS,a[0][b]));for(b=0;b<a[1].length;b+=1)d.push(f(D.declareCSS,a[1][b]));return d}).push(function(){return g})}function x(){return this instanceof x?void o.call(this):new x}function y(b,d,f){var g,h,i=c.defer();if(void 0===d.element)throw new Error("DOM element is required to create Iframe Gadget "+b);if(!a.contains(d.element))throw new Error("The parent element is not attached to the DOM for "+b);return g=new x,u(g,f),h=a.createElement("iframe"),h.setAttribute("src",b),g.__path=b,g.__element=d.element,d.element.appendChild(h),g.__chan=e.build({window:h.contentWindow,origin:"*",scope:"renderJS"}),g.__chan.bind("declareMethod",function(a,b){return g[b]=function(){var a=arguments,d=new c.Promise(function(c,d){g.__chan.call({method:"methodCall",params:[b,Array.prototype.slice.call(a,0)],success:function(a){c(a)},error:function(a){d(a)}})});return(new c.Queue).push(function(){return d})},"OK"}),g.__chan.bind("ready",function(a){return i.resolve(g),"OK"}),g.__chan.bind("failed",function(a,b){return i.reject(b),"OK"}),g.__chan.bind("acquire",function(a,b){g.__aq_parent.apply(g,b).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}),c.any([i.promise,c.timeout(5e3)])}function z(a,b,e){return(new c.Queue).push(function(){return k(a)}).push(function(b){var c,e=(new d).parseFromString(b.responseText,"text/html"),f=e.createElement("base");return f.href=a,e.head.insertBefore(f,e.head.firstChild),c=new i([e.documentElement.outerHTML],{type:"text/html;charset=UTF-8"}),j(c)}).push(function(a){return y(a,b,e)})}function A(){var d,h,i,j,k,n,q,r,t=l(b.location.href),w=new c.Queue,x=0,y=!1,z=[],A=!1,E=!1;if(F.hasOwnProperty(t))throw new Error("bootstrap should not be called twice");C=new c.Promise(function(l,w){function C(){var b,e,i=D.parseGadgetHTMLDocument(a,t);for(e in i)i.hasOwnProperty(e)&&(d.prototype["__"+e]=i[e]);for(d.__template_element=a.createElement("div"),h.__element=a.body,b=0;b<h.__element.childNodes.length;b+=1)d.__template_element.appendChild(h.__element.childNodes[b].cloneNode(!0));c.all([h.getRequiredJSList(),h.getRequiredCSSList()]).then(function(a){var b,c=a[0],d=a[1];for(b=0;b<c.length;b+=1)G[c[b]]=null;for(b=0;b<d.length;b+=1)H[d[b]]=null;B=void 0}).then(function(){var b=a.querySelector("body"),c=new f(function(b){var c,d,e,f,h,i;b.forEach(function(b){if("childList"===b.type){for(e=b.removedNodes.length,c=0;e>c;c+=1)if(h=b.removedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&p(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],void 0!==h._gadget&&p(h._gadget);for(e=b.addedNodes.length,c=0;e>c;c+=1)if(h=b.addedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&a.contains(h)&&s(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],a.contains(h)&&void 0!==h._gadget&&s(h._gadget)}})}),d={childList:!0,subtree:!0,attributes:!1,characterData:!1};return c.observe(b,d),h}).then(l,function(a){throw w(a),console.error(a),a})}q=new o,q.__acquired_method_dict={reportServiceError:function(a){m(a[0])}},q.__aq_parent=function(a){throw new D.AcquisitionError("No gadget provides "+a)},b.self===b.top?(d=function(){o.call(this)},d.declareMethod=o.declareMethod,d.declareAcquiredMethod=o.declareAcquiredMethod,d.allowPublicAcquisition=o.allowPublicAcquisition,d.__ready_list=o.__ready_list.slice(),d.ready=o.ready,d.__service_list=o.__service_list.slice(),d.declareService=o.declareService,d.prototype=new o,d.prototype.constructor=d,d.prototype.__path=t,F[t]=d,h=new F[t],u(h,q)):(d=v,d.__ready_list=o.__ready_list.slice(),d.__service_list=o.__service_list.slice(),d.prototype.__path=t,h=new v,u(h,q),i=e.build({window:b.parent,origin:"*",scope:"renderJS",onReady:function(){var a;for(n=!1,h.__aq_parent=d.prototype.__aq_parent=function(a,b,d){return new c.Promise(function(c,e){i.call({method:"acquire",params:[a,b],success:function(a){c(a)},error:function(a){e(a)},timeout:d})})},k=function(a){x+=1,i.call({method:"declareMethod",params:a,success:function(){x-=1,j()},error:function(){x-=1}})},a=0;a<z.length;a+=1)k(z[a]);return z=[],A?void i.notify({method:"failed",params:r}):(E=!0,j(),void i.bind("methodCall",function(a,b){h[b[0]].apply(h,b[1]).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}))}}),j=function(){0===x&&y===!0&&i.notify({method:"ready"})},k=function(a){z.push(a)},k("getInterfaceList"),k("getRequiredCSSList"),k("getRequiredJSList"),k("getPath"),k("getTitle"),d.declareMethod=function(a,b){var c=o.declareMethod.apply(this,[a,b]);return k(a),c},d.declareService=o.declareService,d.declareAcquiredMethod=o.declareAcquiredMethod,d.allowPublicAcquisition=o.allowPublicAcquisition,n=!0),d.prototype.__acquired_method_dict={},B=d,a.addEventListener("DOMContentLoaded",C,!1)}),w.push(function(){return C}).push(function(a){function b(){return a}var c;for(d.ready(function(a){return s(a)}),w.push(b),c=0;c<d.__ready_list.length;c+=1)w.push(d.__ready_list[c]).push(b)}),b.self===b.top?w.fail(function(a){throw m(a),a}):w.then(function(){y=!0,E&&j()}).fail(function(a){throw n?(A=!0,r=a.toString(),m(a)):i.notify({method:"failed",params:a.toString()}),a})}var B,C,D,E,F={},G={},H={},I=0,J=new RegExp("^(?:[a-z]+:)?//|data:","i");n.prototype=new Error,n.prototype.constructor=n,E=function(){function a(){var a,b=h.length;for(a=0;b>a;a+=1)h[a].cancel();h=[]}var b,d,e,f,g=this,h=[];return this instanceof E?(b=new c.Promise(function(b,c,h){d=function(b){return f?void 0:(g.isRejected=!0,g.rejectedReason=b,f=!0,a(),c(b))},e=h},a),g.cancel=function(){f||(f=!0,b.cancel(),b.fail(function(a){g.isRejected=!0,g.rejectedReason=a}))},g.then=function(){return b.then.apply(b,arguments)},g.fail=function(){return b.fail.apply(b,arguments)},void(g.monitor=function(a){if(f)throw new n;var b=(new c.Queue).push(function(){return a}).push(function(a){var b,c,d=h.length,e=[];for(c=0;d>c;c+=1)b=h[c],b.isFulfilled||b.isRejected||e.push(b);h=e},function(b){throw b instanceof c.CancellationError&&(a.isFulfilled&&a.isRejected||a.cancel()),d(b),b},function(a){return e(a),a});return h.push(b),this})):new E},E.prototype=Object.create(c.Promise.prototype),E.prototype.constructor=E,o.prototype.__title="",o.prototype.__interface_list=[],o.prototype.__path="",o.prototype.__html="",o.prototype.__required_css_list=[],o.prototype.__required_js_list=[],o.__ready_list=[q,r],o.ready=function(a){return this.__ready_list.push(a),this},o.__service_list=[],o.declareService=function(a){return this.__service_list.push(a),this},o.declareMethod=function(a,b){return this.prototype[a]=function(){var a=this,d=arguments;return(new c.Queue).push(function(){return b.apply(a,d)})},this},o.declareMethod("getInterfaceList",function(){return this.__interface_list}).declareMethod("getRequiredCSSList",function(){return this.__required_css_list}).declareMethod("getRequiredJSList",function(){return this.__required_js_list}).declareMethod("getPath",function(){return this.__path}).declareMethod("getTitle",function(){return this.__title}).declareMethod("getElement",function(){if(void 0===this.__element)throw new Error("No element defined");return this.__element}),o.declareAcquiredMethod=function(a,b){return this.prototype[a]=function(){var a=Array.prototype.slice.call(arguments,0),d=this;return(new c.Queue).push(function(){return d.__aq_parent(b,a)})},this},o.declareAcquiredMethod("aq_reportServiceError","reportServiceError"),o.allowPublicAcquisition=function(a,b){return this.prototype.__acquired_method_dict[a]=b,this},v.__ready_list=o.__ready_list.slice(),v.__service_list=o.__service_list.slice(),v.ready=o.ready,v.declareService=o.declareService,v.prototype=new o,v.prototype.constructor=v,x.__ready_list=o.__ready_list.slice(),x.ready=o.ready,x.__service_list=o.__service_list.slice(),x.declareService=o.declareService,x.prototype=new o,x.prototype.constructor=x,o.declareMethod("declareGadget",function(b,d){var e,f,g=this,h=C;return void 0===d&&(d={}),void 0===d.sandbox&&(d.sandbox="public"),b=D.getAbsoluteURL(b,this.__path),C=(new c.Queue).push(function(){return h}).push(void 0,function(){}).push(function(){var a;if("public"===d.sandbox)a=w;else if("iframe"===d.sandbox)a=y;else{if("dataurl"!==d.sandbox)throw new Error("Unsupported sandbox options '"+d.sandbox+"'");a=z}return a(b,d,g)}).push(function(a){return B=void 0,a}).push(void 0,function(a){throw B=void 0,a}),f=C,e=(new c.Queue).push(function(){return f}).push(function(c){function f(){return c}var h,i;for(h=0;h<c.constructor.__ready_list.length;h+=1)e.push(c.constructor.__ready_list[h]),e.push(f);if(i=d.scope,void 0===i)for(i="RJS_"+I,I+=1;g.__sub_gadget_dict.hasOwnProperty(i);)i="RJS_"+I,I+=1;return g.__sub_gadget_dict[i]=c,c.__element.setAttribute("data-gadget-scope",i),c.__element.setAttribute("data-gadget-url",b),c.__element.setAttribute("data-gadget-sandbox",d.sandbox),c.__element._gadget=c,a.contains(c.__element)&&e.push(s),e.push(f),c})}).declareMethod("getDeclaredGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");return this.__sub_gadget_dict[a]}).declareMethod("dropGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");delete this.__sub_gadget_dict[a]}),D=function(a){var c;if(a===b&&(c=B),void 0===c)throw new Error("Unknown selector '"+a+"'");return c},D.AcquisitionError=function(a){if(this.name="AcquisitionError",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Acquisition failed"},D.AcquisitionError.prototype=new Error,D.AcquisitionError.prototype.constructor=D.AcquisitionError,D.getAbsoluteURL=function(a,b){var c,e,f,g="<!doctype><html><head></head></html>";return a&&b&&!J.test(a)?(c=(new d).parseFromString(g,"text/html"),e=c.createElement("base"),f=c.createElement("link"),c.head.appendChild(e),c.head.appendChild(f),e.href=b,f.href=a,f.href):a},D.declareJS=function(b){var d;return d=G.hasOwnProperty(b)?c.resolve():new c.Promise(function(c,d){var e;e=a.createElement("script"),e.type="text/javascript",e.src=b,e.onload=function(){G[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},D.declareCSS=function(b){var d;return d=H.hasOwnProperty(b)?c.resolve():new c.Promise(function(c,d){var e;e=a.createElement("link"),e.rel="stylesheet",e.type="text/css",e.href=b,e.onload=function(){H[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},D.declareGadgetKlass=function(a){function b(b){var c,e,f;if(!F.hasOwnProperty(a)){c=function(){o.call(this)},c.__ready_list=o.__ready_list.slice(),c.__service_list=o.__service_list.slice(),c.declareMethod=o.declareMethod,c.declareAcquiredMethod=o.declareAcquiredMethod,c.allowPublicAcquisition=o.allowPublicAcquisition,c.ready=o.ready,c.declareService=o.declareService,c.prototype=new o,c.prototype.constructor=c,c.prototype.__path=a,c.prototype.__acquired_method_dict={},c.__template_element=(new d).parseFromString(b.responseText,"text/html"),f=D.parseGadgetHTMLDocument(c.__template_element,a);for(e in f)f.hasOwnProperty(e)&&(c.prototype["__"+e]=f[e]);F[a]=c}return F[a]}var e;return e=F.hasOwnProperty(a)?c.resolve(F[a]):(new c.Queue).push(function(){return k(a)}).push(function(a){return b(a)})},D.clearGadgetKlassList=function(){F={},G={},H={}},D.parseGadgetHTMLDocument=function(a,b){var c,d,e={title:"",interface_list:[],required_css_list:[],required_js_list:[]};if(!b||!J.test(b))throw new Error("The url should be absolute: "+b);if(9!==a.nodeType)throw new Error("The first parameter should be an HTMLDocument");if(e.title=a.title,null!==a.head)for(c=0;c<a.head.children.length;c+=1)d=a.head.children[c],null!==d.href&&("stylesheet"===d.rel?e.required_css_list.push(D.getAbsoluteURL(d.getAttribute("href"),b)):"SCRIPT"!==d.nodeName||"text/javascript"!==d.type&&d.type?"http://www.renderjs.org/rel/interface"===d.rel&&e.interface_list.push(D.getAbsoluteURL(d.getAttribute("href"),b)):e.required_js_list.push(D.getAbsoluteURL(d.getAttribute("src"),b)));return e},b.rJS=b.renderJS=D,b.__RenderJSGadget=o,b.__RenderJSEmbeddedGadget=v,b.__RenderJSIframeGadget=x,A()}(document,window,RSVP,DOMParser,Channel,MutationObserver,Node,FileReader,Blob);
\ No newline at end of file
+var Channel=function(){"use strict";function a(a,b,c,d){function f(b){for(var c=0;c<b.length;c++)if(b[c].win===a)return!0;return!1}var g=!1;if("*"===b){for(var h in e)if(e.hasOwnProperty(h)&&"*"!==h&&"object"==typeof e[h][c]&&(g=f(e[h][c])))break}else e["*"]&&e["*"][c]&&(g=f(e["*"][c])),!g&&e[b]&&e[b][c]&&(g=f(e[b][c]));if(g)throw"A channel is already bound to the same window which overlaps with origin '"+b+"' and has scope '"+c+"'";"object"!=typeof e[b]&&(e[b]={}),"object"!=typeof e[b][c]&&(e[b][c]=[]),e[b][c].push({win:a,handler:d})}function b(a,b,c){for(var d=e[b][c],f=0;f<d.length;f++)d[f].win===a&&d.splice(f,1);0===e[b][c].length&&delete e[b][c]}function c(a){return Array.isArray?Array.isArray(a):-1!=a.constructor.toString().indexOf("Array")}var d=Math.floor(1000001*Math.random()),e={},f={},g=function(a){try{var b=JSON.parse(a.data);if("object"!=typeof b||null===b)throw"malformed"}catch(a){return}var c,d,g,h=a.source,i=a.origin;if("string"==typeof b.method){var j=b.method.split("::");2==j.length?(c=j[0],g=j[1]):g=b.method}if("undefined"!=typeof b.id&&(d=b.id),"string"==typeof g){var k=!1;if(e[i]&&e[i][c])for(var l=0;l<e[i][c].length;l++)if(e[i][c][l].win===h){e[i][c][l].handler(i,g,b),k=!0;break}if(!k&&e["*"]&&e["*"][c])for(var l=0;l<e["*"][c].length;l++)if(e["*"][c][l].win===h){e["*"][c][l].handler(i,g,b);break}}else"undefined"!=typeof d&&f[d]&&f[d](i,g,b)};return window.addEventListener?window.addEventListener("message",g,!1):window.attachEvent&&window.attachEvent("onmessage",g),{build:function(e){var g=function(a){if(e.debugOutput&&window.console&&window.console.log){try{"string"!=typeof a&&(a=JSON.stringify(a))}catch(b){}console.log("["+j+"] "+a)}};if(!window.postMessage)throw"jschannel cannot run this browser, no postMessage";if(!window.JSON||!window.JSON.stringify||!window.JSON.parse)throw"jschannel cannot run this browser, no JSON parsing/serialization";if("object"!=typeof e)throw"Channel build invoked without a proper object argument";if(!e.window||!e.window.postMessage)throw"Channel.build() called without a valid window argument";if(window===e.window)throw"target window is same as present window -- not allowed";var h=!1;if("string"==typeof e.origin){var i;"*"===e.origin?h=!0:null!==(i=e.origin.match(/^https?:\/\/(?:[-a-zA-Z0-9_\.])+(?::\d+)?/))&&(e.origin=i[0].toLowerCase(),h=!0)}if(!h)throw"Channel.build() called with an invalid origin";if("undefined"!=typeof e.scope){if("string"!=typeof e.scope)throw"scope, when specified, must be a string";if(e.scope.split("::").length>1)throw"scope may not contain double colons: '::'"}var j=function(){for(var a="",b="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",c=0;5>c;c++)a+=b.charAt(Math.floor(Math.random()*b.length));return a}(),k={},l={},m={},n=!1,o=[],p=function(a,b,c){var d=!1,e=!1;return{origin:b,invoke:function(b,d){if(!m[a])throw"attempting to invoke a callback of a nonexistent transaction: "+a;for(var e=!1,f=0;f<c.length;f++)if(b===c[f]){e=!0;break}if(!e)throw"request supports no such callback '"+b+"'";t({id:a,callback:b,params:d})},error:function(b,c){if(e=!0,!m[a])throw"error called for nonexistent message: "+a;delete m[a],t({id:a,error:b,message:c})},complete:function(b){if(e=!0,!m[a])throw"complete called for nonexistent message: "+a;delete m[a],t({id:a,result:b})},delayReturn:function(a){return"boolean"==typeof a&&(d=a===!0),d},completed:function(){return e}}},q=function(a,b,c){return window.setTimeout(function(){if(l[a]){var d="timeout ("+b+"ms) exceeded on method '"+c+"'";l[a].error("timeout_error",d),delete l[a],delete f[a]}},b)},r=function(a,b,d){if("function"==typeof e.gotMessageObserver)try{e.gotMessageObserver(a,d)}catch(h){g("gotMessageObserver() raised an exception: "+h.toString())}if(d.id&&b){if(k[b]){var i=p(d.id,a,d.callbacks?d.callbacks:[]);m[d.id]={};try{if(d.callbacks&&c(d.callbacks)&&d.callbacks.length>0)for(var j=0;j<d.callbacks.length;j++){for(var n=d.callbacks[j],o=d.params,q=n.split("/"),r=0;r<q.length-1;r++){var s=q[r];"object"!=typeof o[s]&&(o[s]={}),o=o[s]}o[q[q.length-1]]=function(){var a=n;return function(b){return i.invoke(a,b)}}()}var t=k[b](i,d.params);i.delayReturn()||i.completed()||i.complete(t)}catch(h){var u="runtime_error",v=null;if("string"==typeof h?v=h:"object"==typeof h&&(h&&c(h)&&2==h.length?(u=h[0],v=h[1]):"string"==typeof h.error&&(u=h.error,h.message?"string"==typeof h.message?v=h.message:h=h.message:v="")),null===v)try{v=JSON.stringify(h),"undefined"==typeof v&&(v=h.toString())}catch(w){v=h.toString()}i.error(u,v)}}}else d.id&&d.callback?l[d.id]&&l[d.id].callbacks&&l[d.id].callbacks[d.callback]?l[d.id].callbacks[d.callback](d.params):g("ignoring invalid callback, id:"+d.id+" ("+d.callback+")"):d.id?l[d.id]?(d.error?l[d.id].error(d.error,d.message):void 0!==d.result?l[d.id].success(d.result):l[d.id].success(),delete l[d.id],delete f[d.id]):g("ignoring invalid response: "+d.id):b&&k[b]&&k[b]({origin:a},d.params)};a(e.window,e.origin,"string"==typeof e.scope?e.scope:"",r);var s=function(a){return"string"==typeof e.scope&&e.scope.length&&(a=[e.scope,a].join("::")),a},t=function(a,b){if(!a)throw"postMessage called with null message";var c=n?"post  ":"queue ";if(g(c+" message: "+JSON.stringify(a)),b||n){if("function"==typeof e.postMessageObserver)try{e.postMessageObserver(e.origin,a)}catch(d){g("postMessageObserver() raised an exception: "+d.toString())}e.window.postMessage(JSON.stringify(a),e.origin)}else o.push(a)},u=function(a,b){if(g("ready msg received"),n)throw"received ready message while in ready state.  help!";for(j+="ping"===b?"-R":"-L",v.unbind("__ready"),n=!0,g("ready msg accepted."),"ping"===b&&v.notify({method:"__ready",params:"pong"});o.length;)t(o.pop());"function"==typeof e.onReady&&e.onReady(v)},v={unbind:function(a){if(k[a]){if(!delete k[a])throw"can't delete method: "+a;return!0}return!1},bind:function(a,b){if(!a||"string"!=typeof a)throw"'method' argument to bind must be string";if(!b||"function"!=typeof b)throw"callback missing from bind params";if(k[a])throw"method '"+a+"' is already bound!";return k[a]=b,this},call:function(a){if(!a)throw"missing arguments to call function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to call must be string";if(!a.success||"function"!=typeof a.success)throw"'success' callback missing from call";var b={},c=[],e=function(a,d){if("object"==typeof d)for(var f in d)if(d.hasOwnProperty(f)){var g=a+(a.length?"/":"")+f;"function"==typeof d[f]?(b[g]=d[f],c.push(g),delete d[f]):"object"==typeof d[f]&&e(g,d[f])}};e("",a.params);var g={id:d,method:s(a.method),params:a.params};c.length&&(g.callbacks=c),a.timeout&&q(d,a.timeout,s(a.method)),l[d]={callbacks:b,error:a.error,success:a.success},f[d]=r,d++,t(g)},notify:function(a){if(!a)throw"missing arguments to notify function";if(!a.method||"string"!=typeof a.method)throw"'method' argument to notify must be string";t({method:s(a.method),params:a.params})},destroy:function(){b(e.window,e.origin,"string"==typeof e.scope?e.scope:""),window.removeEventListener?window.removeEventListener("message",r,!1):window.detachEvent&&window.detachEvent("onmessage",r),n=!1,k={},m={},l={},e.origin=null,o=[],g("channel destroyed"),j=""}};return v.bind("__ready",u),setTimeout(function(){t({method:s("__ready"),params:"ping"},!0)},0),v}}}();!function(a){"use strict";var b=a.prototype,c=b.parseFromString;try{if((new a).parseFromString("","text/html"))return}catch(d){}b.parseFromString=function(a,b){var d,e,f,g;return/^\s*text\/html\s*(?:;|$)/i.test(b)?(e=document.implementation.createHTMLDocument(""),f=e.documentElement,f.innerHTML=a,g=f.firstElementChild,1===f.childElementCount&&"html"===g.localName.toLowerCase()&&e.replaceChild(g,f),d=e):d=c.apply(this,arguments),d}}(DOMParser),"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)}),function(a,b,c,d,e,f,g,h,i,j,k){"use strict";function l(a){var b=new h;return new c.Promise(function(c,d){b.addEventListener("load",function(a){c(a.target.result)}),b.addEventListener("error",d),b.readAsDataURL(a)},function(){b.abort()})}function m(a){function b(b,c){function d(){try{0===e.readyState?c(e):4===e.readyState&&(e.status<200||e.status>=300||!/^text\/html[;]?/.test(e.getResponseHeader("Content-Type")||"")?c(e):b(e))}catch(a){c(a)}}e=new XMLHttpRequest,e.open("GET",a),e.onreadystatechange=d,e.setRequestHeader("Accept","text/html"),e.withCredentials=!0,e.send()}function d(){void 0!==e&&e.readyState!==e.DONE&&e.abort()}var e;return new c.Promise(b,d)}function n(a){var b=a.indexOf("#");return b>0&&(a=a.substring(0,b)),a}function o(c){var d,e,f,g,h,i;if(M)return console.info("-- Error dropped, as page is unloaded"),void console.info(c);for(N.push(c),N.push(new Error("stopping renderJS")),e=a.getElementsByTagName("body")[0];e.firstChild;)e.removeChild(e.firstChild);for(f=a.createElement("section"),g=a.createElement("h1"),g.textContent="Unhandled Error",f.appendChild(g),g=a.createElement("p"),g.textContent="Please report this error to the support team",f.appendChild(g),g=a.createElement("p"),g.textContent="Location: ",h=a.createElement("a"),h.href=h.textContent=b.location.toString(),g.appendChild(h),f.appendChild(g),g=a.createElement("p"),g.textContent="User-agent: "+j.userAgent,f.appendChild(g),e.appendChild(f),d=0;d<N.length;d+=1){if(i=N[d],i instanceof k&&(i={string:i.toString(),message:i.message,type:i.type,target:i.target},void 0!==i.target&&N.splice(d+1,0,i.target)),i instanceof XMLHttpRequest&&(i={message:i.toString(),readyState:i.readyState,status:i.status,statusText:i.statusText,response:i.response,responseUrl:i.responseUrl,response_headers:i.getAllResponseHeaders()}),i.constructor===Array||i.constructor===String||i.constructor===Object)try{i=JSON.stringify(i)}catch(l){}f=a.createElement("section"),g=a.createElement("h2"),g.textContent=i.message||i,f.appendChild(g),void 0!==i.fileName&&(g=a.createElement("p"),g.textContent="File: "+i.fileName+": "+i.lineNumber,f.appendChild(g)),void 0!==i.stack&&(g=a.createElement("pre"),g.textContent="Stack: "+i.stack,f.appendChild(g)),e.appendChild(f)}console.error(c.stack),console.error(c)}function p(a){if(this.name="resolved",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Default Message"}function q(){return this instanceof q?void 0:new q}function r(a){void 0!==a.__monitor&&a.__monitor.cancel(),a.__monitor=new G,a.__monitor.fail(function(b){return b instanceof c.CancellationError?void 0:a.aq_reportServiceError(b)}).fail(function(a){return o(a)})}function s(a){a.__sub_gadget_dict={},r(a)}function t(a){var b,d,e,f,g,h=a.__element.querySelectorAll("[data-gadget-url]"),i=[];for(g=0;g<h.length;g+=1)b=h[g],d=b.getAttribute("data-gadget-scope"),e=b.getAttribute("data-gadget-url"),f=b.getAttribute("data-gadget-sandbox"),null!==e&&i.push(a.declareGadget(e,{element:b,scope:d||void 0,sandbox:f||void 0}));return c.all(i)}function u(a){a.__monitor.monitor((new c.Queue).push(function(){var b,c=a.constructor.__service_list;for(b=0;b<c.length;b+=1)a.__monitor.monitor(c[b].apply(a))}))}function v(a,b,d){var e,f,g=this;for(e in g.__sub_gadget_dict)g.__sub_gadget_dict.hasOwnProperty(e)&&g.__sub_gadget_dict[e]===a&&(f=e);return(new c.Queue).push(function(){var a=g.__acquired_method_dict||{};if(a.hasOwnProperty(b))return a[b].apply(g,[d,f]);throw new F.AcquisitionError("aq_dynamic is not defined")}).push(void 0,function(a){if(a instanceof F.AcquisitionError)return g.__aq_parent(b,d);throw a})}function w(a,b){a.__aq_parent=function(c,d){return v.apply(b,[a,c,d])}}function x(){return this instanceof x?void q.call(this):new x}function y(b,d,e){function f(a,b){return function(){return a(b)}}var g;return void 0===d.element&&(d.element=a.createElement("div")),(new c.Queue).push(function(){return F.declareGadgetKlass(b)}).push(function(a){var b,f=a.__template_element.body.childNodes;for(D=a,g=new a,g.__element=d.element,b=0;b<f.length;b+=1)g.__element.appendChild(f[b].cloneNode(!0));return w(g,e),c.all([g.getRequiredJSList(),g.getRequiredCSSList()])}).push(function(a){var b,d=new c.Queue;for(b=0;b<a[0].length;b+=1)d.push(f(F.declareJS,a[0][b]));for(b=0;b<a[1].length;b+=1)d.push(f(F.declareCSS,a[1][b]));return d}).push(function(){return g})}function z(){return this instanceof z?void q.call(this):new z}function A(b,d,f){var g,h,i=c.defer();if(void 0===d.element)throw new Error("DOM element is required to create Iframe Gadget "+b);if(!a.contains(d.element))throw new Error("The parent element is not attached to the DOM for "+b);return g=new z,w(g,f),h=a.createElement("iframe"),h.setAttribute("src",b),g.__path=b,g.__element=d.element,d.element.appendChild(h),g.__chan=e.build({window:h.contentWindow,origin:"*",scope:"renderJS"}),g.__chan.bind("declareMethod",function(a,b){return g[b]=function(){var a=arguments,d=new c.Promise(function(c,d){g.__chan.call({method:"methodCall",params:[b,Array.prototype.slice.call(a,0)],success:function(a){c(a)},error:function(a){d(a)}})});return(new c.Queue).push(function(){return d})},"OK"}),g.__chan.bind("ready",function(a){return i.resolve(g),"OK"}),g.__chan.bind("failed",function(a,b){return i.reject(b),"OK"}),g.__chan.bind("acquire",function(a,b){g.__aq_parent.apply(g,b).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}),c.any([i.promise,(new c.Queue).push(function(){return c.timeout(5e3)}).push(void 0,function(){throw new Error("Timeout while loading: "+b)})])}function B(a,b,e){return(new c.Queue).push(function(){return m(a)}).push(function(b){var c,e=(new d).parseFromString(b.responseText,"text/html"),f=e.createElement("base");return f.href=a,e.head.insertBefore(f,e.head.firstChild),c=new i([e.documentElement.outerHTML],{type:"text/html;charset=UTF-8"}),l(c)}).push(function(a){return A(a,b,e)})}function C(){var d,h,i,j,k,l,m,p,s=n(b.location.href),t=new c.Queue,v=0,y=!1,z=[],A=!1,B=!1;if(H.hasOwnProperty(s))throw new Error("bootstrap should not be called twice");E=new c.Promise(function(n,t){function C(){var b,e,i=F.parseGadgetHTMLDocument(a,s);for(e in i)i.hasOwnProperty(e)&&(d.prototype["__"+e]=i[e]);for(d.__template_element=a.createElement("div"),h.__element=a.body,b=0;b<h.__element.childNodes.length;b+=1)d.__template_element.appendChild(h.__element.childNodes[b].cloneNode(!0));c.all([h.getRequiredJSList(),h.getRequiredCSSList()]).then(function(a){var b,c=a[0],d=a[1];for(b=0;b<c.length;b+=1)I[c[b]]=null;for(b=0;b<d.length;b+=1)J[d[b]]=null;D=void 0}).then(function(){var b=a.querySelector("body"),c=new f(function(b){var c,d,e,f,h,i;b.forEach(function(b){if("childList"===b.type){for(e=b.removedNodes.length,c=0;e>c;c+=1)if(h=b.removedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&r(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],void 0!==h._gadget&&r(h._gadget);for(e=b.addedNodes.length,c=0;e>c;c+=1)if(h=b.addedNodes[c],h.nodeType===g.ELEMENT_NODE)for(h.hasAttribute("data-gadget-url")&&void 0!==h._gadget&&a.contains(h)&&u(h._gadget),i=h.querySelectorAll("[data-gadget-url]"),f=i.length,d=0;f>d;d+=1)h=i[d],a.contains(h)&&void 0!==h._gadget&&u(h._gadget)}})}),d={childList:!0,subtree:!0,attributes:!1,characterData:!1};return c.observe(b,d),h}).then(n,function(a){throw t(a),console.error(a),a})}m=new q,m.__acquired_method_dict={reportServiceError:function(a){o(a[0])}},m.__aq_parent=function(a){throw new F.AcquisitionError("No gadget provides "+a)},b.self===b.top?(d=function(){q.call(this)},d.declareMethod=q.declareMethod,d.declareAcquiredMethod=q.declareAcquiredMethod,d.allowPublicAcquisition=q.allowPublicAcquisition,d.__ready_list=q.__ready_list.slice(),d.ready=q.ready,d.__service_list=q.__service_list.slice(),d.declareService=q.declareService,d.prototype=new q,d.prototype.constructor=d,d.prototype.__path=s,H[s]=d,h=new H[s],w(h,m)):(d=x,d.__ready_list=q.__ready_list.slice(),d.__service_list=q.__service_list.slice(),d.prototype.__path=s,h=new x,w(h,m),i=e.build({window:b.parent,origin:"*",scope:"renderJS",onReady:function(){var a;for(l=!1,h.__aq_parent=d.prototype.__aq_parent=function(a,b,d){return new c.Promise(function(c,e){i.call({method:"acquire",params:[a,b],success:function(a){c(a)},error:function(a){e(a)},timeout:d})})},k=function(a){v+=1,i.call({method:"declareMethod",params:a,success:function(){v-=1,j()},error:function(){v-=1}})},a=0;a<z.length;a+=1)k(z[a]);return z=[],A?void i.notify({method:"failed",params:p}):(B=!0,j(),void i.bind("methodCall",function(a,b){h[b[0]].apply(h,b[1]).then(function(b){a.complete(b)}).fail(function(b){a.error(b.toString())}),a.delayReturn(!0)}))}}),j=function(){0===v&&y===!0&&i.notify({method:"ready"})},k=function(a){z.push(a)},k("getInterfaceList"),k("getRequiredCSSList"),k("getRequiredJSList"),k("getPath"),k("getTitle"),d.declareMethod=function(a,b){var c=q.declareMethod.apply(this,[a,b]);return k(a),c},d.declareService=q.declareService,d.declareAcquiredMethod=q.declareAcquiredMethod,d.allowPublicAcquisition=q.allowPublicAcquisition,l=!0),d.prototype.__acquired_method_dict={},D=d,a.addEventListener("DOMContentLoaded",C,!1)}),t.push(function(){return E}).push(function(a){function b(){return a}var c;for(d.ready(function(a){return u(a)}),t.push(b),c=0;c<d.__ready_list.length;c+=1)t.push(d.__ready_list[c]).push(b)}),b.self===b.top?t.fail(function(a){throw o(a),a}):t.then(function(){y=!0,B&&j()}).fail(function(a){throw l?(A=!0,p=a.toString(),o(a)):i.notify({method:"failed",params:a.toString()}),a})}var D,E,F,G,H={},I={},J={},K=0,L=new RegExp("^(?:[a-z]+:)?//|data:","i"),M=!1,N=[];b.addEventListener("error",function(a){N.push(a)}),b.addEventListener("beforeunload",function(){M=!0}),p.prototype=new Error,p.prototype.constructor=p,G=function(){function a(){var a,b=h.length;for(a=0;b>a;a+=1)h[a].cancel();h=[]}var b,d,e,f,g=this,h=[];return this instanceof G?(b=new c.Promise(function(b,c,h){d=function(b){return f?void 0:(g.isRejected=!0,g.rejectedReason=b,f=!0,a(),c(b))},e=h},a),g.cancel=function(){f||(f=!0,b.cancel(),b.fail(function(a){g.isRejected=!0,g.rejectedReason=a}))},g.then=function(){return b.then.apply(b,arguments)},g.fail=function(){return b.fail.apply(b,arguments)},void(g.monitor=function(a){if(f)throw new p;var b=(new c.Queue).push(function(){return a}).push(function(a){var b,c,d=h.length,e=[];for(c=0;d>c;c+=1)b=h[c],b.isFulfilled||b.isRejected||e.push(b);h=e},function(b){throw b instanceof c.CancellationError&&(a.isFulfilled&&a.isRejected||a.cancel()),d(b),b},function(a){return e(a),a});return h.push(b),this})):new G},G.prototype=Object.create(c.Promise.prototype),G.prototype.constructor=G,q.prototype.__title="",q.prototype.__interface_list=[],q.prototype.__path="",q.prototype.__html="",q.prototype.__required_css_list=[],q.prototype.__required_js_list=[],q.__ready_list=[s,t],q.ready=function(a){return this.__ready_list.push(a),this},q.__service_list=[],q.declareService=function(a){return this.__service_list.push(a),this},q.declareMethod=function(a,b){return this.prototype[a]=function(){var a=this,d=arguments;return(new c.Queue).push(function(){return b.apply(a,d)})},this},q.declareMethod("getInterfaceList",function(){return this.__interface_list}).declareMethod("getRequiredCSSList",function(){return this.__required_css_list}).declareMethod("getRequiredJSList",function(){return this.__required_js_list}).declareMethod("getPath",function(){return this.__path}).declareMethod("getTitle",function(){return this.__title}).declareMethod("getElement",function(){if(void 0===this.__element)throw new Error("No element defined");return this.__element}),q.declareAcquiredMethod=function(a,b){return this.prototype[a]=function(){var a=Array.prototype.slice.call(arguments,0),d=this;return(new c.Queue).push(function(){return d.__aq_parent(b,a)})},this},q.declareAcquiredMethod("aq_reportServiceError","reportServiceError"),q.allowPublicAcquisition=function(a,b){return this.prototype.__acquired_method_dict[a]=b,this},x.__ready_list=q.__ready_list.slice(),x.__service_list=q.__service_list.slice(),x.ready=q.ready,x.declareService=q.declareService,x.prototype=new q,x.prototype.constructor=x,z.__ready_list=q.__ready_list.slice(),z.ready=q.ready,z.__service_list=q.__service_list.slice(),z.declareService=q.declareService,z.prototype=new q,z.prototype.constructor=z,q.declareMethod("declareGadget",function(b,d){var e,f,g=this,h=E;return void 0===d&&(d={}),void 0===d.sandbox&&(d.sandbox="public"),b=F.getAbsoluteURL(b,this.__path),E=(new c.Queue).push(function(){return h}).push(void 0,function(){}).push(function(){var a;if("public"===d.sandbox)a=y;else if("iframe"===d.sandbox)a=A;else{if("dataurl"!==d.sandbox)throw new Error("Unsupported sandbox options '"+d.sandbox+"'");a=B}return a(b,d,g)}).push(function(a){return D=void 0,a}).push(void 0,function(a){throw D=void 0,a}),f=E,e=(new c.Queue).push(function(){return f}).push(function(c){function f(){return c}var h,i;for(h=0;h<c.constructor.__ready_list.length;h+=1)e.push(c.constructor.__ready_list[h]),e.push(f);if(i=d.scope,void 0===i)for(i="RJS_"+K,K+=1;g.__sub_gadget_dict.hasOwnProperty(i);)i="RJS_"+K,K+=1;return g.__sub_gadget_dict[i]=c,c.__element.setAttribute("data-gadget-scope",i),c.__element.setAttribute("data-gadget-url",b),c.__element.setAttribute("data-gadget-sandbox",d.sandbox),c.__element._gadget=c,a.contains(c.__element)&&e.push(u),e.push(f),c})}).declareMethod("getDeclaredGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");return this.__sub_gadget_dict[a]}).declareMethod("dropGadget",function(a){if(!this.__sub_gadget_dict.hasOwnProperty(a))throw new Error("Gadget scope '"+a+"' is not known.");delete this.__sub_gadget_dict[a]}),F=function(a){var c;if(a===b&&(c=D),void 0===c)throw new Error("Unknown selector '"+a+"'");return c},F.AcquisitionError=function(a){if(this.name="AcquisitionError",void 0!==a&&"string"!=typeof a)throw new TypeError("You must pass a string.");this.message=a||"Acquisition failed"},F.AcquisitionError.prototype=new Error,F.AcquisitionError.prototype.constructor=F.AcquisitionError,F.getAbsoluteURL=function(a,b){var c,e,f,g="<!doctype><html><head></head></html>";return a&&b&&!L.test(a)?(c=(new d).parseFromString(g,"text/html"),e=c.createElement("base"),f=c.createElement("link"),c.head.appendChild(e),c.head.appendChild(f),e.href=b,f.href=a,f.href):a},F.declareJS=function(b){var d;return d=I.hasOwnProperty(b)?c.resolve():new c.Promise(function(c,d){var e;e=a.createElement("script"),e.type="text/javascript",e.src=b,e.onload=function(){I[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},F.declareCSS=function(b){var d;return d=J.hasOwnProperty(b)?c.resolve():new c.Promise(function(c,d){var e;e=a.createElement("link"),e.rel="stylesheet",e.type="text/css",e.href=b,e.onload=function(){J[b]=null,c()},e.onerror=function(a){d(a)},a.head.appendChild(e)})},F.declareGadgetKlass=function(a){function b(b){var c,e,f;if(!H.hasOwnProperty(a)){c=function(){q.call(this)},c.__ready_list=q.__ready_list.slice(),c.__service_list=q.__service_list.slice(),c.declareMethod=q.declareMethod,c.declareAcquiredMethod=q.declareAcquiredMethod,c.allowPublicAcquisition=q.allowPublicAcquisition,c.ready=q.ready,c.declareService=q.declareService,c.prototype=new q,c.prototype.constructor=c,c.prototype.__path=a,c.prototype.__acquired_method_dict={},c.__template_element=(new d).parseFromString(b.responseText,"text/html"),f=F.parseGadgetHTMLDocument(c.__template_element,a);for(e in f)f.hasOwnProperty(e)&&(c.prototype["__"+e]=f[e]);H[a]=c}return H[a]}var e;return e=H.hasOwnProperty(a)?c.resolve(H[a]):(new c.Queue).push(function(){return m(a)}).push(function(a){return b(a)})},F.clearGadgetKlassList=function(){H={},I={},J={}},F.parseGadgetHTMLDocument=function(a,b){var c,d,e={title:"",interface_list:[],required_css_list:[],required_js_list:[]};if(!b||!L.test(b))throw new Error("The url should be absolute: "+b);if(9!==a.nodeType)throw new Error("The first parameter should be an HTMLDocument");if(e.title=a.title,null!==a.head)for(c=0;c<a.head.children.length;c+=1)d=a.head.children[c],null!==d.href&&("stylesheet"===d.rel?e.required_css_list.push(F.getAbsoluteURL(d.getAttribute("href"),b)):"SCRIPT"!==d.nodeName||"text/javascript"!==d.type&&d.type?"http://www.renderjs.org/rel/interface"===d.rel&&e.interface_list.push(F.getAbsoluteURL(d.getAttribute("href"),b)):e.required_js_list.push(F.getAbsoluteURL(d.getAttribute("src"),b)));return e},b.rJS=b.renderJS=F,b.__RenderJSGadget=q,b.__RenderJSEmbeddedGadget=x,b.__RenderJSIframeGadget=z,C()}(document,window,RSVP,DOMParser,Channel,MutationObserver,Node,FileReader,Blob,navigator,Event);
\ No newline at end of file
diff --git a/package.json b/package.json
index bcb43b3d4c0abec630779f12e4ed7fe0a35ff759..fe676e4f2dc3a9159d7561a1a0223f5c21e4671d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "renderjs",
-  "version": "0.9.0",
+  "version": "0.10.0",
   "description": "RenderJs provides HTML5 gadgets",
   "main": "dist/renderjs-latest.js",
   "dependencies": {