text: /** @license MIT License (c) copyright 2011-2013 original author or authors */
  
  /**
   * A lightweight CommonJS Promises/A and when() implementation
   * when is part of the cujo.js family of libraries (http://cujojs.com/)
   *
   * Licensed under the MIT License at:
   * http://www.opensource.org/licenses/mit-license.php
   *
   * @author Brian Cavalier
   * @author John Hann
   * @version 2.4.0
   */
  var when=(function(global) { 
  
      'use strict';
      var when;
      // Public API
  
      when.promise   = promise;    // Create a pending promise
      when.resolve   = resolve;    // Create a resolved promise
      when.reject    = reject;     // Create a rejected promise
      when.defer     = defer;      // Create a {promise, resolver} pair
  
      when.join      = join;       // Join 2 or more promises
  
      when.all       = all;        // Resolve a list of promises
      when.map       = map;        // Array.map() for promises
      when.reduce    = reduce;     // Array.reduce() for promises
      when.settle    = settle;     // Settle a list of promises
  
      when.any       = any;        // One-winner race
      when.some      = some;       // Multi-winner race
  
      when.isPromise = isPromiseLike;  // DEPRECATED: use isPromiseLike
      when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable
  
      /**
       * Register an observer for a promise or immediate value.
       *
       * @param {*} promiseOrValue
       * @param {function?} [onFulfilled] callback to be called when promiseOrValue is
       *   successfully fulfilled.  If promiseOrValue is an immediate value, callback
       *   will be invoked immediately.
       * @param {function?} [onRejected] callback to be called when promiseOrValue is
       *   rejected.
       * @param {function?} [onProgress] callback to be called when progress updates
       *   are issued for promiseOrValue.
       * @returns {Promise} a new {@link Promise} that will complete with the return
       *   value of callback or errback or the completion value of promiseOrValue if
       *   callback and/or errback is not supplied.
       */
      function when(promiseOrValue, onFulfilled, onRejected, onProgress) {
  	// Get a trusted promise for the input promiseOrValue, and then
  	// register promise handlers
  	return resolve(promiseOrValue).then(onFulfilled, onRejected, onProgress);
      }
  
      /**
       * Trusted Promise constructor.  A Promise created from this constructor is
       * a trusted when.js promise.  Any other duck-typed promise is considered
       * untrusted.
       * @constructor
       * @param {function} sendMessage function to deliver messages to the promise's handler
       * @param {function?} inspect function that reports the promise's state
       * @name Promise
       */
      function Promise(sendMessage, inspect) {
  	this._message = sendMessage;
  	this.inspect = inspect;
      }
  
      Promise.prototype = {
  	/**
  	 * Register handlers for this promise.
  	 * @param [onFulfilled] {Function} fulfillment handler
  	 * @param [onRejected] {Function} rejection handler
  	 * @param [onProgress] {Function} progress handler
  	 * @return {Promise} new Promise
  	 */
  	then: function(onFulfilled, onRejected, onProgress) {
  	    /*jshint unused:false*/
  	    var args, sendMessage;
  
  	    args = arguments;
  	    sendMessage = this._message;
  
  	    return _promise(function(resolve, reject, notify) {
  		sendMessage('when', args, resolve, notify);
  	    }, this._status && this._status.observed());
  	},
  
  	/**
  	 * Register a rejection handler.  Shortcut for .then(undefined, onRejected)
  	 * @param {function?} onRejected
  	 * @return {Promise}
  	 */
  	otherwise: function(onRejected) {
  	    return this.then(undef, onRejected);
  	},
  
  	/**
  	 * Ensures that onFulfilledOrRejected will be called regardless of whether
  	 * this promise is fulfilled or rejected.  onFulfilledOrRejected WILL NOT
  	 * receive the promises' value or reason.  Any returned value will be disregarded.
  	 * onFulfilledOrRejected may throw or return a rejected promise to signal
  	 * an additional error.
  	 * @param {function} onFulfilledOrRejected handler to be called regardless of
  	 *  fulfillment or rejection
  	 * @returns {Promise}
  	 */
  	ensure: function(onFulfilledOrRejected) {
  	    return this.then(injectHandler, injectHandler)['yield'](this);
  
  	    function injectHandler() {
  		return resolve(onFulfilledOrRejected());
  	    }
  	},
  
  	/**
  	 * Shortcut for .then(function() { return value; })
  	 * @param  {*} value
  	 * @return {Promise} a promise that:
  	 *  - is fulfilled if value is not a promise, or
  	 *  - if value is a promise, will fulfill with its value, or reject
  	 *    with its reason.
  	 */
  	'yield': function(value) {
  	    return this.then(function() {
  		return value;
  	    });
  	},
  
  	/**
  	 * Runs a side effect when this promise fulfills, without changing the
  	 * fulfillment value.
  	 * @param {function} onFulfilledSideEffect
  	 * @returns {Promise}
  	 */
  	tap: function(onFulfilledSideEffect) {
  	    return this.then(onFulfilledSideEffect)['yield'](this);
  	},
  
  	/**
  	 * Assumes that this promise will fulfill with an array, and arranges
  	 * for the onFulfilled to be called with the array as its argument list
  	 * i.e. onFulfilled.apply(undefined, array).
  	 * @param {function} onFulfilled function to receive spread arguments
  	 * @return {Promise}
  	 */
  	spread: function(onFulfilled) {
  	    return this.then(function(array) {
  		// array may contain promises, so resolve its contents.
  		return all(array, function(array) {
  		    return onFulfilled.apply(undef, array);
  		});
  	    });
  	},
  
  	/**
  	 * Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected)
  	 * @deprecated
  	 */
  	always: function(onFulfilledOrRejected, onProgress) {
  	    return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress);
  	}
      };
  
      /**
       * Returns a resolved promise. The returned promise will be
       *  - fulfilled with promiseOrValue if it is a value, or
       *  - if promiseOrValue is a promise
       *    - fulfilled with promiseOrValue's value after it is fulfilled
       *    - rejected with promiseOrValue's reason after it is rejected
       * @param  {*} value
       * @return {Promise}
       */
      function resolve(value) {
  	return promise(function(resolve) {
  	    resolve(value);
  	});
      }
  
      /**
       * Returns a rejected promise for the supplied promiseOrValue.  The returned
       * promise will be rejected with:
       * - promiseOrValue, if it is a value, or
       * - if promiseOrValue is a promise
       *   - promiseOrValue's value after it is fulfilled
       *   - promiseOrValue's reason after it is rejected
       * @param {*} promiseOrValue the rejected value of the returned {@link Promise}
       * @return {Promise} rejected {@link Promise}
       */
      function reject(promiseOrValue) {
  	return when(promiseOrValue, rejected);
      }
  
      /**
       * Creates a {promise, resolver} pair, either or both of which
       * may be given out safely to consumers.
       * The resolver has resolve, reject, and progress.  The promise
       * has then plus extended promise API.
       *
       * @return {{
       * promise: Promise,
       * resolve: function:Promise,
       * reject: function:Promise,
       * notify: function:Promise
       * resolver: {
       *	resolve: function:Promise,
       *	reject: function:Promise,
       *	notify: function:Promise
       * }}}
       */
      function defer() {
  	var deferred, pending, resolved;
  
  	// Optimize object shape
  	deferred = {
  	    promise: undef, resolve: undef, reject: undef, notify: undef,
  	    resolver: { resolve: undef, reject: undef, notify: undef }
  	};
  
  	deferred.promise = pending = promise(makeDeferred);
  
  	return deferred;
  
  	function makeDeferred(resolvePending, rejectPending, notifyPending) {
  	    deferred.resolve = deferred.resolver.resolve = function(value) {
  		if(resolved) {
  		    return resolve(value);
  		}
  		resolved = true;
  		resolvePending(value);
  		return pending;
  	    };
  
  	    deferred.reject  = deferred.resolver.reject  = function(reason) {
  		if(resolved) {
  		    return resolve(rejected(reason));
  		}
  		resolved = true;
  		rejectPending(reason);
  		return pending;
  	    };
  
  	    deferred.notify  = deferred.resolver.notify  = function(update) {
  		notifyPending(update);
  		return update;
  	    };
  	}
      }
  
      /**
       * Creates a new promise whose fate is determined by resolver.
       * @param {function} resolver function(resolve, reject, notify)
       * @returns {Promise} promise whose fate is determine by resolver
       */
      function promise(resolver) {
  	return _promise(resolver, monitorApi.PromiseStatus && monitorApi.PromiseStatus());
      }
  
      /**
       * Creates a new promise, linked to parent, whose fate is determined
       * by resolver.
       * @param {function} resolver function(resolve, reject, notify)
       * @param {Promise?} status promise from which the new promise is begotten
       * @returns {Promise} promise whose fate is determine by resolver
       * @private
       */
      function _promise(resolver, status) {
  	var self, value, consumers = [];
  
  	self = new Promise(_message, inspect);
  	self._status = status;
  
  	// Call the provider resolver to seal the promise's fate
  	try {
  	    resolver(promiseResolve, promiseReject, promiseNotify);
  	} catch(e) {
  	    promiseReject(e);
  	}
  
  	// Return the promise
  	return self;
  
  	/**
  	 * Private message delivery. Queues and delivers messages to
  	 * the promise's ultimate fulfillment value or rejection reason.
  	 * @private
  	 * @param {String} type
  	 * @param {Array} args
  	 * @param {Function} resolve
  	 * @param {Function} notify
  	 */
  	function _message(type, args, resolve, notify) {
  	    consumers ? consumers.push(deliver) : enqueue(function() { deliver(value); });
  
  	    function deliver(p) {
  		p._message(type, args, resolve, notify);
  	    }
  	}
  
  	/**
  	 * Returns a snapshot of the promise's state at the instant inspect()
  	 * is called. The returned object is not live and will not update as
  	 * the promise's state changes.
  	 * @returns {{ state:String, value?:*, reason?:* }} status snapshot
  	 *  of the promise.
  	 */
  	function inspect() {
  	    return value ? value.inspect() : toPendingState();
  	}
  
  	/**
  	 * Transition from pre-resolution state to post-resolution state, notifying
  	 * all listeners of the ultimate fulfillment or rejection
  	 * @param {*|Promise} val resolution value
  	 */
  	function promiseResolve(val) {
  	    if(!consumers) {
  		return;
  	    }
  
  	    value = coerce(val);
  	    scheduleConsumers(consumers, value);
  	    consumers = undef;
  
  	    if(status) {
  		updateStatus(value, status);
  	    }
  	}
  
  	/**
  	 * Reject this promise with the supplied reason, which will be used verbatim.
  	 * @param {*} reason reason for the rejection
  	 */
  	function promiseReject(reason) {
  	    promiseResolve(rejected(reason));
  	}
  
  	/**
  	 * Issue a progress event, notifying all progress listeners
  	 * @param {*} update progress event payload to pass to all listeners
  	 */
  	function promiseNotify(update) {
  	    if(consumers) {
  		scheduleConsumers(consumers, progressed(update));
  	    }
  	}
      }
  
      /**
       * Creates a fulfilled, local promise as a proxy for a value
       * NOTE: must never be exposed
       * @param {*} value fulfillment value
       * @returns {Promise}
       */
      function fulfilled(value) {
  	return near(
  	    new NearFulfilledProxy(value),
  	    function() { return toFulfilledState(value); }
  	);
      }
  
      /**
       * Creates a rejected, local promise with the supplied reason
       * NOTE: must never be exposed
       * @param {*} reason rejection reason
       * @returns {Promise}
       */
      function rejected(reason) {
  	return near(
  	    new NearRejectedProxy(reason),
  	    function() { return toRejectedState(reason); }
  	);
      }
  
      /**
       * Creates a near promise using the provided proxy
       * NOTE: must never be exposed
       * @param {object} proxy proxy for the promise's ultimate value or reason
       * @param {function} inspect function that returns a snapshot of the
       *  returned near promise's state
       * @returns {Promise}
       */
      function near(proxy, inspect) {
  	return new Promise(function (type, args, resolve) {
  	    try {
  		resolve(proxy[type].apply(proxy, args));
  	    } catch(e) {
  		resolve(rejected(e));
  	    }
  	}, inspect);
      }
  
      /**
       * Create a progress promise with the supplied update.
       * @private
       * @param {*} update
       * @return {Promise} progress promise
       */
      function progressed(update) {
  	return new Promise(function (type, args, _, notify) {
  	    var onProgress = args[2];
  	    try {
  		notify(typeof onProgress === 'function' ? onProgress(update) : update);
  	    } catch(e) {
  		notify(e);
  	    }
  	});
      }
  
      /**
       * Coerces x to a trusted Promise
       *
       * @private
       * @param {*} x thing to coerce
       * @returns {*} Guaranteed to return a trusted Promise.  If x
       *   is trusted, returns x, otherwise, returns a new, trusted, already-resolved
       *   Promise whose resolution value is:
       *   * the resolution value of x if it's a foreign promise, or
       *   * x if it's a value
       */
      function coerce(x) {
  	if (x instanceof Promise) {
  	    return x;
  	}
  
  	if (!(x === Object(x) && 'then' in x)) {
  	    return fulfilled(x);
  	}
  
  	return promise(function(resolve, reject, notify) {
  	    enqueue(function() {
  		try {
  		    // We must check and assimilate in the same tick, but not the
  		    // current tick, careful only to access promiseOrValue.then once.
  		    var untrustedThen = x.then;
  
  		    if(typeof untrustedThen === 'function') {
  			fcall(untrustedThen, x, resolve, reject, notify);
  		    } else {
  			// It's a value, create a fulfilled wrapper
  			resolve(fulfilled(x));
  		    }
  
  		} catch(e) {
  		    // Something went wrong, reject
  		    reject(e);
  		}
  	    });
  	});
      }
  
      /**
       * Proxy for a near, fulfilled value
       * @param {*} value
       * @constructor
       */
      function NearFulfilledProxy(value) {
  	this.value = value;
      }
  
      NearFulfilledProxy.prototype.when = function(onResult) {
  	return typeof onResult === 'function' ? onResult(this.value) : this.value;
      };
  
      /**
       * Proxy for a near rejection
       * @param {*} reason
       * @constructor
       */
      function NearRejectedProxy(reason) {
  	this.reason = reason;
      }
  
      NearRejectedProxy.prototype.when = function(_, onError) {
  	if(typeof onError === 'function') {
  	    return onError(this.reason);
  	} else {
  	    throw this.reason;
  	}
      };
  
      /**
       * Schedule a task that will process a list of handlers
       * in the next queue drain run.
       * @private
       * @param {Array} handlers queue of handlers to execute
       * @param {*} value passed as the only arg to each handler
       */
      function scheduleConsumers(handlers, value) {
  	enqueue(function() {
  	    var handler, i = 0;
  	    while (handler = handlers[i++]) {
  		handler(value);
  	    }
  	});
      }
  
      function updateStatus(value, status) {
  	value.then(statusFulfilled, statusRejected);
  
  	function statusFulfilled() { status.fulfilled(); }
  	function statusRejected(r) { status.rejected(r); }
      }
  
      /**
       * Determines if x is promise-like, i.e. a thenable object
       * NOTE: Will return true for *any thenable object*, and isn't truly
       * safe, since it may attempt to access the `then` property of x (i.e.
       *  clever/malicious getters may do weird things)
       * @param {*} x anything
       * @returns {boolean} true if x is promise-like
       */
      function isPromiseLike(x) {
  	return x && typeof x.then === 'function';
      }
  
      /**
       * Initiates a competitive race, returning a promise that will resolve when
       * howMany of the supplied promisesOrValues have resolved, or will reject when
       * it becomes impossible for howMany to resolve, for example, when
       * (promisesOrValues.length - howMany) + 1 input promises reject.
       *
       * @param {Array} promisesOrValues array of anything, may contain a mix
       *      of promises and values
       * @param howMany {number} number of promisesOrValues to resolve
       * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
       * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
       * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
       * @returns {Promise} promise that will resolve to an array of howMany values that
       *  resolved first, or will reject with an array of
       *  (promisesOrValues.length - howMany) + 1 rejection reasons.
       */
      function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) {
  
  	return when(promisesOrValues, function(promisesOrValues) {
  
  	    return promise(resolveSome).then(onFulfilled, onRejected, onProgress);
  
  	    function resolveSome(resolve, reject, notify) {
  		var toResolve, toReject, values, reasons, fulfillOne, rejectOne, len, i;
  
  		len = promisesOrValues.length >>> 0;
  
  		toResolve = Math.max(0, Math.min(howMany, len));
  		values = [];
  
  		toReject = (len - toResolve) + 1;
  		reasons = [];
  
  		// No items in the input, resolve immediately
  		if (!toResolve) {
  		    resolve(values);
  
  		} else {
  		    rejectOne = function(reason) {
  			reasons.push(reason);
  			if(!--toReject) {
  			    fulfillOne = rejectOne = identity;
  			    reject(reasons);
  			}
  		    };
  
  		    fulfillOne = function(val) {
  			// This orders the values based on promise resolution order
  			values.push(val);
  			if (!--toResolve) {
  			    fulfillOne = rejectOne = identity;
  			    resolve(values);
  			}
  		    };
  
  		    for(i = 0; i < len; ++i) {
  			if(i in promisesOrValues) {
  			    when(promisesOrValues[i], fulfiller, rejecter, notify);
  			}
  		    }
  		}
  
  		function rejecter(reason) {
  		    rejectOne(reason);
  		}
  
  		function fulfiller(val) {
  		    fulfillOne(val);
  		}
  	    }
  	});
      }
  
      /**
       * Initiates a competitive race, returning a promise that will resolve when
       * any one of the supplied promisesOrValues has resolved or will reject when
       * *all* promisesOrValues have rejected.
       *
       * @param {Array|Promise} promisesOrValues array of anything, may contain a mix
       *      of {@link Promise}s and values
       * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
       * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
       * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
       * @returns {Promise} promise that will resolve to the value that resolved first, or
       * will reject with an array of all rejected inputs.
       */
      function any(promisesOrValues, onFulfilled, onRejected, onProgress) {
  
  	function unwrapSingleResult(val) {
  	    return onFulfilled ? onFulfilled(val[0]) : val[0];
  	}
  
  	return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress);
      }
  
      /**
       * Return a promise that will resolve only once all the supplied promisesOrValues
       * have resolved. The resolution value of the returned promise will be an array
       * containing the resolution values of each of the promisesOrValues.
       * @memberOf when
       *
       * @param {Array|Promise} promisesOrValues array of anything, may contain a mix
       *      of {@link Promise}s and values
       * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then()
       * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then()
       * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then()
       * @returns {Promise}
       */
      function all(promisesOrValues, onFulfilled, onRejected, onProgress) {
  	return _map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress);
      }
  
      /**
       * Joins multiple promises into a single returned promise.
       * @return {Promise} a promise that will fulfill when *all* the input promises
       * have fulfilled, or will reject when *any one* of the input promises rejects.
       */
      function join(/* ...promises */) {
  	return _map(arguments, identity);
      }
  
      /**
       * Settles all input promises such that they are guaranteed not to
       * be pending once the returned promise fulfills. The returned promise
       * will always fulfill, except in the case where `array` is a promise
       * that rejects.
       * @param {Array|Promise} array or promise for array of promises to settle
       * @returns {Promise} promise that always fulfills with an array of
       *  outcome snapshots for each input promise.
       */
      function settle(array) {
  	return _map(array, toFulfilledState, toRejectedState);
      }
  
      /**
       * Promise-aware array map function, similar to `Array.prototype.map()`,
       * but input array may contain promises or values.
       * @param {Array|Promise} array array of anything, may contain promises and values
       * @param {function} mapFunc map function which may return a promise or value
       * @returns {Promise} promise that will fulfill with an array of mapped values
       *  or reject if any input promise rejects.
       */
      function map(array, mapFunc) {
  	return _map(array, mapFunc);
      }
  
      /**
       * Internal map that allows a fallback to handle rejections
       * @param {Array|Promise} array array of anything, may contain promises and values
       * @param {function} mapFunc map function which may return a promise or value
       * @param {function?} fallback function to handle rejected promises
       * @returns {Promise} promise that will fulfill with an array of mapped values
       *  or reject if any input promise rejects.
       */
      function _map(array, mapFunc, fallback) {
  	return when(array, function(array) {
  
  	    return _promise(resolveMap);
  
  	    function resolveMap(resolve, reject, notify) {
  		var results, len, toResolve, i;
  
  		// Since we know the resulting length, we can preallocate the results
  		// array to avoid array expansions.
  		toResolve = len = array.length >>> 0;
  		results = [];
  
  		if(!toResolve) {
  		    resolve(results);
  		    return;
  		}
  
  		// Since mapFunc may be async, get all invocations of it into flight
  		for(i = 0; i < len; i++) {
  		    if(i in array) {
  			resolveOne(array[i], i);
  		    } else {
  			--toResolve;
  		    }
  		}
  
  		function resolveOne(item, i) {
  		    when(item, mapFunc, fallback).then(function(mapped) {
  			results[i] = mapped;
  			notify(mapped);
  
  			if(!--toResolve) {
  			    resolve(results);
  			}
  		    }, reject);
  		}
  	    }
  	});
      }
  
      /**
       * Traditional reduce function, similar to `Array.prototype.reduce()`, but
       * input may contain promises and/or values, and reduceFunc
       * may return either a value or a promise, *and* initialValue may
       * be a promise for the starting value.
       *
       * @param {Array|Promise} promise array or promise for an array of anything,
       *      may contain a mix of promises and values.
       * @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total),
       *      where total is the total number of items being reduced, and will be the same
       *      in each call to reduceFunc.
       * @returns {Promise} that will resolve to the final reduced value
       */
      function reduce(promise, reduceFunc /*, initialValue */) {
  	var args = fcall(slice, arguments, 1);
  
  	return when(promise, function(array) {
  	    var total;
  
  	    total = array.length;
  
  	    // Wrap the supplied reduceFunc with one that handles promises and then
  	    // delegates to the supplied.
  	    args[0] = function (current, val, i) {
  		return when(current, function (c) {
  		    return when(val, function (value) {
  			return reduceFunc(c, value, i, total);
  		    });
  		});
  	    };
  
  	    return reduceArray.apply(array, args);
  	});
      }
  
      // Snapshot states
  
      /**
       * Creates a fulfilled state snapshot
       * @private
       * @param {*} x any value
       * @returns {{state:'fulfilled',value:*}}
       */
      function toFulfilledState(x) {
  	return { state: 'fulfilled', value: x };
      }
  
      /**
       * Creates a rejected state snapshot
       * @private
       * @param {*} x any reason
       * @returns {{state:'rejected',reason:*}}
       */
      function toRejectedState(x) {
  	return { state: 'rejected', reason: x };
      }
  
      /**
       * Creates a pending state snapshot
       * @private
       * @returns {{state:'pending'}}
       */
      function toPendingState() {
  	return { state: 'pending' };
      }
  
      //
      // Internals, utilities, etc.
      //
  
      var reduceArray, slice, fcall, nextTick, handlerQueue,
  	setTimeout, funcProto, call, arrayProto, monitorApi,
  	undef;
  
      //
      // Shared handler queue processing
      //
      // Credit to Twisol (https://github.com/Twisol) for suggesting
      // this type of extensible queue + trampoline approach for
      // next-tick conflation.
  
      handlerQueue = [];
  
      /**
       * Enqueue a task. If the queue is not currently scheduled to be
       * drained, schedule it.
       * @param {function} task
       */
      function enqueue(task) {
  	if(handlerQueue.push(task) === 1) {
  	    nextTick(drainQueue);
  	}
      }
  
      /**
       * Drain the handler queue entirely, being careful to allow the
       * queue to be extended while it is being processed, and to continue
       * processing until it is truly empty.
       */
      function drainQueue() {
  	var task, i = 0;
  
  	while(task = handlerQueue[i++]) {
  	    task();
  	}
  
  	handlerQueue = [];
      }
  
      // capture setTimeout to avoid being caught by fake timers
      // used in time based tests
      setTimeout = global.setTimeout;
  
      // Allow attaching the monitor to when() if env has no console
      monitorApi = typeof console != 'undefined' ? console : when;
  
      // Prefer setImmediate or MessageChannel, cascade to node,
      // vertx and finally setTimeout
      /*global setImmediate,MessageChannel,process*/
      if (typeof setImmediate === 'function') {
  	nextTick = setImmediate.bind(global);
      } else if(typeof MessageChannel !== 'undefined') {
  	var channel = new MessageChannel();
  	channel.port1.onmessage = drainQueue;
  	nextTick = function() { channel.port2.postMessage(0); };
      } else if (typeof process === 'object' && process.nextTick) {
  	nextTick = process.nextTick;
      } else {
  	nextTick = function(t) { setTimeout(t, 0); };
      }
  
      //
      // Capture/polyfill function and array utils
      //
  
      // Safe function calls
      funcProto = Function.prototype;
      call = funcProto.call;
      fcall = funcProto.bind
  	? call.bind(call)
  	: function(f, context) {
  	    return f.apply(context, slice.call(arguments, 2));
  	};
  
      // Safe array ops
      arrayProto = [];
      slice = arrayProto.slice;
  
      // ES5 reduce implementation if native not available
      // See: http://es5.github.com/#x15.4.4.21 as there are many
      // specifics and edge cases.  ES5 dictates that reduce.length === 1
      // This implementation deviates from ES5 spec in the following ways:
      // 1. It does not check if reduceFunc is a Callable
      reduceArray = arrayProto.reduce ||
  	function(reduceFunc /*, initialValue */) {
  	    /*jshint maxcomplexity: 7*/
  	    var arr, args, reduced, len, i;
  
  	    i = 0;
  	    arr = Object(this);
  	    len = arr.length >>> 0;
  	    args = arguments;
  
  	    // If no initialValue, use first item of array (we know length !== 0 here)
  	    // and adjust i to start at second item
  	    if(args.length <= 1) {
  		// Skip to the first real element in the array
  		for(;;) {
  		    if(i in arr) {
  			reduced = arr[i++];
  			break;
  		    }
  
  		    // If we reached the end of the array without finding any real
  		    // elements, it's a TypeError
  		    if(++i >= len) {
  			throw new TypeError();
  		    }
  		}
  	    } else {
  		// If initialValue provided, use it
  		reduced = args[1];
  	    }
  
  	    // Do the actual reduce
  	    for(;i < len; ++i) {
  		if(i in arr) {
  		    reduced = reduceFunc(reduced, arr[i], i, arr);
  		}
  	    }
  
  	    return reduced;
  	};
  
      function identity(x) {
  	return x;
      }
  
      return when;
  })(window.document===undefined?this:window);
  