text: // vim:ts=4:sts=4:sw=4:
  /*!
   *
   * Copyright 2009-2012 Kris Kowal under the terms of the MIT
   * license found at http://github.com/kriskowal/q/raw/master/LICENSE
   *
   * With parts by Tyler Close
   * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found
   * at http://www.opensource.org/licenses/mit-license.html
   * Forked at ref_send.js version: 2009-05-11
   *
   * With parts by Mark Miller
   * Copyright (C) 2011 Google Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  
  (function (definition) {
      // Turn off strict mode for this function so we can assign to global.Q
      /* jshint strict: false */
  
      // This file will function properly as a <script> tag, or a module
      // using CommonJS and NodeJS or RequireJS module formats.  In
      // Common/Node/RequireJS, the module exports the Q API and when
      // executed as a simple <script>, it creates a Q global instead.
  
      // Montage Require
      if (typeof bootstrap === "function") {
          bootstrap("promise", definition);
  
      // CommonJS
      } else if (typeof exports === "object") {
          module.exports = definition();
  
      // RequireJS
      } else if (typeof define === "function" && define.amd) {
          define(definition);
  
      // SES (Secure EcmaScript)
      } else if (typeof ses !== "undefined") {
          if (!ses.ok()) {
              return;
          } else {
              ses.makeQ = definition;
          }
  
      // <script>
      } else {
          Q = definition();
      }
  
  })(function () {
  "use strict";
  
  var hasStacks = false;
  try {
      throw new Error();
  } catch (e) {
      hasStacks = !!e.stack;
  }
  
  // All code after this point will be filtered from stack traces reported
  // by Q.
  var qStartingLine = captureLine();
  var qFileName;
  
  // shims
  
  function noop() {}
  
  // Use the fastest possible means to execute a task in a future turn
  // of the event loop.
  var nextTick =(function () {
      // linked list of tasks (single, with head node)
      var head = {task: void 0, next: null};
      var tail = head;
      var flushing = false;
      var requestTick = void 0;
      var isNodeJS = false;
  
      function flush() {
          /* jshint loopfunc: true */
  
          while (head.next) {
              head = head.next;
              var task = head.task;
              head.task = void 0;
              var domain = head.domain;
  
              if (domain) {
                  head.domain = void 0;
                  domain.enter();
              }
  
              try {
                  task();
  
              } catch (e) {
                  if (isNodeJS) {
                      // In node, uncaught exceptions are considered fatal errors.
                      // Re-throw them synchronously to interrupt flushing!
  
                      // Ensure continuation if the uncaught exception is suppressed
                      // listening "uncaughtException" events (as domains does).
                      // Continue in next event to avoid tick recursion.
                      if (domain) {
                          domain.exit();
                      }
                      setTimeout(flush, 0);
                      if (domain) {
                          domain.enter();
                      }
  
                      throw e;
  
                  } else {
                      // In browsers, uncaught exceptions are not fatal.
                      // Re-throw them asynchronously to avoid slow-downs.
                      setTimeout(function() {
                         throw e;
                      }, 0);
                  }
              }
  
              if (domain) {
                  domain.exit();
              }
          }
  
          flushing = false;
      }
  
      nextTick = function (task) {
          tail = tail.next = {
              task: task,
              domain: isNodeJS && process.domain,
              next: null
          };
  
          if (!flushing) {
              flushing = true;
              requestTick();
          }
      };
  
      if (typeof process !== "undefined" && process.nextTick) {
          // Node.js before 0.9. Note that some fake-Node environments, like the
          // Mocha test runner, introduce a `process` global without a `nextTick`.
          isNodeJS = true;
  
          requestTick = function () {
              process.nextTick(flush);
          };
  
      } else if (typeof setImmediate === "function") {
          // In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate
          if (typeof window !== "undefined") {
              requestTick = setImmediate.bind(window, flush);
          } else {
              requestTick = function () {
                  setImmediate(flush);
              };
          }
  
      } else if (typeof MessageChannel !== "undefined") {
          // modern browsers
          // http://www.nonblocking.io/2011/06/windownexttick.html
          var channel = new MessageChannel();
          channel.port1.onmessage = flush;
          requestTick = function () {
              channel.port2.postMessage(0);
          };
  
      } else {
          // old browsers
          requestTick = function () {
              setTimeout(flush, 0);
          };
      }
  
      return nextTick;
  })();
  
  // Attempt to make generics safe in the face of downstream
  // modifications.
  // There is no situation where this is necessary.
  // If you need a security guarantee, these primordials need to be
  // deeply frozen anyway, and if you don’t need a security guarantee,
  // this is just plain paranoid.
  // However, this does have the nice side-effect of reducing the size
  // of the code by reducing x.call() to merely x(), eliminating many
  // hard-to-minify characters.
  // See Mark Miller’s explanation of what this does.
  // http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
  function uncurryThis(f) {
      var call = Function.call;
      return function () {
          return call.apply(f, arguments);
      };
  }
  // This is equivalent, but slower:
  // uncurryThis = Function_bind.bind(Function_bind.call);
  // http://jsperf.com/uncurrythis
  
  var array_slice = uncurryThis(Array.prototype.slice);
  
  var array_reduce = uncurryThis(
      Array.prototype.reduce || function (callback, basis) {
          var index = 0,
              length = this.length;
          // concerning the initial value, if one is not provided
          if (arguments.length === 1) {
              // seek to the first value in the array, accounting
              // for the possibility that is is a sparse array
              do {
                  if (index in this) {
                      basis = this[index++];
                      break;
                  }
                  if (++index >= length) {
                      throw new TypeError();
                  }
              } while (1);
          }
          // reduce
          for (; index < length; index++) {
              // account for the possibility that the array is sparse
              if (index in this) {
                  basis = callback(basis, this[index], index);
              }
          }
          return basis;
      }
  );
  
  var array_indexOf = uncurryThis(
      Array.prototype.indexOf || function (value) {
          // not a very good shim, but good enough for our one use of it
          for (var i = 0; i < this.length; i++) {
              if (this[i] === value) {
                  return i;
              }
          }
          return -1;
      }
  );
  
  var array_map = uncurryThis(
      Array.prototype.map || function (callback, thisp) {
          var self = this;
          var collect = [];
          array_reduce(self, function (undefined, value, index) {
              collect.push(callback.call(thisp, value, index, self));
          }, void 0);
          return collect;
      }
  );
  
  var object_create = Object.create || function (prototype) {
      function Type() { }
      Type.prototype = prototype;
      return new Type();
  };
  
  var object_hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
  
  var object_keys = Object.keys || function (object) {
      var keys = [];
      for (var key in object) {
          if (object_hasOwnProperty(object, key)) {
              keys.push(key);
          }
      }
      return keys;
  };
  
  function isObject(value) {
      return value === Object(value);
  }
  
  // iterator related shims
  
  function iterate(values) {
      if (!values) {
          throw new Error("Can't iterate: " + values);
      } else if (typeof values.iterator === "function") {
          return values.iterator();
      } else if (typeof values.next === "function") {
          return values;
      } else if (typeof values.length === "number") {
          return array_iterate(values);
      } else {
          throw new Error("Can't iterate: " + values);
      }
  }
  
  function array_iterate(values) {
      var index = 0;
      function next() {
          while (index < values.length && !(index in values)) {
              index++;
          }
          if (index < values.length) {
              return {value: values[index], index: index++};
          } else {
              return {done: true};
          }
      }
      return {next: next, send: next};
  }
  
  // long stack traces
  
  var STACK_JUMP_SEPARATOR = "From previous event:";
  
  function makeStackTraceLong(error, promise) {
      // If possible, transform the error stack trace by removing Node and Q
      // cruft, then concatenating with the stack trace of `promise`. See #57.
      if (hasStacks &&
          promise.stack &&
          typeof error === "object" &&
          error !== null &&
          error.stack &&
          error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1
      ) {
          var stacks = [];
          for (var p = promise; !!p; p = p.source) {
              if (p.stack) {
                  stacks.unshift(p.stack);
              }
          }
          stacks.unshift(error.stack);
  
          var concatedStacks = stacks.join("\n" + STACK_JUMP_SEPARATOR + "\n");
          error.stack = filterStackString(concatedStacks);
      }
  }
  
  function filterStackString(stackString) {
      var lines = stackString.split("\n");
      var desiredLines = [];
      for (var i = 0; i < lines.length; ++i) {
          var line = lines[i];
  
          if (!isInternalFrame(line) && !isNodeFrame(line) && line) {
              desiredLines.push(line);
          }
      }
      return desiredLines.join("\n");
  }
  
  function isNodeFrame(stackLine) {
      return stackLine.indexOf("(module.js:") !== -1 ||
             stackLine.indexOf("(node.js:") !== -1;
  }
  
  function getFileNameAndLineNumber(stackLine) {
      // Named functions: "at functionName (filename:lineNumber:columnNumber)"
      // In IE10 function name can have spaces ("Anonymous function") O_o
      var attempt1 = /at .+ \((.+):(\d+):(?:\d+)\)$/.exec(stackLine);
      if (attempt1) {
          return [attempt1[1], Number(attempt1[2])];
      }
  
      // Anonymous functions: "at filename:lineNumber:columnNumber"
      var attempt2 = /at ([^ ]+):(\d+):(?:\d+)$/.exec(stackLine);
      if (attempt2) {
          return [attempt2[1], Number(attempt2[2])];
      }
  
      // Firefox style: "function@filename:lineNumber or @filename:lineNumber"
      var attempt3 = /.*@(.+):(\d+)$/.exec(stackLine);
      if (attempt3) {
          return [attempt3[1], Number(attempt3[2])];
      }
  }
  
  function isInternalFrame(stackLine) {
      var fileNameAndLineNumber = getFileNameAndLineNumber(stackLine);
  
      if (!fileNameAndLineNumber) {
          return false;
      }
  
      var fileName = fileNameAndLineNumber[0];
      var lineNumber = fileNameAndLineNumber[1];
  
      return fileName === qFileName &&
          lineNumber >= qStartingLine &&
          lineNumber <= qEndingLine;
  }
  
  // discover own file name and line number range for filtering stack
  // traces
  function captureLine() {
      if (!hasStacks) {
          return;
      }
  
      try {
          throw new Error();
      } catch (e) {
          var lines = e.stack.split("\n");
          var firstLine = lines[0].indexOf("@") > 0 ? lines[1] : lines[2];
          var fileNameAndLineNumber = getFileNameAndLineNumber(firstLine);
          if (!fileNameAndLineNumber) {
              return;
          }
  
          qFileName = fileNameAndLineNumber[0];
          return fileNameAndLineNumber[1];
      }
  }
  
  function deprecate(callback, name, alternative) {
      return function () {
          if (typeof console !== "undefined" &&
              typeof console.warn === "function") {
              console.warn(name + " is deprecated, use " + alternative +
                           " instead.", new Error("").stack);
          }
          return callback.apply(callback, arguments);
      };
  }
  
  // end of shims
  // beginning of real work
  
  /**
   * Constructs a promise for an immediate reference, passes promises through, or
   * coerces promises from different systems.
   * @param value immediate reference or promise
   */
  function Q(value) {
      // If the object is already a Promise, return it directly.  This enables
      // the resolve function to both be used to created references from objects,
      // but to tolerably coerce non-promises to promises.
      if (Q.isPromise(value)) {
          return value;
      }
  
      // assimilate thenables
      if (Q.isPromiseAlike(value)) {
          return coerce(value);
      } else {
          return fulfill(value);
      }
  }
  Q.resolve = Q;
  
  /**
   * Performs a task in a future turn of the event loop.
   * @param {Function} task
   */
  Q.nextTick = nextTick;
  
  /**
   * Controls whether or not long stack traces will be on
   */
  Q.longStackSupport = false;
  
  /**
   * Constructs a {promise, resolve, reject} object.
   *
   * `resolve` is a callback to invoke with a more resolved value for the
   * promise. To fulfill the promise, invoke `resolve` with any value that is
   * not a thenable. To reject the promise, invoke `resolve` with a rejected
   * thenable, or invoke `reject` with the reason directly. To resolve the
   * promise to another thenable, thus putting it in the same state, invoke
   * `resolve` with that other thenable.
   */
  Q.defer = defer;
  function defer() {
      // if "messages" is an "Array", that indicates that the promise has not yet
      // been resolved.  If it is "undefined", it has been resolved.  Each
      // element of the messages array is itself an array of complete arguments to
      // forward to the resolved promise.  We coerce the resolution value to a
      // promise using the `resolve` function because it handles both fully
      // non-thenable values and other thenables gracefully.
      var messages = [], progressListeners = [], resolvedPromise;
  
      var deferred = object_create(defer.prototype);
      var promise = object_create(Promise.prototype);
  
      promise.promiseDispatch = function (resolve, op, operands) {
          var args = array_slice(arguments);
          if (messages) {
              messages.push(args);
              if (op === "when" && operands[1]) { // progress operand
                  progressListeners.push(operands[1]);
              }
          } else {
              nextTick(function () {
                  resolvedPromise.promiseDispatch.apply(resolvedPromise, args);
              });
          }
      };
  
      // XXX deprecated
      promise.valueOf = deprecate(function () {
          if (messages) {
              return promise;
          }
          var nearerValue = Q.nearer(resolvedPromise);
          if (Q.isPromise(nearerValue)) {
              resolvedPromise = nearerValue; // shorten chain
          }
          return nearerValue;
      }, "valueOf", "inspect");
  
      promise.inspect = function () {
          if (!resolvedPromise) {
              return { state: "pending" };
          }
          return resolvedPromise.inspect();
      };
  
      if (Q.longStackSupport && hasStacks) {
          try {
              throw new Error();
          } catch (e) {
              // NOTE: don't try to use `Error.captureStackTrace` or transfer the
              // accessor around; that causes memory leaks as per GH-111. Just
              // reify the stack trace as a string ASAP.
              //
              // At the same time, cut off the first line; it's always just
              // "[object Promise]\n", as per the `toString`.
              promise.stack = e.stack.substring(e.stack.indexOf("\n") + 1);
          }
      }
  
      // NOTE: we do the checks for `resolvedPromise` in each method, instead of
      // consolidating them into `become`, since otherwise we'd create new
      // promises with the lines `become(whatever(value))`. See e.g. GH-252.
  
      function become(newPromise) {
          resolvedPromise = newPromise;
          promise.source = newPromise;
  
          array_reduce(messages, function (undefined, message) {
              nextTick(function () {
                  newPromise.promiseDispatch.apply(newPromise, message);
              });
          }, void 0);
  
          messages = void 0;
          progressListeners = void 0;
      }
  
      deferred.promise = promise;
      deferred.resolve = function (value) {
          if (resolvedPromise) {
              return;
          }
  
          become(Q(value));
      };
  
      deferred.fulfill = function (value) {
          if (resolvedPromise) {
              return;
          }
  
          become(fulfill(value));
      };
      deferred.reject = function (reason) {
          if (resolvedPromise) {
              return;
          }
  
          become(reject(reason));
      };
      deferred.notify = function (progress) {
          if (resolvedPromise) {
              return;
          }
  
          array_reduce(progressListeners, function (undefined, progressListener) {
              nextTick(function () {
                  progressListener(progress);
              });
          }, void 0);
      };
  
      return deferred;
  }
  
  /**
   * Creates a Node-style callback that will resolve or reject the deferred
   * promise.
   * @returns a nodeback
   */
  defer.prototype.makeNodeResolver = function () {
      var self = this;
      return function (error, value) {
          if (error) {
              self.reject(error);
          } else if (arguments.length > 2) {
              self.resolve(array_slice(arguments, 1));
          } else {
              self.resolve(value);
          }
      };
  };
  
  /**
   * @param resolver {Function} a function that returns nothing and accepts
   * the resolve, reject, and notify functions for a deferred.
   * @returns a promise that may be resolved with the given resolve and reject
   * functions, or rejected by a thrown exception in resolver
   */
  Q.promise = promise;
  function promise(resolver) {
      if (typeof resolver !== "function") {
          throw new TypeError("resolver must be a function.");
      }
      var deferred = defer();
      try {
          resolver(deferred.resolve, deferred.reject, deferred.notify);
      } catch (reason) {
          deferred.reject(reason);
      }
      return deferred.promise;
  }
  
  // XXX experimental.  This method is a way to denote that a local value is
  // serializable and should be immediately dispatched to a remote upon request,
  // instead of passing a reference.
  Q.passByCopy = function (object) {
      //freeze(object);
      //passByCopies.set(object, true);
      return object;
  };
  
  Promise.prototype.passByCopy = function () {
      //freeze(object);
      //passByCopies.set(object, true);
      return this;
  };
  
  /**
   * If two promises eventually fulfill to the same value, promises that value,
   * but otherwise rejects.
   * @param x {Any*}
   * @param y {Any*}
   * @returns {Any*} a promise for x and y if they are the same, but a rejection
   * otherwise.
   *
   */
  Q.join = function (x, y) {
      return Q(x).join(y);
  };
  
  Promise.prototype.join = function (that) {
      return Q([this, that]).spread(function (x, y) {
          if (x === y) {
              // TODO: "===" should be Object.is or equiv
              return x;
          } else {
              throw new Error("Can't join: not the same: " + x + " " + y);
          }
      });
  };
  
  /**
   * Returns a promise for the first of an array of promises to become fulfilled.
   * @param answers {Array[Any*]} promises to race
   * @returns {Any*} the first promise to be fulfilled
   */
  Q.race = race;
  function race(answerPs) {
      return promise(function(resolve, reject) {
          // Switch to this once we can assume at least ES5
          // answerPs.forEach(function(answerP) {
          //     Q(answerP).then(resolve, reject);
          // });
          // Use this in the meantime
          for (var i = 0, len = answerPs.length; i < len; i++) {
              Q(answerPs[i]).then(resolve, reject);
          }
      });
  }
  
  Promise.prototype.race = function () {
      return this.then(Q.race);
  };
  
  /**
   * Constructs a Promise with a promise descriptor object and optional fallback
   * function.  The descriptor contains methods like when(rejected), get(name),
   * set(name, value), post(name, args), and delete(name), which all
   * return either a value, a promise for a value, or a rejection.  The fallback
   * accepts the operation name, a resolver, and any further arguments that would
   * have been forwarded to the appropriate method above had a method been
   * provided with the proper name.  The API makes no guarantees about the nature
   * of the returned object, apart from that it is usable whereever promises are
   * bought and sold.
   */
  Q.makePromise = Promise;
  function Promise(descriptor, fallback, inspect) {
      if (fallback === void 0) {
          fallback = function (op) {
              return reject(new Error(
                  "Promise does not support operation: " + op
              ));
          };
      }
      if (inspect === void 0) {
          inspect = function () {
              return {state: "unknown"};
          };
      }
  
      var promise = object_create(Promise.prototype);
  
      promise.promiseDispatch = function (resolve, op, args) {
          var result;
          try {
              if (descriptor[op]) {
                  result = descriptor[op].apply(promise, args);
              } else {
                  result = fallback.call(promise, op, args);
              }
          } catch (exception) {
              result = reject(exception);
          }
          if (resolve) {
              resolve(result);
          }
      };
  
      promise.inspect = inspect;
  
      // XXX deprecated `valueOf` and `exception` support
      if (inspect) {
          var inspected = inspect();
          if (inspected.state === "rejected") {
              promise.exception = inspected.reason;
          }
  
          promise.valueOf = deprecate(function () {
              var inspected = inspect();
              if (inspected.state === "pending" ||
                  inspected.state === "rejected") {
                  return promise;
              }
              return inspected.value;
          });
      }
  
      return promise;
  }
  
  Promise.prototype.toString = function () {
      return "[object Promise]";
  };
  
  Promise.prototype.then = function (fulfilled, rejected, progressed) {
      var self = this;
      var deferred = defer();
      var done = false;   // ensure the untrusted promise makes at most a
                          // single call to one of the callbacks
  
      function _fulfilled(value) {
          try {
              return typeof fulfilled === "function" ? fulfilled(value) : value;
          } catch (exception) {
              return reject(exception);
          }
      }
  
      function _rejected(exception) {
          if (typeof rejected === "function") {
              makeStackTraceLong(exception, self);
              try {
                  return rejected(exception);
              } catch (newException) {
                  return reject(newException);
              }
          }
          return reject(exception);
      }
  
      function _progressed(value) {
          return typeof progressed === "function" ? progressed(value) : value;
      }
  
      nextTick(function () {
          self.promiseDispatch(function (value) {
              if (done) {
                  return;
              }
              done = true;
  
              deferred.resolve(_fulfilled(value));
          }, "when", [function (exception) {
              if (done) {
                  return;
              }
              done = true;
  
              deferred.resolve(_rejected(exception));
          }]);
      });
  
      // Progress propagator need to be attached in the current tick.
      self.promiseDispatch(void 0, "when", [void 0, function (value) {
          var newValue;
          var threw = false;
          try {
              newValue = _progressed(value);
          } catch (e) {
              threw = true;
              if (Q.onerror) {
                  Q.onerror(e);
              } else {
                  throw e;
              }
          }
  
          if (!threw) {
              deferred.notify(newValue);
          }
      }]);
  
      return deferred.promise;
  };
  
  /**
   * Registers an observer on a promise.
   *
   * Guarantees:
   *
   * 1. that fulfilled and rejected will be called only once.
   * 2. that either the fulfilled callback or the rejected callback will be
   *    called, but not both.
   * 3. that fulfilled and rejected will not be called in this turn.
   *
   * @param value      promise or immediate reference to observe
   * @param fulfilled  function to be called with the fulfilled value
   * @param rejected   function to be called with the rejection exception
   * @param progressed function to be called on any progress notifications
   * @return promise for the return value from the invoked callback
   */
  Q.when = function (value, fulfilled, rejected, progressed) {
      return Q(value).then(fulfilled, rejected, progressed);
  };
  
  Promise.prototype.thenResolve = function (value) {
      return this.then(function () { return value; });
  };
  
  Q.thenResolve = function (promise, value) {
      return Q(promise).thenResolve(value);
  };
  
  Promise.prototype.thenReject = function (reason) {
      return this.then(function () { throw reason; });
  };
  
  Q.thenReject = function (promise, reason) {
      return Q(promise).thenReject(reason);
  };
  
  /**
   * If an object is not a promise, it is as "near" as possible.
   * If a promise is rejected, it is as "near" as possible too.
   * If it’s a fulfilled promise, the fulfillment value is nearer.
   * If it’s a deferred promise and the deferred has been resolved, the
   * resolution is "nearer".
   * @param object
   * @returns most resolved (nearest) form of the object
   */
  
  // XXX should we re-do this?
  Q.nearer = function (value) {
      if (Q.isPromise(value)) {
          var inspected = value.inspect();
          if (inspected.state === "fulfilled") {
              return inspected.value;
          }
      }
      return value;
  };
  
  /**
   * @returns whether the given object is a promise.
   * Otherwise it is a fulfilled value.
   */
  Q.isPromise = function (object) {
      return isObject(object) &&
          typeof object.promiseDispatch === "function" &&
          typeof object.inspect === "function";
  };
  
  Q.isPromiseAlike = function (object) {
      return isObject(object) && typeof object.then === "function";
  };
  
  /**
   * @returns whether the given object is a pending promise, meaning not
   * fulfilled or rejected.
   */
  Q.isPending = function (object) {
      return Q.isPromise(object) && object.inspect().state === "pending";
  };
  
  Promise.prototype.isPending = function () {
      return this.inspect().state === "pending";
  };
  
  /**
   * @returns whether the given object is a value or fulfilled
   * promise.
   */
  Q.isFulfilled = function (object) {
      return !Q.isPromise(object) || object.inspect().state === "fulfilled";
  };
  
  Promise.prototype.isFulfilled = function () {
      return this.inspect().state === "fulfilled";
  };
  
  /**
   * @returns whether the given object is a rejected promise.
   */
  Q.isRejected = function (object) {
      return Q.isPromise(object) && object.inspect().state === "rejected";
  };
  
  Promise.prototype.isRejected = function () {
      return this.inspect().state === "rejected";
  };
  
  //// BEGIN UNHANDLED REJECTION TRACKING
  
  // This promise library consumes exceptions thrown in handlers so they can be
  // handled by a subsequent promise.  The exceptions get added to this array when
  // they are created, and removed when they are handled.  Note that in ES6 or
  // shimmed environments, this would naturally be a `Set`.
  var unhandledReasons = [];
  var unhandledRejections = [];
  var unhandledReasonsDisplayed = false;
  var trackUnhandledRejections = true;
  function displayUnhandledReasons() {
      if (
          !unhandledReasonsDisplayed &&
          typeof window !== "undefined" &&
          !window.Touch &&
          window.console
      ) {
          console.warn("[Q] Unhandled rejection reasons (should be empty):",
                       unhandledReasons);
      }
  
      unhandledReasonsDisplayed = true;
  }
  
  function logUnhandledReasons() {
      for (var i = 0; i < unhandledReasons.length; i++) {
          var reason = unhandledReasons[i];
          if (reason && typeof reason.stack !== "undefined") {
              console.warn("Unhandled rejection reason:", reason.stack);
          } else {
              console.warn("Unhandled rejection reason (no stack):", reason);
          }
      }
  }
  
  function resetUnhandledRejections() {
      unhandledReasons.length = 0;
      unhandledRejections.length = 0;
      unhandledReasonsDisplayed = false;
  
      if (!trackUnhandledRejections) {
          trackUnhandledRejections = true;
  
          // Show unhandled rejection reasons if Node exits without handling an
          // outstanding rejection.  (Note that Browserify presently produces a
          // `process` global without the `EventEmitter` `on` method.)
          if (typeof process !== "undefined" && process.on) {
              process.on("exit", logUnhandledReasons);
          }
      }
  }
  
  function trackRejection(promise, reason) {
      if (!trackUnhandledRejections) {
          return;
      }
  
      unhandledRejections.push(promise);
      unhandledReasons.push(reason);
      displayUnhandledReasons();
  }
  
  function untrackRejection(promise) {
      if (!trackUnhandledRejections) {
          return;
      }
  
      var at = array_indexOf(unhandledRejections, promise);
      if (at !== -1) {
          unhandledRejections.splice(at, 1);
          unhandledReasons.splice(at, 1);
      }
  }
  
  Q.resetUnhandledRejections = resetUnhandledRejections;
  
  Q.getUnhandledReasons = function () {
      // Make a copy so that consumers can't interfere with our internal state.
      return unhandledReasons.slice();
  };
  
  Q.stopUnhandledRejectionTracking = function () {
      resetUnhandledRejections();
      if (typeof process !== "undefined" && process.on) {
          process.removeListener("exit", logUnhandledReasons);
      }
      trackUnhandledRejections = false;
  };
  
  resetUnhandledRejections();
  
  //// END UNHANDLED REJECTION TRACKING
  
  /**
   * Constructs a rejected promise.
   * @param reason value describing the failure
   */
  Q.reject = reject;
  function reject(reason) {
      var rejection = Promise({
          "when": function (rejected) {
              // note that the error has been handled
              if (rejected) {
                  untrackRejection(this);
              }
              return rejected ? rejected(reason) : this;
          }
      }, function fallback() {
          return this;
      }, function inspect() {
          return { state: "rejected", reason: reason };
      });
  
      // Note that the reason has not been handled.
      trackRejection(rejection, reason);
  
      return rejection;
  }
  
  /**
   * Constructs a fulfilled promise for an immediate reference.
   * @param value immediate reference
   */
  Q.fulfill = fulfill;
  function fulfill(value) {
      return Promise({
          "when": function () {
              return value;
          },
          "get": function (name) {
              return value[name];
          },
          "set": function (name, rhs) {
              value[name] = rhs;
          },
          "delete": function (name) {
              delete value[name];
          },
          "post": function (name, args) {
              // Mark Miller proposes that post with no name should apply a
              // promised function.
              if (name === null || name === void 0) {
                  return value.apply(void 0, args);
              } else {
                  return value[name].apply(value, args);
              }
          },
          "apply": function (thisp, args) {
              return value.apply(thisp, args);
          },
          "keys": function () {
              return object_keys(value);
          },
          "iterate": function () {
              return iterate(value);
          }
      }, void 0, function inspect() {
          return { state: "fulfilled", value: value };
      });
  }
  
  /**
   * Converts thenables to Q promises.
   * @param promise thenable promise
   * @returns a Q promise
   */
  function coerce(promise) {
      var deferred = defer();
      nextTick(function () {
          try {
              promise.then(deferred.resolve, deferred.reject, deferred.notify);
          } catch (exception) {
              deferred.reject(exception);
          }
      });
      return deferred.promise;
  }
  
  /**
   * Annotates an object such that it will never be
   * transferred away from this process over any promise
   * communication channel.
   * @param object
   * @returns promise a wrapping of that object that
   * additionally responds to the "isDef" message
   * without a rejection.
   */
  Q.master = master;
  function master(object) {
      var promise = Q(object);
      return Promise({
          "isDef": function () {}
      }, function fallback(op, args) {
          return promise.dispatch(op, args);
      }, function () {
          return promise.inspect();
      });
  }
  
  /**
   * Spreads the values of a promised array of arguments into the
   * fulfillment callback.
   * @param fulfilled callback that receives variadic arguments from the
   * promised array
   * @param rejected callback that receives the exception if the promise
   * is rejected.
   * @returns a promise for the return value or thrown exception of
   * either callback.
   */
  Q.spread = spread;
  function spread(value, fulfilled, rejected) {
      return Q(value).spread(fulfilled, rejected);
  }
  
  Promise.prototype.spread = function (fulfilled, rejected) {
      return this.all().then(function (array) {
          return fulfilled.apply(void 0, array);
      }, rejected);
  };
  
  /**
   * The async function is a decorator for generator functions, turning
   * them into asynchronous generators.  Although generators are only part
   * of the newest ECMAScript 6 drafts, this code does not cause syntax
   * errors in older engines.  This code should continue to work and will
   * in fact improve over time as the language improves.
   *
   * ES6 generators are currently part of V8 version 3.19 with the
   * --harmony-generators runtime flag enabled.  SpiderMonkey has had them
   * for longer, but under an older Python-inspired form.  This function
   * works on both kinds of generators.
   *
   * Decorates a generator function such that:
   *  - it may yield promises
   *  - execution will continue when that promise is fulfilled
   *  - the value of the yield expression will be the fulfilled value
   *  - it returns a promise for the return value (when the generator
   *    stops iterating)
   *  - the decorated function returns a promise for the return value
   *    of the generator or the first rejected promise among those
   *    yielded.
   *  - if an error is thrown in the generator, it propagates through
   *    every following yield until it is caught, or until it escapes
   *    the generator function altogether, and is translated into a
   *    rejection for the promise returned by the decorated generator.
   */
  Q.async = function (makeGenerator) {
      return function () {
          // when verb is "send", arg is a value
          // when verb is "throw", arg is an exception
          function continuer(verb, arg) {
              var result;
              try {
                  result = generator[verb](arg);
              } catch (exception) {
                  return reject(exception);
              }
              if (result.done) {
                  return result.value;
              } else {
                  return Q(result.value).then(callback, errback);
              }
          }
          var generator = makeGenerator.apply(this, arguments);
          var callback = continuer.bind(continuer, "send");
          var errback = continuer.bind(continuer, "throw");
          return callback();
      };
  };
  
  /**
   * The spawn function is a small wrapper around async that immediately
   * calls the generator and also ends the promise chain, so that any
   * unhandled errors are thrown instead of forwarded to the error
   * handler. This is useful because it's extremely common to run
   * generators at the top-level to work with libraries.
   */
  Q.spawn = function (makeGenerator) {
      Q.done(Q.async(makeGenerator)());
  };
  
  /**
   * The promised function decorator ensures that any promise arguments
   * are settled and passed as values (`this` is also settled and passed
   * as a value).  It will also ensure that the result of a function is
   * always a promise.
   *
   * @example
   * var add = Q.promised(function (a, b) {
   *     return a + b;
   * });
   * add(Q(a), Q(B));
   *
   * @param {function} callback The function to decorate
   * @returns {function} a function that has been decorated.
   */
  Q.promised = function (callback) {
      return function () {
          return spread([this, Q.all(arguments)], function (self, args) {
              return callback.apply(self, args);
          });
      };
  };
  
  /**
   * sends a message to a value in a future turn
   * @param object* the recipient
   * @param op the name of the message operation, e.g., "when",
   * @param args further arguments to be forwarded to the operation
   * @returns result {Promise} a promise for the result of the operation
   */
  Q.dispatch = dispatch;
  function dispatch(object, op, args) {
      return Q(object).dispatch(op, args);
  }
  
  Promise.prototype.dispatch = function (op, args) {
      var self = this;
      var deferred = defer();
      nextTick(function () {
          self.promiseDispatch(deferred.resolve, op, args);
      });
      return deferred.promise;
  };
  
  /**
   * Gets the value of a property in a future turn.
   * @param object    promise or immediate reference for target object
   * @param name      name of property to get
   * @return promise for the property value
   */
  Q.get = function (object, key) {
      return Q(object).dispatch("get", [key]);
  };
  
  Promise.prototype.get = function (key) {
      return this.dispatch("get", [key]);
  };
  
  /**
   * Sets the value of a property in a future turn.
   * @param object    promise or immediate reference for object object
   * @param name      name of property to set
   * @param value     new value of property
   * @return promise for the return value
   */
  Q.set = function (object, key, value) {
      return Q(object).dispatch("set", [key, value]);
  };
  
  Promise.prototype.set = function (key, value) {
      return this.dispatch("set", [key, value]);
  };
  
  /**
   * Deletes a property in a future turn.
   * @param object    promise or immediate reference for target object
   * @param name      name of property to delete
   * @return promise for the return value
   */
  Q.del = // XXX legacy
  Q["delete"] = function (object, key) {
      return Q(object).dispatch("delete", [key]);
  };
  
  Promise.prototype.del = // XXX legacy
  Promise.prototype["delete"] = function (key) {
      return this.dispatch("delete", [key]);
  };
  
  /**
   * Invokes a method in a future turn.
   * @param object    promise or immediate reference for target object
   * @param name      name of method to invoke
   * @param value     a value to post, typically an array of
   *                  invocation arguments for promises that
   *                  are ultimately backed with `resolve` values,
   *                  as opposed to those backed with URLs
   *                  wherein the posted value can be any
   *                  JSON serializable object.
   * @return promise for the return value
   */
  // bound locally because it is used by other methods
  Q.mapply = // XXX As proposed by "Redsandro"
  Q.post = function (object, name, args) {
      return Q(object).dispatch("post", [name, args]);
  };
  
  Promise.prototype.mapply = // XXX As proposed by "Redsandro"
  Promise.prototype.post = function (name, args) {
      return this.dispatch("post", [name, args]);
  };
  
  /**
   * Invokes a method in a future turn.
   * @param object    promise or immediate reference for target object
   * @param name      name of method to invoke
   * @param ...args   array of invocation arguments
   * @return promise for the return value
   */
  Q.send = // XXX Mark Miller's proposed parlance
  Q.mcall = // XXX As proposed by "Redsandro"
  Q.invoke = function (object, name /*...args*/) {
      return Q(object).dispatch("post", [name, array_slice(arguments, 2)]);
  };
  
  Promise.prototype.send = // XXX Mark Miller's proposed parlance
  Promise.prototype.mcall = // XXX As proposed by "Redsandro"
  Promise.prototype.invoke = function (name /*...args*/) {
      return this.dispatch("post", [name, array_slice(arguments, 1)]);
  };
  
  /**
   * Applies the promised function in a future turn.
   * @param object    promise or immediate reference for target function
   * @param args      array of application arguments
   */
  Q.fapply = function (object, args) {
      return Q(object).dispatch("apply", [void 0, args]);
  };
  
  Promise.prototype.fapply = function (args) {
      return this.dispatch("apply", [void 0, args]);
  };
  
  /**
   * Calls the promised function in a future turn.
   * @param object    promise or immediate reference for target function
   * @param ...args   array of application arguments
   */
  Q["try"] =
  Q.fcall = function (object /* ...args*/) {
      return Q(object).dispatch("apply", [void 0, array_slice(arguments, 1)]);
  };
  
  Promise.prototype.fcall = function (/*...args*/) {
      return this.dispatch("apply", [void 0, array_slice(arguments)]);
  };
  
  /**
   * Binds the promised function, transforming return values into a fulfilled
   * promise and thrown errors into a rejected one.
   * @param object    promise or immediate reference for target function
   * @param ...args   array of application arguments
   */
  Q.fbind = function (object /*...args*/) {
      var promise = Q(object);
      var args = array_slice(arguments, 1);
      return function fbound() {
          return promise.dispatch("apply", [
              this,
              args.concat(array_slice(arguments))
          ]);
      };
  };
  Promise.prototype.fbind = function (/*...args*/) {
      var promise = this;
      var args = array_slice(arguments);
      return function fbound() {
          return promise.dispatch("apply", [
              this,
              args.concat(array_slice(arguments))
          ]);
      };
  };
  
  /**
   * Requests the names of the owned properties of a promised
   * object in a future turn.
   * @param object    promise or immediate reference for target object
   * @return promise for the keys of the eventually settled object
   */
  Q.keys = function (object) {
      return Q(object).dispatch("keys", []);
  };
  
  Promise.prototype.keys = function () {
      return this.dispatch("keys", []);
  };
  
  /**
   */
  Q.iterate = function (object) {
      return Q(object).dispatch("iterate", []);
  };
  
  Promise.prototype.iterate = function () {
      return this.dispatch("iterate", []);
  };
  
  /**
   * Aggregates all of the input into a single value, asynchronously.  `reduce`
   * uses a pool of acreted values, optionally starting with some `basis`.  Each
   * time a value becomes available both from the input and the pool of bases,
   * the values are taken out and asynchronously combined.  When the combination
   * has been fulfilled, the result is placed back in the pool.  When the input
   * is exhausted, the result is the last value remaining in in the pool of
   * accumulated values.
   *
   * The result is rejected if and when any of the input values or combined
   * values are rejected.
   *
   * By default, the reducer will consume the entire input as it becomes
   * available.  With a `maxInFlight` argument, the reducer will only consume
   * enough to keep that number of concurrent reductions in progress.
   *
   * @param {Iterable*} input
   * @param {Function} callback a function that accepts a value from the base
   * pool and a value from the input, and produces a combined base to be returned
   * to the pool.
   * @param {Number?} maxInFlight the maximum number of concurrent reductions to
   * perform at any given time.  If `undefined`, there is no upper bound.
   * @param {Function} notify an optional callback to inform when the number of
   * `inFlight` reductions changes.  The callback also receives `maxInFlight`.
   * @returns {Any*} a promise for the last remaining base after all other bases
   * have been combined with values from the input.
   */
  Q.reduce = function (object, callback, basis, maxInFlight, notify) {
      if (arguments.length < 2) {
          return Q(object).reduce(callback);
      } else {
          return Q(object).reduce(callback, basis, maxInFlight, notify);
      }
  };
  
  Promise.prototype.reduce = function (callback, basis, maxInFlight, notify) {
      var iterator = this.dispatch("iterate", []);
      var inFlight = 0;
      var done = false;
      var deferred = defer();
  
      // fulfilled bases, ready for aggregation
      var bases = new Queue();
      var semaphore = new Semaphore(maxInFlight);
  
      callback = Q(callback);
      if (notify) {
          notify = Q(notify);
      }
  
      var needsBasis;
      if (arguments.length < 2) {
          needsBasis = true;
      } else {
          Q(basis).then(bases.put);
          needsBasis = false;
      }
  
      function next() {
          return semaphore.get()
          .then(function () {
              return iterator.invoke("next");
          })
          .then(function (iteration) {
              if (iteration.done) {
                  done = true;
                  check();
              } else if (needsBasis) {
                  Q(iteration.value)
                      .then(function (value) {
                          bases.put(value);
                          semaphore.put();
                      })
                      .then(null, deferred.reject);
                  needsBasis = false;
                  next();
              } else {
                  ++inFlight;
                  if (notify) {
                      notify.fcall(inFlight, maxInFlight).done();
                  }
                  next();
                  return Q(iteration.value)
                  .then(function (value) {
                      bases.get().then(function (basis) {
                          callback.fcall(basis, value, iteration.index)
                              .then(function (value) {
                                  bases.put(value);
                                  semaphore.put();
                              })
                              .then(null, deferred.reject);
                          --inFlight;
                          if (notify) {
                              notify.fcall(inFlight, maxInFlight).done();
                          }
                          check();
                      })
                      .then(null, deferred.reject);
                  });
              }
          })
          .then(null, deferred.reject);
      }
  
      function check() {
          if (inFlight === 0 && done) {
              if (needsBasis) {
                  deferred.reject(new Error("Can't reduce empty source without a basis"));
              } else {
                  deferred.resolve(bases.get());
              }
          }
      }
  
      next();
  
      return deferred.promise;
  };
  
  /**
   * Transforms input values into output values asynchronously.
   * @param {Iterable*} input an iterable (albeit an array or iterator) (or a
   * promise for such)
   * @param {Function} callback a relation from the inputs to the outputs, which
   * may return a promise.
   * @param {Number} maxInFlight the number of transformations to process at any
   * given time.
   * @param {Function} notify a callback to inform how many transformations are
   * being processed at any time.  Sends both the `inFlight` and `maxInFlight`
   * numbers.
   * @param {Queue*} output a promise for a Queue of the respective outputs
   * through the relation when they are fulfilled.
   */
  
  Q.map = function (object, callback, maxInFlight, notify) {
      return Q(object).map(callback, maxInFlight, notify);
  };
  
  Promise.prototype.map = function (callback, maxInFlight, notify) {
      var inFlight = 0;
      var done = false;
      var pipe = Pipe(this, maxInFlight, notify);
      callback = Q(callback);
      Q.reduce(pipe.input, function (undefined, value, index) {
          inFlight++;
          callback.fcall(value)
          .then(function (value) {
              inFlight--;
              pipe.output.send(value, index);
              if (done && inFlight === 0) {
                  pipe.output["return"]();
              }
          })
          .then(null, function (error) {
              pipe.output["throw"](error);
          });
      }, void 0)
      .then(function () {
          done = true;
          if (inFlight === 0) {
              pipe.output["return"]();
          }
      });
      return Q(pipe.output);
  };
  
  /**
   * Accepts a source of promises and returns a promise to send the corresponding
   * values to the given callback, serially or with limited concurrency.
   * With a `maxInFlight` value of 1, `forEach` waits for the returned promise
   * from the previous callback before sending the next value.
   * @param {Iterable*} source an iterable (albeit an array, queue, iterator,
   * generator) (or a promise for such) that produces a sequence of values (or
   * promises for values)
   * @param {Function} callback a function to call with each value, which returns
   * undefined (or a promise for undefined) when the callback has completed its
   * work.
   * @param {Number?} maxInFlight the maximum number of iterations to process
   * concurrently.  The default is 1.
   * @param {Function?} notify
   * @returns {Undefined*} a promise for the completion.  Note that for
   * generators, this is the completion value.  Other iterators may also send a
   * completion value if `next` returns `{done, value}`.
   */
  
  Q.forEach = function (object, callback, maxInFlight, notify) {
      return Q(object).forEach(callback, maxInFlight, notify);
  };
  
  Promise.prototype.forEach = function (callback, maxInFlight, notify) {
      if (maxInFlight === void 0) {
          maxInFlight = 1;
      }
  
      // initialize the semaphore
      var semaphore = new Semaphore(maxInFlight);
      var inFlight = 0;
  
      var iterator = this.dispatch("iterate", []);
      var deferred = defer();
  
      callback = Q(callback);
      if (notify) {
          notify = Q(notify);
      }
  
      function next() {
          semaphore.get().then(function () {
              return iterator.invoke("next")
              .then(function (iteration) {
                  if (notify) {
                      notify.fcall(++inFlight, maxInFlight).done();
                  }
                  if (iteration.done) {
                      deferred.resolve(iteration.value);
                  } else {
                      next();
                      return Q(iteration.value)
                      .then(function (value) {
                          return callback.fcall(value, iteration.index);
                      })
                      .then(function () {
                          if (notify) {
                              notify.fcall(--inFlight, maxInFlight).done();
                          }
                          semaphore.put();
                      }, deferred.reject);
                  }
              });
          });
      }
  
      next();
  
      return deferred.promise;
  };
  
  /**
   * Fills a local buffer with as many as `maxInFlight` values from a source
   * stream and provides them on demand.  This is useful before `forEach` if the
   * source has high latency on `next`, such as a remote iterable.
   * @param {Iterable*} input
   * @param {Number} maxInFlight maximum number of values from input to
   * accumulate in this buffer.
   * @param {Function?} notify a callback to inform when the number of buffered
   * values (`inFlight`) changes.  The callback also receives the `maxInFlight`.
   * @returns {Queue*} output
   */
  Q.buffer = buffer;
  function buffer(object, maxInFlight, notify) {
      return Q(object).buffer(maxInFlight, notify);
  }
  
  Promise.prototype.buffer = function (maxInFlight, notify) {
      var pipe = new Pipe(this, maxInFlight, notify);
      var iterator = Q(pipe.input).iterate();
      function next() {
          return iterator.invoke("next")
          .then(function (iteration) {
              next();
              pipe.output.put(iteration);
          })
          .then(null, function (error) {
              pipe.output["throw"](error);
          });
      }
      next();
      return Q(pipe.output);
  };
  
  /**
   * Turns an array of promises into a promise for an array.  If any of
   * the promises gets rejected, the whole array is rejected immediately.
   * @param {Iterable*} input array or promise (or a promise for such) of values
   * (or promises for values)
   * @returns a promise for an array of the corresponding values
   */
  Q.all = function (input) {
      var output = [];
      return Q.reduce(input, function (undefined, value, index) {
          output[index] = value;
      }, void 0)
      .then(function () {
          return output;
      });
  };
  
  Promise.prototype.all = function () {
      return Q.all(this);
  };
  
  /**
   */
  Q.allSettled = function (values) {
      return Q(values).allSettled();
  };
  
  Promise.prototype.allSettled = function () {
      return this.then(function (promises) {
          return Q.all(array_map(promises, function (value) {
              var promise = Q(value);
              function regardless() {
                  return promise.inspect();
              }
              return promise.then(regardless, regardless);
          }));
      });
  };
  
  /**
   * Captures the failure of a promise, giving an oportunity to recover
   * with a callback.  If the given promise is fulfilled, the returned
   * promise is fulfilled.
   * @param {Any*} promise for something
   * @param {Function} callback to fulfill the returned promise if the
   * given promise is rejected
   * @returns a promise for the return value of the callback
   */
  Q.fail = // XXX legacy
  Q["catch"] = function (object, rejected) {
      return Q(object).then(void 0, rejected);
  };
  
  Promise.prototype.fail = // XXX legacy
  Promise.prototype["catch"] = function (rejected) {
      return this.then(void 0, rejected);
  };
  
  /**
   * Attaches a listener that can respond to progress notifications from a
   * promise's originating deferred. This listener receives the exact arguments
   * passed to ``deferred.notify``.
   * @param {Any*} promise for something
   * @param {Function} callback to receive any progress notifications
   * @returns the given promise, unchanged
   */
  Q.progress = progress;
  function progress(object, progressed) {
      return Q(object).then(void 0, void 0, progressed);
  }
  
  Promise.prototype.progress = function (progressed) {
      return this.then(void 0, void 0, progressed);
  };
  
  /**
   * Provides an opportunity to observe the settling of a promise,
   * regardless of whether the promise is fulfilled or rejected.  Forwards
   * the resolution to the returned promise when the callback is done.
   * The callback can return a promise to defer completion.
   * @param {Any*} promise
   * @param {Function} callback to observe the resolution of the given
   * promise, takes no arguments.
   * @returns a promise for the resolution of the given promise when
   * ``fin`` is done.
   */
  Q.fin = // XXX legacy
  Q["finally"] = function (object, callback) {
      return Q(object)["finally"](callback);
  };
  
  Promise.prototype.fin = // XXX legacy
  Promise.prototype["finally"] = function (callback) {
      callback = Q(callback);
      return this.then(function (value) {
          return callback.fcall().then(function () {
              return value;
          });
      }, function (reason) {
          // TODO attempt to recycle the rejection with "this".
          return callback.fcall().then(function () {
              throw reason;
          });
      });
  };
  
  /**
   * Terminates a chain of promises, forcing rejections to be
   * thrown as exceptions.
   * @param {Any*} promise at the end of a chain of promises
   * @returns nothing
   */
  Q.done = function (object, fulfilled, rejected, progress) {
      return Q(object).done(fulfilled, rejected, progress);
  };
  
  Promise.prototype.done = function (fulfilled, rejected, progress) {
      var onUnhandledError = function (error) {
          // forward to a future turn so that ``when``
          // does not catch it and turn it into a rejection.
          nextTick(function () {
              makeStackTraceLong(error, promise);
              if (Q.onerror) {
                  Q.onerror(error);
              } else {
                  throw error;
              }
          });
      };
  
      // Avoid unnecessary `nextTick`ing via an unnecessary `when`.
      var promise = fulfilled || rejected || progress ?
          this.then(fulfilled, rejected, progress) :
          this;
  
      if (typeof process === "object" && process && process.domain) {
          onUnhandledError = process.domain.bind(onUnhandledError);
      }
  
      promise.then(void 0, onUnhandledError);
  };
  
  /**
   * Causes a promise to be rejected if it does not get fulfilled before
   * some milliseconds time out.
   * @param {Any*} promise
   * @param {Number} milliseconds timeout
   * @param {String} custom error message (optional)
   * @returns a promise for the resolution of the given promise if it is
   * fulfilled before the timeout, otherwise rejected.
   */
  Q.timeout = function (object, ms, message) {
      return Q(object).timeout(ms, message);
  };
  
  Promise.prototype.timeout = function (ms, message) {
      var deferred = defer();
      var timeoutId = setTimeout(function () {
          deferred.reject(new Error(message || "Timed out after " + ms + " ms"));
      }, ms);
  
      this.then(function (value) {
          clearTimeout(timeoutId);
          deferred.resolve(value);
      }, function (exception) {
          clearTimeout(timeoutId);
          deferred.reject(exception);
      }, deferred.notify);
  
      return deferred.promise;
  };
  
  /**
   * Returns a promise for the given value (or promised value), some
   * milliseconds after it resolved. Passes rejections immediately.
   * @param {Any*} promise
   * @param {Number} milliseconds
   * @returns a promise for the resolution of the given promise after milliseconds
   * time has elapsed since the resolution of the given promise.
   * If the given promise rejects, that is passed immediately.
   */
  Q.delay = function (object, timeout) {
      if (timeout === void 0) {
          timeout = object;
          object = void 0;
      }
      return Q(object).delay(timeout);
  };
  
  Promise.prototype.delay = function (timeout) {
      return this.then(function (value) {
          var deferred = defer();
          setTimeout(function () {
              deferred.resolve(value);
          }, timeout);
          return deferred.promise;
      });
  };
  
  /**
   * Passes a continuation to a Node function, which is called with the given
   * arguments provided as an array, and returns a promise.
   *
   *      Q.nfapply(FS.readFile, [__filename])
   *      .then(function (content) {
   *      })
   *
   */
  Q.nfapply = function (callback, args) {
      return Q(callback).nfapply(args);
  };
  
  Promise.prototype.nfapply = function (args) {
      var deferred = defer();
      var nodeArgs = array_slice(args);
      nodeArgs.push(deferred.makeNodeResolver());
      this.fapply(nodeArgs).fail(deferred.reject);
      return deferred.promise;
  };
  
  /**
   * Passes a continuation to a Node function, which is called with the given
   * arguments provided individually, and returns a promise.
   * @example
   * Q.nfcall(FS.readFile, __filename)
   * .then(function (content) {
   * })
   *
   */
  Q.nfcall = function (callback /*...args*/) {
      var args = array_slice(arguments, 1);
      return Q(callback).nfapply(args);
  };
  
  Promise.prototype.nfcall = function (/*...args*/) {
      var nodeArgs = array_slice(arguments);
      var deferred = defer();
      nodeArgs.push(deferred.makeNodeResolver());
      this.fapply(nodeArgs).fail(deferred.reject);
      return deferred.promise;
  };
  
  /**
   * Wraps a NodeJS continuation passing function and returns an equivalent
   * version that returns a promise.
   * @example
   * Q.nfbind(FS.readFile, __filename)("utf-8")
   * .then(console.log)
   * .done()
   */
  Q.nfbind =
  Q.denodeify = function (callback /*...args*/) {
      var baseArgs = array_slice(arguments, 1);
      return function () {
          var nodeArgs = baseArgs.concat(array_slice(arguments));
          var deferred = defer();
          nodeArgs.push(deferred.makeNodeResolver());
          Q(callback).fapply(nodeArgs).fail(deferred.reject);
          return deferred.promise;
      };
  };
  
  Promise.prototype.nfbind =
  Promise.prototype.denodeify = function (/*...args*/) {
      var args = array_slice(arguments);
      args.unshift(this);
      return Q.denodeify.apply(void 0, args);
  };
  
  Q.nbind = function (callback, thisp /*...args*/) {
      var baseArgs = array_slice(arguments, 2);
      return function () {
          var nodeArgs = baseArgs.concat(array_slice(arguments));
          var deferred = defer();
          nodeArgs.push(deferred.makeNodeResolver());
          function bound() {
              return callback.apply(thisp, arguments);
          }
          Q(bound).fapply(nodeArgs).fail(deferred.reject);
          return deferred.promise;
      };
  };
  
  Promise.prototype.nbind = function (/*thisp, ...args*/) {
      var args = array_slice(arguments, 0);
      args.unshift(this);
      return Q.nbind.apply(void 0, args);
  };
  
  /**
   * Calls a method of a Node-style object that accepts a Node-style
   * callback with a given array of arguments, plus a provided callback.
   * @param object an object that has the named method
   * @param {String} name name of the method of object
   * @param {Array} args arguments to pass to the method; the callback
   * will be provided by Q and appended to these arguments.
   * @returns a promise for the value or error
   */
  Q.nmapply = // XXX As proposed by "Redsandro"
  Q.npost = function (object, name, args) {
      return Q(object).npost(name, args);
  };
  
  Promise.prototype.nmapply = // XXX As proposed by "Redsandro"
  Promise.prototype.npost = function (name, args) {
      var nodeArgs = array_slice(args || []);
      var deferred = defer();
      nodeArgs.push(deferred.makeNodeResolver());
      this.dispatch("post", [name, nodeArgs]).fail(deferred.reject);
      return deferred.promise;
  };
  
  /**
   * Calls a method of a Node-style object that accepts a Node-style
   * callback, forwarding the given variadic arguments, plus a provided
   * callback argument.
   * @param object an object that has the named method
   * @param {String} name name of the method of object
   * @param ...args arguments to pass to the method; the callback will
   * be provided by Q and appended to these arguments.
   * @returns a promise for the value or error
   */
  Q.nsend = // XXX Based on Mark Miller's proposed "send"
  Q.nmcall = // XXX Based on "Redsandro's" proposal
  Q.ninvoke = function (object, name /*...args*/) {
      var nodeArgs = array_slice(arguments, 2);
      var deferred = defer();
      nodeArgs.push(deferred.makeNodeResolver());
      Q(object).dispatch("post", [name, nodeArgs]).fail(deferred.reject);
      return deferred.promise;
  };
  
  Promise.prototype.nsend = // XXX Based on Mark Miller's proposed "send"
  Promise.prototype.nmcall = // XXX Based on "Redsandro's" proposal
  Promise.prototype.ninvoke = function (name /*...args*/) {
      var nodeArgs = array_slice(arguments, 1);
      var deferred = defer();
      nodeArgs.push(deferred.makeNodeResolver());
      this.dispatch("post", [name, nodeArgs]).fail(deferred.reject);
      return deferred.promise;
  };
  
  /**
   * If a function would like to support both Node continuation-passing-style and
   * promise-returning-style, it can end its internal promise chain with
   * `nodeify(nodeback)`, forwarding the optional nodeback argument.  If the user
   * elects to use a nodeback, the result will be sent there.  If they do not
   * pass a nodeback, they will receive the result promise.
   * @param object a result (or a promise for a result)
   * @param {Function} nodeback a Node.js-style callback
   * @returns either the promise or nothing
   */
  Q.nodeify = function (object, nodeback) {
      return Q(object).nodeify(nodeback);
  };
  
  Promise.prototype.nodeify = function (nodeback) {
      if (nodeback) {
          this.then(function (value) {
              nextTick(function () {
                  nodeback(null, value);
              });
          }, function (error) {
              nextTick(function () {
                  nodeback(error);
              });
          });
      } else {
          return this;
      }
  };
  
  /**
   * An infinite promise queue is an asynchronous linked list that allows the
   * consumer to get a promise for a value before the producer has put one, or a
   * producer to put a value before the the consumer has asked for it.  Of
   * course, the more mundane case of a producer putting and then the consumer
   * getting works just as well.
   *
   * Additionally, a Queue supports the iterator API, specifically the iterator
   * API as returned by ES6 generators, with one crucial difference.  `next`
   * returns a promise for the next iteration.  This works by using an infinite
   * promise queue as an asynchronous transport for iterations.  Borrowing the
   * terms from the generator API, `send` and `throw`, and supplementing them
   * with `return`, the queue can be teased to behave like a generator by calling
   * these functions to produce a sequence of iterations.
   *
   * @constructor
   */
  Q.Queue = Queue;
  function Queue() {
      if (!(this instanceof Queue)) {
          return new Queue();
      }
      var ends = Q.defer();
      this.put = function (value) {
          var next = Q.defer();
          ends.resolve({
              head: value,
              tail: next.promise
          });
          ends.resolve = next.resolve;
      };
      this.get = function () {
          var result = ends.promise.get("head");
          ends.promise = ends.promise.get("tail");
          return result;
      };
      this.index = 0;
  }
  
  /**
   * When using a Queue as an asycnronous iteration transport, returns a promise
   * for the next iteration.  Iterations are objects like `{value}` for an
   * iteration, which can be supplemented with an index like `{value, index}` if
   * the source is an array or array-like, and `{value, done: true}` for the
   * completion of the iteration, optionally with a return value, or a rejected
   * promise if the simulated generator threw an error.
   * @returns {Iteration*}
   */
  Queue.prototype.next = function () {
      return this.get();
  };
  
  /**
   * When using a Queue as an asynchronous iteration transport, adds a value to
   * the queue of iterations.  The value may be at an optional given index.  If
   * no index is provided, the iteration will be given a sequence number.
   * @param {Any} value
   * @param {Number?} index
   */
  Queue.prototype.send = function (value, index) {
      if (index === undefined) {
          index = this.index++;
      }
      return this.put({value: value, index: index});
  };
  
  /**
   * When using a Queue as an asynchronous iteration transport, adds a completion
   * value to the queue of iterations.  This signals the end of the sequence,
   * like closing a stream.
   */
  Queue.prototype["return"] = function (value) {
      this.put({value: value, done: true});
  };
  
  /**
   * When using a Queue as an asynchronous iteration transport, adds a thrown
   * exception to the queue.  This signals the end of the sequence, like closing
   * a stream with an error, or throwing an exception from a generator.
   */
  Queue.prototype["throw"] = function (error) {
      this.put(Q.reject(error));
  };
  
  /**
   * Allows the iteration to interoperate with shimmed ES6 iterators with the
   * Iterable duck type.  The queue itself is the iterator, so simply returns
   * itself.
   * @returns this
   */
  Queue.prototype.iterator = function () {
      return this;
  };
  
  /**
   * @see Promise#map
   */
  Queue.prototype.map = function (callback, maxInFlight, notify) {
      return Q(this).map(callback, maxInFlight, notify);
  };
  
  /**
   * @see Promise#reduce
   */
  Queue.prototype.reduce = function (callback, basis, maxInFlight) {
      if (arguments.length < 2) {
          return Q(this).reduce(callback);
      } else {
          return Q(this).reduce(callback, basis, maxInFlight);
      }
  };
  
  /**
   * @see Promise#forEach
   */
  Queue.prototype.forEach = function (callback, maxInFlight) {
      return Q(this).forEach(callback, maxInFlight);
  };
  
  /**
   * @see Promise#buffer
   */
  Queue.prototype.buffer = function (maxInFlight, notify) {
      return Q(this).buffer(maxInFlight, notify);
  };
  
  /**
   * @see Promise#all
   */
  Queue.prototype.all = function () {
      return Q(this).all();
  };
  
  /**
   * A convenient constructor for a Queue that is used to synchronize a limited
   * resource, like a buffer, database connection pool, or similar.  Since
   * it is common within this library to make buffering optional, an unspecified
   * `maxInFlight` argument implies that this should not behave as a semaphore
   * at all, so `get` and `put` become effectively no-ops.
   * @param {Number?} maxInFlight the maximum number of the underlying resource.
   * This can be manipulated at run time by calling `put` (to increase by one),
   * but this is a convenient place to initialize it.
   * @constructor
   */
  Q.Semaphore = Semaphore;
  function Semaphore(maxInFlight) {
      if (!(this instanceof Semaphore)) {
          return new Semaphore(maxInFlight);
      }
      if (maxInFlight !== void 0) {
          var queue = new Queue();
          this.get = queue.get;
          this.put = queue.put;
          for (var i = 0; i < maxInFlight; i++) {
              queue.put();
          }
      } else {
          this.get = Q;
          this.put = noop;
      }
  }
  
  Semaphore.prototype = object_create(Queue.prototype);
  
  /**
   * A pipe is a tool for controlling scheduling of work by watching input and
   * output streams.  The pipe receives the true input and produces controlled
   * input and output streams.  The producer is responsible for sending results
   * to the output Queue using the generator API.  The rate at which the producer
   * sends data will regulate the rate at which the consumer can take values from
   * the input iterator.
   * @param {Iterable} trueInput
   * @param {Number?} maxInFlight (infinite if undefined)
   * @returns {{input, output}} pipe The input is an iterator that will only
   * yield up to `maxInFlight` values at a time.  Sending data to the output
   * Queue signals that some input has been taken out of flight.
   * @constructor
   */
  Q.Pipe = Pipe;
  function Pipe(trueInput, maxInFlight, notify) {
      if (!(this instanceof Pipe)) {
          return new Pipe(trueInput, maxInFlight);
      }
  
      trueInput = Q(trueInput).iterate();
      if (notify) {
          notify = Q(notify);
      }
  
      var semaphore = new Semaphore(maxInFlight);
      var inFlight = 0;
  
      var input = {
          next: function () {
              return semaphore.get().then(function () {
                  if (notify) {
                      inFlight++;
                      notify.fcall(inFlight, maxInFlight).done();
                  }
                  return trueInput.invoke("next");
              });
          }
      };
  
      var output = object_create(Queue.prototype);
      var trueOutput = new Queue();
      output.get = function () {
          if (notify) {
              inFlight--;
              notify.fcall(inFlight, maxInFlight).done();
          }
          semaphore.put();
          return trueOutput.get();
      };
      output.put = trueOutput.put;
  
      this.input = input;
      this.output = output;
  }
  
  // All code before this point will be filtered from stack traces.
  var qEndingLine = captureLine();
  
  return Q;
  
  });
  