{"version":3,"sources":["jsdelivr-header.js","/npm/jschannel@1.0.2/src/jschannel.js"],"names":[],"mappings":"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","file":"/npm/jschannel@1.0.2/src/jschannel.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/jschannel@1.0.2/src/jschannel.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/*\n * js_channel is a very lightweight abstraction on top of\n * postMessage which defines message formats and semantics\n * to support interactions more rich than just message passing\n * js_channel supports:\n *  + query/response - traditional rpc\n *  + query/update/response - incremental async return of results\n *    to a query\n *  + notifications - fire and forget\n *  + error handling\n *\n * js_channel is based heavily on json-rpc, but is focused at the\n * problem of inter-iframe RPC.\n *\n * Message types:\n *  There are 5 types of messages that can flow over this channel,\n *  and you may determine what type of message an object is by\n *  examining its parameters:\n *  1. Requests\n *    + integer id\n *    + string method\n *    + (optional) any params\n *  2. Callback Invocations (or just \"Callbacks\")\n *    + integer id\n *    + string callback\n *    + (optional) params\n *  3. Error Responses (or just \"Errors)\n *    + integer id\n *    + string error\n *    + (optional) string message\n *  4. Responses\n *    + integer id\n *    + (optional) any result\n *  5. Notifications\n *    + string method\n *    + (optional) any params\n */\n\n// Universal module definition //\n(function (root, factory) {\n  if (typeof exports === 'object') {\n    // CommonJS\n    module.exports = factory();\n  } else if (typeof define === 'function' && define.amd) {\n    // AMD\n    define([], function () {\n      return (root.Channel = factory());\n    });\n  } else {\n    // Global Variables\n    root.Channel = factory();\n  }\n}(this, function () {\n  \"use strict\";\n  var Channel = (function() {\n\n    // current transaction id, start out at a random *odd* number between 1 and a million\n    // There is one current transaction counter id per page, and it's shared between\n    // channel instances.  That means of all messages posted from a single javascript\n    // evaluation context, we'll never have two with the same id.\n    var s_curTranId = Math.floor(Math.random()*1000001);\n\n    // no two bound channels in the same javascript evaluation context may have the same origin, scope, and window.\n    // further if two bound channels have the same window and scope, they may not have *overlapping* origins\n    // (either one or both support '*').  This restriction allows a single onMessage handler to efficiently\n    // route messages based on origin and scope.  The s_boundChans maps origins to scopes, to message\n    // handlers.  Request and Notification messages are routed using this table.\n    // Finally, channels are inserted into this table when built, and removed when destroyed.\n    var s_boundChans = { };\n\n    // add a channel to s_boundChans, throwing if a dup exists\n    function s_addBoundChan(win, origin, scope, handler) {\n        function hasWin(arr) {\n            for (var i = 0; i < arr.length; i++) if (arr[i].win === win) return true;\n            return false;\n        }\n\n        // does she exist?\n        var exists = false;\n\n        if (origin === '*') {\n            // we must check all other origins, sadly.\n            for (var k in s_boundChans) {\n                if (!s_boundChans.hasOwnProperty(k)) continue;\n                if (k === '*') continue;\n                if (typeof s_boundChans[k][scope] === 'object') {\n                    exists = hasWin(s_boundChans[k][scope]);\n                    if (exists) break;\n                }\n            }\n        } else {\n            // we must check only '*'\n            if ((s_boundChans['*'] && s_boundChans['*'][scope])) {\n                exists = hasWin(s_boundChans['*'][scope]);\n            }\n            if (!exists && s_boundChans[origin] && s_boundChans[origin][scope])\n            {\n                exists = hasWin(s_boundChans[origin][scope]);\n            }\n        }\n        if (exists) throw \"A channel is already bound to the same window which overlaps with origin '\"+ origin +\"' and has scope '\"+scope+\"'\";\n\n        if (typeof s_boundChans[origin] != 'object') s_boundChans[origin] = { };\n        if (typeof s_boundChans[origin][scope] != 'object') s_boundChans[origin][scope] = [ ];\n        s_boundChans[origin][scope].push({win: win, handler: handler});\n    }\n\n    function s_removeBoundChan(win, origin, scope) {\n        var arr = s_boundChans[origin][scope];\n        for (var i = 0; i < arr.length; i++) {\n            if (arr[i].win === win) {\n                arr.splice(i,1);\n            }\n        }\n        if (s_boundChans[origin][scope].length === 0) {\n            delete s_boundChans[origin][scope];\n        }\n    }\n\n    function s_isArray(obj) {\n        if (Array.isArray) return Array.isArray(obj);\n        else {\n            return (obj.constructor.toString().indexOf(\"Array\") != -1);\n        }\n    }\n\n    // No two outstanding outbound messages may have the same id, period.  Given that, a single table\n    // mapping \"transaction ids\" to message handlers, allows efficient routing of Callback, Error, and\n    // Response messages.  Entries are added to this table when requests are sent, and removed when\n    // responses are received.\n    var s_transIds = { };\n\n    // class singleton onMessage handler\n    // this function is registered once and all incoming messages route through here.  This\n    // arrangement allows certain efficiencies, message data is only parsed once and dispatch\n    // is more efficient, especially for large numbers of simultaneous channels.\n    var s_onMessage = function(e) {\n        try {\n          var m = JSON.parse(e.data);\n          if (typeof m !== 'object' || m === null) throw \"malformed\";\n        } catch(e) {\n          // just ignore any posted messages that do not consist of valid JSON\n          return;\n        }\n\n        var w = e.source;\n        var o = e.origin;\n        var s, i, meth;\n\n        if (typeof m.method === 'string') {\n            var ar = m.method.split('::');\n            if (ar.length == 2) {\n                s = ar[0];\n                meth = ar[1];\n            } else {\n                meth = m.method;\n            }\n        }\n\n        if (typeof m.id !== 'undefined') i = m.id;\n\n        // w is message source window\n        // o is message origin\n        // m is parsed message\n        // s is message scope\n        // i is message id (or undefined)\n        // meth is unscoped method name\n        // ^^ based on these factors we can route the message\n\n        // if it has a method it's either a notification or a request,\n        // route using s_boundChans\n        if (typeof meth === 'string') {\n            var delivered = false;\n            if (s_boundChans[o] && s_boundChans[o][s]) {\n                for (var j = 0; j < s_boundChans[o][s].length; j++) {\n                    if (s_boundChans[o][s][j].win === w) {\n                        s_boundChans[o][s][j].handler(o, meth, m);\n                        delivered = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!delivered && s_boundChans['*'] && s_boundChans['*'][s]) {\n                for (var j = 0; j < s_boundChans['*'][s].length; j++) {\n                    if (s_boundChans['*'][s][j].win === w) {\n                        s_boundChans['*'][s][j].handler(o, meth, m);\n                        break;\n                    }\n                }\n            }\n        }\n        // otherwise it must have an id (or be poorly formed\n        else if (typeof i != 'undefined') {\n            if (s_transIds[i]) s_transIds[i](o, meth, m);\n        }\n    };\n\n    // Setup postMessage event listeners\n    if (window.addEventListener) window.addEventListener('message', s_onMessage, false);\n    else if(window.attachEvent) window.attachEvent('onmessage', s_onMessage);\n\n    /* a messaging channel is constructed from a window and an origin.\n     * the channel will assert that all messages received over the\n     * channel match the origin\n     *\n     * Arguments to Channel.build(cfg):\n     *\n     *   cfg.window - the remote window with which we'll communicate\n     *   cfg.origin - the expected origin of the remote window, may be '*'\n     *                which matches any origin\n     *   cfg.scope  - the 'scope' of messages.  a scope string that is\n     *                prepended to message names.  local and remote endpoints\n     *                of a single channel must agree upon scope. Scope may\n     *                not contain double colons ('::').\n     *   cfg.debugOutput - A boolean value.  If true and window.console.log is\n     *                a function, then debug strings will be emitted to that\n     *                function.\n     *   cfg.postMessageObserver - A function that will be passed two arguments,\n     *                an origin and a message.  It will be passed these immediately\n     *                before messages are posted.\n     *   cfg.gotMessageObserver - A function that will be passed two arguments,\n     *                an origin and a message.  It will be passed these arguments\n     *                immediately after they pass scope and origin checks, but before\n     *                they are processed.\n     *   cfg.onReady - A function that will be invoked when a channel becomes \"ready\",\n     *                this occurs once both sides of the channel have been\n     *                instantiated and an application level handshake is exchanged.\n     *                the onReady function will be passed a single argument which is\n     *                the channel object that was returned from build().\n     *   cfg.reconnect - A boolean value - if true, the channel allows reconnection\n     *                useful when the page in a child frame is reloaded and wants\n     *                to re-establish connection with parent window using the same\n     *                origin, scope and bindings.\n     *   cfg.publish - A boolean value. If true, bind will automatically publish\n     *                the method on the remote side. The method will be published under\n     *                channelObject.remote, but it will not be available before the onReady\n     *                callback is called on the other side.\n     *   cfg.remote - An array of method names for which stubs should be generated without\n     *                waiting for remote end to publish them. A string (for a single method name)\n     *                is also accepted. This allows methods under channelObject.remote to be called\n     *                also before onReady callback is called; the invocations will be queued until\n     *                the channel is ready. If the methods do not exist on remote side, the\n     *                error callback will be called.\n     */\n    return {\n        build: function(cfg) {\n            var debug = function(m) {\n                if (cfg.debugOutput && window.console && window.console.log) {\n                    // try to stringify, if it doesn't work we'll let javascript's built in toString do its magic\n                    try {\n                        if (typeof m !== 'string') {\n                            m = JSON.stringify(m);\n                        }\n                    }\n                    catch(e) {\n                    }\n                    window.console.log(\"[\"+chanId+\"] \" + m);\n                }\n            };\n\n            /* browser capabilities check */\n            if (!window.postMessage) throw(\"jschannel cannot run this browser, no postMessage\");\n            if (!window.JSON || !window.JSON.stringify || ! window.JSON.parse) {\n                throw(\"jschannel cannot run this browser, no JSON parsing/serialization\");\n            }\n\n            /* basic argument validation */\n            if (typeof cfg != 'object') throw(\"Channel build invoked without a proper object argument\");\n\n            if (!cfg.window || !cfg.window.postMessage) throw(\"Channel.build() called without a valid window argument\");\n\n            /* we'd have to do a little more work to be able to run multiple channels that intercommunicate the same\n             * window...  Not sure if we care to support that */\n            if (window === cfg.window) debug(\"target window is same as present window -- use at your own risk\");\n\n            // let's require that the client specify an origin.  if we just assume '*' we'll be\n            // propagating unsafe practices.  that would be lame.\n            var validOrigin = false;\n            if (typeof cfg.origin === 'string') {\n                var oMatch;\n                if (cfg.origin === \"*\") validOrigin = true;\n                // allow valid domains under http and https.  Also, trim paths off otherwise valid origins.\n                else if (null !== (oMatch = cfg.origin.match(/^https?:\\/\\/(?:[-a-zA-Z0-9_\\.])+(?::\\d+)?/))) {\n                    cfg.origin = oMatch[0].toLowerCase();\n                    validOrigin = true;\n                }\n            }\n\n            if (!validOrigin) throw (\"Channel.build() called with an invalid origin\");\n\n            if (typeof cfg.scope !== 'undefined') {\n                if (typeof cfg.scope !== 'string') throw 'scope, when specified, must be a string';\n                if (cfg.scope.split('::').length > 1) throw \"scope may not contain double colons: '::'\";\n            } else {\n                cfg.scope = \"__default\";\n            }\n\n            /* private variables */\n            // generate a random and psuedo unique id for this channel\n            var chanId = (function () {\n                var text = \"\";\n                var alpha = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\";\n                for(var i=0; i < 5; i++) text += alpha.charAt(Math.floor(Math.random() * alpha.length));\n                return text;\n            })();\n\n            // registrations: mapping method names to call objects\n            var regTbl = { };\n            // current oustanding sent requests\n            var outTbl = { };\n            // current oustanding received requests\n            var inTbl = { };\n            // are we ready yet?  when false we will block outbound messages.\n            var ready = false;\n            var pendingQueue = [ ];\n            var publishQueue = [ ];\n\n            var createTransaction = function(id,origin,callbacks) {\n                var shouldDelayReturn = false;\n                var completed = false;\n\n                return {\n                    origin: origin,\n                    invoke: function(cbName, v) {\n                        // verify in table\n                        if (!inTbl[id]) throw \"attempting to invoke a callback of a nonexistent transaction: \" + id;\n                        // verify that the callback name is valid\n                        var valid = false;\n                        for (var i = 0; i < callbacks.length; i++) if (cbName === callbacks[i]) { valid = true; break; }\n                        if (!valid) throw \"request supports no such callback '\" + cbName + \"'\";\n\n                        // send callback invocation\n                        postMessage({ id: id, callback: cbName, params: v});\n                    },\n                    error: function(error, message) {\n                        completed = true;\n                        // verify in table\n                        if (!inTbl[id]) throw \"error called for nonexistent message: \" + id;\n\n                        // remove transaction from table\n                        delete inTbl[id];\n\n                        // send error\n                        postMessage({ id: id, error: error, message: message });\n                    },\n                    complete: function(v) {\n                        completed = true;\n                        // verify in table\n                        if (!inTbl[id]) throw \"complete called for nonexistent message: \" + id;\n                        // remove transaction from table\n                        delete inTbl[id];\n                        // send complete\n                        postMessage({ id: id, result: v });\n                    },\n                    delayReturn: function(delay) {\n                        if (typeof delay === 'boolean') {\n                            shouldDelayReturn = (delay === true);\n                        }\n                        return shouldDelayReturn;\n                    },\n                    completed: function() {\n                        return completed;\n                    }\n                };\n            };\n\n            var setTransactionTimeout = function(transId, timeout, method) {\n              return window.setTimeout(function() {\n                if (outTbl[transId]) {\n                  // XXX: what if client code raises an exception here?\n                  var msg = \"timeout (\" + timeout + \"ms) exceeded on method '\" + method + \"'\";\n                  if (outTbl[transId].error) {\n                      outTbl[transId].error(\"timeout_error\", msg);\n                  }\n                  delete outTbl[transId];\n                  delete s_transIds[transId];\n                }\n              }, timeout);\n            };\n\n            var onMessage = function(origin, method, m) {\n                // if an observer was specified at allocation time, invoke it\n                if (typeof cfg.gotMessageObserver === 'function') {\n                    // pass observer a clone of the object so that our\n                    // manipulations are not visible (i.e. method unscoping).\n                    // This is not particularly efficient, but then we expect\n                    // that message observers are primarily for debugging anyway.\n                    try {\n                        cfg.gotMessageObserver(origin, m);\n                    } catch (e) {\n                        debug(\"gotMessageObserver() raised an exception: \" + e.toString());\n                    }\n                }\n\n                // now, what type of message is this?\n                if (m.id && method) {\n                    inTbl[m.id] = { };\n                    var trans = createTransaction(m.id, origin, m.callbacks ? m.callbacks : [ ]);\n                    // a request!  do we have a registered handler for this request?\n                    if (regTbl[method]) {\n                        try {\n                            // callback handling.  we'll magically create functions inside the parameter list for each\n                            // callback\n                            if (m.callbacks && s_isArray(m.callbacks) && m.callbacks.length > 0) {\n                                for (var i = 0; i < m.callbacks.length; i++) {\n                                    var path = m.callbacks[i];\n                                    var obj = m.params;\n                                    var pathItems = path.split('/');\n                                    for (var j = 0; j < pathItems.length - 1; j++) {\n                                        var cp = pathItems[j];\n                                        if (typeof obj[cp] !== 'object') obj[cp] = { };\n                                        obj = obj[cp];\n                                    }\n                                    obj[pathItems[pathItems.length - 1]] = (function() {\n                                        var cbName = path;\n                                        return function(params) {\n                                            return trans.invoke(cbName, params);\n                                        };\n                                    })();\n                                }\n                            }\n                            var resp = regTbl[method](trans, m.params);\n                            if (!trans.delayReturn() && !trans.completed()) trans.complete(resp);\n                        } catch(e) {\n                            // automagic handling of exceptions:\n                            var error = \"runtime_error\";\n                            var message = null;\n                            // * if it's a string then it gets an error code of 'runtime_error' and string is the message\n                            if (typeof e === 'string') {\n                                message = e;\n                            } else if (typeof e === 'object') {\n                                // if it's an Error instance we use the constructor name to set the error property\n                                // and we just copy the error message\n                                if (e instanceof Error) {\n                                    error = e.constructor.name;\n                                    message = e.message;\n                                }\n                                // Otherwise, it's either an array or an object\n                                // * if it's an array of length two, then  array[0] is the code, array[1] is the error message\n                                else if (e && s_isArray(e) && e.length == 2) {\n                                    error = e[0];\n                                    message = e[1];\n                                }\n                                // * if it's an object then we'll look form error and message parameters\n                                else if (typeof e.error === 'string') {\n                                    error = e.error;\n                                    if (!e.message) message = \"\";\n                                    else if (typeof e.message === 'string') message = e.message;\n                                    else e = e.message; // let the stringify/toString message give us a reasonable verbose error string\n                                }\n                            }\n\n                            // message is *still* null, let's try harder\n                            if (message === null) {\n                                try {\n                                    message = JSON.stringify(e);\n                                    /* On MSIE8, this can result in 'out of memory', which\n                                     * leaves message undefined. */\n                                    if (typeof(message) == 'undefined')\n                                      message = e.toString();\n                                } catch (e2) {\n                                    message = e.toString();\n                                }\n                            }\n\n                            trans.error(error,message);\n                        }\n                    } else { // if no method found, send error\n                        trans.error(\"method_not_found\", \"No method '\" + method + \"' was (yet) bound by the provider\");\n                    }\n                } else if (m.id && m.callback) {\n                    if (!outTbl[m.id] ||!outTbl[m.id].callbacks || !outTbl[m.id].callbacks[m.callback])\n                    {\n                        debug(\"ignoring invalid callback, id:\"+m.id+ \" (\" + m.callback +\")\");\n                    } else {\n                        // XXX: what if client code raises an exception here?\n                        outTbl[m.id].callbacks[m.callback](m.params);\n                    }\n                } else if (m.id) {\n                    if (!outTbl[m.id]) {\n                        debug(\"ignoring invalid response: \" + m.id);\n                    } else {\n                        // XXX: what if client code raises an exception here?\n                        if (m.error) {\n                            // We might not have an error callback\n                            if(outTbl[m.id].error) {\n                                outTbl[m.id].error(m.error, m.message);\n                            }\n                        } else {\n                            // But we always have a success callback\n                            if (m.result !== undefined) {\n                                outTbl[m.id].success(m.result);\n                            } else {\n                                outTbl[m.id].success();\n                            }\n                        }\n                        delete outTbl[m.id];\n                        delete s_transIds[m.id];\n                    }\n                } else if (method) {\n                    // tis a notification.\n                    if (regTbl[method]) {\n                        // yep, there's a handler for that.\n                        // transaction has only origin for notifications.\n                        regTbl[method]({ origin: origin }, m.params);\n                        // if the client throws, we'll just let it bubble out\n                        // what can we do?  Also, here we'll ignore return values\n                    }\n                }\n            };\n\n            // now register our bound channel for msg routing\n            s_addBoundChan(cfg.window, cfg.origin, cfg.scope, onMessage);\n\n            // scope method names based on cfg.scope specified when the Channel was instantiated\n            var scopeMethod = function(m) {\n                return [cfg.scope, m].join(\"::\");\n            };\n\n            // a small wrapper around postmessage whose primary function is to handle the\n            // case that clients start sending messages before the other end is \"ready\"\n            var postMessage = function(msg, force) {\n                if (!msg) throw \"postMessage called with null message\";\n\n                // delay posting if we're not ready yet.\n                if (!force && !ready) {\n                    debug(\"queue message: \" + JSON.stringify(msg));\n                    pendingQueue.push(msg);\n                } else {\n                    if (typeof cfg.postMessageObserver === 'function') {\n                        try {\n                            cfg.postMessageObserver(cfg.origin, msg);\n                        } catch (e) {\n                            debug(\"postMessageObserver() raised an exception: \" + e.toString());\n                        }\n                    }\n                    debug(\"post message: \" + JSON.stringify(msg) + \" with origin \" + cfg.origin);\n                    cfg.window.postMessage(JSON.stringify(msg), cfg.origin);\n                }\n            };\n\n            var onReady = function(trans, params) {\n                debug('ready msg received');\n                if (ready && !cfg.reconnect) {\n                    throw \"received ready message while in ready state.\";\n                }\n                ready = true;\n\n                // only append suffix to chanId once:\n                if (chanId.length < 6) {\n\t                if (params.type === 'publish-request') {\n\t                    chanId += '-R';\n\t                } else {\n\t                    chanId += '-L';\n\t                }\n                }\n                debug('ready msg accepted.');\n\n                if (params.type === 'publish-request') {\n                    obj.notify({ method: '__ready', params: {\n                        type:'publish-reply',\n                        publish: publishQueue\n                    } });\n                }\n\n                for (var i = 0; i < params.publish.length; i++) {\n                    if (params.publish[i].action === \"bind\") {\n                        createStubs([params.publish[i].method], obj.remote);\n                    } else { // unbind\n                        delete obj.remote[params.publish[i].method];\n                    }\n                }\n\n                //unbind ready handler unless we allow reconnecting:\n                if (!cfg.reconnect) {\n                    obj.unbind('__ready', true); // now this handler isn't needed any more.\n                }\n\n                // flush queue\n                while (pendingQueue.length) {\n                    postMessage(pendingQueue.splice(0, 1)[0]);\n                }\n                publishQueue = [];\n                // invoke onReady observer if provided\n                if (typeof cfg.onReady === 'function') cfg.onReady(obj);\n\n            };\n\n            var createStubs = function(stubList, targetObj) {\n                stubList = [].concat(stubList); // Coerce into array, allows string to be used for single-item array\n                var method;\n                for(var i=0; i < stubList.length; i++) {\n                    method = stubList[i].toString();\n                    targetObj[method] = function(m) {\n                        return function(params, success, error) {\n                            if (success) {\n                                obj.call({\n                                    method: m,\n                                    params: params,\n                                    success: success,\n                                    error: error\n                                });\n                            } else {\n                                obj.notify({\n                                    method: m,\n                                    params: params\n                                });\n                            }\n                        };\n                    }(method);\n                }\n            }\n\n            // Dynamic publish from remote\n            var onBind = function(trans, method) {\n                createStubs([method], obj.remote);\n            };\n\n            // Dynamic unpublish from remote\n            var onUnbind = function(trans, method) {\n                if (obj.remote[method]) {\n                    delete obj.remote[method];\n                }\n            };\n\n            var obj = {\n\n                remote: {},\n\n                // tries to unbind a bound message handler.  returns false if not possible\n                unbind: function (method, doNotPublish) {\n                    if (regTbl[method]) {\n                        if (!(delete regTbl[method])) throw (\"can't delete method: \" + method);\n                        if (cfg.publish && ! doNotPublish) {\n                            if (ready) {\n                                obj.notify({ method: '__unbind', params: method });\n                            } else {\n                                publishQueue.push({ action: 'unbind', method: method });\n                            }\n                        }\n                        return true;\n                    }\n                    return false;\n                },\n                bind: function (method, cb, doNotPublish) {\n                    if (!method || typeof method !== 'string') throw \"'method' argument to bind must be string\";\n                    if (!cb || typeof cb !== 'function') throw \"callback missing from bind params\";\n\n                    if (regTbl[method]) throw \"method '\"+method+\"' is already bound!\";\n                    regTbl[method] = cb;\n                    if (cfg.publish && ! doNotPublish) {\n                        if (ready) {\n                            obj.notify({ method: '__bind', params: method });\n                        } else {\n                            publishQueue.push({ action: 'bind', method: method });\n                        }\n                    }\n                    return this;\n                },\n                call: function(m) {\n                    if (!m) throw 'missing arguments to call function';\n                    if (!m.method || typeof m.method !== 'string') throw \"'method' argument to call must be string\";\n                    if (!m.success || typeof m.success !== 'function') throw \"'success' callback missing from call\";\n\n                    // now it's time to support the 'callback' feature of jschannel.  We'll traverse the argument\n                    // object and pick out all of the functions that were passed as arguments.\n                    var callbacks = { };\n                    var callbackNames = [ ];\n                    var seen = [ ];\n\n                    var pruneFunctions = function (path, obj) {\n                        if (seen.indexOf(obj) >= 0) {\n                            throw \"params cannot be a recursive data structure\"\n                        }\n                        if(obj) {\n                            seen.push(obj);\n                        }\n\n                        if (typeof obj === 'object') {\n                            for (var k in obj) {\n                                if (!obj.hasOwnProperty(k)) continue;\n                                var np = path + (path.length ? '/' : '') + k;\n                                if (typeof obj[k] === 'function') {\n                                    callbacks[np] = obj[k];\n                                    callbackNames.push(np);\n                                    delete obj[k];\n                                } else if (typeof obj[k] === 'object') {\n                                    pruneFunctions(np, obj[k]);\n                                }\n                            }\n                        }\n                    };\n                    pruneFunctions(\"\", m.params);\n\n                    // build a 'request' message and send it\n                    var msg = { id: s_curTranId, method: scopeMethod(m.method), params: m.params };\n                    if (callbackNames.length) msg.callbacks = callbackNames;\n\n                    if (m.timeout)\n                      // XXX: This function returns a timeout ID, but we don't do anything with it.\n                      // We might want to keep track of it so we can cancel it using clearTimeout()\n                      // when the transaction completes.\n                      setTransactionTimeout(s_curTranId, m.timeout, scopeMethod(m.method));\n\n                    // insert into the transaction table\n                    outTbl[s_curTranId] = { callbacks: callbacks, error: m.error, success: m.success };\n                    s_transIds[s_curTranId] = onMessage;\n\n                    // increment current id\n                    s_curTranId++;\n\n                    postMessage(msg);\n                },\n                notify: function(m) {\n                    if (!m) throw 'missing arguments to notify function';\n                    if (!m.method || typeof m.method !== 'string') throw \"'method' argument to notify must be string\";\n\n                    // no need to go into any transaction table\n                    postMessage({ method: scopeMethod(m.method), params: m.params });\n                },\n                destroy: function () {\n                    s_removeBoundChan(cfg.window, cfg.origin, cfg.scope);\n                    if (window.removeEventListener) window.removeEventListener('message', onMessage, false);\n                    else if(window.detachEvent) window.detachEvent('onmessage', onMessage);\n                    ready = false;\n                    regTbl = { };\n                    inTbl = { };\n                    outTbl = { };\n                    cfg.origin = null;\n                    pendingQueue = [ ];\n                    debug(\"channel destroyed\");\n                    chanId = \"\";\n                }\n            };\n\n            obj.bind('__ready', onReady, true);\n            obj.bind('__bind', onBind, true);\n            obj.bind('__unbind', onUnbind, true);\n            if (cfg.remote) {\n                createStubs(cfg.remote, obj.remote);\n            }\n            setTimeout(function() {\n                if (chanId.length > 0) { // The channel might already have been destroyed\n                    postMessage({ method: scopeMethod('__ready'), params: {\n                        type: \"publish-request\",\n                        publish: publishQueue\n                    } }, true);\n                }\n\n            }, 0);\n\n            return obj;\n        }\n    };\n  })();\n\n\n  return Channel;\n}));\n"]}