(function (global, undefined) { "use strict"; var tasks = (function () { function Task(handler, args) { this.handler = handler; this.args = Array.prototype.slice.call(args); } Task.prototype.run = function () { // See steps in section 5 of the spec. if (typeof this.handler === "function") { // Choice of `thisArg` is not in the setImmediate spec; `undefined` is in the setTimeout spec though: // http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html this.handler.apply(undefined, this.args); } else { var scriptSource = "" + this.handler; /*jshint evil: true */ eval(scriptSource); } }; var nextHandle = 1; // Spec says greater than zero var tasksByHandle = {}; var currentlyRunningATask = false; return { addFromSetImmediateArguments: function (args) { var handler = args[0]; var argsToHandle = Array.prototype.slice.call(args, 1); var task = new Task(handler, argsToHandle); var thisHandle = nextHandle++; tasksByHandle[thisHandle] = task; return thisHandle; }, runIfPresent: function (handle) { // From the spec: "Wait until any invocations of this algorithm started before this one have completed." // So if we're currently running a task, we'll need to delay this invocation. if (!currentlyRunningATask) { var task = tasksByHandle[handle]; if (task) { currentlyRunningATask = true; try { task.run(); } finally { delete tasksByHandle[handle]; currentlyRunningATask = false; } } } else { // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a // "too much recursion" error. global.setTimeout(function () { tasks.runIfPresent(handle); }, 0); } }, remove: function (handle) { delete tasksByHandle[handle]; } }; }()); function canUseNextTick() { // Don't get fooled by e.g. browserify environments. return typeof process === "object" && Object.prototype.toString.call(process) === "[object process]"; } function canUseMessageChannel() { return !!global.MessageChannel; } function canUsePostMessage() { // The test against `importScripts` prevents this implementation from being installed inside a web worker, // where `global.postMessage` means something completely different and can't be used for this purpose. if (!global.postMessage || global.importScripts) { return false; } var postMessageIsAsynchronous = true; var oldOnMessage = global.onmessage; global.onmessage = function () { postMessageIsAsynchronous = false; }; global.postMessage("", "*"); global.onmessage = oldOnMessage; return postMessageIsAsynchronous; } function canUseReadyStateChange() { return "document" in global && "onreadystatechange" in global.document.createElement("script"); } function installNextTickImplementation(attachTo) { attachTo.setImmediate = function () { var handle = tasks.addFromSetImmediateArguments(arguments); process.nextTick(function () { tasks.runIfPresent(handle); }); return handle; }; } function installMessageChannelImplementation(attachTo) { var channel = new global.MessageChannel(); channel.port1.onmessage = function (event) { var handle = event.data; tasks.runIfPresent(handle); }; attachTo.setImmediate = function () { var handle = tasks.addFromSetImmediateArguments(arguments); channel.port2.postMessage(handle); return handle; }; } function installPostMessageImplementation(attachTo) { // Installs an event handler on `global` for the `message` event: see // * https://developer.mozilla.org/en/DOM/window.postMessage // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages var MESSAGE_PREFIX = "com.bn.NobleJS.setImmediate" + Math.random(); function isStringAndStartsWith(string, putativeStart) { return typeof string === "string" && string.substring(0, putativeStart.length) === putativeStart; } function onGlobalMessage(event) { // This will catch all incoming messages (even from other windows!), so we need to try reasonably hard to // avoid letting anyone else trick us into firing off. We test the origin is still this window, and that a // (randomly generated) unpredictable identifying prefix is present. if (event.source === global && isStringAndStartsWith(event.data, MESSAGE_PREFIX)) { var handle = event.data.substring(MESSAGE_PREFIX.length); tasks.runIfPresent(handle); } } if (global.addEventListener) { global.addEventListener("message", onGlobalMessage, false); } else { global.attachEvent("onmessage", onGlobalMessage); } attachTo.setImmediate = function () { var handle = tasks.addFromSetImmediateArguments(arguments); // Make `global` post a message to itself with the handle and identifying prefix, thus asynchronously // invoking our onGlobalMessage listener above. global.postMessage(MESSAGE_PREFIX + handle, "*"); return handle; }; } function installReadyStateChangeImplementation(attachTo) { attachTo.setImmediate = function () { var handle = tasks.addFromSetImmediateArguments(arguments); // Create a