“use strict”; module.exports = function(Promise, Context,

enableAsyncHooks, disableAsyncHooks) {

var async = Promise._async; var Warning = require(“./errors”).Warning; var util = require(“./util”); var es5 = require(“./es5”); var canAttachTrace = util.canAttachTrace; var unhandledRejectionHandled; var possiblyUnhandledRejection; var bluebirdFramePattern =

/[\\\/]bluebird[\\\/]js[\\\/](release|debug|instrumented)/;

var nodeFramePattern = /((?:timers.js):d+:d+)/; var parseLinePattern = /[/<(](.+?):(d+):(d+))?s*$/; var stackFramePattern = null; var formatStack = null; var indentStackFrames = false; var printWarning; var debugging = !!(util.env(“BLUEBIRD_DEBUG”) != 0 &&

(false ||
 util.env("BLUEBIRD_DEBUG") ||
 util.env("NODE_ENV") === "development"));

var warnings = !!(util.env(“BLUEBIRD_WARNINGS”) != 0 &&

(debugging || util.env("BLUEBIRD_WARNINGS")));

var longStackTraces = !!(util.env(“BLUEBIRD_LONG_STACK_TRACES”) != 0 &&

(debugging || util.env("BLUEBIRD_LONG_STACK_TRACES")));

var wForgottenReturn = util.env(“BLUEBIRD_W_FORGOTTEN_RETURN”) != 0 &&

(warnings || !!util.env("BLUEBIRD_W_FORGOTTEN_RETURN"));

var deferUnhandledRejectionCheck; (function() {

var promises = [];

function unhandledRejectionCheck() {
    for (var i = 0; i < promises.length; ++i) {
        promises[i]._notifyUnhandledRejection();
    }
    unhandledRejectionClear();
}

function unhandledRejectionClear() {
    promises.length = 0;
}

if (util.isNode) {
    deferUnhandledRejectionCheck = (function() {
        var timers = require("timers");
        var timerSetTimeout = timers.setTimeout;
        var timer = timerSetTimeout(unhandledRejectionCheck, 1);
        timer.unref();

        return function(promise) {
            promises.push(promise);
            if (typeof timer.refresh === "function") {
                timer.refresh();
            } else {
                timerSetTimeout(unhandledRejectionCheck, 1).unref();
            }
        };
    })();
} else if (typeof document === "object" && document.createElement) {
    deferUnhandledRejectionCheck = (function() {
        var iframeSetTimeout;

        function checkIframe() {
            if (document.body) {
                var iframe = document.createElement("iframe");
                document.body.appendChild(iframe);
                if (iframe.contentWindow &&
                    iframe.contentWindow.setTimeout) {
                    iframeSetTimeout = iframe.contentWindow.setTimeout;
                }
                document.body.removeChild(iframe);
            }
        }
        checkIframe();
        return function(promise) {
            promises.push(promise);
            if (iframeSetTimeout) {
                iframeSetTimeout(unhandledRejectionCheck, 1);
            } else {
                checkIframe();
            }
        };
    })();
} else {
    deferUnhandledRejectionCheck = function(promise) {
        promises.push(promise);
        setTimeout(unhandledRejectionCheck, 1);
    };
}

es5.defineProperty(Promise, "_unhandledRejectionCheck", {
    value: unhandledRejectionCheck
});
es5.defineProperty(Promise, "_unhandledRejectionClear", {
    value: unhandledRejectionClear
});

})();

Promise.prototype.suppressUnhandledRejections = function() {

var target = this._target();
target._bitField = ((target._bitField & (~1048576)) |
                  524288);

};

Promise.prototype._ensurePossibleRejectionHandled = function () {

if ((this._bitField & 524288) !== 0) return;
this._setRejectionIsUnhandled();
deferUnhandledRejectionCheck(this);

};

Promise.prototype._notifyUnhandledRejectionIsHandled = function () {

fireRejectionEvent("rejectionHandled",
                              unhandledRejectionHandled, undefined, this);

};

Promise.prototype._setReturnedNonUndefined = function() {

this._bitField = this._bitField | 268435456;

};

Promise.prototype._returnedNonUndefined = function() {

return (this._bitField & 268435456) !== 0;

};

Promise.prototype._notifyUnhandledRejection = function () {

if (this._isRejectionUnhandled()) {
    var reason = this._settledValue();
    this._setUnhandledRejectionIsNotified();
    fireRejectionEvent("unhandledRejection",
                                  possiblyUnhandledRejection, reason, this);
}

};

Promise.prototype._setUnhandledRejectionIsNotified = function () {

this._bitField = this._bitField | 262144;

};

Promise.prototype._unsetUnhandledRejectionIsNotified = function () {

this._bitField = this._bitField & (~262144);

};

Promise.prototype._isUnhandledRejectionNotified = function () {

return (this._bitField & 262144) > 0;

};

Promise.prototype._setRejectionIsUnhandled = function () {

this._bitField = this._bitField | 1048576;

};

Promise.prototype._unsetRejectionIsUnhandled = function () {

this._bitField = this._bitField & (~1048576);
if (this._isUnhandledRejectionNotified()) {
    this._unsetUnhandledRejectionIsNotified();
    this._notifyUnhandledRejectionIsHandled();
}

};

Promise.prototype._isRejectionUnhandled = function () {

return (this._bitField & 1048576) > 0;

};

Promise.prototype._warn = function(message, shouldUseOwnTrace, promise) {

return warn(message, shouldUseOwnTrace, promise || this);

};

Promise.onPossiblyUnhandledRejection = function (fn) {

var context = Promise._getContext();
possiblyUnhandledRejection = util.contextBind(context, fn);

};

Promise.onUnhandledRejectionHandled = function (fn) {

var context = Promise._getContext();
unhandledRejectionHandled = util.contextBind(context, fn);

};

var disableLongStackTraces = function() {}; Promise.longStackTraces = function () {

if (async.haveItemsQueued() && !config.longStackTraces) {
    throw new Error("cannot enable long stack traces after promises have been created\u000a\u000a    See http://goo.gl/MqrFmX\u000a");
}
if (!config.longStackTraces && longStackTracesIsSupported()) {
    var Promise_captureStackTrace = Promise.prototype._captureStackTrace;
    var Promise_attachExtraTrace = Promise.prototype._attachExtraTrace;
    var Promise_dereferenceTrace = Promise.prototype._dereferenceTrace;
    config.longStackTraces = true;
    disableLongStackTraces = function() {
        if (async.haveItemsQueued() && !config.longStackTraces) {
            throw new Error("cannot enable long stack traces after promises have been created\u000a\u000a    See http://goo.gl/MqrFmX\u000a");
        }
        Promise.prototype._captureStackTrace = Promise_captureStackTrace;
        Promise.prototype._attachExtraTrace = Promise_attachExtraTrace;
        Promise.prototype._dereferenceTrace = Promise_dereferenceTrace;
        Context.deactivateLongStackTraces();
        config.longStackTraces = false;
    };
    Promise.prototype._captureStackTrace = longStackTracesCaptureStackTrace;
    Promise.prototype._attachExtraTrace = longStackTracesAttachExtraTrace;
    Promise.prototype._dereferenceTrace = longStackTracesDereferenceTrace;
    Context.activateLongStackTraces();
}

};

Promise.hasLongStackTraces = function () {

return config.longStackTraces && longStackTracesIsSupported();

};

var legacyHandlers = {

unhandledrejection: {
    before: function() {
        var ret = util.global.onunhandledrejection;
        util.global.onunhandledrejection = null;
        return ret;
    },
    after: function(fn) {
        util.global.onunhandledrejection = fn;
    }
},
rejectionhandled: {
    before: function() {
        var ret = util.global.onrejectionhandled;
        util.global.onrejectionhandled = null;
        return ret;
    },
    after: function(fn) {
        util.global.onrejectionhandled = fn;
    }
}

};

var fireDomEvent = (function() {

var dispatch = function(legacy, e) {
    if (legacy) {
        var fn;
        try {
            fn = legacy.before();
            return !util.global.dispatchEvent(e);
        } finally {
            legacy.after(fn);
        }
    } else {
        return !util.global.dispatchEvent(e);
    }
};
try {
    if (typeof CustomEvent === "function") {
        var event = new CustomEvent("CustomEvent");
        util.global.dispatchEvent(event);
        return function(name, event) {
            name = name.toLowerCase();
            var eventData = {
                detail: event,
                cancelable: true
            };
            var domEvent = new CustomEvent(name, eventData);
            es5.defineProperty(
                domEvent, "promise", {value: event.promise});
            es5.defineProperty(
                domEvent, "reason", {value: event.reason});

            return dispatch(legacyHandlers[name], domEvent);
        };
    } else if (typeof Event === "function") {
        var event = new Event("CustomEvent");
        util.global.dispatchEvent(event);
        return function(name, event) {
            name = name.toLowerCase();
            var domEvent = new Event(name, {
                cancelable: true
            });
            domEvent.detail = event;
            es5.defineProperty(domEvent, "promise", {value: event.promise});
            es5.defineProperty(domEvent, "reason", {value: event.reason});
            return dispatch(legacyHandlers[name], domEvent);
        };
    } else {
        var event = document.createEvent("CustomEvent");
        event.initCustomEvent("testingtheevent", false, true, {});
        util.global.dispatchEvent(event);
        return function(name, event) {
            name = name.toLowerCase();
            var domEvent = document.createEvent("CustomEvent");
            domEvent.initCustomEvent(name, false, true,
                event);
            return dispatch(legacyHandlers[name], domEvent);
        };
    }
} catch (e) {}
return function() {
    return false;
};

})();

var fireGlobalEvent = (function() {

if (util.isNode) {
    return function() {
        return process.emit.apply(process, arguments);
    };
} else {
    if (!util.global) {
        return function() {
            return false;
        };
    }
    return function(name) {
        var methodName = "on" + name.toLowerCase();
        var method = util.global[methodName];
        if (!method) return false;
        method.apply(util.global, [].slice.call(arguments, 1));
        return true;
    };
}

})();

function generatePromiseLifecycleEventObject(name, promise) {

return {promise: promise};

}

var eventToObjectGenerator = {

promiseCreated: generatePromiseLifecycleEventObject,
promiseFulfilled: generatePromiseLifecycleEventObject,
promiseRejected: generatePromiseLifecycleEventObject,
promiseResolved: generatePromiseLifecycleEventObject,
promiseCancelled: generatePromiseLifecycleEventObject,
promiseChained: function(name, promise, child) {
    return {promise: promise, child: child};
},
warning: function(name, warning) {
    return {warning: warning};
},
unhandledRejection: function (name, reason, promise) {
    return {reason: reason, promise: promise};
},
rejectionHandled: generatePromiseLifecycleEventObject

};

var activeFireEvent = function (name) {

var globalEventFired = false;
try {
    globalEventFired = fireGlobalEvent.apply(null, arguments);
} catch (e) {
    async.throwLater(e);
    globalEventFired = true;
}

var domEventFired = false;
try {
    domEventFired = fireDomEvent(name,
                eventToObjectGenerator[name].apply(null, arguments));
} catch (e) {
    async.throwLater(e);
    domEventFired = true;
}

return domEventFired || globalEventFired;

};

Promise.config = function(opts) {

opts = Object(opts);
if ("longStackTraces" in opts) {
    if (opts.longStackTraces) {
        Promise.longStackTraces();
    } else if (!opts.longStackTraces && Promise.hasLongStackTraces()) {
        disableLongStackTraces();
    }
}
if ("warnings" in opts) {
    var warningsOption = opts.warnings;
    config.warnings = !!warningsOption;
    wForgottenReturn = config.warnings;

    if (util.isObject(warningsOption)) {
        if ("wForgottenReturn" in warningsOption) {
            wForgottenReturn = !!warningsOption.wForgottenReturn;
        }
    }
}
if ("cancellation" in opts && opts.cancellation && !config.cancellation) {
    if (async.haveItemsQueued()) {
        throw new Error(
            "cannot enable cancellation after promises are in use");
    }
    Promise.prototype._clearCancellationData =
        cancellationClearCancellationData;
    Promise.prototype._propagateFrom = cancellationPropagateFrom;
    Promise.prototype._onCancel = cancellationOnCancel;
    Promise.prototype._setOnCancel = cancellationSetOnCancel;
    Promise.prototype._attachCancellationCallback =
        cancellationAttachCancellationCallback;
    Promise.prototype._execute = cancellationExecute;
    propagateFromFunction = cancellationPropagateFrom;
    config.cancellation = true;
}
if ("monitoring" in opts) {
    if (opts.monitoring && !config.monitoring) {
        config.monitoring = true;
        Promise.prototype._fireEvent = activeFireEvent;
    } else if (!opts.monitoring && config.monitoring) {
        config.monitoring = false;
        Promise.prototype._fireEvent = defaultFireEvent;
    }
}
if ("asyncHooks" in opts && util.nodeSupportsAsyncResource) {
    var prev = config.asyncHooks;
    var cur = !!opts.asyncHooks;
    if (prev !== cur) {
        config.asyncHooks = cur;
        if (cur) {
            enableAsyncHooks();
        } else {
            disableAsyncHooks();
        }
    }
}
return Promise;

};

function defaultFireEvent() { return false; }

Promise.prototype._fireEvent = defaultFireEvent; Promise.prototype._execute = function(executor, resolve, reject) {

try {
    executor(resolve, reject);
} catch (e) {
    return e;
}

}; Promise.prototype._onCancel = function () {}; Promise.prototype._setOnCancel = function (handler) { ; }; Promise.prototype._attachCancellationCallback = function(onCancel) {

;

}; Promise.prototype._captureStackTrace = function () {}; Promise.prototype._attachExtraTrace = function () {}; Promise.prototype._dereferenceTrace = function () {}; Promise.prototype._clearCancellationData = function() {}; Promise.prototype._propagateFrom = function (parent, flags) {

;
;

};

function cancellationExecute(executor, resolve, reject) {

var promise = this;
try {
    executor(resolve, reject, function(onCancel) {
        if (typeof onCancel !== "function") {
            throw new TypeError("onCancel must be a function, got: " +
                                util.toString(onCancel));
        }
        promise._attachCancellationCallback(onCancel);
    });
} catch (e) {
    return e;
}

}

function cancellationAttachCancellationCallback(onCancel) {

if (!this._isCancellable()) return this;

var previousOnCancel = this._onCancel();
if (previousOnCancel !== undefined) {
    if (util.isArray(previousOnCancel)) {
        previousOnCancel.push(onCancel);
    } else {
        this._setOnCancel([previousOnCancel, onCancel]);
    }
} else {
    this._setOnCancel(onCancel);
}

}

function cancellationOnCancel() {

return this._onCancelField;

}

function cancellationSetOnCancel(onCancel) {

this._onCancelField = onCancel;

}

function cancellationClearCancellationData() {

this._cancellationParent = undefined;
this._onCancelField = undefined;

}

function cancellationPropagateFrom(parent, flags) {

if ((flags & 1) !== 0) {
    this._cancellationParent = parent;
    var branchesRemainingToCancel = parent._branchesRemainingToCancel;
    if (branchesRemainingToCancel === undefined) {
        branchesRemainingToCancel = 0;
    }
    parent._branchesRemainingToCancel = branchesRemainingToCancel + 1;
}
if ((flags & 2) !== 0 && parent._isBound()) {
    this._setBoundTo(parent._boundTo);
}

}

function bindingPropagateFrom(parent, flags) {

if ((flags & 2) !== 0 && parent._isBound()) {
    this._setBoundTo(parent._boundTo);
}

} var propagateFromFunction = bindingPropagateFrom;

function boundValueFunction() {

var ret = this._boundTo;
if (ret !== undefined) {
    if (ret instanceof Promise) {
        if (ret.isFulfilled()) {
            return ret.value();
        } else {
            return undefined;
        }
    }
}
return ret;

}

function longStackTracesCaptureStackTrace() {

this._trace = new CapturedTrace(this._peekContext());

}

function longStackTracesAttachExtraTrace(error, ignoreSelf) {

if (canAttachTrace(error)) {
    var trace = this._trace;
    if (trace !== undefined) {
        if (ignoreSelf) trace = trace._parent;
    }
    if (trace !== undefined) {
        trace.attachExtraTrace(error);
    } else if (!error.__stackCleaned__) {
        var parsed = parseStackAndMessage(error);
        util.notEnumerableProp(error, "stack",
            parsed.message + "\n" + parsed.stack.join("\n"));
        util.notEnumerableProp(error, "__stackCleaned__", true);
    }
}

}

function longStackTracesDereferenceTrace() {

this._trace = undefined;

}

function checkForgottenReturns(returnValue, promiseCreated, name, promise,

                           parent) {
if (returnValue === undefined && promiseCreated !== null &&
    wForgottenReturn) {
    if (parent !== undefined && parent._returnedNonUndefined()) return;
    if ((promise._bitField & 65535) === 0) return;

    if (name) name = name + " ";
    var handlerLine = "";
    var creatorLine = "";
    if (promiseCreated._trace) {
        var traceLines = promiseCreated._trace.stack.split("\n");
        var stack = cleanStack(traceLines);
        for (var i = stack.length - 1; i >= 0; --i) {
            var line = stack[i];
            if (!nodeFramePattern.test(line)) {
                var lineMatches = line.match(parseLinePattern);
                if (lineMatches) {
                    handlerLine  = "at " + lineMatches[1] +
                        ":" + lineMatches[2] + ":" + lineMatches[3] + " ";
                }
                break;
            }
        }

        if (stack.length > 0) {
            var firstUserLine = stack[0];
            for (var i = 0; i < traceLines.length; ++i) {

                if (traceLines[i] === firstUserLine) {
                    if (i > 0) {
                        creatorLine = "\n" + traceLines[i - 1];
                    }
                    break;
                }
            }

        }
    }
    var msg = "a promise was created in a " + name +
        "handler " + handlerLine + "but was not returned from it, " +
        "see http://goo.gl/rRqMUw" +
        creatorLine;
    promise._warn(msg, true, promiseCreated);
}

}

function deprecated(name, replacement) {

var message = name +
    " is deprecated and will be removed in a future version.";
if (replacement) message += " Use " + replacement + " instead.";
return warn(message);

}

function warn(message, shouldUseOwnTrace, promise) {

if (!config.warnings) return;
var warning = new Warning(message);
var ctx;
if (shouldUseOwnTrace) {
    promise._attachExtraTrace(warning);
} else if (config.longStackTraces && (ctx = Promise._peekContext())) {
    ctx.attachExtraTrace(warning);
} else {
    var parsed = parseStackAndMessage(warning);
    warning.stack = parsed.message + "\n" + parsed.stack.join("\n");
}

if (!activeFireEvent("warning", warning)) {
    formatAndLogError(warning, "", true);
}

}

function reconstructStack(message, stacks) {

for (var i = 0; i < stacks.length - 1; ++i) {
    stacks[i].push("From previous event:");
    stacks[i] = stacks[i].join("\n");
}
if (i < stacks.length) {
    stacks[i] = stacks[i].join("\n");
}
return message + "\n" + stacks.join("\n");

}

function removeDuplicateOrEmptyJumps(stacks) {

for (var i = 0; i < stacks.length; ++i) {
    if (stacks[i].length === 0 ||
        ((i + 1 < stacks.length) && stacks[i][0] === stacks[i+1][0])) {
        stacks.splice(i, 1);
        i--;
    }
}

}

function removeCommonRoots(stacks) {

var current = stacks[0];
for (var i = 1; i < stacks.length; ++i) {
    var prev = stacks[i];
    var currentLastIndex = current.length - 1;
    var currentLastLine = current[currentLastIndex];
    var commonRootMeetPoint = -1;

    for (var j = prev.length - 1; j >= 0; --j) {
        if (prev[j] === currentLastLine) {
            commonRootMeetPoint = j;
            break;
        }
    }

    for (var j = commonRootMeetPoint; j >= 0; --j) {
        var line = prev[j];
        if (current[currentLastIndex] === line) {
            current.pop();
            currentLastIndex--;
        } else {
            break;
        }
    }
    current = prev;
}

}

function cleanStack(stack) {

var ret = [];
for (var i = 0; i < stack.length; ++i) {
    var line = stack[i];
    var isTraceLine = "    (No stack trace)" === line ||
        stackFramePattern.test(line);
    var isInternalFrame = isTraceLine && shouldIgnore(line);
    if (isTraceLine && !isInternalFrame) {
        if (indentStackFrames && line.charAt(0) !== " ") {
            line = "    " + line;
        }
        ret.push(line);
    }
}
return ret;

}

function stackFramesAsArray(error) {

var stack = error.stack.replace(/\s+$/g, "").split("\n");
for (var i = 0; i < stack.length; ++i) {
    var line = stack[i];
    if ("    (No stack trace)" === line || stackFramePattern.test(line)) {
        break;
    }
}
if (i > 0 && error.name != "SyntaxError") {
    stack = stack.slice(i);
}
return stack;

}

function parseStackAndMessage(error) {

var stack = error.stack;
var message = error.toString();
stack = typeof stack === "string" && stack.length > 0
            ? stackFramesAsArray(error) : ["    (No stack trace)"];
return {
    message: message,
    stack: error.name == "SyntaxError" ? stack : cleanStack(stack)
};

}

function formatAndLogError(error, title, isSoft) {

if (typeof console !== "undefined") {
    var message;
    if (util.isObject(error)) {
        var stack = error.stack;
        message = title + formatStack(stack, error);
    } else {
        message = title + String(error);
    }
    if (typeof printWarning === "function") {
        printWarning(message, isSoft);
    } else if (typeof console.log === "function" ||
        typeof console.log === "object") {
        console.log(message);
    }
}

}

function fireRejectionEvent(name, localHandler, reason, promise) {

var localEventFired = false;
try {
    if (typeof localHandler === "function") {
        localEventFired = true;
        if (name === "rejectionHandled") {
            localHandler(promise);
        } else {
            localHandler(reason, promise);
        }
    }
} catch (e) {
    async.throwLater(e);
}

if (name === "unhandledRejection") {
    if (!activeFireEvent(name, reason, promise) && !localEventFired) {
        formatAndLogError(reason, "Unhandled rejection ");
    }
} else {
    activeFireEvent(name, promise);
}

}

function formatNonError(obj) {

var str;
if (typeof obj === "function") {
    str = "[function " +
        (obj.name || "anonymous") +
        "]";
} else {
    str = obj && typeof obj.toString === "function"
        ? obj.toString() : util.toString(obj);
    var ruselessToString = /\[object [a-zA-Z0-9$_]+\]/;
    if (ruselessToString.test(str)) {
        try {
            var newStr = JSON.stringify(obj);
            str = newStr;
        }
        catch(e) {

        }
    }
    if (str.length === 0) {
        str = "(empty array)";
    }
}
return ("(<" + snip(str) + ">, no stack trace)");

}

function snip(str) {

var maxChars = 41;
if (str.length < maxChars) {
    return str;
}
return str.substr(0, maxChars - 3) + "...";

}

function longStackTracesIsSupported() {

return typeof captureStackTrace === "function";

}

var shouldIgnore = function() { return false; }; var parseLineInfoRegex = /[/<(]([^:/]+):(d+):(?:d+))?s*$/; function parseLineInfo(line) {

var matches = line.match(parseLineInfoRegex);
if (matches) {
    return {
        fileName: matches[1],
        line: parseInt(matches[2], 10)
    };
}

}

function setBounds(firstLineError, lastLineError) {

if (!longStackTracesIsSupported()) return;
var firstStackLines = (firstLineError.stack || "").split("\n");
var lastStackLines = (lastLineError.stack || "").split("\n");
var firstIndex = -1;
var lastIndex = -1;
var firstFileName;
var lastFileName;
for (var i = 0; i < firstStackLines.length; ++i) {
    var result = parseLineInfo(firstStackLines[i]);
    if (result) {
        firstFileName = result.fileName;
        firstIndex = result.line;
        break;
    }
}
for (var i = 0; i < lastStackLines.length; ++i) {
    var result = parseLineInfo(lastStackLines[i]);
    if (result) {
        lastFileName = result.fileName;
        lastIndex = result.line;
        break;
    }
}
if (firstIndex < 0 || lastIndex < 0 || !firstFileName || !lastFileName ||
    firstFileName !== lastFileName || firstIndex >= lastIndex) {
    return;
}

shouldIgnore = function(line) {
    if (bluebirdFramePattern.test(line)) return true;
    var info = parseLineInfo(line);
    if (info) {
        if (info.fileName === firstFileName &&
            (firstIndex <= info.line && info.line <= lastIndex)) {
            return true;
        }
    }
    return false;
};

}

function CapturedTrace(parent) {

this._parent = parent;
this._promisesCreated = 0;
var length = this._length = 1 + (parent === undefined ? 0 : parent._length);
captureStackTrace(this, CapturedTrace);
if (length > 32) this.uncycle();

} util.inherits(CapturedTrace, Error); Context.CapturedTrace = CapturedTrace;

CapturedTrace.prototype.uncycle = function() {

var length = this._length;
if (length < 2) return;
var nodes = [];
var stackToIndex = {};

for (var i = 0, node = this; node !== undefined; ++i) {
    nodes.push(node);
    node = node._parent;
}
length = this._length = i;
for (var i = length - 1; i >= 0; --i) {
    var stack = nodes[i].stack;
    if (stackToIndex[stack] === undefined) {
        stackToIndex[stack] = i;
    }
}
for (var i = 0; i < length; ++i) {
    var currentStack = nodes[i].stack;
    var index = stackToIndex[currentStack];
    if (index !== undefined && index !== i) {
        if (index > 0) {
            nodes[index - 1]._parent = undefined;
            nodes[index - 1]._length = 1;
        }
        nodes[i]._parent = undefined;
        nodes[i]._length = 1;
        var cycleEdgeNode = i > 0 ? nodes[i - 1] : this;

        if (index < length - 1) {
            cycleEdgeNode._parent = nodes[index + 1];
            cycleEdgeNode._parent.uncycle();
            cycleEdgeNode._length =
                cycleEdgeNode._parent._length + 1;
        } else {
            cycleEdgeNode._parent = undefined;
            cycleEdgeNode._length = 1;
        }
        var currentChildLength = cycleEdgeNode._length + 1;
        for (var j = i - 2; j >= 0; --j) {
            nodes[j]._length = currentChildLength;
            currentChildLength++;
        }
        return;
    }
}

};

CapturedTrace.prototype.attachExtraTrace = function(error) {

if (error.__stackCleaned__) return;
this.uncycle();
var parsed = parseStackAndMessage(error);
var message = parsed.message;
var stacks = [parsed.stack];

var trace = this;
while (trace !== undefined) {
    stacks.push(cleanStack(trace.stack.split("\n")));
    trace = trace._parent;
}
removeCommonRoots(stacks);
removeDuplicateOrEmptyJumps(stacks);
util.notEnumerableProp(error, "stack", reconstructStack(message, stacks));
util.notEnumerableProp(error, "__stackCleaned__", true);

};

var captureStackTrace = (function stackDetection() {

var v8stackFramePattern = /^\s*at\s*/;
var v8stackFormatter = function(stack, error) {
    if (typeof stack === "string") return stack;

    if (error.name !== undefined &&
        error.message !== undefined) {
        return error.toString();
    }
    return formatNonError(error);
};

if (typeof Error.stackTraceLimit === "number" &&
    typeof Error.captureStackTrace === "function") {
    Error.stackTraceLimit += 6;
    stackFramePattern = v8stackFramePattern;
    formatStack = v8stackFormatter;
    var captureStackTrace = Error.captureStackTrace;

    shouldIgnore = function(line) {
        return bluebirdFramePattern.test(line);
    };
    return function(receiver, ignoreUntil) {
        Error.stackTraceLimit += 6;
        captureStackTrace(receiver, ignoreUntil);
        Error.stackTraceLimit -= 6;
    };
}
var err = new Error();

if (typeof err.stack === "string" &&
    err.stack.split("\n")[0].indexOf("stackDetection@") >= 0) {
    stackFramePattern = /@/;
    formatStack = v8stackFormatter;
    indentStackFrames = true;
    return function captureStackTrace(o) {
        o.stack = new Error().stack;
    };
}

var hasStackAfterThrow;
try { throw new Error(); }
catch(e) {
    hasStackAfterThrow = ("stack" in e);
}
if (!("stack" in err) && hasStackAfterThrow &&
    typeof Error.stackTraceLimit === "number") {
    stackFramePattern = v8stackFramePattern;
    formatStack = v8stackFormatter;
    return function captureStackTrace(o) {
        Error.stackTraceLimit += 6;
        try { throw new Error(); }
        catch(e) { o.stack = e.stack; }
        Error.stackTraceLimit -= 6;
    };
}

formatStack = function(stack, error) {
    if (typeof stack === "string") return stack;

    if ((typeof error === "object" ||
        typeof error === "function") &&
        error.name !== undefined &&
        error.message !== undefined) {
        return error.toString();
    }
    return formatNonError(error);
};

return null;

})([]);

if (typeof console !== “undefined” && typeof console.warn !== “undefined”) {

printWarning = function (message) {
    console.warn(message);
};
if (util.isNode && process.stderr.isTTY) {
    printWarning = function(message, isSoft) {
        var color = isSoft ? "\u001b[33m" : "\u001b[31m";
        console.warn(color + message + "\u001b[0m\n");
    };
} else if (!util.isNode && typeof (new Error().stack) === "string") {
    printWarning = function(message, isSoft) {
        console.warn("%c" + message,
                    isSoft ? "color: darkorange" : "color: red");
    };
}

}

var config = {

warnings: warnings,
longStackTraces: false,
cancellation: false,
monitoring: false,
asyncHooks: false

};

if (longStackTraces) Promise.longStackTraces();

return {

asyncHooks: function() {
    return config.asyncHooks;
},
longStackTraces: function() {
    return config.longStackTraces;
},
warnings: function() {
    return config.warnings;
},
cancellation: function() {
    return config.cancellation;
},
monitoring: function() {
    return config.monitoring;
},
propagateFromFunction: function() {
    return propagateFromFunction;
},
boundValueFunction: function() {
    return boundValueFunction;
},
checkForgottenReturns: checkForgottenReturns,
setBounds: setBounds,
warn: warn,
deprecated: deprecated,
CapturedTrace: CapturedTrace,
fireDomEvent: fireDomEvent,
fireGlobalEvent: fireGlobalEvent

}; };