“use strict”; module.exports = function() { var async = require(“./async.js”); var util = require(“./util.js”); var bluebirdFramePattern =

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

var stackFramePattern = null; var formatStack = null; var indentStackFrames = false; var warn;

function CapturedTrace(parent) {

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

} util.inherits(CapturedTrace, Error);

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.parent = function() {

return this._parent;

};

CapturedTrace.prototype.hasParent = function() {

return this._parent !== undefined;

};

CapturedTrace.prototype.attachExtraTrace = function(error) {

if (error.__stackCleaned__) return;
this.uncycle();
var parsed = CapturedTrace.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);

};

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 = stackFramePattern.test(line) ||
        "    (No stack trace)" === 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) {
    stack = stack.slice(i);
}
return stack;

}

CapturedTrace.parseStackAndMessage = function(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: cleanStack(stack)
};

};

CapturedTrace.formatAndLogError = function(error, title) {

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

};

CapturedTrace.unhandledRejection = function (reason) {

CapturedTrace.formatAndLogError(reason, "^--- With additional stack trace: ");

};

CapturedTrace.isSupported = function () {

return typeof captureStackTrace === "function";

};

CapturedTrace.fireRejectionEvent = function(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);
}

var globalEventFired = false;
try {
    globalEventFired = fireGlobalEvent(name, reason, promise);
} catch (e) {
    globalEventFired = true;
    async.throwLater(e);
}

var domEventFired = false;
if (fireDomEvent) {
    try {
        domEventFired = fireDomEvent(name.toLowerCase(), {
            reason: reason,
            promise: promise
        });
    } catch (e) {
        domEventFired = true;
        async.throwLater(e);
    }
}

if (!globalEventFired && !localEventFired && !domEventFired &&
    name === "unhandledRejection") {
    CapturedTrace.formatAndLogError(reason, "Unhandled rejection ");
}

};

function formatNonError(obj) {

var str;
if (typeof obj === "function") {
    str = "[function " +
        (obj.name || "anonymous") +
        "]";
} else {
    str = obj.toString();
    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) + "...";

}

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)
    };
}

} CapturedTrace.setBounds = function(firstLineError, lastLineError) {

if (!CapturedTrace.isSupported()) 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;
};

};

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 = Error.stackTraceLimit + 6;
    stackFramePattern = v8stackFramePattern;
    formatStack = v8stackFormatter;
    var captureStackTrace = Error.captureStackTrace;

    shouldIgnore = function(line) {
        return bluebirdFramePattern.test(line);
    };
    return function(receiver, ignoreUntil) {
        Error.stackTraceLimit = Error.stackTraceLimit + 6;
        captureStackTrace(receiver, ignoreUntil);
        Error.stackTraceLimit = 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 = Error.stackTraceLimit + 6;
        try { throw new Error(); }
        catch(e) { o.stack = e.stack; }
        Error.stackTraceLimit = 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;

})([]);

var fireDomEvent; var fireGlobalEvent = (function() {

if (util.isNode) {
    return function(name, reason, promise) {
        if (name === "rejectionHandled") {
            return process.emit(name, promise);
        } else {
            return process.emit(name, reason, promise);
        }
    };
} else {
    var customEventWorks = false;
    var anyEventWorks = true;
    try {
        var ev = new self.CustomEvent("test");
        customEventWorks = ev instanceof CustomEvent;
    } catch (e) {}
    if (!customEventWorks) {
        try {
            var event = document.createEvent("CustomEvent");
            event.initCustomEvent("testingtheevent", false, true, {});
            self.dispatchEvent(event);
        } catch (e) {
            anyEventWorks = false;
        }
    }
    if (anyEventWorks) {
        fireDomEvent = function(type, detail) {
            var event;
            if (customEventWorks) {
                event = new self.CustomEvent(type, {
                    detail: detail,
                    bubbles: false,
                    cancelable: true
                });
            } else if (self.dispatchEvent) {
                event = document.createEvent("CustomEvent");
                event.initCustomEvent(type, false, true, detail);
            }

            return event ? !self.dispatchEvent(event) : false;
        };
    }

    var toWindowMethodNameMap = {};
    toWindowMethodNameMap["unhandledRejection"] = ("on" +
        "unhandledRejection").toLowerCase();
    toWindowMethodNameMap["rejectionHandled"] = ("on" +
        "rejectionHandled").toLowerCase();

    return function(name, reason, promise) {
        var methodName = toWindowMethodNameMap[name];
        var method = self[methodName];
        if (!method) return false;
        if (name === "rejectionHandled") {
            method.call(self, promise);
        } else {
            method.call(self, reason, promise);
        }
        return true;
    };
}

})();

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

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

}

return CapturedTrace; };