text: // vim:ts=4:sts=4:sw=4:
  /*jshint browser: true, node: true,
    curly: true, eqeqeq: true, noarg: true, nonew: true, trailing: true,
    undef: true */
  /*global define: false, Q: true, msSetImmediate: false, setImmediate: false,
    ReturnValue: false, cajaVM: false, ses: false */
  /*!
   *
   * 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.
   *
   * With formatStackTrace and formatSourcePosition functions
   * Copyright 2006-2008 the V8 project authors. All rights reserved.
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are
   * met:
   *
   *     * Redistributions of source code must retain the above copyright
   *       notice, this list of conditions and the following disclaimer.
   *     * Redistributions in binary form must reproduce the above
   *       copyright notice, this list of conditions and the following
   *       disclaimer in the documentation and/or other materials provided
   *       with the distribution.
   *     * Neither the name of Google Inc. nor the names of its
   *       contributors may be used to endorse or promote products derived
   *       from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  (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.
  
      // RequireJS
      if (typeof define === "function") {
          define(definition);
  
      // CommonJS
      } else if (typeof exports === "object") {
          definition(void 0, exports);
  
      // SES (Secure EcmaScript)
      } else if (typeof ses !== "undefined") {
          if (!ses.ok()) {
              return;
          } else {
              ses.makeQ = function () {
                  var Q = {};
                  return definition(void 0, Q);
              };
          }
  
      // <script>
      } else {
          definition(void 0, Q = {});
      }
  
  })(function (require, exports) {
  "use strict";
  
  // shims
  
  // used for fallback "defend" and in "allResolved"
  var noop = function () {};
  
  // for the security conscious, defend may be a deep freeze as provided
  // by cajaVM.  Otherwise we try to provide a shallow freeze just to
  // discourage promise changes that are not compatible with secure
  // usage.  If Object.freeze does not exist, fall back to doing nothing
  // (no op).
  var defend = Object.freeze || noop;
  if (typeof cajaVM !== "undefined") {
      defend = cajaVM.def;
  }
  
  // use the fastest possible means to execute a task in a future turn
  // of the event loop.
  var nextTick;
  if (typeof process !== "undefined") {
      // node
      nextTick = process.nextTick;
  } else if (typeof msSetImmediate === "function") {
      // IE 10 only, at the moment
      // And yes, ``bind``ing to ``window`` is necessary O_o.
      nextTick = msSetImmediate.bind(window);
  } else if (typeof setImmediate === "function") {
      // https://github.com/NobleJS/setImmediate
      nextTick = setImmediate;
  } else if (typeof MessageChannel !== "undefined") {
      // modern browsers
      // http://www.nonblocking.io/2011/06/windownexttick.html
      var channel = new MessageChannel();
      // linked list of tasks (single, with head node)
      var head = {}, tail = head;
      channel.port1.onmessage = function () {
          head = head.next;
          var task = head.task;
          delete head.task;
          task();
      };
      nextTick = function (task) {
          tail = tail.next = {task: task};
          channel.port2.postMessage(0);
      };
  } else {
      // old browsers
      nextTick = function (task) {
          setTimeout(task, 0);
      };
  }
  
  // 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
  var uncurryThis;
  // I have kept both variations because the first is theoretically
  // faster, if bind is available.
  if (Function.prototype.bind) {
      var Function_bind = Function.prototype.bind;
      uncurryThis = Function_bind.bind(Function_bind.call);
  } else {
      uncurryThis = function (f) {
          return function (thisp) {
              return f.call.apply(f, arguments);
          };
      };
  }
  
  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_keys = Object.keys || function (object) {
      var keys = [];
      for (var key in object) {
          keys.push(key);
      }
      return keys;
  };
  
  var object_toString = Object.prototype.toString;
  
  // generator related shims
  
  function isStopIteration(exception) {
      return (
          object_toString(exception) === "[object StopIteration]" ||
          exception instanceof QReturnValue
      );
  }
  
  var QReturnValue;
  if (typeof ReturnValue !== "undefined") {
      QReturnValue = ReturnValue;
  } else {
      QReturnValue = function (value) {
          this.value = value;
      };
  }
  
  // long stack traces
  
  function formatStackTrace(error, frames) {
      var lines = [];
      try {
          lines.push(error.toString());
      } catch (e) {
          try {
              lines.push("<error: " + e + ">");
          } catch (ee) {
              lines.push("<error>");
          }
      }
      for (var i = 0; i < frames.length; i++) {
          var frame = frames[i];
          var line;
  
          // <Inserted by @domenic>
          if (typeof frame === "string") {
              lines.push(frame);
          // </Inserted by @domenic>
          } else {
              try {
                  line = formatSourcePosition(frame);
              } catch (e) {
                  try {
                      line = "<error: " + e + ">";
                  } catch (ee) {
                      // Any code that reaches this point is seriously nasty!
                      line = "<error>";
                  }
              }
              lines.push("    at " + line);
          }
      }
      return lines.join("\n");
  }
  
  function formatSourcePosition(frame) {
      var fileLocation = "";
      if (frame.isNative()) {
          fileLocation = "native";
      } else if (frame.isEval()) {
          fileLocation = "eval at " + frame.getEvalOrigin();
      } else {
          var fileName = frame.getFileName();
          if (fileName) {
              fileLocation += fileName;
              var lineNumber = frame.getLineNumber();
              if (lineNumber !== null) {
                  fileLocation += ":" + lineNumber;
                  var columnNumber = frame.getColumnNumber();
                  if (columnNumber) {
                      fileLocation += ":" + columnNumber;
                  }
              }
          }
      }
      if (!fileLocation) {
          fileLocation = "unknown source";
      }
      var line = "";
      var functionName = frame.getFunction().name;
      var addPrefix = true;
      var isConstructor = frame.isConstructor();
      var isMethodCall = !(frame.isToplevel() || isConstructor);
      if (isMethodCall) {
          var methodName = frame.getMethodName();
          line += frame.getTypeName() + ".";
          if (functionName) {
              line += functionName;
              if (methodName && (methodName !== functionName)) {
                  line += " [as " + methodName + "]";
              }
          } else {
              line += methodName || "<anonymous>";
          }
      } else if (isConstructor) {
          line += "new " + (functionName || "<anonymous>");
      } else if (functionName) {
          line += functionName;
      } else {
          line += fileLocation;
          addPrefix = false;
      }
      if (addPrefix) {
          line += " (" + fileLocation + ")";
      }
      return line;
  }
  
  /*
   * Retrieves an array of structured stack frames parsed from the ``stack``
   * property of a given object.
   *
   * @param objectWithStack {Object} an object with a ``stack`` property: usually
   * an error or promise.
   *
   * @returns an array of stack frame objects. For more information, see
   * [V8's JavaScript stack trace API documentation](http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi).
   */
  function getStackFrames(objectWithStack) {
      var oldPrepareStackTrace = Error.prepareStackTrace;
  
      Error.prepareStackTrace = function (error, frames) {
          // Filter out frames from the innards of Node and Q.
          return frames.filter(function (frame) {
              var fileName = frame.getFileName();
              return (
                  fileName !== "module.js" &&
                  fileName !== "node.js" &&
                  fileName !== qFileName
              );
          });
      };
  
      var stack = objectWithStack.stack;
  
      Error.prepareStackTrace = oldPrepareStackTrace;
  
      return stack;
  }
  
  // discover own file name for filtering stack traces
  var qFileName;
  if (Error.captureStackTrace) {
      qFileName = (function () {
          var fileName;
  
          var oldPrepareStackTrace = Error.prepareStackTrace;
  
          Error.prepareStackTrace = function (error, frames) {
              fileName = frames[0].getFileName();
          };
  
          // teases call of temporary prepareStackTrace
          // JSHint and Closure Compiler generate known warnings here
          /*jshint expr: true */
          new Error().stack;
  
          Error.prepareStackTrace = oldPrepareStackTrace;
  
          return fileName;
      })();
  }
  
  function deprecate(fn, name, alternative){
      return function () {
          if (typeof console !== "undefined" && typeof console.warn === "function"){
              console.warn(name + " is deprecated, use " + alternative + " instead.");
          }
          return fn.apply(fn,arguments);
      };
  }
  
  // end of shims
  // beginning of real work
  
  /**
   * Performs a task in a future turn of the event loop.
   * @param {Function} task
   */
  exports.nextTick = nextTick;
  
  /**
   * Constructs a {promise, resolve} object.
   *
   * The resolver is a callback to invoke with a more resolved value for the
   * promise. To fulfill the promise, invoke the resolver with any value that is
   * not a function. To reject the promise, invoke the resolver with a rejection
   * object. To put the promise in the same state as another promise, invoke the
   * resolver with that other promise.
   */
  exports.defer = defer;
  function defer() {
      // if "pending" 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 pending array is itself an array of complete arguments to
      // forward to the resolved promise.  We coerce the resolution value to a
      // promise using the ref promise because it handles both fully
      // resolved values and other promises gracefully.
      var pending = [], value;
  
      var deferred = object_create(defer.prototype);
      var promise = object_create(makePromise.prototype);
  
      promise.promiseSend = function () {
          var args = array_slice(arguments);
          if (pending) {
              pending.push(args);
          } else {
              nextTick(function () {
                  value.promiseSend.apply(value, args);
              });
          }
      };
  
      promise.valueOf = function () {
          if (pending) {
              return promise;
          }
          return value.valueOf();
      };
  
      if (Error.captureStackTrace) {
          Error.captureStackTrace(promise, defer);
      }
  
      function become(resolvedValue) {
          if (!pending) {
              return;
          }
          value = resolve(resolvedValue);
          array_reduce(pending, function (undefined, pending) {
              nextTick(function () {
                  value.promiseSend.apply(value, pending);
              });
          }, void 0);
          pending = void 0;
          return value;
      }
  
      defend(promise);
  
      deferred.promise = promise;
      deferred.resolve = become;
      deferred.reject = function (exception) {
          return become(reject(exception));
      };
  
      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);
          }
      };
  };
  // XXX deprecated
  defer.prototype.node = deprecate(defer.prototype.makeNodeResolver, "node", "makeNodeResolver");
  
  /**
   * @param makePromise {Function} a function that returns nothing and accepts
   * the resolve and reject 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 makePromise
   */
  exports.promise = promise;
  function promise(makePromise) {
      var deferred = defer();
      call(
          makePromise,
          void 0,
          deferred.resolve,
          deferred.reject
      ).fail(deferred.reject);
      return deferred.promise;
  }
  
  /**
   * Constructs a Promise with a promise descriptor object and optional fallback
   * function.  The descriptor contains methods like when(rejected), get(name),
   * put(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.
   */
  exports.makePromise = makePromise;
  function makePromise(descriptor, fallback, valueOf, exception) {
      if (fallback === void 0) {
          fallback = function (op) {
              return reject(new Error("Promise does not support operation: " + op));
          };
      }
  
      var promise = object_create(makePromise.prototype);
  
      promise.promiseSend = function (op, resolved /* ...args */) {
          var args = array_slice(arguments, 2);
          var result;
          try {
              if (descriptor[op]) {
                  result = descriptor[op].apply(promise, args);
              } else {
                  result = fallback.apply(promise, [op].concat(args));
              }
          } catch (exception) {
              result = reject(exception);
          }
          resolved(result);
      };
  
      if (valueOf) {
          promise.valueOf = valueOf;
      }
  
      if (exception) {
          promise.exception = exception;
      }
  
      defend(promise);
  
      return promise;
  }
  
  // provide thenables, CommonJS/Promises/A
  makePromise.prototype.then = function (fulfilled, rejected) {
      return when(this, fulfilled, rejected);
  };
  
  // Chainable methods
  array_reduce(
      [
          "isResolved", "isFulfilled", "isRejected",
          "when", "spread", "send",
          "get", "put", "del",
          "post", "invoke",
          "keys",
          "apply", "call", "bind",
          "fapply", "fcall", "fbind",
          "all", "allResolved",
          "view", "viewInfo",
          "timeout", "delay",
          "catch", "finally", "fail", "fin", "end"
      ],
      function (prev, name) {
          makePromise.prototype[name] = function () {
              return exports[name].apply(
                  exports,
                  [this].concat(array_slice(arguments))
              );
          };
      },
      void 0
  );
  
  makePromise.prototype.toSource = function () {
      return this.toString();
  };
  
  makePromise.prototype.toString = function () {
      return "[object Promise]";
  };
  
  defend(makePromise.prototype);
  
  /**
   * 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
   */
  exports.nearer = valueOf;
  function valueOf(value) {
      // if !Object.isObject(value)
      // generates a known JSHint "constructor invocation without new" warning
      // supposed to be fixed, but isn't? https://github.com/jshint/jshint/issues/392
      /*jshint newcap: false */
      if (Object(value) !== value) {
          return value;
      } else {
          return value.valueOf();
      }
  }
  
  /**
   * @returns whether the given object is a promise.
   * Otherwise it is a fulfilled value.
   */
  exports.isPromise = isPromise;
  function isPromise(object) {
      return object && typeof object.promiseSend === "function";
  }
  
  /**
   * @returns whether the given object is a resolved promise.
   */
  exports.isResolved = isResolved;
  function isResolved(object) {
      return isFulfilled(object) || isRejected(object);
  }
  
  /**
   * @returns whether the given object is a value or fulfilled
   * promise.
   */
  exports.isFulfilled = isFulfilled;
  function isFulfilled(object) {
      return !isPromise(valueOf(object));
  }
  
  /**
   * @returns whether the given object is a rejected promise.
   */
  exports.isRejected = isRejected;
  function isRejected(object) {
      object = valueOf(object);
      return isPromise(object) && 'exception' in object;
  }
  
  var rejections = [];
  var errors = [];
  if (typeof window !== "undefined" && window.console) {
      // This promise library consumes exceptions thrown in handlers so
      // they can be handled by a subsequent promise.  The rejected
      // promises get added to this array when they are created, and
      // removed when they are handled.
      console.log("Should be empty:", errors);
  }
  
  /**
   * Constructs a rejected promise.
   * @param exception value describing the failure
   */
  exports.reject = reject;
  function reject(exception) {
      exception = exception || new Error();
      var rejection = makePromise({
          "when": function (rejected) {
              // note that the error has been handled
              if (rejected) {
                  var at = array_indexOf(rejections, this);
                  if (at !== -1) {
                      errors.splice(at, 1);
                      rejections.splice(at, 1);
                  }
              }
              return rejected ? rejected(exception) : reject(exception);
          }
      }, function fallback(op) {
          return reject(exception);
      }, function valueOf() {
          return this;
      }, exception);
      // note that the error has not been handled
      rejections.push(rejection);
      errors.push(exception);
      return rejection;
  }
  
  /**
   * Constructs a promise for an immediate reference.
   * @param value immediate reference
   */
  exports.begin = resolve; // XXX experimental
  exports.resolve = resolve;
  exports.ref = deprecate(resolve, "ref", "resolve"); // XXX deprecated, use resolve
  function resolve(object) {
      // 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 (isPromise(object)) {
          return object;
      }
      // assimilate thenables, CommonJS/Promises/A
      if (object && typeof object.then === "function") {
          var result = defer();
          object.then(result.resolve, result.reject);
          return result.promise;
      }
      return makePromise({
          "when": function (rejected) {
              return object;
          },
          "get": function (name) {
              return object[name];
          },
          "put": function (name, value) {
              return object[name] = value;
          },
          "del": function (name) {
              return delete object[name];
          },
          "post": function (name, value) {
              return object[name].apply(object, value);
          },
          "apply": function (self, args) {
              return object.apply(self, args);
          },
          "fapply": function (args) {
              return object.apply(void 0, args);
          },
          "viewInfo": function () {
              var on = object;
              var properties = {};
  
              function fixFalsyProperty(name) {
                  if (!properties[name]) {
                      properties[name] = typeof on[name];
                  }
              }
  
              while (on) {
                  Object.getOwnPropertyNames(on).forEach(fixFalsyProperty);
                  on = Object.getPrototypeOf(on);
              }
              return {
                  "type": typeof object,
                  "properties": properties
              };
          },
          "keys": function () {
              return object_keys(object);
          }
      }, void 0, function valueOf() {
          return object;
      });
  }
  
  /**
   * 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.
   */
  exports.master = master;
  function master(object) {
      return makePromise({
          "isDef": function () {}
      }, function fallback(op) {
          var args = array_slice(arguments);
          return send.apply(void 0, [object].concat(args));
      }, function () {
          return valueOf(object);
      });
  }
  
  exports.viewInfo = viewInfo;
  function viewInfo(object, info) {
      object = resolve(object);
      if (info) {
          return makePromise({
              "viewInfo": function () {
                  return info;
              }
          }, function fallback(op) {
              var args = array_slice(arguments);
              return send.apply(void 0, [object].concat(args));
          }, function () {
              return valueOf(object);
          });
      } else {
          return send(object, "viewInfo");
      }
  }
  
  exports.view = view;
  function view(object) {
      return viewInfo(object).when(function (info) {
          var view;
          if (info.type === "function") {
              view = function () {
                  return apply(object, void 0, arguments);
              };
          } else {
              view = {};
          }
          var properties = info.properties || {};
          object_keys(properties).forEach(function (name) {
              if (properties[name] === "function") {
                  view[name] = function () {
                      return post(object, name, arguments);
                  };
              }
          });
          return resolve(view);
      });
  }
  
  /**
   * 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
   * @return promise for the return value from the invoked callback
   */
  exports.when = when;
  function when(value, fulfilled, rejected) {
      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 fulfilled ? fulfilled(value) : value;
          } catch (exception) {
              return reject(exception);
          }
      }
  
      function _rejected(exception) {
          try {
              return rejected ? rejected(exception) : reject(exception);
          } catch (newException) {
              return reject(newException);
          }
      }
  
      nextTick(function () {
          resolve(value).promiseSend("when", function (value) {
              if (done) {
                  return;
              }
              done = true;
              resolve(value).promiseSend("when", function (value) {
                  deferred.resolve(_fulfilled(value));
              }, function (exception) {
                  deferred.resolve(_rejected(exception));
              });
          }, function (exception) {
              if (done) {
                  return;
              }
              done = true;
              deferred.resolve(_rejected(exception));
          });
      });
  
      return deferred.promise;
  }
  
  /**
   * 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.
   */
  exports.spread = spread;
  function spread(promise, fulfilled, rejected) {
      return when(promise, function (values) {
          return fulfilled.apply(void 0, values);
      }, rejected);
  }
  
  /**
   * The async function is a decorator for generator functions, turning
   * them into asynchronous generators.  This presently only works in
   * Firefox/Spidermonkey, however, 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.
   *
   * 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.
   *  - in present implementations of generators, when a generator
   *    function is complete, it throws ``StopIteration``, ``return`` is
   *    a syntax error in the presence of ``yield``, so there is no
   *    observable return value. There is a proposal[1] to add support
   *    for ``return``, which would permit the value to be carried by a
   *    ``StopIteration`` instance, in which case it would fulfill the
   *    promise returned by the asynchronous generator.  This can be
   *    emulated today by throwing StopIteration explicitly with a value
   *    property.
   *
   *  [1]: http://wiki.ecmascript.org/doku.php?id=strawman:async_functions#reference_implementation
   *
   */
  exports.async = async;
  function async(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) {
                  if (isStopIteration(exception)) {
                      return exception.value;
                  } else {
                      return reject(exception);
                  }
              }
              return when(result, callback, errback);
          }
          var generator = makeGenerator.apply(this, arguments);
          var callback = continuer.bind(continuer, "send");
          var errback = continuer.bind(continuer, "throw");
          return callback();
      };
  }
  
  /**
   * Throws a ReturnValue exception to stop an asynchronous generator.
   * Only useful presently in Firefox/SpiderMonkey since generators are
   * implemented.
   * @param value the return value for the surrounding generator
   * @throws ReturnValue exception with the value.
   * @example
   * Q.async(function () {
   *      var foo = yield getFooPromise();
   *      var bar = yield getBarPromise();
   *      Q.return(foo + bar);
   * })
   */
  exports['return'] = _return;
  function _return(value) {
      throw new QReturnValue(value);
  }
  
  /**
   * Constructs a promise method that can be used to safely observe resolution of
   * a promise for an arbitrarily named method like "propfind" in a future turn.
   */
  exports.sender = deprecate(sender, "sender", "dispatcher"); // XXX deprecated, use dispatcher
  exports.Method = deprecate(sender, "Method", "dispatcher"); // XXX deprecated, use dispatcher
  function sender(op) {
      return function (object) {
          var args = array_slice(arguments, 1);
          return send.apply(void 0, [object, op].concat(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
   */
  exports.send = deprecate(send, "send", "dispatch"); // XXX deprecated, use dispatch
  function send(object, op) {
      var deferred = defer();
      var args = array_slice(arguments, 2);
      object = resolve(object);
      nextTick(function () {
          object.promiseSend.apply(
              object,
              [op, deferred.resolve].concat(args)
          );
      });
      return deferred.promise;
  }
  
  /**
   * 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
   */
  exports.dispatch = dispatch;
  function dispatch(object, op, args) {
      var deferred = defer();
      object = resolve(object);
      nextTick(function () {
          object.promiseSend.apply(
              object,
              [op, deferred.resolve].concat(args)
          );
      });
      return deferred.promise;
  }
  
  /**
   * Constructs a promise method that can be used to safely observe resolution of
   * a promise for an arbitrarily named method like "propfind" in a future turn.
   *
   * "dispatcher" constructs methods like "get(promise, name)" and "put(promise)".
   */
  exports.dispatcher = dispatcher;
  function dispatcher(op) {
      return function (object) {
          var args = array_slice(arguments, 1);
          return dispatch(object, op, args);
      };
  }
  
  /**
   * 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
   */
  exports.get = dispatcher("get");
  
  /**
   * 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
   */
  exports.put = dispatcher("put");
  
  /**
   * 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
   */
  exports["delete"] = // XXX experimental
  exports.del = dispatcher("del");
  
  /**
   * 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
  var post = exports.post = dispatcher("post");
  
  /**
   * 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
   */
  exports.invoke = function (value, name) {
      var args = array_slice(arguments, 2);
      return post(value, name, args);
  };
  
  /**
   * Applies the promised function in a future turn.
   * @param object    promise or immediate reference for target function
   * @param thisp     the `this` object for the call
   * @param args      array of application arguments
   */
  // XXX deprecated, use fapply
  var apply = exports.apply = deprecate(dispatcher("apply"), "apply", "fapply");
  
  /**
   * Applies the promised function in a future turn.
   * @param object    promise or immediate reference for target function
   * @param args      array of application arguments
   */
  var fapply = exports.fapply = dispatcher("fapply");
  
  /**
   * Calls the promised function in a future turn.
   * @param object    promise or immediate reference for target function
   * @param thisp     the `this` object for the call
   * @param ...args   array of application arguments
   */
  // XXX deprecated, use fcall
  exports.call = deprecate(call, "call", "fcall");
  function call(value, thisp) {
      var args = array_slice(arguments, 2);
      return apply(value, thisp, args);
  }
  
  /**
   * Calls the promised function in a future turn.
   * @param object    promise or immediate reference for target function
   * @param ...args   array of application arguments
   */
  exports["try"] = fcall; // XXX experimental
  exports.fcall = fcall;
  function fcall(value) {
      var args = array_slice(arguments, 1);
      return fapply(value, args);
  }
  
  /**
   * 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 thisp   the `this` object for the call
   * @param ...args   array of application arguments
   */
  exports.bind = deprecate(bind, "bind", "fbind"); // XXX deprecated, use fbind
  function bind(value, thisp) {
      var args = array_slice(arguments, 2);
      return function bound() {
          var allArgs = args.concat(array_slice(arguments));
          return apply(value, thisp, allArgs);
      };
  }
  
  /**
   * 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
   */
  exports.fbind = fbind;
  function fbind(value) {
      var args = array_slice(arguments, 1);
      return function fbound() {
          var allArgs = args.concat(array_slice(arguments));
          return fapply(value, allArgs);
      };
  }
  
  /**
   * 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 resolved object
   */
  exports.keys = dispatcher("keys");
  
  /**
   * 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 {Array*} an array (or promise for an array) of values (or
   * promises for values)
   * @returns a promise for an array of the corresponding values
   */
  // By Mark Miller
  // http://wiki.ecmascript.org/doku.php?id=strawman:concurrency&rev=1308776521#allfulfilled
  exports.all = all;
  function all(promises) {
      return when(promises, function (promises) {
          var countDown = promises.length;
          if (countDown === 0) {
              return resolve(promises);
          }
          var deferred = defer();
          array_reduce(promises, function (undefined, promise, index) {
              when(promise, function (value) {
                  promises[index] = value;
                  if (--countDown === 0) {
                      deferred.resolve(promises);
                  }
              })
              .fail(deferred.reject);
          }, void 0);
          return deferred.promise;
      });
  }
  
  /**
   * Waits for all promises to be resolved, either fulfilled or
   * rejected.  This is distinct from `all` since that would stop
   * waiting at the first rejection.  The promise returned by
   * `allResolved` will never be rejected.
   * @param promises a promise for an array (or an array) of promises
   * (or values)
   * @return a promise for an array of promises
   */
  exports.allResolved = allResolved;
  function allResolved(promises) {
      return when(promises, function (promises) {
          return when(all(array_map(promises, function (promise) {
              return when(promise, noop, noop);
          })), function () {
              return array_map(promises, resolve);
          });
      });
  }
  
  /**
   * 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
   */
  exports["catch"] = // XXX experimental
  exports.fail = fail;
  function fail(promise, rejected) {
      return when(promise, void 0, rejected);
  }
  
  /**
   * Provides an opportunity to observe the rejection 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.
   */
  exports["finally"] = // XXX experimental
  exports.fin = fin;
  function fin(promise, callback) {
      return when(promise, function (value) {
          return when(callback(), function () {
              return value;
          });
      }, function (exception) {
          return when(callback(), function () {
              return reject(exception);
          });
      });
  }
  
  /**
   * 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
   */
  exports.end = end; // XXX stopgap
  function end(promise) {
      when(promise, void 0, function (error) {
          // forward to a future turn so that ``when``
          // does not catch it and turn it into a rejection.
          nextTick(function () {
              // If possible (that is, if in V8), transform the error stack
              // trace by removing Node and Q cruft, then concatenating with
              // the stack trace of the promise we are ``end``ing. See #57.
              if (Error.captureStackTrace && "stack" in error) {
                  var errorStackFrames = getStackFrames(error);
                  var promiseStackFrames = getStackFrames(promise);
  
                  var combinedStackFrames = errorStackFrames.concat(
                      "From previous event:",
                      promiseStackFrames
                  );
                  error.stack = formatStackTrace(error, combinedStackFrames);
              }
  
              throw error;
          });
      });
  }
  
  /**
   * Causes a promise to be rejected if it does not get fulfilled before
   * some milliseconds time out.
   * @param {Any*} promise
   * @param {Number} milliseconds timeout
   * @returns a promise for the resolution of the given promise if it is
   * fulfilled before the timeout, otherwise rejected.
   */
  exports.timeout = timeout;
  function timeout(promise, ms) {
      var deferred = defer();
      var timeoutId = setTimeout(function () {
          deferred.reject(new Error("Timed out after " + ms + " ms"));
      }, ms);
  
      when(promise, function (value) {
          clearTimeout(timeoutId);
          deferred.resolve(value);
      }, deferred.reject);
      return deferred.promise;
  }
  
  /**
   * Returns a promise for the given value (or promised value) after some
   * milliseconds.
   * @param {Any*} promise
   * @param {Number} milliseconds
   * @returns a promise for the resolution of the given promise after some
   * time has elapsed.
   */
  exports.delay = delay;
  function delay(promise, timeout) {
      if (timeout === void 0) {
          timeout = promise;
          promise = void 0;
      }
      var deferred = defer();
      setTimeout(function () {
          deferred.resolve(promise);
      }, timeout);
      return deferred.promise;
  }
  
  /**
   * Passes a continuation to a Node function, which is called with a given
   * `this` value and arguments provided as an array, and returns a promise.
   *
   *      var FS = require("fs");
   *      Q.napply(FS.readFile, FS, [__filename])
   *      .then(function (content) {
   *      })
   *
   */
  exports.napply = napply;
  function napply(callback, thisp, args) {
      return nbind(callback, thisp).apply(void 0, args);
  }
  
  /**
   * Passes a continuation to a Node function, which is called with a given
   * `this` value and arguments provided individually, and returns a promise.
   *
   *      var FS = require("fs");
   *      Q.ncall(FS.readFile, FS, __filename)
   *      .then(function (content) {
   *      })
   *
   */
  exports.ncall = ncall;
  function ncall(callback, thisp /*, ...args*/) {
      var args = array_slice(arguments, 2);
      return napply(callback, thisp, args);
  }
  
  /**
   * Wraps a NodeJS continuation passing function and returns an equivalent
   * version that returns a promise.
   *
   *      Q.nbind(FS.readFile, FS)(__filename)
   *      .then(console.log)
   *      .end()
   *
   */
  exports.nbind = nbind;
  function nbind(callback /* thisp, ...args*/) {
      if (arguments.length > 1) {
          var thisp = arguments[1];
          var args = array_slice(arguments, 2);
  
          var originalCallback = callback;
          callback = function () {
              var combinedArgs = args.concat(array_slice(arguments));
              return originalCallback.apply(thisp, combinedArgs);
          };
      }
      return function () {
          var deferred = defer();
          var args = array_slice(arguments);
          // add a continuation that resolves the promise
          args.push(deferred.makeNodeResolver());
          // trap exceptions thrown by the callback
          fapply(callback, args)
          .fail(deferred.reject);
          return deferred.promise;
      };
  }
  
  /**
   * 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
   */
  exports.npost = npost;
  function npost(object, name, args) {
      return napply(object[name], object, args);
  }
  
  /**
   * 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
   */
  exports.ninvoke = ninvoke;
  function ninvoke(object, name /*, ...args*/) {
      var args = array_slice(arguments, 2);
      return napply(object[name], object, args);
  }
  
  defend(exports);
  
  });
  