text: "use strict";
  module.exports = function(Promise, INTERNAL) {
  var THIS = {};
  var util = require("./util.js");
  var nodebackForPromise = require("./promise_resolver.js")
      ._nodebackForPromise;
  var withAppended = util.withAppended;
  var maybeWrapAsError = util.maybeWrapAsError;
  var canEvaluate = util.canEvaluate;
  var TypeError = require("./errors").TypeError;
  var defaultSuffix = "Async";
  var defaultPromisified = {__isPromisified__: true};
  var noCopyPropsPattern =
      /^(?:length|name|arguments|caller|callee|prototype|__isPromisified__)$/;
  var defaultFilter = function(name, func) {
      return util.isIdentifier(name) &&
          name.charAt(0) !== "_" &&
          !util.isClass(func);
  };
  
  function propsFilter(key) {
      return !noCopyPropsPattern.test(key);
  }
  
  function isPromisified(fn) {
      try {
          return fn.__isPromisified__ === true;
      }
      catch (e) {
          return false;
      }
  }
  
  function hasPromisified(obj, key, suffix) {
      var val = util.getDataPropertyOrDefault(obj, key + suffix,
                                              defaultPromisified);
      return val ? isPromisified(val) : false;
  }
  function checkValid(ret, suffix, suffixRegexp) {
      for (var i = 0; i < ret.length; i += 2) {
          var key = ret[i];
          if (suffixRegexp.test(key)) {
              var keyWithoutAsyncSuffix = key.replace(suffixRegexp, "");
              for (var j = 0; j < ret.length; j += 2) {
                  if (ret[j] === keyWithoutAsyncSuffix) {
                      throw new TypeError("Cannot promisify an API that has normal methods with '%s'-suffix\u000a\u000a    See http://goo.gl/iWrZbw\u000a"
                          .replace("%s", suffix));
                  }
              }
          }
      }
  }
  
  function promisifiableMethods(obj, suffix, suffixRegexp, filter) {
      var keys = util.inheritedDataKeys(obj);
      var ret = [];
      for (var i = 0; i < keys.length; ++i) {
          var key = keys[i];
          var value = obj[key];
          var passesDefaultFilter = filter === defaultFilter
              ? true : defaultFilter(key, value, obj);
          if (typeof value === "function" &&
              !isPromisified(value) &&
              !hasPromisified(obj, key, suffix) &&
              filter(key, value, obj, passesDefaultFilter)) {
              ret.push(key, value);
          }
      }
      checkValid(ret, suffix, suffixRegexp);
      return ret;
  }
  
  var escapeIdentRegex = function(str) {
      return str.replace(/([$])/, "\\$");
  };
  
  var makeNodePromisifiedEval;
  if (!false) {
  var switchCaseArgumentOrder = function(likelyArgumentCount) {
      var ret = [likelyArgumentCount];
      var min = Math.max(0, likelyArgumentCount - 1 - 3);
      for(var i = likelyArgumentCount - 1; i >= min; --i) {
          ret.push(i);
      }
      for(var i = likelyArgumentCount + 1; i <= 3; ++i) {
          ret.push(i);
      }
      return ret;
  };
  
  var argumentSequence = function(argumentCount) {
      return util.filledRange(argumentCount, "_arg", "");
  };
  
  var parameterDeclaration = function(parameterCount) {
      return util.filledRange(
          Math.max(parameterCount, 3), "_arg", "");
  };
  
  var parameterCount = function(fn) {
      if (typeof fn.length === "number") {
          return Math.max(Math.min(fn.length, 1023 + 1), 0);
      }
      return 0;
  };
  
  makeNodePromisifiedEval =
  function(callback, receiver, originalName, fn) {
      var newParameterCount = Math.max(0, parameterCount(fn) - 1);
      var argumentOrder = switchCaseArgumentOrder(newParameterCount);
      var shouldProxyThis = typeof callback === "string" || receiver === THIS;
  
      function generateCallForArgumentCount(count) {
          var args = argumentSequence(count).join(", ");
          var comma = count > 0 ? ", " : "";
          var ret;
          if (shouldProxyThis) {
              ret = "ret = callback.call(this, {{args}}, nodeback); break;\n";
          } else {
              ret = receiver === undefined
                  ? "ret = callback({{args}}, nodeback); break;\n"
                  : "ret = callback.call(receiver, {{args}}, nodeback); break;\n";
          }
          return ret.replace("{{args}}", args).replace(", ", comma);
      }
  
      function generateArgumentSwitchCase() {
          var ret = "";
          for (var i = 0; i < argumentOrder.length; ++i) {
              ret += "case " + argumentOrder[i] +":" +
                  generateCallForArgumentCount(argumentOrder[i]);
          }
  
          ret += "                                                             \n\
          default:                                                             \n\
              var args = new Array(len + 1);                                   \n\
              var i = 0;                                                       \n\
              for (var i = 0; i < len; ++i) {                                  \n\
                 args[i] = arguments[i];                                       \n\
              }                                                                \n\
              args[i] = nodeback;                                              \n\
              [CodeForCall]                                                    \n\
              break;                                                           \n\
          ".replace("[CodeForCall]", (shouldProxyThis
                                  ? "ret = callback.apply(this, args);\n"
                                  : "ret = callback.apply(receiver, args);\n"));
          return ret;
      }
  
      var getFunctionCode = typeof callback === "string"
                                  ? ("this != null ? this['"+callback+"'] : fn")
                                  : "fn";
  
      return new Function("Promise",
                          "fn",
                          "receiver",
                          "withAppended",
                          "maybeWrapAsError",
                          "nodebackForPromise",
                          "tryCatch",
                          "errorObj",
                          "INTERNAL","'use strict';                            \n\
          var ret = function (Parameters) {                                    \n\
              'use strict';                                                    \n\
              var len = arguments.length;                                      \n\
              var promise = new Promise(INTERNAL);                             \n\
              promise._captureStackTrace();                                    \n\
              var nodeback = nodebackForPromise(promise);                      \n\
              var ret;                                                         \n\
              var callback = tryCatch([GetFunctionCode]);                      \n\
              switch(len) {                                                    \n\
                  [CodeForSwitchCase]                                          \n\
              }                                                                \n\
              if (ret === errorObj) {                                          \n\
                  promise._rejectCallback(maybeWrapAsError(ret.e), true, true);\n\
              }                                                                \n\
              return promise;                                                  \n\
          };                                                                   \n\
          ret.__isPromisified__ = true;                                        \n\
          return ret;                                                          \n\
          "
          .replace("Parameters", parameterDeclaration(newParameterCount))
          .replace("[CodeForSwitchCase]", generateArgumentSwitchCase())
          .replace("[GetFunctionCode]", getFunctionCode))(
              Promise,
              fn,
              receiver,
              withAppended,
              maybeWrapAsError,
              nodebackForPromise,
              util.tryCatch,
              util.errorObj,
              INTERNAL
          );
  };
  }
  
  function makeNodePromisifiedClosure(callback, receiver, _, fn) {
      var defaultThis = (function() {return this;})();
      var method = callback;
      if (typeof method === "string") {
          callback = fn;
      }
      function promisified() {
          var _receiver = receiver;
          if (receiver === THIS) _receiver = this;
          var promise = new Promise(INTERNAL);
          promise._captureStackTrace();
          var cb = typeof method === "string" && this !== defaultThis
              ? this[method] : callback;
          var fn = nodebackForPromise(promise);
          try {
              cb.apply(_receiver, withAppended(arguments, fn));
          } catch(e) {
              promise._rejectCallback(maybeWrapAsError(e), true, true);
          }
          return promise;
      }
      promisified.__isPromisified__ = true;
      return promisified;
  }
  
  var makeNodePromisified = canEvaluate
      ? makeNodePromisifiedEval
      : makeNodePromisifiedClosure;
  
  function promisifyAll(obj, suffix, filter, promisifier) {
      var suffixRegexp = new RegExp(escapeIdentRegex(suffix) + "$");
      var methods =
          promisifiableMethods(obj, suffix, suffixRegexp, filter);
  
      for (var i = 0, len = methods.length; i < len; i+= 2) {
          var key = methods[i];
          var fn = methods[i+1];
          var promisifiedKey = key + suffix;
          obj[promisifiedKey] = promisifier === makeNodePromisified
                  ? makeNodePromisified(key, THIS, key, fn, suffix)
                  : promisifier(fn, function() {
                      return makeNodePromisified(key, THIS, key, fn, suffix);
                  });
      }
      util.toFastProperties(obj);
      return obj;
  }
  
  function promisify(callback, receiver) {
      return makeNodePromisified(callback, receiver, undefined, callback);
  }
  
  Promise.promisify = function (fn, receiver) {
      if (typeof fn !== "function") {
          throw new TypeError("fn must be a function\u000a\u000a    See http://goo.gl/916lJJ\u000a");
      }
      if (isPromisified(fn)) {
          return fn;
      }
      var ret = promisify(fn, arguments.length < 2 ? THIS : receiver);
      util.copyDescriptors(fn, ret, propsFilter);
      return ret;
  };
  
  Promise.promisifyAll = function (target, options) {
      if (typeof target !== "function" && typeof target !== "object") {
          throw new TypeError("the target of promisifyAll must be an object or a function\u000a\u000a    See http://goo.gl/9ITlV0\u000a");
      }
      options = Object(options);
      var suffix = options.suffix;
      if (typeof suffix !== "string") suffix = defaultSuffix;
      var filter = options.filter;
      if (typeof filter !== "function") filter = defaultFilter;
      var promisifier = options.promisifier;
      if (typeof promisifier !== "function") promisifier = makeNodePromisified;
  
      if (!util.isIdentifier(suffix)) {
          throw new RangeError("suffix must be a valid identifier\u000a\u000a    See http://goo.gl/8FZo5V\u000a");
      }
  
      var keys = util.inheritedDataKeys(target);
      for (var i = 0; i < keys.length; ++i) {
          var value = target[keys[i]];
          if (keys[i] !== "constructor" &&
              util.isClass(value)) {
              promisifyAll(value.prototype, suffix, filter, promisifier);
              promisifyAll(value, suffix, filter, promisifier);
          }
      }
  
      return promisifyAll(target, suffix, filter, promisifier);
  };
  };
  
  