Bug 1412091 - Export Screenshots 23.0.0 to Firefox (update raven to 3.18.1) draft
authorIan Bicking <ianb@colorstudy.com>
Fri, 27 Oct 2017 13:31:38 -0500
changeset 687768 3398894c0746c76d1768d2fd8bfdccac38b8c0b5
parent 687767 5716ac9948967ce1b9b9829bcdebd68d5997c1d8
child 687769 c45cefae79bf502b20b965cdb9c98b180347e33f
child 697269 56b1df5fdbe2d8b0c7c8974cb30c44648ce6674d
child 697273 e27f7dbebf6dc243cc6e4edfe92e5f14fa03de3a
push id86599
push userbmo:ianb@mozilla.com
push dateFri, 27 Oct 2017 18:33:14 +0000
bugs1412091
milestone58.0a1
Bug 1412091 - Export Screenshots 23.0.0 to Firefox (update raven to 3.18.1) MozReview-Commit-ID: BbW0ZqMw3bu
browser/extensions/screenshots/webextension/build/raven.js
--- a/browser/extensions/screenshots/webextension/build/raven.js
+++ b/browser/extensions/screenshots/webextension/build/raven.js
@@ -1,2256 +1,2587 @@
-/*! Raven.js 3.17.0 (6384830) | github.com/getsentry/raven-js */
+/*! Raven.js 3.18.1 (2dca364) | github.com/getsentry/raven-js */
 
 /*
  * Includes TraceKit
  * https://github.com/getsentry/TraceKit
  *
  * Copyright 2017 Matt Robenolt and other contributors
  * Released under the BSD license
  * https://github.com/getsentry/raven-js/blob/master/LICENSE
  *
  */
 
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Raven = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
-'use strict';
-
-function RavenConfigError(message) {
-    this.name = 'RavenConfigError';
-    this.message = message;
-}
-RavenConfigError.prototype = new Error();
-RavenConfigError.prototype.constructor = RavenConfigError;
-
-module.exports = RavenConfigError;
-
-},{}],2:[function(_dereq_,module,exports){
-'use strict';
-
-var wrapMethod = function(console, level, callback) {
-    var originalConsoleLevel = console[level];
-    var originalConsole = console;
-
-    if (!(level in console)) {
-        return;
+(function(f) {
+  if (typeof exports === 'object' && typeof module !== 'undefined') {
+    module.exports = f();
+  } else if (typeof define === 'function' && define.amd) {
+    define([], f);
+  } else {
+    var g;
+    if (typeof window !== 'undefined') {
+      g = window;
+    } else if (typeof global !== 'undefined') {
+      g = global;
+    } else if (typeof self !== 'undefined') {
+      g = self;
+    } else {
+      g = this;
     }
-
-    var sentryLevel = level === 'warn'
-        ? 'warning'
-        : level;
-
-    console[level] = function () {
-        var args = [].slice.call(arguments);
-
-        var msg = '' + args.join(' ');
-        var data = {level: sentryLevel, logger: 'console', extra: {'arguments': args}};
-        callback && callback(msg, data);
-
-        // this fails for some browsers. :(
-        if (originalConsoleLevel) {
-            // IE9 doesn't allow calling apply on console functions directly
-            // See: https://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function#answer-5473193
-            Function.prototype.apply.call(
-                originalConsoleLevel,
-                originalConsole,
-                args
-            );
+    g.Raven = f();
+  }
+})(function() {
+  var define, module, exports;
+  return (function e(t, n, r) {
+    function s(o, u) {
+      if (!n[o]) {
+        if (!t[o]) {
+          var a = typeof require == 'function' && require;
+          if (!u && a) return a(o, !0);
+          if (i) return i(o, !0);
+          var f = new Error("Cannot find module '" + o + "'");
+          throw ((f.code = 'MODULE_NOT_FOUND'), f);
         }
-    };
-};
-
-module.exports = {
-    wrapMethod: wrapMethod
-};
-
-},{}],3:[function(_dereq_,module,exports){
-(function (global){
-/*global XDomainRequest:false, __DEV__:false*/
-'use strict';
-
-var TraceKit = _dereq_(6);
-var stringify = _dereq_(7);
-var RavenConfigError = _dereq_(1);
-var utils = _dereq_(5);
-
-var isError = utils.isError,
-    isObject = utils.isObject;
-
-var wrapConsoleMethod = _dereq_(2).wrapMethod;
-
-var dsnKeys = 'source protocol user pass host port path'.split(' '),
-    dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
-
-function now() {
-    return +new Date();
-}
-
-// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
-var _window = typeof window !== 'undefined' ? window
-            : typeof global !== 'undefined' ? global
-            : typeof self !== 'undefined' ? self
-            : {};
-var _document = _window.document;
-var _navigator = _window.navigator;
-
-
-function keepOriginalCallback(original, callback) {
-    return isFunction(callback) ?
-    function (data) { return callback(data, original) } :
-    callback;
-}
-
-// First, check for JSON support
-// If there is no JSON, we no-op the core features of Raven
-// since JSON is required to encode the payload
-function Raven() {
-    this._hasJSON = !!(typeof JSON === 'object' && JSON.stringify);
-    // Raven can run in contexts where there's no document (react-native)
-    this._hasDocument = !isUndefined(_document);
-    this._hasNavigator = !isUndefined(_navigator);
-    this._lastCapturedException = null;
-    this._lastData = null;
-    this._lastEventId = null;
-    this._globalServer = null;
-    this._globalKey = null;
-    this._globalProject = null;
-    this._globalContext = {};
-    this._globalOptions = {
-        logger: 'javascript',
-        ignoreErrors: [],
-        ignoreUrls: [],
-        whitelistUrls: [],
-        includePaths: [],
-        crossOrigin: 'anonymous',
-        collectWindowErrors: true,
-        maxMessageLength: 0,
-
-        // By default, truncates URL values to 250 chars
-        maxUrlLength: 250,
-        stackTraceLimit: 50,
-        autoBreadcrumbs: true,
-        instrument: true,
-        sampleRate: 1
-    };
-    this._ignoreOnError = 0;
-    this._isRavenInstalled = false;
-    this._originalErrorStackTraceLimit = Error.stackTraceLimit;
-    // capture references to window.console *and* all its methods first
-    // before the console plugin has a chance to monkey patch
-    this._originalConsole = _window.console || {};
-    this._originalConsoleMethods = {};
-    this._plugins = [];
-    this._startTime = now();
-    this._wrappedBuiltIns = [];
-    this._breadcrumbs = [];
-    this._lastCapturedEvent = null;
-    this._keypressTimeout;
-    this._location = _window.location;
-    this._lastHref = this._location && this._location.href;
-    this._resetBackoff();
-
-    for (var method in this._originalConsole) {  // eslint-disable-line guard-for-in
-      this._originalConsoleMethods[method] = this._originalConsole[method];
+        var l = (n[o] = {exports: {}});
+        t[o][0].call(
+          l.exports,
+          function(e) {
+            var n = t[o][1][e];
+            return s(n ? n : e);
+          },
+          l,
+          l.exports,
+          e,
+          t,
+          n,
+          r
+        );
+      }
+      return n[o].exports;
     }
-}
-
-/*
+    var i = typeof require == 'function' && require;
+    for (var o = 0; o < r.length; o++) s(r[o]);
+    return s;
+  })(
+    {
+      1: [
+        function(_dereq_, module, exports) {
+          function RavenConfigError(message) {
+            this.name = 'RavenConfigError';
+            this.message = message;
+          }
+          RavenConfigError.prototype = new Error();
+          RavenConfigError.prototype.constructor = RavenConfigError;
+
+          module.exports = RavenConfigError;
+        },
+        {}
+      ],
+      2: [
+        function(_dereq_, module, exports) {
+          var wrapMethod = function(console, level, callback) {
+            var originalConsoleLevel = console[level];
+            var originalConsole = console;
+
+            if (!(level in console)) {
+              return;
+            }
+
+            var sentryLevel = level === 'warn' ? 'warning' : level;
+
+            console[level] = function() {
+              var args = [].slice.call(arguments);
+
+              var msg = '' + args.join(' ');
+              var data = {
+                level: sentryLevel,
+                logger: 'console',
+                extra: {arguments: args}
+              };
+
+              if (level === 'assert') {
+                if (args[0] === false) {
+                  // Default browsers message
+                  msg =
+                    'Assertion failed: ' + (args.slice(1).join(' ') || 'console.assert');
+                  data.extra.arguments = args.slice(1);
+                  callback && callback(msg, data);
+                }
+              } else {
+                callback && callback(msg, data);
+              }
+
+              // this fails for some browsers. :(
+              if (originalConsoleLevel) {
+                // IE9 doesn't allow calling apply on console functions directly
+                // See: https://stackoverflow.com/questions/5472938/does-ie9-support-console-log-and-is-it-a-real-function#answer-5473193
+                Function.prototype.apply.call(
+                  originalConsoleLevel,
+                  originalConsole,
+                  args
+                );
+              }
+            };
+          };
+
+          module.exports = {
+            wrapMethod: wrapMethod
+          };
+        },
+        {}
+      ],
+      3: [
+        function(_dereq_, module, exports) {
+          (function(global) {
+            /*global XDomainRequest:false, __DEV__:false*/
+
+            var TraceKit = _dereq_(6);
+            var stringify = _dereq_(7);
+            var RavenConfigError = _dereq_(1);
+            var utils = _dereq_(5);
+
+            var isError = utils.isError,
+              isObject = utils.isObject;
+
+            var wrapConsoleMethod = _dereq_(2).wrapMethod;
+
+            var dsnKeys = 'source protocol user pass host port path'.split(' '),
+              dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
+
+            function now() {
+              return +new Date();
+            }
+
+            // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
+            var _window =
+              typeof window !== 'undefined'
+                ? window
+                : typeof global !== 'undefined'
+                  ? global
+                  : typeof self !== 'undefined' ? self : {};
+            var _document = _window.document;
+            var _navigator = _window.navigator;
+
+            function keepOriginalCallback(original, callback) {
+              return isFunction(callback)
+                ? function(data) {
+                    return callback(data, original);
+                  }
+                : callback;
+            }
+
+            // First, check for JSON support
+            // If there is no JSON, we no-op the core features of Raven
+            // since JSON is required to encode the payload
+            function Raven() {
+              this._hasJSON = !!(typeof JSON === 'object' && JSON.stringify);
+              // Raven can run in contexts where there's no document (react-native)
+              this._hasDocument = !isUndefined(_document);
+              this._hasNavigator = !isUndefined(_navigator);
+              this._lastCapturedException = null;
+              this._lastData = null;
+              this._lastEventId = null;
+              this._globalServer = null;
+              this._globalKey = null;
+              this._globalProject = null;
+              this._globalContext = {};
+              this._globalOptions = {
+                logger: 'javascript',
+                ignoreErrors: [],
+                ignoreUrls: [],
+                whitelistUrls: [],
+                includePaths: [],
+                collectWindowErrors: true,
+                maxMessageLength: 0,
+
+                // By default, truncates URL values to 250 chars
+                maxUrlLength: 250,
+                stackTraceLimit: 50,
+                autoBreadcrumbs: true,
+                instrument: true,
+                sampleRate: 1
+              };
+              this._ignoreOnError = 0;
+              this._isRavenInstalled = false;
+              this._originalErrorStackTraceLimit = Error.stackTraceLimit;
+              // capture references to window.console *and* all its methods first
+              // before the console plugin has a chance to monkey patch
+              this._originalConsole = _window.console || {};
+              this._originalConsoleMethods = {};
+              this._plugins = [];
+              this._startTime = now();
+              this._wrappedBuiltIns = [];
+              this._breadcrumbs = [];
+              this._lastCapturedEvent = null;
+              this._keypressTimeout;
+              this._location = _window.location;
+              this._lastHref = this._location && this._location.href;
+              this._resetBackoff();
+
+              // eslint-disable-next-line guard-for-in
+              for (var method in this._originalConsole) {
+                this._originalConsoleMethods[method] = this._originalConsole[method];
+              }
+            }
+
+            /*
  * The core Raven singleton
  *
  * @this {Raven}
  */
 
-Raven.prototype = {
-    // Hardcode version string so that raven source can be loaded directly via
-    // webpack (using a build step causes webpack #1617). Grunt verifies that
-    // this value matches package.json during build.
-    //   See: https://github.com/getsentry/raven-js/issues/465
-    VERSION: '3.17.0',
-
-    debug: false,
-
-    TraceKit: TraceKit, // alias to TraceKit
-
-    /*
+            Raven.prototype = {
+              // Hardcode version string so that raven source can be loaded directly via
+              // webpack (using a build step causes webpack #1617). Grunt verifies that
+              // this value matches package.json during build.
+              //   See: https://github.com/getsentry/raven-js/issues/465
+              VERSION: '3.18.1',
+
+              debug: false,
+
+              TraceKit: TraceKit, // alias to TraceKit
+
+              /*
      * Configure Raven with a DSN and extra options
      *
      * @param {string} dsn The public Sentry DSN
-     * @param {object} options Optional set of of global options [optional]
+     * @param {object} options Set of global options [optional]
      * @return {Raven}
      */
-    config: function(dsn, options) {
-        var self = this;
-
-        if (self._globalServer) {
-                this._logDebug('error', 'Error: Raven has already been configured');
-            return self;
-        }
-        if (!dsn) return self;
-
-        var globalOptions = self._globalOptions;
-
-        // merge in options
-        if (options) {
-            each(options, function(key, value){
-                // tags and extra are special and need to be put into context
-                if (key === 'tags' || key === 'extra' || key === 'user') {
-                    self._globalContext[key] = value;
-                } else {
-                    globalOptions[key] = value;
+              config: function(dsn, options) {
+                var self = this;
+
+                if (self._globalServer) {
+                  this._logDebug('error', 'Error: Raven has already been configured');
+                  return self;
+                }
+                if (!dsn) return self;
+
+                var globalOptions = self._globalOptions;
+
+                // merge in options
+                if (options) {
+                  each(options, function(key, value) {
+                    // tags and extra are special and need to be put into context
+                    if (key === 'tags' || key === 'extra' || key === 'user') {
+                      self._globalContext[key] = value;
+                    } else {
+                      globalOptions[key] = value;
+                    }
+                  });
                 }
-            });
-        }
-
-        self.setDSN(dsn);
-
-        // "Script error." is hard coded into browsers for errors that it can't read.
-        // this is the result of a script being pulled in from an external domain and CORS.
-        globalOptions.ignoreErrors.push(/^Script error\.?$/);
-        globalOptions.ignoreErrors.push(/^Javascript error: Script error\.? on line 0$/);
-
-        // join regexp rules into one big rule
-        globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
-        globalOptions.ignoreUrls = globalOptions.ignoreUrls.length ? joinRegExp(globalOptions.ignoreUrls) : false;
-        globalOptions.whitelistUrls = globalOptions.whitelistUrls.length ? joinRegExp(globalOptions.whitelistUrls) : false;
-        globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
-        globalOptions.maxBreadcrumbs = Math.max(0, Math.min(globalOptions.maxBreadcrumbs || 100, 100)); // default and hard limit is 100
-
-        var autoBreadcrumbDefaults = {
-            xhr: true,
-            console: true,
-            dom: true,
-            location: true
-        };
-
-        var autoBreadcrumbs = globalOptions.autoBreadcrumbs;
-        if ({}.toString.call(autoBreadcrumbs) === '[object Object]') {
-            autoBreadcrumbs = objectMerge(autoBreadcrumbDefaults, autoBreadcrumbs);
-        } else if (autoBreadcrumbs !== false) {
-            autoBreadcrumbs = autoBreadcrumbDefaults;
-        }
-        globalOptions.autoBreadcrumbs = autoBreadcrumbs;
-
-        var instrumentDefaults = {
-            tryCatch: true
-        };
-
-        var instrument = globalOptions.instrument;
-        if ({}.toString.call(instrument) === '[object Object]') {
-            instrument = objectMerge(instrumentDefaults, instrument);
-        } else if (instrument !== false) {
-            instrument = instrumentDefaults;
-        }
-        globalOptions.instrument = instrument;
-
-        TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
-
-        // return for chaining
-        return self;
-    },
-
-    /*
+
+                self.setDSN(dsn);
+
+                // "Script error." is hard coded into browsers for errors that it can't read.
+                // this is the result of a script being pulled in from an external domain and CORS.
+                globalOptions.ignoreErrors.push(/^Script error\.?$/);
+                globalOptions.ignoreErrors.push(
+                  /^Javascript error: Script error\.? on line 0$/
+                );
+
+                // join regexp rules into one big rule
+                globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
+                globalOptions.ignoreUrls = globalOptions.ignoreUrls.length
+                  ? joinRegExp(globalOptions.ignoreUrls)
+                  : false;
+                globalOptions.whitelistUrls = globalOptions.whitelistUrls.length
+                  ? joinRegExp(globalOptions.whitelistUrls)
+                  : false;
+                globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
+                globalOptions.maxBreadcrumbs = Math.max(
+                  0,
+                  Math.min(globalOptions.maxBreadcrumbs || 100, 100)
+                ); // default and hard limit is 100
+
+                var autoBreadcrumbDefaults = {
+                  xhr: true,
+                  console: true,
+                  dom: true,
+                  location: true
+                };
+
+                var autoBreadcrumbs = globalOptions.autoBreadcrumbs;
+                if ({}.toString.call(autoBreadcrumbs) === '[object Object]') {
+                  autoBreadcrumbs = objectMerge(autoBreadcrumbDefaults, autoBreadcrumbs);
+                } else if (autoBreadcrumbs !== false) {
+                  autoBreadcrumbs = autoBreadcrumbDefaults;
+                }
+                globalOptions.autoBreadcrumbs = autoBreadcrumbs;
+
+                var instrumentDefaults = {
+                  tryCatch: true
+                };
+
+                var instrument = globalOptions.instrument;
+                if ({}.toString.call(instrument) === '[object Object]') {
+                  instrument = objectMerge(instrumentDefaults, instrument);
+                } else if (instrument !== false) {
+                  instrument = instrumentDefaults;
+                }
+                globalOptions.instrument = instrument;
+
+                TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
+
+                // return for chaining
+                return self;
+              },
+
+              /*
      * Installs a global window.onerror error handler
      * to capture and report uncaught exceptions.
      * At this point, install() is required to be called due
      * to the way TraceKit is set up.
      *
      * @return {Raven}
      */
-    install: function() {
-        var self = this;
-        if (self.isSetup() && !self._isRavenInstalled) {
-            TraceKit.report.subscribe(function () {
-                self._handleOnErrorStackInfo.apply(self, arguments);
-            });
-            if (self._globalOptions.instrument && self._globalOptions.instrument.tryCatch) {
-              self._instrumentTryCatch();
-            }
-
-            if (self._globalOptions.autoBreadcrumbs)
-                self._instrumentBreadcrumbs();
-
-            // Install all of the plugins
-            self._drainPlugins();
-
-            self._isRavenInstalled = true;
-        }
-
-        Error.stackTraceLimit = self._globalOptions.stackTraceLimit;
-        return this;
-    },
-
-    /*
+              install: function() {
+                var self = this;
+                if (self.isSetup() && !self._isRavenInstalled) {
+                  TraceKit.report.subscribe(function() {
+                    self._handleOnErrorStackInfo.apply(self, arguments);
+                  });
+                  if (
+                    self._globalOptions.instrument &&
+                    self._globalOptions.instrument.tryCatch
+                  ) {
+                    self._instrumentTryCatch();
+                  }
+
+                  if (self._globalOptions.autoBreadcrumbs) self._instrumentBreadcrumbs();
+
+                  // Install all of the plugins
+                  self._drainPlugins();
+
+                  self._isRavenInstalled = true;
+                }
+
+                Error.stackTraceLimit = self._globalOptions.stackTraceLimit;
+                return this;
+              },
+
+              /*
      * Set the DSN (can be called multiple time unlike config)
      *
      * @param {string} dsn The public Sentry DSN
      */
-    setDSN: function(dsn) {
-        var self = this,
-            uri = self._parseDSN(dsn),
-          lastSlash = uri.path.lastIndexOf('/'),
-          path = uri.path.substr(1, lastSlash);
-
-        self._dsn = dsn;
-        self._globalKey = uri.user;
-        self._globalSecret = uri.pass && uri.pass.substr(1);
-        self._globalProject = uri.path.substr(lastSlash + 1);
-
-        self._globalServer = self._getGlobalServer(uri);
-
-        self._globalEndpoint = self._globalServer +
-            '/' + path + 'api/' + self._globalProject + '/store/';
-
-        // Reset backoff state since we may be pointing at a
-        // new project/server
-        this._resetBackoff();
-    },
-
-    /*
+              setDSN: function(dsn) {
+                var self = this,
+                  uri = self._parseDSN(dsn),
+                  lastSlash = uri.path.lastIndexOf('/'),
+                  path = uri.path.substr(1, lastSlash);
+
+                self._dsn = dsn;
+                self._globalKey = uri.user;
+                self._globalSecret = uri.pass && uri.pass.substr(1);
+                self._globalProject = uri.path.substr(lastSlash + 1);
+
+                self._globalServer = self._getGlobalServer(uri);
+
+                self._globalEndpoint =
+                  self._globalServer +
+                  '/' +
+                  path +
+                  'api/' +
+                  self._globalProject +
+                  '/store/';
+
+                // Reset backoff state since we may be pointing at a
+                // new project/server
+                this._resetBackoff();
+              },
+
+              /*
      * Wrap code within a context so Raven can capture errors
      * reliably across domains that is executed immediately.
      *
      * @param {object} options A specific set of options for this context [optional]
      * @param {function} func The callback to be immediately executed within the context
      * @param {array} args An array of arguments to be called with the callback [optional]
      */
-    context: function(options, func, args) {
-        if (isFunction(options)) {
-            args = func || [];
-            func = options;
-            options = undefined;
-        }
-
-        return this.wrap(options, func).apply(this, args);
-    },
-
-    /*
+              context: function(options, func, args) {
+                if (isFunction(options)) {
+                  args = func || [];
+                  func = options;
+                  options = undefined;
+                }
+
+                return this.wrap(options, func).apply(this, args);
+              },
+
+              /*
      * Wrap code within a context and returns back a new function to be executed
      *
      * @param {object} options A specific set of options for this context [optional]
      * @param {function} func The function to be wrapped in a new context
      * @param {function} func A function to call before the try/catch wrapper [optional, private]
      * @return {function} The newly wrapped functions with a context
      */
-    wrap: function(options, func, _before) {
-        var self = this;
-        // 1 argument has been passed, and it's not a function
-        // so just return it
-        if (isUndefined(func) && !isFunction(options)) {
-            return options;
-        }
-
-        // options is optional
-        if (isFunction(options)) {
-            func = options;
-            options = undefined;
-        }
-
-        // At this point, we've passed along 2 arguments, and the second one
-        // is not a function either, so we'll just return the second argument.
-        if (!isFunction(func)) {
-            return func;
-        }
-
-        // We don't wanna wrap it twice!
-        try {
-            if (func.__raven__) {
-                return func;
-            }
-
-            // If this has already been wrapped in the past, return that
-            if (func.__raven_wrapper__ ){
-                return func.__raven_wrapper__ ;
-            }
-        } catch (e) {
-            // Just accessing custom props in some Selenium environments
-            // can cause a "Permission denied" exception (see raven-js#495).
-            // Bail on wrapping and return the function as-is (defers to window.onerror).
-            return func;
-        }
-
-        function wrapped() {
-            var args = [], i = arguments.length,
-                deep = !options || options && options.deep !== false;
-
-            if (_before && isFunction(_before)) {
-                _before.apply(this, arguments);
-            }
-
-            // Recursively wrap all of a function's arguments that are
-            // functions themselves.
-            while(i--) args[i] = deep ? self.wrap(options, arguments[i]) : arguments[i];
-
-            try {
-                // Attempt to invoke user-land function
-                // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
-                //       means Raven caught an error invoking your application code. This is
-                //       expected behavior and NOT indicative of a bug with Raven.js.
-                return func.apply(this, args);
-            } catch(e) {
-                self._ignoreNextOnError();
-                self.captureException(e, options);
-                throw e;
-            }
-        }
-
-        // copy over properties of the old function
-        for (var property in func) {
-            if (hasKey(func, property)) {
-                wrapped[property] = func[property];
-            }
-        }
-        wrapped.prototype = func.prototype;
-
-        func.__raven_wrapper__ = wrapped;
-        // Signal that this function has been wrapped already
-        // for both debugging and to prevent it to being wrapped twice
-        wrapped.__raven__ = true;
-        wrapped.__inner__ = func;
-
-        return wrapped;
-    },
-
-    /*
+              wrap: function(options, func, _before) {
+                var self = this;
+                // 1 argument has been passed, and it's not a function
+                // so just return it
+                if (isUndefined(func) && !isFunction(options)) {
+                  return options;
+                }
+
+                // options is optional
+                if (isFunction(options)) {
+                  func = options;
+                  options = undefined;
+                }
+
+                // At this point, we've passed along 2 arguments, and the second one
+                // is not a function either, so we'll just return the second argument.
+                if (!isFunction(func)) {
+                  return func;
+                }
+
+                // We don't wanna wrap it twice!
+                try {
+                  if (func.__raven__) {
+                    return func;
+                  }
+
+                  // If this has already been wrapped in the past, return that
+                  if (func.__raven_wrapper__) {
+                    return func.__raven_wrapper__;
+                  }
+                } catch (e) {
+                  // Just accessing custom props in some Selenium environments
+                  // can cause a "Permission denied" exception (see raven-js#495).
+                  // Bail on wrapping and return the function as-is (defers to window.onerror).
+                  return func;
+                }
+
+                function wrapped() {
+                  var args = [],
+                    i = arguments.length,
+                    deep = !options || (options && options.deep !== false);
+
+                  if (_before && isFunction(_before)) {
+                    _before.apply(this, arguments);
+                  }
+
+                  // Recursively wrap all of a function's arguments that are
+                  // functions themselves.
+                  while (i--)
+                    args[i] = deep ? self.wrap(options, arguments[i]) : arguments[i];
+
+                  try {
+                    // Attempt to invoke user-land function
+                    // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
+                    //       means Raven caught an error invoking your application code. This is
+                    //       expected behavior and NOT indicative of a bug with Raven.js.
+                    return func.apply(this, args);
+                  } catch (e) {
+                    self._ignoreNextOnError();
+                    self.captureException(e, options);
+                    throw e;
+                  }
+                }
+
+                // copy over properties of the old function
+                for (var property in func) {
+                  if (hasKey(func, property)) {
+                    wrapped[property] = func[property];
+                  }
+                }
+                wrapped.prototype = func.prototype;
+
+                func.__raven_wrapper__ = wrapped;
+                // Signal that this function has been wrapped already
+                // for both debugging and to prevent it to being wrapped twice
+                wrapped.__raven__ = true;
+                wrapped.__inner__ = func;
+
+                return wrapped;
+              },
+
+              /*
      * Uninstalls the global error handler.
      *
      * @return {Raven}
      */
-    uninstall: function() {
-        TraceKit.report.uninstall();
-
-        this._restoreBuiltIns();
-
-        Error.stackTraceLimit = this._originalErrorStackTraceLimit;
-        this._isRavenInstalled = false;
-
-        return this;
-    },
-
-    /*
+              uninstall: function() {
+                TraceKit.report.uninstall();
+
+                this._restoreBuiltIns();
+
+                Error.stackTraceLimit = this._originalErrorStackTraceLimit;
+                this._isRavenInstalled = false;
+
+                return this;
+              },
+
+              /*
      * Manually capture an exception and send it over to Sentry
      *
      * @param {error} ex An exception to be logged
      * @param {object} options A specific set of options for this error [optional]
      * @return {Raven}
      */
-    captureException: function(ex, options) {
-        // If not an Error is passed through, recall as a message instead
-        if (!isError(ex)) {
-            return this.captureMessage(ex, objectMerge({
-                trimHeadFrames: 1,
-                stacktrace: true // if we fall back to captureMessage, default to attempting a new trace
-            }, options));
-        }
-
-        // Store the raw exception object for potential debugging and introspection
-        this._lastCapturedException = ex;
-
-        // TraceKit.report will re-raise any exception passed to it,
-        // which means you have to wrap it in try/catch. Instead, we
-        // can wrap it here and only re-raise if TraceKit.report
-        // raises an exception different from the one we asked to
-        // report on.
-        try {
-            var stack = TraceKit.computeStackTrace(ex);
-            this._handleStackInfo(stack, options);
-        } catch(ex1) {
-            if(ex !== ex1) {
-                throw ex1;
-            }
-        }
-
-        return this;
-    },
-
-    /*
+              captureException: function(ex, options) {
+                // If not an Error is passed through, recall as a message instead
+                if (!isError(ex)) {
+                  return this.captureMessage(
+                    ex,
+                    objectMerge(
+                      {
+                        trimHeadFrames: 1,
+                        stacktrace: true // if we fall back to captureMessage, default to attempting a new trace
+                      },
+                      options
+                    )
+                  );
+                }
+
+                // Store the raw exception object for potential debugging and introspection
+                this._lastCapturedException = ex;
+
+                // TraceKit.report will re-raise any exception passed to it,
+                // which means you have to wrap it in try/catch. Instead, we
+                // can wrap it here and only re-raise if TraceKit.report
+                // raises an exception different from the one we asked to
+                // report on.
+                try {
+                  var stack = TraceKit.computeStackTrace(ex);
+                  this._handleStackInfo(stack, options);
+                } catch (ex1) {
+                  if (ex !== ex1) {
+                    throw ex1;
+                  }
+                }
+
+                return this;
+              },
+
+              /*
      * Manually send a message to Sentry
      *
      * @param {string} msg A plain message to be captured in Sentry
      * @param {object} options A specific set of options for this message [optional]
      * @return {Raven}
      */
-    captureMessage: function(msg, options) {
-        // config() automagically converts ignoreErrors from a list to a RegExp so we need to test for an
-        // early call; we'll error on the side of logging anything called before configuration since it's
-        // probably something you should see:
-        if (!!this._globalOptions.ignoreErrors.test && this._globalOptions.ignoreErrors.test(msg)) {
-            return;
-        }
-
-        options = options || {};
-
-        var data = objectMerge({
-            message: msg + ''  // Make sure it's actually a string
-        }, options);
-
-        if (this._globalOptions.stacktrace || (options && options.stacktrace)) {
-            var ex;
-            // Generate a "synthetic" stack trace from this point.
-            // NOTE: If you are a Sentry user, and you are seeing this stack frame, it is NOT indicative
-            //       of a bug with Raven.js. Sentry generates synthetic traces either by configuration,
-            //       or if it catches a thrown object without a "stack" property.
-            try {
-                throw new Error(msg);
-            } catch (ex1) {
-                ex = ex1;
-            }
-
-            // null exception name so `Error` isn't prefixed to msg
-            ex.name = null;
-
-            options = objectMerge({
-                // fingerprint on msg, not stack trace (legacy behavior, could be
-                // revisited)
-                fingerprint: msg,
-                // since we know this is a synthetic trace, the top N-most frames
-                // MUST be from Raven.js, so mark them as in_app later by setting
-                // trimHeadFrames
-                trimHeadFrames: (options.trimHeadFrames || 0) + 1
-            }, options);
-
-            var stack = TraceKit.computeStackTrace(ex);
-            var frames = this._prepareFrames(stack, options);
-            data.stacktrace = {
-                // Sentry expects frames oldest to newest
-                frames: frames.reverse()
-            }
-        }
-
-        // Fire away!
-        this._send(data);
-
-        return this;
-    },
-
-    captureBreadcrumb: function (obj) {
-        var crumb = objectMerge({
-            timestamp: now() / 1000
-        }, obj);
-
-        if (isFunction(this._globalOptions.breadcrumbCallback)) {
-            var result = this._globalOptions.breadcrumbCallback(crumb);
-
-            if (isObject(result) && !isEmptyObject(result)) {
-                crumb = result;
-            } else if (result === false) {
+              captureMessage: function(msg, options) {
+                // config() automagically converts ignoreErrors from a list to a RegExp so we need to test for an
+                // early call; we'll error on the side of logging anything called before configuration since it's
+                // probably something you should see:
+                if (
+                  !!this._globalOptions.ignoreErrors.test &&
+                  this._globalOptions.ignoreErrors.test(msg)
+                ) {
+                  return;
+                }
+
+                options = options || {};
+
+                var data = objectMerge(
+                  {
+                    message: msg + '' // Make sure it's actually a string
+                  },
+                  options
+                );
+
+                if (this._globalOptions.stacktrace || (options && options.stacktrace)) {
+                  var ex;
+                  // Generate a "synthetic" stack trace from this point.
+                  // NOTE: If you are a Sentry user, and you are seeing this stack frame, it is NOT indicative
+                  //       of a bug with Raven.js. Sentry generates synthetic traces either by configuration,
+                  //       or if it catches a thrown object without a "stack" property.
+                  try {
+                    throw new Error(msg);
+                  } catch (ex1) {
+                    ex = ex1;
+                  }
+
+                  // null exception name so `Error` isn't prefixed to msg
+                  ex.name = null;
+
+                  options = objectMerge(
+                    {
+                      // fingerprint on msg, not stack trace (legacy behavior, could be
+                      // revisited)
+                      fingerprint: msg,
+                      // since we know this is a synthetic trace, the top N-most frames
+                      // MUST be from Raven.js, so mark them as in_app later by setting
+                      // trimHeadFrames
+                      trimHeadFrames: (options.trimHeadFrames || 0) + 1
+                    },
+                    options
+                  );
+
+                  var stack = TraceKit.computeStackTrace(ex);
+                  var frames = this._prepareFrames(stack, options);
+                  data.stacktrace = {
+                    // Sentry expects frames oldest to newest
+                    frames: frames.reverse()
+                  };
+                }
+
+                // Fire away!
+                this._send(data);
+
                 return this;
-            }
-        }
-
-        this._breadcrumbs.push(crumb);
-        if (this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs) {
-            this._breadcrumbs.shift();
-        }
-        return this;
-    },
-
-    addPlugin: function(plugin /*arg1, arg2, ... argN*/) {
-        var pluginArgs = [].slice.call(arguments, 1);
-
-        this._plugins.push([plugin, pluginArgs]);
-        if (this._isRavenInstalled) {
-            this._drainPlugins();
-        }
-
-        return this;
-    },
-
-    /*
+              },
+
+              captureBreadcrumb: function(obj) {
+                var crumb = objectMerge(
+                  {
+                    timestamp: now() / 1000
+                  },
+                  obj
+                );
+
+                if (isFunction(this._globalOptions.breadcrumbCallback)) {
+                  var result = this._globalOptions.breadcrumbCallback(crumb);
+
+                  if (isObject(result) && !isEmptyObject(result)) {
+                    crumb = result;
+                  } else if (result === false) {
+                    return this;
+                  }
+                }
+
+                this._breadcrumbs.push(crumb);
+                if (this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs) {
+                  this._breadcrumbs.shift();
+                }
+                return this;
+              },
+
+              addPlugin: function(plugin /*arg1, arg2, ... argN*/) {
+                var pluginArgs = [].slice.call(arguments, 1);
+
+                this._plugins.push([plugin, pluginArgs]);
+                if (this._isRavenInstalled) {
+                  this._drainPlugins();
+                }
+
+                return this;
+              },
+
+              /*
      * Set/clear a user to be sent along with the payload.
      *
      * @param {object} user An object representing user data [optional]
      * @return {Raven}
      */
-    setUserContext: function(user) {
-        // Intentionally do not merge here since that's an unexpected behavior.
-        this._globalContext.user = user;
-
-        return this;
-    },
-
-    /*
+              setUserContext: function(user) {
+                // Intentionally do not merge here since that's an unexpected behavior.
+                this._globalContext.user = user;
+
+                return this;
+              },
+
+              /*
      * Merge extra attributes to be sent along with the payload.
      *
      * @param {object} extra An object representing extra data [optional]
      * @return {Raven}
      */
-    setExtraContext: function(extra) {
-        this._mergeContext('extra', extra);
-
-        return this;
-    },
-
-    /*
+              setExtraContext: function(extra) {
+                this._mergeContext('extra', extra);
+
+                return this;
+              },
+
+              /*
      * Merge tags to be sent along with the payload.
      *
      * @param {object} tags An object representing tags [optional]
      * @return {Raven}
      */
-    setTagsContext: function(tags) {
-        this._mergeContext('tags', tags);
-
-        return this;
-    },
-
-    /*
+              setTagsContext: function(tags) {
+                this._mergeContext('tags', tags);
+
+                return this;
+              },
+
+              /*
      * Clear all of the context.
      *
      * @return {Raven}
      */
-    clearContext: function() {
-        this._globalContext = {};
-
-        return this;
-    },
-
-    /*
+              clearContext: function() {
+                this._globalContext = {};
+
+                return this;
+              },
+
+              /*
      * Get a copy of the current context. This cannot be mutated.
      *
      * @return {object} copy of context
      */
-    getContext: function() {
-        // lol javascript
-        return JSON.parse(stringify(this._globalContext));
-    },
-
-
-    /*
+              getContext: function() {
+                // lol javascript
+                return JSON.parse(stringify(this._globalContext));
+              },
+
+              /*
      * Set environment of application
      *
      * @param {string} environment Typically something like 'production'.
      * @return {Raven}
      */
-    setEnvironment: function(environment) {
-        this._globalOptions.environment = environment;
-
-        return this;
-    },
-
-    /*
+              setEnvironment: function(environment) {
+                this._globalOptions.environment = environment;
+
+                return this;
+              },
+
+              /*
      * Set release version of application
      *
      * @param {string} release Typically something like a git SHA to identify version
      * @return {Raven}
      */
-    setRelease: function(release) {
-        this._globalOptions.release = release;
-
-        return this;
-    },
-
-    /*
+              setRelease: function(release) {
+                this._globalOptions.release = release;
+
+                return this;
+              },
+
+              /*
      * Set the dataCallback option
      *
      * @param {function} callback The callback to run which allows the
      *                            data blob to be mutated before sending
      * @return {Raven}
      */
-    setDataCallback: function(callback) {
-        var original = this._globalOptions.dataCallback;
-        this._globalOptions.dataCallback =
-          keepOriginalCallback(original, callback);
-        return this;
-    },
-
-    /*
+              setDataCallback: function(callback) {
+                var original = this._globalOptions.dataCallback;
+                this._globalOptions.dataCallback = keepOriginalCallback(
+                  original,
+                  callback
+                );
+                return this;
+              },
+
+              /*
      * Set the breadcrumbCallback option
      *
      * @param {function} callback The callback to run which allows filtering
      *                            or mutating breadcrumbs
      * @return {Raven}
      */
-    setBreadcrumbCallback: function(callback) {
-        var original = this._globalOptions.breadcrumbCallback;
-        this._globalOptions.breadcrumbCallback =
-          keepOriginalCallback(original, callback);
-        return this;
-    },
-
-    /*
+              setBreadcrumbCallback: function(callback) {
+                var original = this._globalOptions.breadcrumbCallback;
+                this._globalOptions.breadcrumbCallback = keepOriginalCallback(
+                  original,
+                  callback
+                );
+                return this;
+              },
+
+              /*
      * Set the shouldSendCallback option
      *
      * @param {function} callback The callback to run which allows
      *                            introspecting the blob before sending
      * @return {Raven}
      */
-    setShouldSendCallback: function(callback) {
-        var original = this._globalOptions.shouldSendCallback;
-        this._globalOptions.shouldSendCallback =
-          keepOriginalCallback(original, callback);
-        return this;
-    },
-
-    /**
+              setShouldSendCallback: function(callback) {
+                var original = this._globalOptions.shouldSendCallback;
+                this._globalOptions.shouldSendCallback = keepOriginalCallback(
+                  original,
+                  callback
+                );
+                return this;
+              },
+
+              /**
      * Override the default HTTP transport mechanism that transmits data
      * to the Sentry server.
      *
      * @param {function} transport Function invoked instead of the default
      *                             `makeRequest` handler.
      *
      * @return {Raven}
      */
-    setTransport: function(transport) {
-        this._globalOptions.transport = transport;
-
-        return this;
-    },
-
-    /*
+              setTransport: function(transport) {
+                this._globalOptions.transport = transport;
+
+                return this;
+              },
+
+              /*
      * Get the latest raw exception that was captured by Raven.
      *
      * @return {error}
      */
-    lastException: function() {
-        return this._lastCapturedException;
-    },
-
-    /*
+              lastException: function() {
+                return this._lastCapturedException;
+              },
+
+              /*
      * Get the last event id
      *
      * @return {string}
      */
-    lastEventId: function() {
-        return this._lastEventId;
-    },
-
-    /*
+              lastEventId: function() {
+                return this._lastEventId;
+              },
+
+              /*
      * Determine if Raven is setup and ready to go.
      *
      * @return {boolean}
      */
-    isSetup: function() {
-        if (!this._hasJSON) return false;  // needs JSON support
-        if (!this._globalServer) {
-            if (!this.ravenNotConfiguredError) {
-              this.ravenNotConfiguredError = true;
-              this._logDebug('error', 'Error: Raven has not been configured.');
-            }
-            return false;
-        }
-        return true;
-    },
-
-    afterLoad: function () {
-        // TODO: remove window dependence?
-
-        // Attempt to initialize Raven on load
-        var RavenConfig = _window.RavenConfig;
-        if (RavenConfig) {
-            this.config(RavenConfig.dsn, RavenConfig.config).install();
-        }
-    },
-
-    showReportDialog: function (options) {
-        if (!_document) // doesn't work without a document (React native)
-            return;
-
-        options = options || {};
-
-        var lastEventId = options.eventId || this.lastEventId();
-        if (!lastEventId) {
-            throw new RavenConfigError('Missing eventId');
-        }
-
-        var dsn = options.dsn || this._dsn;
-        if (!dsn) {
-            throw new RavenConfigError('Missing DSN');
-        }
-
-        var encode = encodeURIComponent;
-        var qs = '';
-        qs += '?eventId=' + encode(lastEventId);
-        qs += '&dsn=' + encode(dsn);
-
-        var user = options.user || this._globalContext.user;
-        if (user) {
-            if (user.name)  qs += '&name=' + encode(user.name);
-            if (user.email) qs += '&email=' + encode(user.email);
-        }
-
-        var globalServer = this._getGlobalServer(this._parseDSN(dsn));
-
-        var script = _document.createElement('script');
-        script.async = true;
-        script.src = globalServer + '/api/embed/error-page/' + qs;
-        (_document.head || _document.body).appendChild(script);
-    },
-
-    /**** Private functions ****/
-    _ignoreNextOnError: function () {
-        var self = this;
-        this._ignoreOnError += 1;
-        setTimeout(function () {
-            // onerror should trigger before setTimeout
-            self._ignoreOnError -= 1;
-        });
-    },
-
-    _triggerEvent: function(eventType, options) {
-        // NOTE: `event` is a native browser thing, so let's avoid conflicting wiht it
-        var evt, key;
-
-        if (!this._hasDocument)
-            return;
-
-        options = options || {};
-
-        eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
-
-        if (_document.createEvent) {
-            evt = _document.createEvent('HTMLEvents');
-            evt.initEvent(eventType, true, true);
-        } else {
-            evt = _document.createEventObject();
-            evt.eventType = eventType;
-        }
-
-        for (key in options) if (hasKey(options, key)) {
-            evt[key] = options[key];
-        }
-
-        if (_document.createEvent) {
-            // IE9 if standards
-            _document.dispatchEvent(evt);
-        } else {
-            // IE8 regardless of Quirks or Standards
-            // IE9 if quirks
-            try {
-                _document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
-            } catch(e) {
-                // Do nothing
-            }
-        }
-    },
-
-    /**
+              isSetup: function() {
+                if (!this._hasJSON) return false; // needs JSON support
+                if (!this._globalServer) {
+                  if (!this.ravenNotConfiguredError) {
+                    this.ravenNotConfiguredError = true;
+                    this._logDebug('error', 'Error: Raven has not been configured.');
+                  }
+                  return false;
+                }
+                return true;
+              },
+
+              afterLoad: function() {
+                // TODO: remove window dependence?
+
+                // Attempt to initialize Raven on load
+                var RavenConfig = _window.RavenConfig;
+                if (RavenConfig) {
+                  this.config(RavenConfig.dsn, RavenConfig.config).install();
+                }
+              },
+
+              showReportDialog: function(options) {
+                if (
+                  !_document // doesn't work without a document (React native)
+                )
+                  return;
+
+                options = options || {};
+
+                var lastEventId = options.eventId || this.lastEventId();
+                if (!lastEventId) {
+                  throw new RavenConfigError('Missing eventId');
+                }
+
+                var dsn = options.dsn || this._dsn;
+                if (!dsn) {
+                  throw new RavenConfigError('Missing DSN');
+                }
+
+                var encode = encodeURIComponent;
+                var qs = '';
+                qs += '?eventId=' + encode(lastEventId);
+                qs += '&dsn=' + encode(dsn);
+
+                var user = options.user || this._globalContext.user;
+                if (user) {
+                  if (user.name) qs += '&name=' + encode(user.name);
+                  if (user.email) qs += '&email=' + encode(user.email);
+                }
+
+                var globalServer = this._getGlobalServer(this._parseDSN(dsn));
+
+                var script = _document.createElement('script');
+                script.async = true;
+                script.src = globalServer + '/api/embed/error-page/' + qs;
+                (_document.head || _document.body).appendChild(script);
+              },
+
+              /**** Private functions ****/
+              _ignoreNextOnError: function() {
+                var self = this;
+                this._ignoreOnError += 1;
+                setTimeout(function() {
+                  // onerror should trigger before setTimeout
+                  self._ignoreOnError -= 1;
+                });
+              },
+
+              _triggerEvent: function(eventType, options) {
+                // NOTE: `event` is a native browser thing, so let's avoid conflicting wiht it
+                var evt, key;
+
+                if (!this._hasDocument) return;
+
+                options = options || {};
+
+                eventType =
+                  'raven' + eventType.substr(0, 1).toUpperCase() + eventType.substr(1);
+
+                if (_document.createEvent) {
+                  evt = _document.createEvent('HTMLEvents');
+                  evt.initEvent(eventType, true, true);
+                } else {
+                  evt = _document.createEventObject();
+                  evt.eventType = eventType;
+                }
+
+                for (key in options)
+                  if (hasKey(options, key)) {
+                    evt[key] = options[key];
+                  }
+
+                if (_document.createEvent) {
+                  // IE9 if standards
+                  _document.dispatchEvent(evt);
+                } else {
+                  // IE8 regardless of Quirks or Standards
+                  // IE9 if quirks
+                  try {
+                    _document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
+                  } catch (e) {
+                    // Do nothing
+                  }
+                }
+              },
+
+              /**
      * Wraps addEventListener to capture UI breadcrumbs
      * @param evtName the event name (e.g. "click")
      * @returns {Function}
      * @private
      */
-    _breadcrumbEventHandler: function(evtName) {
-        var self = this;
-        return function (evt) {
-            // reset keypress timeout; e.g. triggering a 'click' after
-            // a 'keypress' will reset the keypress debounce so that a new
-            // set of keypresses can be recorded
-            self._keypressTimeout = null;
-
-            // It's possible this handler might trigger multiple times for the same
-            // event (e.g. event propagation through node ancestors). Ignore if we've
-            // already captured the event.
-            if (self._lastCapturedEvent === evt)
-                return;
-
-            self._lastCapturedEvent = evt;
-
-            // try/catch both:
-            // - accessing evt.target (see getsentry/raven-js#838, #768)
-            // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly
-            //   can throw an exception in some circumstances.
-            var target;
-            try {
-                target = htmlTreeAsString(evt.target);
-            } catch (e) {
-                target = '<unknown>';
-            }
-
-            self.captureBreadcrumb({
-                category: 'ui.' + evtName, // e.g. ui.click, ui.input
-                message: target
-            });
-        };
-    },
-
-    /**
+              _breadcrumbEventHandler: function(evtName) {
+                var self = this;
+                return function(evt) {
+                  // reset keypress timeout; e.g. triggering a 'click' after
+                  // a 'keypress' will reset the keypress debounce so that a new
+                  // set of keypresses can be recorded
+                  self._keypressTimeout = null;
+
+                  // It's possible this handler might trigger multiple times for the same
+                  // event (e.g. event propagation through node ancestors). Ignore if we've
+                  // already captured the event.
+                  if (self._lastCapturedEvent === evt) return;
+
+                  self._lastCapturedEvent = evt;
+
+                  // try/catch both:
+                  // - accessing evt.target (see getsentry/raven-js#838, #768)
+                  // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly
+                  //   can throw an exception in some circumstances.
+                  var target;
+                  try {
+                    target = htmlTreeAsString(evt.target);
+                  } catch (e) {
+                    target = '<unknown>';
+                  }
+
+                  self.captureBreadcrumb({
+                    category: 'ui.' + evtName, // e.g. ui.click, ui.input
+                    message: target
+                  });
+                };
+              },
+
+              /**
      * Wraps addEventListener to capture keypress UI events
      * @returns {Function}
      * @private
      */
-    _keypressEventHandler: function() {
-        var self = this,
-            debounceDuration = 1000; // milliseconds
-
-        // TODO: if somehow user switches keypress target before
-        //       debounce timeout is triggered, we will only capture
-        //       a single breadcrumb from the FIRST target (acceptable?)
-        return function (evt) {
-            var target;
-            try {
-                target = evt.target;
-            } catch (e) {
-                // just accessing event properties can throw an exception in some rare circumstances
-                // see: https://github.com/getsentry/raven-js/issues/838
-                return;
-            }
-            var tagName = target && target.tagName;
-
-            // only consider keypress events on actual input elements
-            // this will disregard keypresses targeting body (e.g. tabbing
-            // through elements, hotkeys, etc)
-            if (!tagName || tagName !== 'INPUT' && tagName !== 'TEXTAREA' && !target.isContentEditable)
-                return;
-
-            // record first keypress in a series, but ignore subsequent
-            // keypresses until debounce clears
-            var timeout = self._keypressTimeout;
-            if (!timeout) {
-                self._breadcrumbEventHandler('input')(evt);
-            }
-            clearTimeout(timeout);
-            self._keypressTimeout = setTimeout(function () {
-                self._keypressTimeout = null;
-            }, debounceDuration);
-        };
-    },
-
-    /**
+              _keypressEventHandler: function() {
+                var self = this,
+                  debounceDuration = 1000; // milliseconds
+
+                // TODO: if somehow user switches keypress target before
+                //       debounce timeout is triggered, we will only capture
+                //       a single breadcrumb from the FIRST target (acceptable?)
+                return function(evt) {
+                  var target;
+                  try {
+                    target = evt.target;
+                  } catch (e) {
+                    // just accessing event properties can throw an exception in some rare circumstances
+                    // see: https://github.com/getsentry/raven-js/issues/838
+                    return;
+                  }
+                  var tagName = target && target.tagName;
+
+                  // only consider keypress events on actual input elements
+                  // this will disregard keypresses targeting body (e.g. tabbing
+                  // through elements, hotkeys, etc)
+                  if (
+                    !tagName ||
+                    (tagName !== 'INPUT' &&
+                      tagName !== 'TEXTAREA' &&
+                      !target.isContentEditable)
+                  )
+                    return;
+
+                  // record first keypress in a series, but ignore subsequent
+                  // keypresses until debounce clears
+                  var timeout = self._keypressTimeout;
+                  if (!timeout) {
+                    self._breadcrumbEventHandler('input')(evt);
+                  }
+                  clearTimeout(timeout);
+                  self._keypressTimeout = setTimeout(function() {
+                    self._keypressTimeout = null;
+                  }, debounceDuration);
+                };
+              },
+
+              /**
      * Captures a breadcrumb of type "navigation", normalizing input URLs
      * @param to the originating URL
      * @param from the target URL
      * @private
      */
-    _captureUrlChange: function(from, to) {
-        var parsedLoc = parseUrl(this._location.href);
-        var parsedTo = parseUrl(to);
-        var parsedFrom = parseUrl(from);
-
-        // because onpopstate only tells you the "new" (to) value of location.href, and
-        // not the previous (from) value, we need to track the value of the current URL
-        // state ourselves
-        this._lastHref = to;
-
-        // Use only the path component of the URL if the URL matches the current
-        // document (almost all the time when using pushState)
-        if (parsedLoc.protocol === parsedTo.protocol && parsedLoc.host === parsedTo.host)
-            to = parsedTo.relative;
-        if (parsedLoc.protocol === parsedFrom.protocol && parsedLoc.host === parsedFrom.host)
-            from = parsedFrom.relative;
-
-        this.captureBreadcrumb({
-            category: 'navigation',
-            data: {
-                to: to,
-                from: from
-            }
-        });
-    },
-
-    /**
+              _captureUrlChange: function(from, to) {
+                var parsedLoc = parseUrl(this._location.href);
+                var parsedTo = parseUrl(to);
+                var parsedFrom = parseUrl(from);
+
+                // because onpopstate only tells you the "new" (to) value of location.href, and
+                // not the previous (from) value, we need to track the value of the current URL
+                // state ourselves
+                this._lastHref = to;
+
+                // Use only the path component of the URL if the URL matches the current
+                // document (almost all the time when using pushState)
+                if (
+                  parsedLoc.protocol === parsedTo.protocol &&
+                  parsedLoc.host === parsedTo.host
+                )
+                  to = parsedTo.relative;
+                if (
+                  parsedLoc.protocol === parsedFrom.protocol &&
+                  parsedLoc.host === parsedFrom.host
+                )
+                  from = parsedFrom.relative;
+
+                this.captureBreadcrumb({
+                  category: 'navigation',
+                  data: {
+                    to: to,
+                    from: from
+                  }
+                });
+              },
+
+              /**
      * Wrap timer functions and event targets to catch errors and provide
      * better metadata.
      */
-    _instrumentTryCatch: function() {
-        var self = this;
-
-        var wrappedBuiltIns = self._wrappedBuiltIns;
-
-        function wrapTimeFn(orig) {
-            return function (fn, t) { // preserve arity
-                // Make a copy of the arguments to prevent deoptimization
-                // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
-                var args = new Array(arguments.length);
-                for(var i = 0; i < args.length; ++i) {
-                    args[i] = arguments[i];
-                }
-                var originalCallback = args[0];
-                if (isFunction(originalCallback)) {
-                    args[0] = self.wrap(originalCallback);
-                }
-
-                // IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it
-                // also supports only two arguments and doesn't care what this is, so we
-                // can just call the original function directly.
-                if (orig.apply) {
-                    return orig.apply(this, args);
-                } else {
-                    return orig(args[0], args[1]);
+              _instrumentTryCatch: function() {
+                var self = this;
+
+                var wrappedBuiltIns = self._wrappedBuiltIns;
+
+                function wrapTimeFn(orig) {
+                  return function(fn, t) {
+                    // preserve arity
+                    // Make a copy of the arguments to prevent deoptimization
+                    // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
+                    var args = new Array(arguments.length);
+                    for (var i = 0; i < args.length; ++i) {
+                      args[i] = arguments[i];
+                    }
+                    var originalCallback = args[0];
+                    if (isFunction(originalCallback)) {
+                      args[0] = self.wrap(originalCallback);
+                    }
+
+                    // IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it
+                    // also supports only two arguments and doesn't care what this is, so we
+                    // can just call the original function directly.
+                    if (orig.apply) {
+                      return orig.apply(this, args);
+                    } else {
+                      return orig(args[0], args[1]);
+                    }
+                  };
                 }
-            };
-        }
-
-        var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
-
-        function wrapEventTarget(global) {
-            var proto = _window[global] && _window[global].prototype;
-            if (proto && proto.hasOwnProperty && proto.hasOwnProperty('addEventListener')) {
-                fill(proto, 'addEventListener', function(orig) {
-                    return function (evtName, fn, capture, secure) { // preserve arity
-                        try {
+
+                var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
+
+                function wrapEventTarget(global) {
+                  var proto = _window[global] && _window[global].prototype;
+                  if (
+                    proto &&
+                    proto.hasOwnProperty &&
+                    proto.hasOwnProperty('addEventListener')
+                  ) {
+                    fill(
+                      proto,
+                      'addEventListener',
+                      function(orig) {
+                        return function(evtName, fn, capture, secure) {
+                          // preserve arity
+                          try {
                             if (fn && fn.handleEvent) {
-                                fn.handleEvent = self.wrap(fn.handleEvent);
+                              fn.handleEvent = self.wrap(fn.handleEvent);
                             }
-                        } catch (err) {
+                          } catch (err) {
                             // can sometimes get 'Permission denied to access property "handle Event'
-                        }
-
-                        // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs`
-                        // so that we don't have more than one wrapper function
-                        var before,
-                            clickHandler,
-                            keypressHandler;
-
-                        if (autoBreadcrumbs && autoBreadcrumbs.dom && (global === 'EventTarget' || global === 'Node')) {
+                          }
+
+                          // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs`
+                          // so that we don't have more than one wrapper function
+                          var before, clickHandler, keypressHandler;
+
+                          if (
+                            autoBreadcrumbs &&
+                            autoBreadcrumbs.dom &&
+                            (global === 'EventTarget' || global === 'Node')
+                          ) {
                             // NOTE: generating multiple handlers per addEventListener invocation, should
                             //       revisit and verify we can just use one (almost certainly)
                             clickHandler = self._breadcrumbEventHandler('click');
                             keypressHandler = self._keypressEventHandler();
-                            before = function (evt) {
-                                // need to intercept every DOM event in `before` argument, in case that
-                                // same wrapped method is re-used for different events (e.g. mousemove THEN click)
-                                // see #724
-                                if (!evt) return;
-
-                                var eventType;
-                                try {
-                                    eventType = evt.type
-                                } catch (e) {
-                                    // just accessing event properties can throw an exception in some rare circumstances
-                                    // see: https://github.com/getsentry/raven-js/issues/838
-                                    return;
-                                }
-                                if (eventType === 'click')
-                                    return clickHandler(evt);
-                                else if (eventType === 'keypress')
-                                    return keypressHandler(evt);
+                            before = function(evt) {
+                              // need to intercept every DOM event in `before` argument, in case that
+                              // same wrapped method is re-used for different events (e.g. mousemove THEN click)
+                              // see #724
+                              if (!evt) return;
+
+                              var eventType;
+                              try {
+                                eventType = evt.type;
+                              } catch (e) {
+                                // just accessing event properties can throw an exception in some rare circumstances
+                                // see: https://github.com/getsentry/raven-js/issues/838
+                                return;
+                              }
+                              if (eventType === 'click') return clickHandler(evt);
+                              else if (eventType === 'keypress')
+                                return keypressHandler(evt);
                             };
-                        }
-                        return orig.call(this, evtName, self.wrap(fn, undefined, before), capture, secure);
-                    };
-                }, wrappedBuiltIns);
-                fill(proto, 'removeEventListener', function (orig) {
-                    return function (evt, fn, capture, secure) {
-                        try {
-                            fn = fn && (fn.__raven_wrapper__ ? fn.__raven_wrapper__  : fn);
-                        } catch (e) {
+                          }
+                          return orig.call(
+                            this,
+                            evtName,
+                            self.wrap(fn, undefined, before),
+                            capture,
+                            secure
+                          );
+                        };
+                      },
+                      wrappedBuiltIns
+                    );
+                    fill(
+                      proto,
+                      'removeEventListener',
+                      function(orig) {
+                        return function(evt, fn, capture, secure) {
+                          try {
+                            fn = fn && (fn.__raven_wrapper__ ? fn.__raven_wrapper__ : fn);
+                          } catch (e) {
                             // ignore, accessing __raven_wrapper__ will throw in some Selenium environments
-                        }
-                        return orig.call(this, evt, fn, capture, secure);
-                    };
-                }, wrappedBuiltIns);
-            }
-        }
-
-        fill(_window, 'setTimeout', wrapTimeFn, wrappedBuiltIns);
-        fill(_window, 'setInterval', wrapTimeFn, wrappedBuiltIns);
-        if (_window.requestAnimationFrame) {
-            fill(_window, 'requestAnimationFrame', function (orig) {
-                return function (cb) {
-                    return orig(self.wrap(cb));
-                };
-            }, wrappedBuiltIns);
-        }
-
-        // event targets borrowed from bugsnag-js:
-        // https://github.com/bugsnag/bugsnag-js/blob/master/src/bugsnag.js#L666
-        var eventTargets = ['EventTarget', 'Window', 'Node', 'ApplicationCache', 'AudioTrackList', 'ChannelMergerNode', 'CryptoOperation', 'EventSource', 'FileReader', 'HTMLUnknownElement', 'IDBDatabase', 'IDBRequest', 'IDBTransaction', 'KeyOperation', 'MediaController', 'MessagePort', 'ModalWindow', 'Notification', 'SVGElementInstance', 'Screen', 'TextTrack', 'TextTrackCue', 'TextTrackList', 'WebSocket', 'WebSocketWorker', 'Worker', 'XMLHttpRequest', 'XMLHttpRequestEventTarget', 'XMLHttpRequestUpload'];
-        for (var i = 0; i < eventTargets.length; i++) {
-            wrapEventTarget(eventTargets[i]);
-        }
-    },
-
-
-    /**
+                          }
+                          return orig.call(this, evt, fn, capture, secure);
+                        };
+                      },
+                      wrappedBuiltIns
+                    );
+                  }
+                }
+
+                fill(_window, 'setTimeout', wrapTimeFn, wrappedBuiltIns);
+                fill(_window, 'setInterval', wrapTimeFn, wrappedBuiltIns);
+                if (_window.requestAnimationFrame) {
+                  fill(
+                    _window,
+                    'requestAnimationFrame',
+                    function(orig) {
+                      return function(cb) {
+                        return orig(self.wrap(cb));
+                      };
+                    },
+                    wrappedBuiltIns
+                  );
+                }
+
+                // event targets borrowed from bugsnag-js:
+                // https://github.com/bugsnag/bugsnag-js/blob/master/src/bugsnag.js#L666
+                var eventTargets = [
+                  'EventTarget',
+                  'Window',
+                  'Node',
+                  'ApplicationCache',
+                  'AudioTrackList',
+                  'ChannelMergerNode',
+                  'CryptoOperation',
+                  'EventSource',
+                  'FileReader',
+                  'HTMLUnknownElement',
+                  'IDBDatabase',
+                  'IDBRequest',
+                  'IDBTransaction',
+                  'KeyOperation',
+                  'MediaController',
+                  'MessagePort',
+                  'ModalWindow',
+                  'Notification',
+                  'SVGElementInstance',
+                  'Screen',
+                  'TextTrack',
+                  'TextTrackCue',
+                  'TextTrackList',
+                  'WebSocket',
+                  'WebSocketWorker',
+                  'Worker',
+                  'XMLHttpRequest',
+                  'XMLHttpRequestEventTarget',
+                  'XMLHttpRequestUpload'
+                ];
+                for (var i = 0; i < eventTargets.length; i++) {
+                  wrapEventTarget(eventTargets[i]);
+                }
+              },
+
+              /**
      * Instrument browser built-ins w/ breadcrumb capturing
      *  - XMLHttpRequests
      *  - DOM interactions (click/typing)
      *  - window.location changes
      *  - console
      *
      * Can be disabled or individually configured via the `autoBreadcrumbs` config option
      */
-    _instrumentBreadcrumbs: function () {
-        var self = this;
-        var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
-
-        var wrappedBuiltIns = self._wrappedBuiltIns;
-
-        function wrapProp(prop, xhr) {
-            if (prop in xhr && isFunction(xhr[prop])) {
-                fill(xhr, prop, function (orig) {
-                    return self.wrap(orig);
-                }); // intentionally don't track filled methods on XHR instances
-            }
-        }
-
-        if (autoBreadcrumbs.xhr && 'XMLHttpRequest' in _window) {
-            var xhrproto = XMLHttpRequest.prototype;
-            fill(xhrproto, 'open', function(origOpen) {
-                return function (method, url) { // preserve arity
-
-                    // if Sentry key appears in URL, don't capture
-                    if (isString(url) && url.indexOf(self._globalKey) === -1) {
-                        this.__raven_xhr = {
+              _instrumentBreadcrumbs: function() {
+                var self = this;
+                var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
+
+                var wrappedBuiltIns = self._wrappedBuiltIns;
+
+                function wrapProp(prop, xhr) {
+                  if (prop in xhr && isFunction(xhr[prop])) {
+                    fill(xhr, prop, function(orig) {
+                      return self.wrap(orig);
+                    }); // intentionally don't track filled methods on XHR instances
+                  }
+                }
+
+                if (autoBreadcrumbs.xhr && 'XMLHttpRequest' in _window) {
+                  var xhrproto = XMLHttpRequest.prototype;
+                  fill(
+                    xhrproto,
+                    'open',
+                    function(origOpen) {
+                      return function(method, url) {
+                        // preserve arity
+
+                        // if Sentry key appears in URL, don't capture
+                        if (isString(url) && url.indexOf(self._globalKey) === -1) {
+                          this.__raven_xhr = {
                             method: method,
                             url: url,
                             status_code: null
-                        };
-                    }
-
-                    return origOpen.apply(this, arguments);
-                };
-            }, wrappedBuiltIns);
-
-            fill(xhrproto, 'send', function(origSend) {
-                return function (data) { // preserve arity
-                    var xhr = this;
-
-                    function onreadystatechangeHandler() {
-                        if (xhr.__raven_xhr && (xhr.readyState === 1 || xhr.readyState === 4)) {
+                          };
+                        }
+
+                        return origOpen.apply(this, arguments);
+                      };
+                    },
+                    wrappedBuiltIns
+                  );
+
+                  fill(
+                    xhrproto,
+                    'send',
+                    function(origSend) {
+                      return function(data) {
+                        // preserve arity
+                        var xhr = this;
+
+                        function onreadystatechangeHandler() {
+                          if (xhr.__raven_xhr && xhr.readyState === 4) {
                             try {
-                                // touching statusCode in some platforms throws
-                                // an exception
-                                xhr.__raven_xhr.status_code = xhr.status;
-                            } catch (e) { /* do nothing */ }
+                              // touching statusCode in some platforms throws
+                              // an exception
+                              xhr.__raven_xhr.status_code = xhr.status;
+                            } catch (e) {
+                              /* do nothing */
+                            }
+
                             self.captureBreadcrumb({
-                                type: 'http',
-                                category: 'xhr',
-                                data: xhr.__raven_xhr
+                              type: 'http',
+                              category: 'xhr',
+                              data: xhr.__raven_xhr
                             });
+                          }
+                        }
+
+                        var props = ['onload', 'onerror', 'onprogress'];
+                        for (var j = 0; j < props.length; j++) {
+                          wrapProp(props[j], xhr);
+                        }
+
+                        if (
+                          'onreadystatechange' in xhr &&
+                          isFunction(xhr.onreadystatechange)
+                        ) {
+                          fill(
+                            xhr,
+                            'onreadystatechange',
+                            function(orig) {
+                              return self.wrap(
+                                orig,
+                                undefined,
+                                onreadystatechangeHandler
+                              );
+                            } /* intentionally don't track this instrumentation */
+                          );
+                        } else {
+                          // if onreadystatechange wasn't actually set by the page on this xhr, we
+                          // are free to set our own and capture the breadcrumb
+                          xhr.onreadystatechange = onreadystatechangeHandler;
+                        }
+
+                        return origSend.apply(this, arguments);
+                      };
+                    },
+                    wrappedBuiltIns
+                  );
+                }
+
+                if (autoBreadcrumbs.xhr && 'fetch' in _window) {
+                  fill(
+                    _window,
+                    'fetch',
+                    function(origFetch) {
+                      return function(fn, t) {
+                        // preserve arity
+                        // Make a copy of the arguments to prevent deoptimization
+                        // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
+                        var args = new Array(arguments.length);
+                        for (var i = 0; i < args.length; ++i) {
+                          args[i] = arguments[i];
                         }
-                    }
-
-                    var props = ['onload', 'onerror', 'onprogress'];
-                    for (var j = 0; j < props.length; j++) {
-                        wrapProp(props[j], xhr);
-                    }
-
-                    if ('onreadystatechange' in xhr && isFunction(xhr.onreadystatechange)) {
-                        fill(xhr, 'onreadystatechange', function (orig) {
-                            return self.wrap(orig, undefined, onreadystatechangeHandler);
-                        } /* intentionally don't track this instrumentation */);
-                    } else {
-                        // if onreadystatechange wasn't actually set by the page on this xhr, we
-                        // are free to set our own and capture the breadcrumb
-                        xhr.onreadystatechange = onreadystatechangeHandler;
-                    }
-
-                    return origSend.apply(this, arguments);
-                };
-            }, wrappedBuiltIns);
-        }
-
-        if (autoBreadcrumbs.xhr && 'fetch' in _window) {
-            fill(_window, 'fetch', function(origFetch) {
-                return function (fn, t) { // preserve arity
-                    // Make a copy of the arguments to prevent deoptimization
-                    // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
-                    var args = new Array(arguments.length);
-                    for (var i = 0; i < args.length; ++i) {
-                        args[i] = arguments[i];
-                    }
-
-                    var fetchInput = args[0];
-                    var method = 'GET';
-                    var url;
-
-                    if (typeof fetchInput === 'string') {
-                        url = fetchInput;
-                    } else {
-                        url = fetchInput.url;
-                        if (fetchInput.method) {
+
+                        var fetchInput = args[0];
+                        var method = 'GET';
+                        var url;
+
+                        if (typeof fetchInput === 'string') {
+                          url = fetchInput;
+                        } else {
+                          url = fetchInput.url;
+                          if (fetchInput.method) {
                             method = fetchInput.method;
+                          }
                         }
-                    }
-
-                    if (args[1] && args[1].method) {
-                        method = args[1].method;
+
+                        if (args[1] && args[1].method) {
+                          method = args[1].method;
+                        }
+
+                        var fetchData = {
+                          method: method,
+                          url: url,
+                          status_code: null
+                        };
+
+                        self.captureBreadcrumb({
+                          type: 'http',
+                          category: 'fetch',
+                          data: fetchData
+                        });
+
+                        return origFetch.apply(this, args).then(function(response) {
+                          fetchData.status_code = response.status;
+
+                          return response;
+                        });
+                      };
+                    },
+                    wrappedBuiltIns
+                  );
+                }
+
+                // Capture breadcrumbs from any click that is unhandled / bubbled up all the way
+                // to the document. Do this before we instrument addEventListener.
+                if (autoBreadcrumbs.dom && this._hasDocument) {
+                  if (_document.addEventListener) {
+                    _document.addEventListener(
+                      'click',
+                      self._breadcrumbEventHandler('click'),
+                      false
+                    );
+                    _document.addEventListener(
+                      'keypress',
+                      self._keypressEventHandler(),
+                      false
+                    );
+                  } else {
+                    // IE8 Compatibility
+                    _document.attachEvent(
+                      'onclick',
+                      self._breadcrumbEventHandler('click')
+                    );
+                    _document.attachEvent('onkeypress', self._keypressEventHandler());
+                  }
+                }
+
+                // record navigation (URL) changes
+                // NOTE: in Chrome App environment, touching history.pushState, *even inside
+                //       a try/catch block*, will cause Chrome to output an error to console.error
+                // borrowed from: https://github.com/angular/angular.js/pull/13945/files
+                var chrome = _window.chrome;
+                var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime;
+                var hasPushState =
+                  !isChromePackagedApp && _window.history && history.pushState;
+                if (autoBreadcrumbs.location && hasPushState) {
+                  // TODO: remove onpopstate handler on uninstall()
+                  var oldOnPopState = _window.onpopstate;
+                  _window.onpopstate = function() {
+                    var currentHref = self._location.href;
+                    self._captureUrlChange(self._lastHref, currentHref);
+
+                    if (oldOnPopState) {
+                      return oldOnPopState.apply(this, arguments);
                     }
-
-                    var fetchData = {
-                        method: method,
-                        url: url,
-                        status_code: null
-                    };
-
+                  };
+
+                  fill(
+                    history,
+                    'pushState',
+                    function(origPushState) {
+                      // note history.pushState.length is 0; intentionally not declaring
+                      // params to preserve 0 arity
+                      return function(/* state, title, url */) {
+                        var url = arguments.length > 2 ? arguments[2] : undefined;
+
+                        // url argument is optional
+                        if (url) {
+                          // coerce to string (this is what pushState does)
+                          self._captureUrlChange(self._lastHref, url + '');
+                        }
+
+                        return origPushState.apply(this, arguments);
+                      };
+                    },
+                    wrappedBuiltIns
+                  );
+                }
+
+                if (autoBreadcrumbs.console && 'console' in _window && console.log) {
+                  // console
+                  var consoleMethodCallback = function(msg, data) {
                     self.captureBreadcrumb({
-                        type: 'http',
-                        category: 'fetch',
-                        data: fetchData
-                    });
-
-                    return origFetch.apply(this, args).then(function (response) {
-                        fetchData.status_code = response.status;
-
-                        return response;
+                      message: msg,
+                      level: data.level,
+                      category: 'console'
                     });
-                };
-            }, wrappedBuiltIns);
-        }
-
-        // Capture breadcrumbs from any click that is unhandled / bubbled up all the way
-        // to the document. Do this before we instrument addEventListener.
-        if (autoBreadcrumbs.dom && this._hasDocument) {
-            if (_document.addEventListener) {
-                _document.addEventListener('click', self._breadcrumbEventHandler('click'), false);
-                _document.addEventListener('keypress', self._keypressEventHandler(), false);
-            }
-            else {
-                // IE8 Compatibility
-                _document.attachEvent('onclick', self._breadcrumbEventHandler('click'));
-                _document.attachEvent('onkeypress', self._keypressEventHandler());
-            }
-        }
-
-        // record navigation (URL) changes
-        // NOTE: in Chrome App environment, touching history.pushState, *even inside
-        //       a try/catch block*, will cause Chrome to output an error to console.error
-        // borrowed from: https://github.com/angular/angular.js/pull/13945/files
-        var chrome = _window.chrome;
-        var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime;
-        var hasPushState = !isChromePackagedApp && _window.history && history.pushState;
-        if (autoBreadcrumbs.location && hasPushState) {
-            // TODO: remove onpopstate handler on uninstall()
-            var oldOnPopState = _window.onpopstate;
-            _window.onpopstate = function () {
-                var currentHref = self._location.href;
-                self._captureUrlChange(self._lastHref, currentHref);
-
-                if (oldOnPopState) {
-                    return oldOnPopState.apply(this, arguments);
+                  };
+
+                  each(['debug', 'info', 'warn', 'error', 'log'], function(_, level) {
+                    wrapConsoleMethod(console, level, consoleMethodCallback);
+                  });
                 }
-            };
-
-            fill(history, 'pushState', function (origPushState) {
-                // note history.pushState.length is 0; intentionally not declaring
-                // params to preserve 0 arity
-                return function (/* state, title, url */) {
-                    var url = arguments.length > 2 ? arguments[2] : undefined;
-
-                    // url argument is optional
-                    if (url) {
-                        // coerce to string (this is what pushState does)
-                        self._captureUrlChange(self._lastHref, url + '');
-                    }
-
-                    return origPushState.apply(this, arguments);
-                };
-            }, wrappedBuiltIns);
-        }
-
-        if (autoBreadcrumbs.console && 'console' in _window && console.log) {
-            // console
-            var consoleMethodCallback = function (msg, data) {
-                self.captureBreadcrumb({
-                    message: msg,
-                    level: data.level,
-                    category: 'console'
+              },
+
+              _restoreBuiltIns: function() {
+                // restore any wrapped builtins
+                var builtin;
+                while (this._wrappedBuiltIns.length) {
+                  builtin = this._wrappedBuiltIns.shift();
+
+                  var obj = builtin[0],
+                    name = builtin[1],
+                    orig = builtin[2];
+
+                  obj[name] = orig;
+                }
+              },
+
+              _drainPlugins: function() {
+                var self = this;
+
+                // FIX ME TODO
+                each(this._plugins, function(_, plugin) {
+                  var installer = plugin[0];
+                  var args = plugin[1];
+                  installer.apply(self, [self].concat(args));
                 });
-            };
-
-            each(['debug', 'info', 'warn', 'error', 'log'], function (_, level) {
-                wrapConsoleMethod(console, level, consoleMethodCallback);
-            });
-        }
-
-    },
-
-    _restoreBuiltIns: function () {
-        // restore any wrapped builtins
-        var builtin;
-        while (this._wrappedBuiltIns.length) {
-            builtin = this._wrappedBuiltIns.shift();
-
-            var obj = builtin[0],
-              name = builtin[1],
-              orig = builtin[2];
-
-            obj[name] = orig;
-        }
-    },
-
-    _drainPlugins: function() {
-        var self = this;
-
-        // FIX ME TODO
-        each(this._plugins, function(_, plugin) {
-            var installer = plugin[0];
-            var args = plugin[1];
-            installer.apply(self, [self].concat(args));
-        });
-    },
-
-    _parseDSN: function(str) {
-        var m = dsnPattern.exec(str),
-            dsn = {},
-            i = 7;
-
-        try {
-            while (i--) dsn[dsnKeys[i]] = m[i] || '';
-        } catch(e) {
-            throw new RavenConfigError('Invalid DSN: ' + str);
-        }
-
-        if (dsn.pass && !this._globalOptions.allowSecretKey) {
-            throw new RavenConfigError('Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key');
-        }
-
-        return dsn;
-    },
-
-    _getGlobalServer: function(uri) {
-        // assemble the endpoint from the uri pieces
-        var globalServer = '//' + uri.host +
-            (uri.port ? ':' + uri.port : '');
-
-        if (uri.protocol) {
-            globalServer = uri.protocol + ':' + globalServer;
-        }
-        return globalServer;
-    },
-
-    _handleOnErrorStackInfo: function() {
-        // if we are intentionally ignoring errors via onerror, bail out
-        if (!this._ignoreOnError) {
-            this._handleStackInfo.apply(this, arguments);
-        }
-    },
-
-    _handleStackInfo: function(stackInfo, options) {
-        var frames = this._prepareFrames(stackInfo, options);
-
-        this._triggerEvent('handle', {
-            stackInfo: stackInfo,
-            options: options
-        });
-
-        this._processException(
-            stackInfo.name,
-            stackInfo.message,
-            stackInfo.url,
-            stackInfo.lineno,
-            frames,
-            options
-        );
-    },
-
-    _prepareFrames: function(stackInfo, options) {
-        var self = this;
-        var frames = [];
-        if (stackInfo.stack && stackInfo.stack.length) {
-            each(stackInfo.stack, function(i, stack) {
-                var frame = self._normalizeFrame(stack);
-                if (frame) {
-                    frames.push(frame);
+              },
+
+              _parseDSN: function(str) {
+                var m = dsnPattern.exec(str),
+                  dsn = {},
+                  i = 7;
+
+                try {
+                  while (i--) dsn[dsnKeys[i]] = m[i] || '';
+                } catch (e) {
+                  throw new RavenConfigError('Invalid DSN: ' + str);
+                }
+
+                if (dsn.pass && !this._globalOptions.allowSecretKey) {
+                  throw new RavenConfigError(
+                    'Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key'
+                  );
+                }
+
+                return dsn;
+              },
+
+              _getGlobalServer: function(uri) {
+                // assemble the endpoint from the uri pieces
+                var globalServer = '//' + uri.host + (uri.port ? ':' + uri.port : '');
+
+                if (uri.protocol) {
+                  globalServer = uri.protocol + ':' + globalServer;
+                }
+                return globalServer;
+              },
+
+              _handleOnErrorStackInfo: function() {
+                // if we are intentionally ignoring errors via onerror, bail out
+                if (!this._ignoreOnError) {
+                  this._handleStackInfo.apply(this, arguments);
+                }
+              },
+
+              _handleStackInfo: function(stackInfo, options) {
+                var frames = this._prepareFrames(stackInfo, options);
+
+                this._triggerEvent('handle', {
+                  stackInfo: stackInfo,
+                  options: options
+                });
+
+                this._processException(
+                  stackInfo.name,
+                  stackInfo.message,
+                  stackInfo.url,
+                  stackInfo.lineno,
+                  frames,
+                  options
+                );
+              },
+
+              _prepareFrames: function(stackInfo, options) {
+                var self = this;
+                var frames = [];
+                if (stackInfo.stack && stackInfo.stack.length) {
+                  each(stackInfo.stack, function(i, stack) {
+                    var frame = self._normalizeFrame(stack, stackInfo.url);
+                    if (frame) {
+                      frames.push(frame);
+                    }
+                  });
+
+                  // e.g. frames captured via captureMessage throw
+                  if (options && options.trimHeadFrames) {
+                    for (
+                      var j = 0;
+                      j < options.trimHeadFrames && j < frames.length;
+                      j++
+                    ) {
+                      frames[j].in_app = false;
+                    }
+                  }
+                }
+                frames = frames.slice(0, this._globalOptions.stackTraceLimit);
+                return frames;
+              },
+
+              _normalizeFrame: function(frame, stackInfoUrl) {
+                // normalize the frames data
+                var normalized = {
+                  filename: frame.url,
+                  lineno: frame.line,
+                  colno: frame.column,
+                  function: frame.func || '?'
+                };
+
+                // Case when we don't have any information about the error
+                // E.g. throwing a string or raw object, instead of an `Error` in Firefox
+                // Generating synthetic error doesn't add any value here
+                //
+                // We should probably somehow let a user know that they should fix their code
+                if (!frame.url) {
+                  normalized.filename = stackInfoUrl; // fallback to whole stacks url from onerror handler
                 }
-            });
-
-            // e.g. frames captured via captureMessage throw
-            if (options && options.trimHeadFrames) {
-                for (var j = 0; j < options.trimHeadFrames && j < frames.length; j++) {
-                    frames[j].in_app = false;
+
+                normalized.in_app = !// determine if an exception came from outside of our app
+                // first we check the global includePaths list.
+                (
+                  (!!this._globalOptions.includePaths.test &&
+                    !this._globalOptions.includePaths.test(normalized.filename)) ||
+                  // Now we check for fun, if the function name is Raven or TraceKit
+                  /(Raven|TraceKit)\./.test(normalized['function']) ||
+                  // finally, we do a last ditch effort and check for raven.min.js
+                  /raven\.(min\.)?js$/.test(normalized.filename)
+                );
+
+                return normalized;
+              },
+
+              _processException: function(
+                type,
+                message,
+                fileurl,
+                lineno,
+                frames,
+                options
+              ) {
+                var testString = (type || '') + ': ' + (message || '');
+
+                if (
+                  !!this._globalOptions.ignoreErrors.test &&
+                  this._globalOptions.ignoreErrors.test(testString)
+                )
+                  return;
+
+                var stacktrace;
+
+                if (frames && frames.length) {
+                  fileurl = frames[0].filename || fileurl;
+                  // Sentry expects frames oldest to newest
+                  // and JS sends them as newest to oldest
+                  frames.reverse();
+                  stacktrace = {frames: frames};
+                } else if (fileurl) {
+                  stacktrace = {
+                    frames: [
+                      {
+                        filename: fileurl,
+                        lineno: lineno,
+                        in_app: true
+                      }
+                    ]
+                  };
                 }
-            }
-        }
-        frames = frames.slice(0, this._globalOptions.stackTraceLimit);
-        return frames;
-    },
-
-
-    _normalizeFrame: function(frame) {
-        if (!frame.url) return;
-
-        // normalize the frames data
-        var normalized = {
-            filename:   frame.url,
-            lineno:     frame.line,
-            colno:      frame.column,
-            'function': frame.func || '?'
-        };
-
-        normalized.in_app = !( // determine if an exception came from outside of our app
-            // first we check the global includePaths list.
-            !!this._globalOptions.includePaths.test && !this._globalOptions.includePaths.test(normalized.filename) ||
-            // Now we check for fun, if the function name is Raven or TraceKit
-            /(Raven|TraceKit)\./.test(normalized['function']) ||
-            // finally, we do a last ditch effort and check for raven.min.js
-            /raven\.(min\.)?js$/.test(normalized.filename)
-        );
-
-        return normalized;
-    },
-
-    _processException: function(type, message, fileurl, lineno, frames, options) {
-        var stacktrace;
-        if (!!this._globalOptions.ignoreErrors.test && this._globalOptions.ignoreErrors.test(message)) return;
-
-        message += '';
-
-        if (frames && frames.length) {
-            fileurl = frames[0].filename || fileurl;
-            // Sentry expects frames oldest to newest
-            // and JS sends them as newest to oldest
-            frames.reverse();
-            stacktrace = {frames: frames};
-        } else if (fileurl) {
-            stacktrace = {
-                frames: [{
-                    filename: fileurl,
-                    lineno: lineno,
-                    in_app: true
-                }]
-            };
-        }
-
-        if (!!this._globalOptions.ignoreUrls.test && this._globalOptions.ignoreUrls.test(fileurl)) return;
-        if (!!this._globalOptions.whitelistUrls.test && !this._globalOptions.whitelistUrls.test(fileurl)) return;
-
-        var data = objectMerge({
-            // sentry.interfaces.Exception
-            exception: {
-                values: [{
-                    type: type,
-                    value: message,
-                    stacktrace: stacktrace
-                }]
-            },
-            culprit: fileurl
-        }, options);
-
-        // Fire away!
-        this._send(data);
-    },
-
-    _trimPacket: function(data) {
-        // For now, we only want to truncate the two different messages
-        // but this could/should be expanded to just trim everything
-        var max = this._globalOptions.maxMessageLength;
-        if (data.message) {
-            data.message = truncate(data.message, max);
-        }
-        if (data.exception) {
-            var exception = data.exception.values[0];
-            exception.value = truncate(exception.value, max);
-        }
-
-        var request = data.request;
-        if (request) {
-            if (request.url) {
-                request.url = truncate(request.url, this._globalOptions.maxUrlLength);
-            }
-            if (request.Referer) {
-                request.Referer = truncate(request.Referer, this._globalOptions.maxUrlLength);
-            }
-        }
-
-        if (data.breadcrumbs && data.breadcrumbs.values)
-            this._trimBreadcrumbs(data.breadcrumbs);
-
-        return data;
-    },
-
-    /**
+
+                if (
+                  !!this._globalOptions.ignoreUrls.test &&
+                  this._globalOptions.ignoreUrls.test(fileurl)
+                )
+                  return;
+                if (
+                  !!this._globalOptions.whitelistUrls.test &&
+                  !this._globalOptions.whitelistUrls.test(fileurl)
+                )
+                  return;
+
+                var data = objectMerge(
+                  {
+                    // sentry.interfaces.Exception
+                    exception: {
+                      values: [
+                        {
+                          type: type,
+                          value: message,
+                          stacktrace: stacktrace
+                        }
+                      ]
+                    },
+                    culprit: fileurl
+                  },
+                  options
+                );
+
+                // Fire away!
+                this._send(data);
+              },
+
+              _trimPacket: function(data) {
+                // For now, we only want to truncate the two different messages
+                // but this could/should be expanded to just trim everything
+                var max = this._globalOptions.maxMessageLength;
+                if (data.message) {
+                  data.message = truncate(data.message, max);
+                }
+                if (data.exception) {
+                  var exception = data.exception.values[0];
+                  exception.value = truncate(exception.value, max);
+                }
+
+                var request = data.request;
+                if (request) {
+                  if (request.url) {
+                    request.url = truncate(request.url, this._globalOptions.maxUrlLength);
+                  }
+                  if (request.Referer) {
+                    request.Referer = truncate(
+                      request.Referer,
+                      this._globalOptions.maxUrlLength
+                    );
+                  }
+                }
+
+                if (data.breadcrumbs && data.breadcrumbs.values)
+                  this._trimBreadcrumbs(data.breadcrumbs);
+
+                return data;
+              },
+
+              /**
      * Truncate breadcrumb values (right now just URLs)
      */
-    _trimBreadcrumbs: function (breadcrumbs) {
-        // known breadcrumb properties with urls
-        // TODO: also consider arbitrary prop values that start with (https?)?://
-        var urlProps = ['to', 'from', 'url'],
-            urlProp,
-            crumb,
-            data;
-
-        for (var i = 0; i < breadcrumbs.values.length; ++i) {
-            crumb = breadcrumbs.values[i];
-            if (!crumb.hasOwnProperty('data') || !isObject(crumb.data) || objectFrozen(crumb.data))
-                continue;
-
-            data = objectMerge({}, crumb.data);
-            for (var j = 0; j < urlProps.length; ++j) {
-                urlProp = urlProps[j];
-                if (data.hasOwnProperty(urlProp)) {
-                    data[urlProp] = truncate(data[urlProp], this._globalOptions.maxUrlLength);
+              _trimBreadcrumbs: function(breadcrumbs) {
+                // known breadcrumb properties with urls
+                // TODO: also consider arbitrary prop values that start with (https?)?://
+                var urlProps = ['to', 'from', 'url'],
+                  urlProp,
+                  crumb,
+                  data;
+
+                for (var i = 0; i < breadcrumbs.values.length; ++i) {
+                  crumb = breadcrumbs.values[i];
+                  if (
+                    !crumb.hasOwnProperty('data') ||
+                    !isObject(crumb.data) ||
+                    objectFrozen(crumb.data)
+                  )
+                    continue;
+
+                  data = objectMerge({}, crumb.data);
+                  for (var j = 0; j < urlProps.length; ++j) {
+                    urlProp = urlProps[j];
+                    if (data.hasOwnProperty(urlProp) && data[urlProp]) {
+                      data[urlProp] = truncate(
+                        data[urlProp],
+                        this._globalOptions.maxUrlLength
+                      );
+                    }
+                  }
+                  breadcrumbs.values[i].data = data;
                 }
-            }
-            breadcrumbs.values[i].data = data;
-        }
-    },
-
-    _getHttpData: function() {
-        if (!this._hasNavigator && !this._hasDocument) return;
-        var httpData = {};
-
-        if (this._hasNavigator && _navigator.userAgent) {
-            httpData.headers = {
-              'User-Agent': navigator.userAgent
-            };
-        }
-
-        if (this._hasDocument) {
-            if (_document.location && _document.location.href) {
-                httpData.url = _document.location.href;
-            }
-            if (_document.referrer) {
-                if (!httpData.headers) httpData.headers = {};
-                httpData.headers.Referer = _document.referrer;
-            }
-        }
-
-        return httpData;
-    },
-
-    _resetBackoff: function() {
-        this._backoffDuration = 0;
-        this._backoffStart = null;
-    },
-
-    _shouldBackoff: function() {
-        return this._backoffDuration && now() - this._backoffStart < this._backoffDuration;
-    },
-
-    /**
+              },
+
+              _getHttpData: function() {
+                if (!this._hasNavigator && !this._hasDocument) return;
+                var httpData = {};
+
+                if (this._hasNavigator && _navigator.userAgent) {
+                  httpData.headers = {
+                    'User-Agent': navigator.userAgent
+                  };
+                }
+
+                if (this._hasDocument) {
+                  if (_document.location && _document.location.href) {
+                    httpData.url = _document.location.href;
+                  }
+                  if (_document.referrer) {
+                    if (!httpData.headers) httpData.headers = {};
+                    httpData.headers.Referer = _document.referrer;
+                  }
+                }
+
+                return httpData;
+              },
+
+              _resetBackoff: function() {
+                this._backoffDuration = 0;
+                this._backoffStart = null;
+              },
+
+              _shouldBackoff: function() {
+                return (
+                  this._backoffDuration &&
+                  now() - this._backoffStart < this._backoffDuration
+                );
+              },
+
+              /**
      * Returns true if the in-process data payload matches the signature
      * of the previously-sent data
      *
      * NOTE: This has to be done at this level because TraceKit can generate
      *       data from window.onerror WITHOUT an exception object (IE8, IE9,
      *       other old browsers). This can take the form of an "exception"
      *       data object with a single frame (derived from the onerror args).
      */
-    _isRepeatData: function (current) {
-        var last = this._lastData;
-
-        if (!last ||
-            current.message !== last.message || // defined for captureMessage
-            current.culprit !== last.culprit)   // defined for captureException/onerror
-            return false;
-
-        // Stacktrace interface (i.e. from captureMessage)
-        if (current.stacktrace || last.stacktrace) {
-            return isSameStacktrace(current.stacktrace, last.stacktrace);
-        }
-        // Exception interface (i.e. from captureException/onerror)
-        else if (current.exception || last.exception) {
-            return isSameException(current.exception, last.exception);
-        }
-
-        return true;
-    },
-
-    _setBackoffState: function(request) {
-        // If we are already in a backoff state, don't change anything
-        if (this._shouldBackoff()) {
-            return;
-        }
-
-        var status = request.status;
-
-        // 400 - project_id doesn't exist or some other fatal
-        // 401 - invalid/revoked dsn
-        // 429 - too many requests
-        if (!(status === 400 || status === 401 || status === 429))
-            return;
-
-        var retry;
-        try {
-            // If Retry-After is not in Access-Control-Expose-Headers, most
-            // browsers will throw an exception trying to access it
-            retry = request.getResponseHeader('Retry-After');
-            retry = parseInt(retry, 10) * 1000; // Retry-After is returned in seconds
-        } catch (e) {
-            /* eslint no-empty:0 */
-        }
-
-
-        this._backoffDuration = retry
-            // If Sentry server returned a Retry-After value, use it
-            ? retry
-            // Otherwise, double the last backoff duration (starts at 1 sec)
-            : this._backoffDuration * 2 || 1000;
-
-        this._backoffStart = now();
-    },
-
-    _send: function(data) {
-        var globalOptions = this._globalOptions;
-
-        var baseData = {
-            project: this._globalProject,
-            logger: globalOptions.logger,
-            platform: 'javascript'
-        }, httpData = this._getHttpData();
-
-        if (httpData) {
-            baseData.request = httpData;
-        }
-
-        // HACK: delete `trimHeadFrames` to prevent from appearing in outbound payload
-        if (data.trimHeadFrames) delete data.trimHeadFrames;
-
-        data = objectMerge(baseData, data);
-
-        // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
-        data.tags = objectMerge(objectMerge({}, this._globalContext.tags), data.tags);
-        data.extra = objectMerge(objectMerge({}, this._globalContext.extra), data.extra);
-
-        // Send along our own collected metadata with extra
-        data.extra['session:duration'] = now() - this._startTime;
-
-        if (this._breadcrumbs && this._breadcrumbs.length > 0) {
-            // intentionally make shallow copy so that additions
-            // to breadcrumbs aren't accidentally sent in this request
-            data.breadcrumbs = {
-                values: [].slice.call(this._breadcrumbs, 0)
+              _isRepeatData: function(current) {
+                var last = this._lastData;
+
+                if (
+                  !last ||
+                  current.message !== last.message || // defined for captureMessage
+                  current.culprit !== last.culprit // defined for captureException/onerror
+                )
+                  return false;
+
+                // Stacktrace interface (i.e. from captureMessage)
+                if (current.stacktrace || last.stacktrace) {
+                  return isSameStacktrace(current.stacktrace, last.stacktrace);
+                } else if (current.exception || last.exception) {
+                  // Exception interface (i.e. from captureException/onerror)
+                  return isSameException(current.exception, last.exception);
+                }
+
+                return true;
+              },
+
+              _setBackoffState: function(request) {
+                // If we are already in a backoff state, don't change anything
+                if (this._shouldBackoff()) {
+                  return;
+                }
+
+                var status = request.status;
+
+                // 400 - project_id doesn't exist or some other fatal
+                // 401 - invalid/revoked dsn
+                // 429 - too many requests
+                if (!(status === 400 || status === 401 || status === 429)) return;
+
+                var retry;
+                try {
+                  // If Retry-After is not in Access-Control-Expose-Headers, most
+                  // browsers will throw an exception trying to access it
+                  retry = request.getResponseHeader('Retry-After');
+                  retry = parseInt(retry, 10) * 1000; // Retry-After is returned in seconds
+                } catch (e) {
+                  /* eslint no-empty:0 */
+                }
+
+                this._backoffDuration = retry
+                  ? // If Sentry server returned a Retry-After value, use it
+                    retry
+                  : // Otherwise, double the last backoff duration (starts at 1 sec)
+                    this._backoffDuration * 2 || 1000;
+
+                this._backoffStart = now();
+              },
+
+              _send: function(data) {
+                var globalOptions = this._globalOptions;
+
+                var baseData = {
+                    project: this._globalProject,
+                    logger: globalOptions.logger,
+                    platform: 'javascript'
+                  },
+                  httpData = this._getHttpData();
+
+                if (httpData) {
+                  baseData.request = httpData;
+                }
+
+                // HACK: delete `trimHeadFrames` to prevent from appearing in outbound payload
+                if (data.trimHeadFrames) delete data.trimHeadFrames;
+
+                data = objectMerge(baseData, data);
+
+                // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
+                data.tags = objectMerge(
+                  objectMerge({}, this._globalContext.tags),
+                  data.tags
+                );
+                data.extra = objectMerge(
+                  objectMerge({}, this._globalContext.extra),
+                  data.extra
+                );
+
+                // Send along our own collected metadata with extra
+                data.extra['session:duration'] = now() - this._startTime;
+
+                if (this._breadcrumbs && this._breadcrumbs.length > 0) {
+                  // intentionally make shallow copy so that additions
+                  // to breadcrumbs aren't accidentally sent in this request
+                  data.breadcrumbs = {
+                    values: [].slice.call(this._breadcrumbs, 0)
+                  };
+                }
+
+                // If there are no tags/extra, strip the key from the payload alltogther.
+                if (isEmptyObject(data.tags)) delete data.tags;
+
+                if (this._globalContext.user) {
+                  // sentry.interfaces.User
+                  data.user = this._globalContext.user;
+                }
+
+                // Include the environment if it's defined in globalOptions
+                if (globalOptions.environment)
+                  data.environment = globalOptions.environment;
+
+                // Include the release if it's defined in globalOptions
+                if (globalOptions.release) data.release = globalOptions.release;
+
+                // Include server_name if it's defined in globalOptions
+                if (globalOptions.serverName) data.server_name = globalOptions.serverName;
+
+                if (isFunction(globalOptions.dataCallback)) {
+                  data = globalOptions.dataCallback(data) || data;
+                }
+
+                // Why??????????
+                if (!data || isEmptyObject(data)) {
+                  return;
+                }
+
+                // Check if the request should be filtered or not
+                if (
+                  isFunction(globalOptions.shouldSendCallback) &&
+                  !globalOptions.shouldSendCallback(data)
+                ) {
+                  return;
+                }
+
+                // Backoff state: Sentry server previously responded w/ an error (e.g. 429 - too many requests),
+                // so drop requests until "cool-off" period has elapsed.
+                if (this._shouldBackoff()) {
+                  this._logDebug('warn', 'Raven dropped error due to backoff: ', data);
+                  return;
+                }
+
+                if (typeof globalOptions.sampleRate === 'number') {
+                  if (Math.random() < globalOptions.sampleRate) {
+                    this._sendProcessedPayload(data);
+                  }
+                } else {
+                  this._sendProcessedPayload(data);
+                }
+              },
+
+              _getUuid: function() {
+                return uuid4();
+              },
+
+              _sendProcessedPayload: function(data, callback) {
+                var self = this;
+                var globalOptions = this._globalOptions;
+
+                if (!this.isSetup()) return;
+
+                // Try and clean up the packet before sending by truncating long values
+                data = this._trimPacket(data);
+
+                // ideally duplicate error testing should occur *before* dataCallback/shouldSendCallback,
+                // but this would require copying an un-truncated copy of the data packet, which can be
+                // arbitrarily deep (extra_data) -- could be worthwhile? will revisit
+                if (!this._globalOptions.allowDuplicates && this._isRepeatData(data)) {
+                  this._logDebug('warn', 'Raven dropped repeat event: ', data);
+                  return;
+                }
+
+                // Send along an event_id if not explicitly passed.
+                // This event_id can be used to reference the error within Sentry itself.
+                // Set lastEventId after we know the error should actually be sent
+                this._lastEventId = data.event_id || (data.event_id = this._getUuid());
+
+                // Store outbound payload after trim
+                this._lastData = data;
+
+                this._logDebug('debug', 'Raven about to send:', data);
+
+                var auth = {
+                  sentry_version: '7',
+                  sentry_client: 'raven-js/' + this.VERSION,
+                  sentry_key: this._globalKey
+                };
+
+                if (this._globalSecret) {
+                  auth.sentry_secret = this._globalSecret;
+                }
+
+                var exception = data.exception && data.exception.values[0];
+                this.captureBreadcrumb({
+                  category: 'sentry',
+                  message: exception
+                    ? (exception.type ? exception.type + ': ' : '') + exception.value
+                    : data.message,
+                  event_id: data.event_id,
+                  level: data.level || 'error' // presume error unless specified
+                });
+
+                var url = this._globalEndpoint;
+                (globalOptions.transport || this._makeRequest).call(this, {
+                  url: url,
+                  auth: auth,
+                  data: data,
+                  options: globalOptions,
+                  onSuccess: function success() {
+                    self._resetBackoff();
+
+                    self._triggerEvent('success', {
+                      data: data,
+                      src: url
+                    });
+                    callback && callback();
+                  },
+                  onError: function failure(error) {
+                    self._logDebug('error', 'Raven transport failed to send: ', error);
+
+                    if (error.request) {
+                      self._setBackoffState(error.request);
+                    }
+
+                    self._triggerEvent('failure', {
+                      data: data,
+                      src: url
+                    });
+                    error =
+                      error ||
+                      new Error('Raven send failed (no additional details provided)');
+                    callback && callback(error);
+                  }
+                });
+              },
+
+              _makeRequest: function(opts) {
+                var request = _window.XMLHttpRequest && new _window.XMLHttpRequest();
+                if (!request) return;
+
+                // if browser doesn't support CORS (e.g. IE7), we are out of luck
+                var hasCORS =
+                  'withCredentials' in request || typeof XDomainRequest !== 'undefined';
+
+                if (!hasCORS) return;
+
+                var url = opts.url;
+
+                if ('withCredentials' in request) {
+                  request.onreadystatechange = function() {
+                    if (request.readyState !== 4) {
+                      return;
+                    } else if (request.status === 200) {
+                      opts.onSuccess && opts.onSuccess();
+                    } else if (opts.onError) {
+                      var err = new Error('Sentry error code: ' + request.status);
+                      err.request = request;
+                      opts.onError(err);
+                    }
+                  };
+                } else {
+                  request = new XDomainRequest();
+                  // xdomainrequest cannot go http -> https (or vice versa),
+                  // so always use protocol relative
+                  url = url.replace(/^https?:/, '');
+
+                  // onreadystatechange not supported by XDomainRequest
+                  if (opts.onSuccess) {
+                    request.onload = opts.onSuccess;
+                  }
+                  if (opts.onError) {
+                    request.onerror = function() {
+                      var err = new Error('Sentry error code: XDomainRequest');
+                      err.request = request;
+                      opts.onError(err);
+                    };
+                  }
+                }
+
+                // NOTE: auth is intentionally sent as part of query string (NOT as custom
+                //       HTTP header) so as to avoid preflight CORS requests
+                request.open('POST', url + '?' + urlencode(opts.auth));
+                request.send(stringify(opts.data));
+              },
+
+              _logDebug: function(level) {
+                if (this._originalConsoleMethods[level] && this.debug) {
+                  // In IE<10 console methods do not have their own 'apply' method
+                  Function.prototype.apply.call(
+                    this._originalConsoleMethods[level],
+                    this._originalConsole,
+                    [].slice.call(arguments, 1)
+                  );
+                }
+              },
+
+              _mergeContext: function(key, context) {
+                if (isUndefined(context)) {
+                  delete this._globalContext[key];
+                } else {
+                  this._globalContext[key] = objectMerge(
+                    this._globalContext[key] || {},
+                    context
+                  );
+                }
+              }
             };
-        }
-
-        // If there are no tags/extra, strip the key from the payload alltogther.
-        if (isEmptyObject(data.tags)) delete data.tags;
-
-        if (this._globalContext.user) {
-            // sentry.interfaces.User
-            data.user = this._globalContext.user;
-        }
-
-        // Include the environment if it's defined in globalOptions
-        if (globalOptions.environment) data.environment = globalOptions.environment;
-
-        // Include the release if it's defined in globalOptions
-        if (globalOptions.release) data.release = globalOptions.release;
-
-        // Include server_name if it's defined in globalOptions
-        if (globalOptions.serverName) data.server_name = globalOptions.serverName;
-
-        if (isFunction(globalOptions.dataCallback)) {
-            data = globalOptions.dataCallback(data) || data;
-        }
-
-        // Why??????????
-        if (!data || isEmptyObject(data)) {
-            return;
-        }
-
-        // Check if the request should be filtered or not
-        if (isFunction(globalOptions.shouldSendCallback) && !globalOptions.shouldSendCallback(data)) {
-            return;
-        }
-
-        // Backoff state: Sentry server previously responded w/ an error (e.g. 429 - too many requests),
-        // so drop requests until "cool-off" period has elapsed.
-        if (this._shouldBackoff()) {
-            this._logDebug('warn', 'Raven dropped error due to backoff: ', data);
-            return;
-        }
-
-        if (typeof globalOptions.sampleRate === 'number') {
-            if (Math.random() < globalOptions.sampleRate) {
-                this._sendProcessedPayload(data);
-            }
-        } else {
-            this._sendProcessedPayload(data);
-        }
-    },
-
-    _getUuid: function () {
-      return uuid4();
-    },
-
-    _sendProcessedPayload: function(data, callback) {
-        var self = this;
-        var globalOptions = this._globalOptions;
-
-        if (!this.isSetup()) return;
-
-        // Send along an event_id if not explicitly passed.
-        // This event_id can be used to reference the error within Sentry itself.
-        // Set lastEventId after we know the error should actually be sent
-        this._lastEventId = data.event_id || (data.event_id = this._getUuid());
-
-        // Try and clean up the packet before sending by truncating long values
-        data = this._trimPacket(data);
-
-        // ideally duplicate error testing should occur *before* dataCallback/shouldSendCallback,
-        // but this would require copying an un-truncated copy of the data packet, which can be
-        // arbitrarily deep (extra_data) -- could be worthwhile? will revisit
-        if (!this._globalOptions.allowDuplicates && this._isRepeatData(data)) {
-            this._logDebug('warn', 'Raven dropped repeat event: ', data);
-            return;
-        }
-
-        // Store outbound payload after trim
-        this._lastData = data;
-
-        this._logDebug('debug', 'Raven about to send:', data);
-
-        var auth = {
-            sentry_version: '7',
-            sentry_client: 'raven-js/' + this.VERSION,
-            sentry_key: this._globalKey
-        };
-        if (this._globalSecret) {
-            auth.sentry_secret = this._globalSecret;
-        }
-
-        var exception = data.exception && data.exception.values[0];
-        this.captureBreadcrumb({
-            category: 'sentry',
-            message: exception
-                ? (exception.type ? exception.type + ': ' : '') + exception.value
-                : data.message,
-            event_id: data.event_id,
-            level: data.level || 'error' // presume error unless specified
-        });
-
-        var url = this._globalEndpoint;
-        (globalOptions.transport || this._makeRequest).call(this, {
-            url: url,
-            auth: auth,
-            data: data,
-            options: globalOptions,
-            onSuccess: function success() {
-                self._resetBackoff();
-
-                self._triggerEvent('success', {
-                    data: data,
-                    src: url
-                });
-                callback && callback();
-            },
-            onError: function failure(error) {
-                self._logDebug('error', 'Raven transport failed to send: ', error);
-
-                if (error.request) {
-                    self._setBackoffState(error.request);
-                }
-
-                self._triggerEvent('failure', {
-                    data: data,
-                    src: url
-                });
-                error = error || new Error('Raven send failed (no additional details provided)');
-                callback && callback(error);
-            }
-        });
-    },
-
-    _makeRequest: function(opts) {
-        var request = new XMLHttpRequest();
-
-        // if browser doesn't support CORS (e.g. IE7), we are out of luck
-        var hasCORS =
-            'withCredentials' in request ||
-            typeof XDomainRequest !== 'undefined';
-
-        if (!hasCORS) return;
-
-        var url = opts.url;
-
-        if ('withCredentials' in request) {
-            request.onreadystatechange = function () {
-                if (request.readyState !== 4) {
-                    return;
-                } else if (request.status === 200) {
-                    opts.onSuccess && opts.onSuccess();
-                } else if (opts.onError) {
-                    var err = new Error('Sentry error code: ' + request.status);
-                    err.request = request;
-                    opts.onError(err);
-                }
-            };
-        } else {
-            request = new XDomainRequest();
-            // xdomainrequest cannot go http -> https (or vice versa),
-            // so always use protocol relative
-            url = url.replace(/^https?:/, '');
-
-            // onreadystatechange not supported by XDomainRequest
-            if (opts.onSuccess) {
-                request.onload = opts.onSuccess;
-            }
-            if (opts.onError) {
-                request.onerror = function () {
-                    var err = new Error('Sentry error code: XDomainRequest');
-                    err.request = request;
-                    opts.onError(err);
-                }
-            }
-        }
-
-        // NOTE: auth is intentionally sent as part of query string (NOT as custom
-        //       HTTP header) so as to avoid preflight CORS requests
-        request.open('POST', url + '?' + urlencode(opts.auth));
-        request.send(stringify(opts.data));
-    },
-
-    _logDebug: function(level) {
-        if (this._originalConsoleMethods[level] && this.debug) {
-            // In IE<10 console methods do not have their own 'apply' method
-            Function.prototype.apply.call(
-                this._originalConsoleMethods[level],
-                this._originalConsole,
-                [].slice.call(arguments, 1)
-            );
-        }
-    },
-
-    _mergeContext: function(key, context) {
-        if (isUndefined(context)) {
-            delete this._globalContext[key];
-        } else {
-            this._globalContext[key] = objectMerge(this._globalContext[key] || {}, context);
-        }
-    }
-};
-
-/*------------------------------------------------
+
+            /*------------------------------------------------
  * utils
  *
  * conditionally exported for test via Raven.utils
  =================================================
  */
-var objectPrototype = Object.prototype;
-
-function isUndefined(what) {
-    return what === void 0;
-}
-
-function isFunction(what) {
-    return typeof what === 'function';
-}
-
-function isString(what) {
-    return objectPrototype.toString.call(what) === '[object String]';
-}
-
-
-function isEmptyObject(what) {
-    for (var _ in what) return false;  // eslint-disable-line guard-for-in, no-unused-vars
-    return true;
-}
-
-function each(obj, callback) {
-    var i, j;
-
-    if (isUndefined(obj.length)) {
-        for (i in obj) {
-            if (hasKey(obj, i)) {
-                callback.call(null, i, obj[i]);
+            var objectPrototype = Object.prototype;
+
+            function isUndefined(what) {
+              return what === void 0;
+            }
+
+            function isFunction(what) {
+              return typeof what === 'function';
+            }
+
+            function isString(what) {
+              return objectPrototype.toString.call(what) === '[object String]';
+            }
+
+            function isEmptyObject(what) {
+              for (var _ in what) return false; // eslint-disable-line guard-for-in, no-unused-vars
+              return true;
             }
-        }
-    } else {
-        j = obj.length;
-        if (j) {
-            for (i = 0; i < j; i++) {
-                callback.call(null, i, obj[i]);
+
+            function each(obj, callback) {
+              var i, j;
+
+              if (isUndefined(obj.length)) {
+                for (i in obj) {
+                  if (hasKey(obj, i)) {
+                    callback.call(null, i, obj[i]);
+                  }
+                }
+              } else {
+                j = obj.length;
+                if (j) {
+                  for (i = 0; i < j; i++) {
+                    callback.call(null, i, obj[i]);
+                  }
+                }
+              }
             }
-        }
-    }
-}
-
-function objectMerge(obj1, obj2) {
-    if (!obj2) {
-        return obj1;
-    }
-    each(obj2, function(key, value){
-        obj1[key] = value;
-    });
-    return obj1;
-}
-
-/**
+
+            function objectMerge(obj1, obj2) {
+              if (!obj2) {
+                return obj1;
+              }
+              each(obj2, function(key, value) {
+                obj1[key] = value;
+              });
+              return obj1;
+            }
+
+            /**
  * This function is only used for react-native.
  * react-native freezes object that have already been sent over the
  * js bridge. We need this function in order to check if the object is frozen.
  * So it's ok that objectFrozen returns false if Object.isFrozen is not
  * supported because it's not relevant for other "platforms". See related issue:
  * https://github.com/getsentry/react-native-sentry/issues/57
  */
-function objectFrozen(obj) {
-    if (!Object.isFrozen) {
-        return false;
-    }
-    return Object.isFrozen(obj);
-}
-
-function truncate(str, max) {
-    return !max || str.length <= max ? str : str.substr(0, max) + '\u2026';
-}
-
-/**
+            function objectFrozen(obj) {
+              if (!Object.isFrozen) {
+                return false;
+              }
+              return Object.isFrozen(obj);
+            }
+
+            function truncate(str, max) {
+              return !max || str.length <= max ? str : str.substr(0, max) + '\u2026';
+            }
+
+            /**
  * hasKey, a better form of hasOwnProperty
  * Example: hasKey(MainHostObject, property) === true/false
  *
  * @param {Object} host object to check property
  * @param {string} key to check
  */
-function hasKey(object, key) {
-    return objectPrototype.hasOwnProperty.call(object, key);
-}
-
-function joinRegExp(patterns) {
-    // Combine an array of regular expressions and strings into one large regexp
-    // Be mad.
-    var sources = [],
-        i = 0, len = patterns.length,
-        pattern;
-
-    for (; i < len; i++) {
-        pattern = patterns[i];
-        if (isString(pattern)) {
-            // If it's a string, we need to escape it
-            // Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
-            sources.push(pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'));
-        } else if (pattern && pattern.source) {
-            // If it's a regexp already, we want to extract the source
-            sources.push(pattern.source);
-        }
-        // Intentionally skip other cases
-    }
-    return new RegExp(sources.join('|'), 'i');
-}
-
-function urlencode(o) {
-    var pairs = [];
-    each(o, function(key, value) {
-        pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
-    });
-    return pairs.join('&');
-}
-
-// borrowed from https://tools.ietf.org/html/rfc3986#appendix-B
-// intentionally using regex and not <a/> href parsing trick because React Native and other
-// environments where DOM might not be available
-function parseUrl(url) {
-    var match = url.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/);
-    if (!match) return {};
-
-    // coerce to undefined values to empty string so we don't get 'undefined'
-    var query = match[6] || '';
-    var fragment = match[8] || '';
-    return {
-        protocol: match[2],
-        host: match[4],
-        path: match[5],
-        relative: match[5] + query + fragment // everything minus origin
-    };
-}
-function uuid4() {
-    var crypto = _window.crypto || _window.msCrypto;
-
-    if (!isUndefined(crypto) && crypto.getRandomValues) {
-        // Use window.crypto API if available
-        var arr = new Uint16Array(8);
-        crypto.getRandomValues(arr);
-
-        // set 4 in byte 7
-        arr[3] = arr[3] & 0xFFF | 0x4000;
-        // set 2 most significant bits of byte 9 to '10'
-        arr[4] = arr[4] & 0x3FFF | 0x8000;
-
-        var pad = function(num) {
-            var v = num.toString(16);
-            while (v.length < 4) {
-                v = '0' + v;
+            function hasKey(object, key) {
+              return objectPrototype.hasOwnProperty.call(object, key);
+            }
+
+            function joinRegExp(patterns) {
+              // Combine an array of regular expressions and strings into one large regexp
+              // Be mad.
+              var sources = [],
+                i = 0,
+                len = patterns.length,
+                pattern;
+
+              for (; i < len; i++) {
+                pattern = patterns[i];
+                if (isString(pattern)) {
+                  // If it's a string, we need to escape it
+                  // Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
+                  sources.push(pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'));
+                } else if (pattern && pattern.source) {
+                  // If it's a regexp already, we want to extract the source
+                  sources.push(pattern.source);
+                }
+                // Intentionally skip other cases
+              }
+              return new RegExp(sources.join('|'), 'i');
+            }
+
+            function urlencode(o) {
+              var pairs = [];
+              each(o, function(key, value) {
+                pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
+              });
+              return pairs.join('&');
             }
-            return v;
-        };
-
-        return pad(arr[0]) + pad(arr[1]) + pad(arr[2]) + pad(arr[3]) + pad(arr[4]) +
-        pad(arr[5]) + pad(arr[6]) + pad(arr[7]);
-    } else {
-        // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
-        return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
-            var r = Math.random()*16|0,
-                v = c === 'x' ? r : r&0x3|0x8;
-            return v.toString(16);
-        });
-    }
-}
-
-/**
+
+            // borrowed from https://tools.ietf.org/html/rfc3986#appendix-B
+            // intentionally using regex and not <a/> href parsing trick because React Native and other
+            // environments where DOM might not be available
+            function parseUrl(url) {
+              var match = url.match(
+                /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/
+              );
+              if (!match) return {};
+
+              // coerce to undefined values to empty string so we don't get 'undefined'
+              var query = match[6] || '';
+              var fragment = match[8] || '';
+              return {
+                protocol: match[2],
+                host: match[4],
+                path: match[5],
+                relative: match[5] + query + fragment // everything minus origin
+              };
+            }
+            function uuid4() {
+              var crypto = _window.crypto || _window.msCrypto;
+
+              if (!isUndefined(crypto) && crypto.getRandomValues) {
+                // Use window.crypto API if available
+                // eslint-disable-next-line no-undef
+                var arr = new Uint16Array(8);
+                crypto.getRandomValues(arr);
+
+                // set 4 in byte 7
+                arr[3] = (arr[3] & 0xfff) | 0x4000;
+                // set 2 most significant bits of byte 9 to '10'
+                arr[4] = (arr[4] & 0x3fff) | 0x8000;
+
+                var pad = function(num) {
+                  var v = num.toString(16);
+                  while (v.length < 4) {
+                    v = '0' + v;
+                  }
+                  return v;
+                };
+
+                return (
+                  pad(arr[0]) +
+                  pad(arr[1]) +
+                  pad(arr[2]) +
+                  pad(arr[3]) +
+                  pad(arr[4]) +
+                  pad(arr[5]) +
+                  pad(arr[6]) +
+                  pad(arr[7])
+                );
+              } else {
+                // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
+                return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+                  var r = (Math.random() * 16) | 0,
+                    v = c === 'x' ? r : (r & 0x3) | 0x8;
+                  return v.toString(16);
+                });
+              }
+            }
+
+            /**
  * Given a child DOM element, returns a query-selector statement describing that
  * and its ancestors
  * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]
  * @param elem
  * @returns {string}
  */
-function htmlTreeAsString(elem) {
-    /* eslint no-extra-parens:0*/
-    var MAX_TRAVERSE_HEIGHT = 5,
-        MAX_OUTPUT_LEN = 80,
-        out = [],
-        height = 0,
-        len = 0,
-        separator = ' > ',
-        sepLength = separator.length,
-        nextStr;
-
-    while (elem && height++ < MAX_TRAVERSE_HEIGHT) {
-
-        nextStr = htmlElementAsString(elem);
-        // bail out if
-        // - nextStr is the 'html' element
-        // - the length of the string that would be created exceeds MAX_OUTPUT_LEN
-        //   (ignore this limit if we are on the first iteration)
-        if (nextStr === 'html' || height > 1 && len + (out.length * sepLength) + nextStr.length >= MAX_OUTPUT_LEN) {
-            break;
-        }
-
-        out.push(nextStr);
-
-        len += nextStr.length;
-        elem = elem.parentNode;
-    }
-
-    return out.reverse().join(separator);
-}
-
-/**
+            function htmlTreeAsString(elem) {
+              /* eslint no-extra-parens:0*/
+              var MAX_TRAVERSE_HEIGHT = 5,
+                MAX_OUTPUT_LEN = 80,
+                out = [],
+                height = 0,
+                len = 0,
+                separator = ' > ',
+                sepLength = separator.length,
+                nextStr;
+
+              while (elem && height++ < MAX_TRAVERSE_HEIGHT) {
+                nextStr = htmlElementAsString(elem);
+                // bail out if
+                // - nextStr is the 'html' element
+                // - the length of the string that would be created exceeds MAX_OUTPUT_LEN
+                //   (ignore this limit if we are on the first iteration)
+                if (
+                  nextStr === 'html' ||
+                  (height > 1 &&
+                    len + out.length * sepLength + nextStr.length >= MAX_OUTPUT_LEN)
+                ) {
+                  break;
+                }
+
+                out.push(nextStr);
+
+                len += nextStr.length;
+                elem = elem.parentNode;
+              }
+
+              return out.reverse().join(separator);
+            }
+
+            /**
  * Returns a simple, query-selector representation of a DOM element
  * e.g. [HTMLElement] => input#foo.btn[name=baz]
  * @param HTMLElement
  * @returns {string}
  */
-function htmlElementAsString(elem) {
-    var out = [],
-        className,
-        classes,
-        key,
-        attr,
-        i;
-
-    if (!elem || !elem.tagName) {
-        return '';
-    }
-
-    out.push(elem.tagName.toLowerCase());
-    if (elem.id) {
-        out.push('#' + elem.id);
-    }
-
-    className = elem.className;
-    if (className && isString(className)) {
-        classes = className.split(/\s+/);
-        for (i = 0; i < classes.length; i++) {
-            out.push('.' + classes[i]);
-        }
-    }
-    var attrWhitelist = ['type', 'name', 'title', 'alt'];
-    for (i = 0; i < attrWhitelist.length; i++) {
-        key = attrWhitelist[i];
-        attr = elem.getAttribute(key);
-        if (attr) {
-            out.push('[' + key + '="' + attr + '"]');
-        }
-    }
-    return out.join('');
-}
-
-/**
+            function htmlElementAsString(elem) {
+              var out = [],
+                className,
+                classes,
+                key,
+                attr,
+                i;
+
+              if (!elem || !elem.tagName) {
+                return '';
+              }
+
+              out.push(elem.tagName.toLowerCase());
+              if (elem.id) {
+                out.push('#' + elem.id);
+              }
+
+              className = elem.className;
+              if (className && isString(className)) {
+                classes = className.split(/\s+/);
+                for (i = 0; i < classes.length; i++) {
+                  out.push('.' + classes[i]);
+                }
+              }
+              var attrWhitelist = ['type', 'name', 'title', 'alt'];
+              for (i = 0; i < attrWhitelist.length; i++) {
+                key = attrWhitelist[i];
+                attr = elem.getAttribute(key);
+                if (attr) {
+                  out.push('[' + key + '="' + attr + '"]');
+                }
+              }
+              return out.join('');
+            }
+
+            /**
  * Returns true if either a OR b is truthy, but not both
  */
-function isOnlyOneTruthy(a, b) {
-    return !!(!!a ^ !!b);
-}
-
-/**
+            function isOnlyOneTruthy(a, b) {
+              return !!(!!a ^ !!b);
+            }
+
+            /**
  * Returns true if the two input exception interfaces have the same content
  */
-function isSameException(ex1, ex2) {
-    if (isOnlyOneTruthy(ex1, ex2))
-        return false;
-
-    ex1 = ex1.values[0];
-    ex2 = ex2.values[0];
-
-    if (ex1.type !== ex2.type ||
-        ex1.value !== ex2.value)
-        return false;
-
-    return isSameStacktrace(ex1.stacktrace, ex2.stacktrace);
-}
-
-/**
+            function isSameException(ex1, ex2) {
+              if (isOnlyOneTruthy(ex1, ex2)) return false;
+
+              ex1 = ex1.values[0];
+              ex2 = ex2.values[0];
+
+              if (ex1.type !== ex2.type || ex1.value !== ex2.value) return false;
+
+              return isSameStacktrace(ex1.stacktrace, ex2.stacktrace);
+            }
+
+            /**
  * Returns true if the two input stack trace interfaces have the same content
  */
-function isSameStacktrace(stack1, stack2) {
-    if (isOnlyOneTruthy(stack1, stack2))
-        return false;
-
-    var frames1 = stack1.frames;
-    var frames2 = stack2.frames;
-
-    // Exit early if frame count differs
-    if (frames1.length !== frames2.length)
-        return false;
-
-    // Iterate through every frame; bail out if anything differs
-    var a, b;
-    for (var i = 0; i < frames1.length; i++) {
-        a = frames1[i];
-        b = frames2[i];
-        if (a.filename !== b.filename ||
-            a.lineno !== b.lineno ||
-            a.colno !== b.colno ||
-            a['function'] !== b['function'])
-            return false;
-    }
-    return true;
-}
-
-/**
+            function isSameStacktrace(stack1, stack2) {
+              if (isOnlyOneTruthy(stack1, stack2)) return false;
+
+              var frames1 = stack1.frames;
+              var frames2 = stack2.frames;
+
+              // Exit early if frame count differs
+              if (frames1.length !== frames2.length) return false;
+
+              // Iterate through every frame; bail out if anything differs
+              var a, b;
+              for (var i = 0; i < frames1.length; i++) {
+                a = frames1[i];
+                b = frames2[i];
+                if (
+                  a.filename !== b.filename ||
+                  a.lineno !== b.lineno ||
+                  a.colno !== b.colno ||
+                  a['function'] !== b['function']
+                )
+                  return false;
+              }
+              return true;
+            }
+
+            /**
  * Polyfill a method
  * @param obj object e.g. `document`
  * @param name method name present on object e.g. `addEventListener`
  * @param replacement replacement function
  * @param track {optional} record instrumentation to an array
  */
-function fill(obj, name, replacement, track) {
-    var orig = obj[name];
-    obj[name] = replacement(orig);
-    if (track) {
-        track.push([obj, name, orig]);
-    }
-}
-
-if (typeof __DEV__ !== 'undefined' && __DEV__) {
-    Raven.utils = {
-        isUndefined: isUndefined,
-        isFunction: isFunction,
-        isString: isString,
-        isObject: isObject,
-        isEmptyObject: isEmptyObject,
-        isError: isError,
-        each: each,
-        objectMerge: objectMerge,
-        truncate: truncate,
-        hasKey: hasKey,
-        joinRegExp: joinRegExp,
-        urlencode: urlencode,
-        uuid4: uuid4,
-        htmlTreeAsString: htmlTreeAsString,
-        htmlElementAsString: htmlElementAsString,
-        parseUrl: parseUrl,
-        fill: fill
-    };
-};
-
-// Deprecations
-Raven.prototype.setUser = Raven.prototype.setUserContext;
-Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
-
-module.exports = Raven;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"1":1,"2":2,"5":5,"6":6,"7":7}],4:[function(_dereq_,module,exports){
-(function (global){
-/**
+            function fill(obj, name, replacement, track) {
+              var orig = obj[name];
+              obj[name] = replacement(orig);
+              if (track) {
+                track.push([obj, name, orig]);
+              }
+            }
+
+            if (typeof __DEV__ !== 'undefined' && __DEV__) {
+              Raven.utils = {
+                isUndefined: isUndefined,
+                isFunction: isFunction,
+                isString: isString,
+                isObject: isObject,
+                isEmptyObject: isEmptyObject,
+                isError: isError,
+                each: each,
+                objectMerge: objectMerge,
+                truncate: truncate,
+                hasKey: hasKey,
+                joinRegExp: joinRegExp,
+                urlencode: urlencode,
+                uuid4: uuid4,
+                htmlTreeAsString: htmlTreeAsString,
+                htmlElementAsString: htmlElementAsString,
+                parseUrl: parseUrl,
+                fill: fill
+              };
+            }
+
+            // Deprecations
+            Raven.prototype.setUser = Raven.prototype.setUserContext;
+            Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
+
+            module.exports = Raven;
+          }.call(
+            this,
+            typeof global !== 'undefined'
+              ? global
+              : typeof self !== 'undefined'
+                ? self
+                : typeof window !== 'undefined' ? window : {}
+          ));
+        },
+        {'1': 1, '2': 2, '5': 5, '6': 6, '7': 7}
+      ],
+      4: [
+        function(_dereq_, module, exports) {
+          (function(global) {
+            /**
  * Enforces a single instance of the Raven client, and the
  * main entry point for Raven. If you are a consumer of the
  * Raven library, you SHOULD load this file (vs raven.js).
  **/
 
-'use strict';
-
-var RavenConstructor = _dereq_(3);
-
-// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
-var _window = typeof window !== 'undefined' ? window
-            : typeof global !== 'undefined' ? global
-            : typeof self !== 'undefined' ? self
-            : {};
-var _Raven = _window.Raven;
-
-var Raven = new RavenConstructor();
-
-/*
+            var RavenConstructor = _dereq_(3);
+
+            // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
+            var _window =
+              typeof window !== 'undefined'
+                ? window
+                : typeof global !== 'undefined'
+                  ? global
+                  : typeof self !== 'undefined' ? self : {};
+            var _Raven = _window.Raven;
+
+            var Raven = new RavenConstructor();
+
+            /*
  * Allow multiple versions of Raven to be installed.
  * Strip Raven from the global context and returns the instance.
  *
  * @return {Raven}
  */
-Raven.noConflict = function () {
-	_window.Raven = _Raven;
-	return Raven;
-};
-
-Raven.afterLoad();
-
-module.exports = Raven;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"3":3}],5:[function(_dereq_,module,exports){
-'use strict';
-
-function isObject(what) {
-    return typeof what === 'object' && what !== null;
-}
-
-// Yanked from https://git.io/vS8DV re-used under CC0
-// with some tiny modifications
-function isError(value) {
-  switch ({}.toString.call(value)) {
-    case '[object Error]': return true;
-    case '[object Exception]': return true;
-    case '[object DOMException]': return true;
-    default: return value instanceof Error;
-  }
-}
-
-function wrappedCallback(callback) {
-    function dataCallback(data, original) {
-      var normalizedData = callback(data) || data;
-      if (original) {
-          return original(normalizedData) || normalizedData;
-      }
-      return normalizedData;
-    }
-
-    return dataCallback;
-}
-
-module.exports = {
-    isObject: isObject,
-    isError: isError,
-    wrappedCallback: wrappedCallback
-};
-
-},{}],6:[function(_dereq_,module,exports){
-(function (global){
-'use strict';
-
-var utils = _dereq_(5);
-
-/*
+            Raven.noConflict = function() {
+              _window.Raven = _Raven;
+              return Raven;
+            };
+
+            Raven.afterLoad();
+
+            module.exports = Raven;
+          }.call(
+            this,
+            typeof global !== 'undefined'
+              ? global
+              : typeof self !== 'undefined'
+                ? self
+                : typeof window !== 'undefined' ? window : {}
+          ));
+        },
+        {'3': 3}
+      ],
+      5: [
+        function(_dereq_, module, exports) {
+          function isObject(what) {
+            return typeof what === 'object' && what !== null;
+          }
+
+          // Yanked from https://git.io/vS8DV re-used under CC0
+          // with some tiny modifications
+          function isError(value) {
+            switch ({}.toString.call(value)) {
+              case '[object Error]':
+                return true;
+              case '[object Exception]':
+                return true;
+              case '[object DOMException]':
+                return true;
+              default:
+                return value instanceof Error;
+            }
+          }
+
+          function wrappedCallback(callback) {
+            function dataCallback(data, original) {
+              var normalizedData = callback(data) || data;
+              if (original) {
+                return original(normalizedData) || normalizedData;
+              }
+              return normalizedData;
+            }
+
+            return dataCallback;
+          }
+
+          module.exports = {
+            isObject: isObject,
+            isError: isError,
+            wrappedCallback: wrappedCallback
+          };
+        },
+        {}
+      ],
+      6: [
+        function(_dereq_, module, exports) {
+          (function(global) {
+            var utils = _dereq_(5);
+
+            /*
  TraceKit - Cross brower stack traces
 
  This was originally forked from github.com/occ/TraceKit, but has since been
  largely re-written and is now maintained as part of raven-js.  Tests for
  this are in test/vendor.
 
  MIT license
 */
 
-var TraceKit = {
-    collectWindowErrors: true,
-    debug: false
-};
-
-// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
-var _window = typeof window !== 'undefined' ? window
-            : typeof global !== 'undefined' ? global
-            : typeof self !== 'undefined' ? self
-            : {};
-
-// global reference to slice
-var _slice = [].slice;
-var UNKNOWN_FUNCTION = '?';
-
-// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types
-var ERROR_TYPES_RE = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/;
-
-function getLocationHref() {
-    if (typeof document === 'undefined' || typeof document.location === 'undefined')
-        return '';
-
-    return document.location.href;
-}
-
-
-/**
+            var TraceKit = {
+              collectWindowErrors: true,
+              debug: false
+            };
+
+            // This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
+            var _window =
+              typeof window !== 'undefined'
+                ? window
+                : typeof global !== 'undefined'
+                  ? global
+                  : typeof self !== 'undefined' ? self : {};
+
+            // global reference to slice
+            var _slice = [].slice;
+            var UNKNOWN_FUNCTION = '?';
+
+            // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types
+            var ERROR_TYPES_RE = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/;
+
+            function getLocationHref() {
+              if (typeof document === 'undefined' || document.location == null) return '';
+
+              return document.location.href;
+            }
+
+            /**
  * TraceKit.report: cross-browser processing of unhandled exceptions
  *
  * Syntax:
  *   TraceKit.report.subscribe(function(stackInfo) { ... })
  *   TraceKit.report.unsubscribe(function(stackInfo) { ... })
  *   TraceKit.report(exception)
  *   try { ...code... } catch(ex) { TraceKit.report(ex); }
  *
@@ -2279,211 +2610,217 @@ function getLocationHref() {
  * subscribed handlers. Please note that TraceKit.report will rethrow the
  * exception. This is REQUIRED in order to get a useful stack trace in IE.
  * If the exception does not reach the top of the browser, you will only
  * get a stack trace from the point where TraceKit.report was called.
  *
  * Handlers receive a stackInfo object as described in the
  * TraceKit.computeStackTrace docs.
  */
-TraceKit.report = (function reportModuleWrapper() {
-    var handlers = [],
-        lastArgs = null,
-        lastException = null,
-        lastExceptionStack = null;
-
-    /**
+            TraceKit.report = (function reportModuleWrapper() {
+              var handlers = [],
+                lastArgs = null,
+                lastException = null,
+                lastExceptionStack = null;
+
+              /**
      * Add a crash handler.
      * @param {Function} handler
      */
-    function subscribe(handler) {
-        installGlobalHandler();
-        handlers.push(handler);
-    }
-
-    /**
+              function subscribe(handler) {
+                installGlobalHandler();
+                handlers.push(handler);
+              }
+
+              /**
      * Remove a crash handler.
      * @param {Function} handler
      */
-    function unsubscribe(handler) {
-        for (var i = handlers.length - 1; i >= 0; --i) {
-            if (handlers[i] === handler) {
-                handlers.splice(i, 1);
-            }
-        }
-    }
-
-    /**
+              function unsubscribe(handler) {
+                for (var i = handlers.length - 1; i >= 0; --i) {
+                  if (handlers[i] === handler) {
+                    handlers.splice(i, 1);
+                  }
+                }
+              }
+
+              /**
      * Remove all crash handlers.
      */
-    function unsubscribeAll() {
-        uninstallGlobalHandler();
-        handlers = [];
-    }
-
-    /**
+              function unsubscribeAll() {
+                uninstallGlobalHandler();
+                handlers = [];
+              }
+
+              /**
      * Dispatch stack information to all handlers.
      * @param {Object.<string, *>} stack
      */
-    function notifyHandlers(stack, isWindowError) {
-        var exception = null;
-        if (isWindowError && !TraceKit.collectWindowErrors) {
-          return;
-        }
-        for (var i in handlers) {
-            if (handlers.hasOwnProperty(i)) {
-                try {
-                    handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2)));
-                } catch (inner) {
-                    exception = inner;
+              function notifyHandlers(stack, isWindowError) {
+                var exception = null;
+                if (isWindowError && !TraceKit.collectWindowErrors) {
+                  return;
                 }
-            }
-        }
-
-        if (exception) {
-            throw exception;
-        }
-    }
-
-    var _oldOnerrorHandler, _onErrorHandlerInstalled;
-
-    /**
+                for (var i in handlers) {
+                  if (handlers.hasOwnProperty(i)) {
+                    try {
+                      handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2)));
+                    } catch (inner) {
+                      exception = inner;
+                    }
+                  }
+                }
+
+                if (exception) {
+                  throw exception;
+                }
+              }
+
+              var _oldOnerrorHandler, _onErrorHandlerInstalled;
+
+              /**
      * Ensures all global unhandled exceptions are recorded.
      * Supported by Gecko and IE.
      * @param {string} message Error message.
      * @param {string} url URL of script that generated the exception.
      * @param {(number|string)} lineNo The line number at which the error
      * occurred.
      * @param {?(number|string)} colNo The column number at which the error
      * occurred.
      * @param {?Error} ex The actual Error object.
      */
-    function traceKitWindowOnError(message, url, lineNo, colNo, ex) {
-        var stack = null;
-
-        if (lastExceptionStack) {
-            TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(lastExceptionStack, url, lineNo, message);
-            processLastException();
-        } else if (ex && utils.isError(ex)) {
-            // non-string `ex` arg; attempt to extract stack trace
-
-            // New chrome and blink send along a real error object
-            // Let's just report that like a normal error.
-            // See: https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
-            stack = TraceKit.computeStackTrace(ex);
-            notifyHandlers(stack, true);
-        } else {
-            var location = {
-                'url': url,
-                'line': lineNo,
-                'column': colNo
-            };
-
-            var name = undefined;
-            var msg = message; // must be new var or will modify original `arguments`
-            var groups;
-            if ({}.toString.call(message) === '[object String]') {
-                var groups = message.match(ERROR_TYPES_RE);
-                if (groups) {
-                    name = groups[1];
-                    msg = groups[2];
+              function traceKitWindowOnError(message, url, lineNo, colNo, ex) {
+                var stack = null;
+
+                if (lastExceptionStack) {
+                  TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(
+                    lastExceptionStack,
+                    url,
+                    lineNo,
+                    message
+                  );
+                  processLastException();
+                } else if (ex && utils.isError(ex)) {
+                  // non-string `ex` arg; attempt to extract stack trace
+
+                  // New chrome and blink send along a real error object
+                  // Let's just report that like a normal error.
+                  // See: https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
+                  stack = TraceKit.computeStackTrace(ex);
+                  notifyHandlers(stack, true);
+                } else {
+                  var location = {
+                    url: url,
+                    line: lineNo,
+                    column: colNo
+                  };
+
+                  var name = undefined;
+                  var msg = message; // must be new var or will modify original `arguments`
+                  var groups;
+                  if ({}.toString.call(message) === '[object String]') {
+                    var groups = message.match(ERROR_TYPES_RE);
+                    if (groups) {
+                      name = groups[1];
+                      msg = groups[2];
+                    }
+                  }
+
+                  location.func = UNKNOWN_FUNCTION;
+
+                  stack = {
+                    name: name,
+                    message: msg,
+                    url: getLocationHref(),
+                    stack: [location]
+                  };
+                  notifyHandlers(stack, true);
                 }
-            }
-
-            location.func = UNKNOWN_FUNCTION;
-
-            stack = {
-                'name': name,
-                'message': msg,
-                'url': getLocationHref(),
-                'stack': [location]
-            };
-            notifyHandlers(stack, true);
-        }
-
-        if (_oldOnerrorHandler) {
-            return _oldOnerrorHandler.apply(this, arguments);
-        }
-
-        return false;
-    }
-
-    function installGlobalHandler ()
-    {
-        if (_onErrorHandlerInstalled) {
-            return;
-        }
-        _oldOnerrorHandler = _window.onerror;
-        _window.onerror = traceKitWindowOnError;
-        _onErrorHandlerInstalled = true;
-    }
-
-    function uninstallGlobalHandler ()
-    {
-        if (!_onErrorHandlerInstalled) {
-            return;
-        }
-        _window.onerror = _oldOnerrorHandler;
-        _onErrorHandlerInstalled = false;
-        _oldOnerrorHandler = undefined;
-    }
-
-    function processLastException() {
-        var _lastExceptionStack = lastExceptionStack,
-            _lastArgs = lastArgs;
-        lastArgs = null;
-        lastExceptionStack = null;
-        lastException = null;
-        notifyHandlers.apply(null, [_lastExceptionStack, false].concat(_lastArgs));
-    }
-
-    /**
+
+                if (_oldOnerrorHandler) {
+                  return _oldOnerrorHandler.apply(this, arguments);
+                }
+
+                return false;
+              }
+
+              function installGlobalHandler() {
+                if (_onErrorHandlerInstalled) {
+                  return;
+                }
+                _oldOnerrorHandler = _window.onerror;
+                _window.onerror = traceKitWindowOnError;
+                _onErrorHandlerInstalled = true;
+              }
+
+              function uninstallGlobalHandler() {
+                if (!_onErrorHandlerInstalled) {
+                  return;
+                }
+                _window.onerror = _oldOnerrorHandler;
+                _onErrorHandlerInstalled = false;
+                _oldOnerrorHandler = undefined;
+              }
+
+              function processLastException() {
+                var _lastExceptionStack = lastExceptionStack,
+                  _lastArgs = lastArgs;
+                lastArgs = null;
+                lastExceptionStack = null;
+                lastException = null;
+                notifyHandlers.apply(
+                  null,
+                  [_lastExceptionStack, false].concat(_lastArgs)
+                );
+              }
+
+              /**
      * Reports an unhandled Error to TraceKit.
      * @param {Error} ex
      * @param {?boolean} rethrow If false, do not re-throw the exception.
      * Only used for window.onerror to not cause an infinite loop of
      * rethrowing.
      */
-    function report(ex, rethrow) {
-        var args = _slice.call(arguments, 1);
-        if (lastExceptionStack) {
-            if (lastException === ex) {
-                return; // already caught by an inner catch block, ignore
-            } else {
-              processLastException();
-            }
-        }
-
-        var stack = TraceKit.computeStackTrace(ex);
-        lastExceptionStack = stack;
-        lastException = ex;
-        lastArgs = args;
-
-        // If the stack trace is incomplete, wait for 2 seconds for
-        // slow slow IE to see if onerror occurs or not before reporting
-        // this exception; otherwise, we will end up with an incomplete
-        // stack trace
-        setTimeout(function () {
-            if (lastException === ex) {
-                processLastException();
-            }
-        }, (stack.incomplete ? 2000 : 0));
-
-        if (rethrow !== false) {
-            throw ex; // re-throw to propagate to the top level (and cause window.onerror)
-        }
-    }
-
-    report.subscribe = subscribe;
-    report.unsubscribe = unsubscribe;
-    report.uninstall = unsubscribeAll;
-    return report;
-}());
-
-/**
+              function report(ex, rethrow) {
+                var args = _slice.call(arguments, 1);
+                if (lastExceptionStack) {
+                  if (lastException === ex) {
+                    return; // already caught by an inner catch block, ignore
+                  } else {
+                    processLastException();
+                  }
+                }
+
+                var stack = TraceKit.computeStackTrace(ex);
+                lastExceptionStack = stack;
+                lastException = ex;
+                lastArgs = args;
+
+                // If the stack trace is incomplete, wait for 2 seconds for
+                // slow slow IE to see if onerror occurs or not before reporting
+                // this exception; otherwise, we will end up with an incomplete
+                // stack trace
+                setTimeout(function() {
+                  if (lastException === ex) {
+                    processLastException();
+                  }
+                }, stack.incomplete ? 2000 : 0);
+
+                if (rethrow !== false) {
+                  throw ex; // re-throw to propagate to the top level (and cause window.onerror)
+                }
+              }
+
+              report.subscribe = subscribe;
+              report.unsubscribe = unsubscribe;
+              report.uninstall = unsubscribeAll;
+              return report;
+            })();
+
+            /**
  * TraceKit.computeStackTrace: cross-browser stack traces in JavaScript
  *
  * Syntax:
  *   s = TraceKit.computeStackTrace(exception) // consider using TraceKit.report instead (see below)
  * Returns:
  *   s.name              - exception name
  *   s.message           - exception message
  *   s.stack[i].url      - JavaScript or HTML file URL
@@ -2524,351 +2861,414 @@ TraceKit.report = (function reportModule
  *
  * This is okay for tracing (because you are likely to be calling
  * computeStackTrace from the function you want to be the topmost element
  * of the stack trace anyway), but not okay for logging unhandled
  * exceptions (because your catch block will likely be far away from the
  * inner function that actually caused the exception).
  *
  */
-TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
-    // Contents of Exception in various browsers.
-    //
-    // SAFARI:
-    // ex.message = Can't find variable: qq
-    // ex.line = 59
-    // ex.sourceId = 580238192
-    // ex.sourceURL = http://...
-    // ex.expressionBeginOffset = 96
-    // ex.expressionCaretOffset = 98
-    // ex.expressionEndOffset = 98
-    // ex.name = ReferenceError
-    //
-    // FIREFOX:
-    // ex.message = qq is not defined
-    // ex.fileName = http://...
-    // ex.lineNumber = 59
-    // ex.columnNumber = 69
-    // ex.stack = ...stack trace... (see the example below)
-    // ex.name = ReferenceError
-    //
-    // CHROME:
-    // ex.message = qq is not defined
-    // ex.name = ReferenceError
-    // ex.type = not_defined
-    // ex.arguments = ['aa']
-    // ex.stack = ...stack trace...
-    //
-    // INTERNET EXPLORER:
-    // ex.message = ...
-    // ex.name = ReferenceError
-    //
-    // OPERA:
-    // ex.message = ...message... (see the example below)
-    // ex.name = ReferenceError
-    // ex.opera#sourceloc = 11  (pretty much useless, duplicates the info in ex.message)
-    // ex.stacktrace = n/a; see 'opera:config#UserPrefs|Exceptions Have Stacktrace'
-
-    /**
+            TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
+              // Contents of Exception in various browsers.
+              //
+              // SAFARI:
+              // ex.message = Can't find variable: qq
+              // ex.line = 59
+              // ex.sourceId = 580238192
+              // ex.sourceURL = http://...
+              // ex.expressionBeginOffset = 96
+              // ex.expressionCaretOffset = 98
+              // ex.expressionEndOffset = 98
+              // ex.name = ReferenceError
+              //
+              // FIREFOX:
+              // ex.message = qq is not defined
+              // ex.fileName = http://...
+              // ex.lineNumber = 59
+              // ex.columnNumber = 69
+              // ex.stack = ...stack trace... (see the example below)
+              // ex.name = ReferenceError
+              //
+              // CHROME:
+              // ex.message = qq is not defined
+              // ex.name = ReferenceError
+              // ex.type = not_defined
+              // ex.arguments = ['aa']
+              // ex.stack = ...stack trace...
+              //
+              // INTERNET EXPLORER:
+              // ex.message = ...
+              // ex.name = ReferenceError
+              //
+              // OPERA:
+              // ex.message = ...message... (see the example below)
+              // ex.name = ReferenceError
+              // ex.opera#sourceloc = 11  (pretty much useless, duplicates the info in ex.message)
+              // ex.stacktrace = n/a; see 'opera:config#UserPrefs|Exceptions Have Stacktrace'
+
+              /**
      * Computes stack trace information from the stack property.
      * Chrome and Gecko use this property.
      * @param {Error} ex
      * @return {?Object.<string, *>} Stack trace information.
      */
-    function computeStackTraceFromStackProp(ex) {
-        if (typeof ex.stack === 'undefined' || !ex.stack) return;
-
-        var chrome = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,
-            gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i,
-            winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
-
-            // Used to additionally parse URL/line/column from eval frames
-            geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i,
-            chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/,
-
-            lines = ex.stack.split('\n'),
-            stack = [],
-            submatch,
-            parts,
-            element,
-            reference = /^(.*) is undefined$/.exec(ex.message);
-
-        for (var i = 0, j = lines.length; i < j; ++i) {
-            if ((parts = chrome.exec(lines[i]))) {
-                var isNative = parts[2] && parts[2].indexOf('native') === 0; // start of line
-                var isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
-                if (isEval && (submatch = chromeEval.exec(parts[2]))) {
-                    // throw out eval line/column and use top-most line/column number
-                    parts[2] = submatch[1]; // url
-                    parts[3] = submatch[2]; // line
-                    parts[4] = submatch[3]; // column
+              function computeStackTraceFromStackProp(ex) {
+                if (typeof ex.stack === 'undefined' || !ex.stack) return;
+
+                var chrome = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,
+                  gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i,
+                  winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
+                  // Used to additionally parse URL/line/column from eval frames
+                  geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i,
+                  chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/,
+                  lines = ex.stack.split('\n'),
+                  stack = [],
+                  submatch,
+                  parts,
+                  element,
+                  reference = /^(.*) is undefined$/.exec(ex.message);
+
+                for (var i = 0, j = lines.length; i < j; ++i) {
+                  if ((parts = chrome.exec(lines[i]))) {
+                    var isNative = parts[2] && parts[2].indexOf('native') === 0; // start of line
+                    var isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
+                    if (isEval && (submatch = chromeEval.exec(parts[2]))) {
+                      // throw out eval line/column and use top-most line/column number
+                      parts[2] = submatch[1]; // url
+                      parts[3] = submatch[2]; // line
+                      parts[4] = submatch[3]; // column
+                    }
+                    element = {
+                      url: !isNative ? parts[2] : null,
+                      func: parts[1] || UNKNOWN_FUNCTION,
+                      args: isNative ? [parts[2]] : [],
+                      line: parts[3] ? +parts[3] : null,
+                      column: parts[4] ? +parts[4] : null
+                    };
+                  } else if ((parts = winjs.exec(lines[i]))) {
+                    element = {
+                      url: parts[2],
+                      func: parts[1] || UNKNOWN_FUNCTION,
+                      args: [],
+                      line: +parts[3],
+                      column: parts[4] ? +parts[4] : null
+                    };
+                  } else if ((parts = gecko.exec(lines[i]))) {
+                    var isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
+                    if (isEval && (submatch = geckoEval.exec(parts[3]))) {
+                      // throw out eval line/column and use top-most line number
+                      parts[3] = submatch[1];
+                      parts[4] = submatch[2];
+                      parts[5] = null; // no column when eval
+                    } else if (
+                      i === 0 &&
+                      !parts[5] &&
+                      typeof ex.columnNumber !== 'undefined'
+                    ) {
+                      // FireFox uses this awesome columnNumber property for its top frame
+                      // Also note, Firefox's column number is 0-based and everything else expects 1-based,
+                      // so adding 1
+                      // NOTE: this hack doesn't work if top-most frame is eval
+                      stack[0].column = ex.columnNumber + 1;
+                    }
+                    element = {
+                      url: parts[3],
+                      func: parts[1] || UNKNOWN_FUNCTION,
+                      args: parts[2] ? parts[2].split(',') : [],
+                      line: parts[4] ? +parts[4] : null,
+                      column: parts[5] ? +parts[5] : null
+                    };
+                  } else {
+                    continue;
+                  }
+
+                  if (!element.func && element.line) {
+                    element.func = UNKNOWN_FUNCTION;
+                  }
+
+                  stack.push(element);
                 }
-                element = {
-                    'url': !isNative ? parts[2] : null,
-                    'func': parts[1] || UNKNOWN_FUNCTION,
-                    'args': isNative ? [parts[2]] : [],
-                    'line': parts[3] ? +parts[3] : null,
-                    'column': parts[4] ? +parts[4] : null
-                };
-            } else if ( parts = winjs.exec(lines[i]) ) {
-                element = {
-                    'url': parts[2],
-                    'func': parts[1] || UNKNOWN_FUNCTION,
-                    'args': [],
-                    'line': +parts[3],
-                    'column': parts[4] ? +parts[4] : null
+
+                if (!stack.length) {
+                  return null;
+                }
+
+                return {
+                  name: ex.name,
+                  message: ex.message,
+                  url: getLocationHref(),
+                  stack: stack
                 };
-            } else if ((parts = gecko.exec(lines[i]))) {
-                var isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
-                if (isEval && (submatch = geckoEval.exec(parts[3]))) {
-                    // throw out eval line/column and use top-most line number
-                    parts[3] = submatch[1];
-                    parts[4] = submatch[2];
-                    parts[5] = null; // no column when eval
-                } else if (i === 0 && !parts[5] && typeof ex.columnNumber !== 'undefined') {
-                    // FireFox uses this awesome columnNumber property for its top frame
-                    // Also note, Firefox's column number is 0-based and everything else expects 1-based,
-                    // so adding 1
-                    // NOTE: this hack doesn't work if top-most frame is eval
-                    stack[0].column = ex.columnNumber + 1;
-                }
-                element = {
-                    'url': parts[3],
-                    'func': parts[1] || UNKNOWN_FUNCTION,
-                    'args': parts[2] ? parts[2].split(',') : [],
-                    'line': parts[4] ? +parts[4] : null,
-                    'column': parts[5] ? +parts[5] : null
-                };
-            } else {
-                continue;
-            }
-
-            if (!element.func && element.line) {
-                element.func = UNKNOWN_FUNCTION;
-            }
-
-            stack.push(element);
-        }
-
-        if (!stack.length) {
-            return null;
-        }
-
-        return {
-            'name': ex.name,
-            'message': ex.message,
-            'url': getLocationHref(),
-            'stack': stack
-        };
-    }
-
-    /**
+              }
+
+              /**
      * Adds information about the first frame to incomplete stack traces.
      * Safari and IE require this to get complete data on the first frame.
      * @param {Object.<string, *>} stackInfo Stack trace information from
      * one of the compute* methods.
      * @param {string} url The URL of the script that caused an error.
      * @param {(number|string)} lineNo The line number of the script that
      * caused an error.
      * @param {string=} message The error generated by the browser, which
      * hopefully contains the name of the object that caused the error.
      * @return {boolean} Whether or not the stack information was
      * augmented.
      */
-    function augmentStackTraceWithInitialElement(stackInfo, url, lineNo, message) {
-        var initial = {
-            'url': url,
-            'line': lineNo
-        };
-
-        if (initial.url && initial.line) {
-            stackInfo.incomplete = false;
-
-            if (!initial.func) {
-                initial.func = UNKNOWN_FUNCTION;
-            }
-
-            if (stackInfo.stack.length > 0) {
-                if (stackInfo.stack[0].url === initial.url) {
-                    if (stackInfo.stack[0].line === initial.line) {
+              function augmentStackTraceWithInitialElement(
+                stackInfo,
+                url,
+                lineNo,
+                message
+              ) {
+                var initial = {
+                  url: url,
+                  line: lineNo
+                };
+
+                if (initial.url && initial.line) {
+                  stackInfo.incomplete = false;
+
+                  if (!initial.func) {
+                    initial.func = UNKNOWN_FUNCTION;
+                  }
+
+                  if (stackInfo.stack.length > 0) {
+                    if (stackInfo.stack[0].url === initial.url) {
+                      if (stackInfo.stack[0].line === initial.line) {
                         return false; // already in stack trace
-                    } else if (!stackInfo.stack[0].line && stackInfo.stack[0].func === initial.func) {
+                      } else if (
+                        !stackInfo.stack[0].line &&
+                        stackInfo.stack[0].func === initial.func
+                      ) {
                         stackInfo.stack[0].line = initial.line;
                         return false;
+                      }
                     }
+                  }
+
+                  stackInfo.stack.unshift(initial);
+                  stackInfo.partial = true;
+                  return true;
+                } else {
+                  stackInfo.incomplete = true;
                 }
-            }
-
-            stackInfo.stack.unshift(initial);
-            stackInfo.partial = true;
-            return true;
-        } else {
-            stackInfo.incomplete = true;
-        }
-
-        return false;
-    }
-
-    /**
+
+                return false;
+              }
+
+              /**
      * Computes stack trace information by walking the arguments.caller
      * chain at the time the exception occurred. This will cause earlier
      * frames to be missed but is the only way to get any stack trace in
      * Safari and IE. The top frame is restored by
      * {@link augmentStackTraceWithInitialElement}.
      * @param {Error} ex
      * @return {?Object.<string, *>} Stack trace information.
      */
-    function computeStackTraceByWalkingCallerChain(ex, depth) {
-        var functionName = /function\s+([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)?\s*\(/i,
-            stack = [],
-            funcs = {},
-            recursion = false,
-            parts,
-            item,
-            source;
-
-        for (var curr = computeStackTraceByWalkingCallerChain.caller; curr && !recursion; curr = curr.caller) {
-            if (curr === computeStackTrace || curr === TraceKit.report) {
-                // console.log('skipping internal function');
-                continue;
-            }
-
-            item = {
-                'url': null,
-                'func': UNKNOWN_FUNCTION,
-                'line': null,
-                'column': null
-            };
-
-            if (curr.name) {
-                item.func = curr.name;
-            } else if ((parts = functionName.exec(curr.toString()))) {
-                item.func = parts[1];
-            }
-
-            if (typeof item.func === 'undefined') {
-              try {
-                item.func = parts.input.substring(0, parts.input.indexOf('{'));
-              } catch (e) { }
-            }
-
-            if (funcs['' + curr]) {
-                recursion = true;
-            }else{
-                funcs['' + curr] = true;
-            }
-
-            stack.push(item);
-        }
-
-        if (depth) {
-            // console.log('depth is ' + depth);
-            // console.log('stack is ' + stack.length);
-            stack.splice(0, depth);
-        }
-
-        var result = {
-            'name': ex.name,
-            'message': ex.message,
-            'url': getLocationHref(),
-            'stack': stack
-        };
-        augmentStackTraceWithInitialElement(result, ex.sourceURL || ex.fileName, ex.line || ex.lineNumber, ex.message || ex.description);
-        return result;
-    }
-
-    /**
+              function computeStackTraceByWalkingCallerChain(ex, depth) {
+                var functionName = /function\s+([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)?\s*\(/i,
+                  stack = [],
+                  funcs = {},
+                  recursion = false,
+                  parts,
+                  item,
+                  source;
+
+                for (
+                  var curr = computeStackTraceByWalkingCallerChain.caller;
+                  curr && !recursion;
+                  curr = curr.caller
+                ) {
+                  if (curr === computeStackTrace || curr === TraceKit.report) {
+                    // console.log('skipping internal function');
+                    continue;
+                  }
+
+                  item = {
+                    url: null,
+                    func: UNKNOWN_FUNCTION,
+                    line: null,
+                    column: null
+                  };
+
+                  if (curr.name) {
+                    item.func = curr.name;
+                  } else if ((parts = functionName.exec(curr.toString()))) {
+                    item.func = parts[1];
+                  }
+
+                  if (typeof item.func === 'undefined') {
+                    try {
+                      item.func = parts.input.substring(0, parts.input.indexOf('{'));
+                    } catch (e) {}
+                  }
+
+                  if (funcs['' + curr]) {
+                    recursion = true;
+                  } else {
+                    funcs['' + curr] = true;
+                  }
+
+                  stack.push(item);
+                }
+
+                if (depth) {
+                  // console.log('depth is ' + depth);
+                  // console.log('stack is ' + stack.length);
+                  stack.splice(0, depth);
+                }
+
+                var result = {
+                  name: ex.name,
+                  message: ex.message,
+                  url: getLocationHref(),
+                  stack: stack
+                };
+                augmentStackTraceWithInitialElement(
+                  result,
+                  ex.sourceURL || ex.fileName,
+                  ex.line || ex.lineNumber,
+                  ex.message || ex.description
+                );
+                return result;
+              }
+
+              /**
      * Computes a stack trace for an exception.
      * @param {Error} ex
      * @param {(string|number)=} depth
      */
-    function computeStackTrace(ex, depth) {
-        var stack = null;
-        depth = (depth == null ? 0 : +depth);
-
-        try {
-            stack = computeStackTraceFromStackProp(ex);
-            if (stack) {
-                return stack;
-            }
-        } catch (e) {
-            if (TraceKit.debug) {
-                throw e;
-            }
-        }
-
-        try {
-            stack = computeStackTraceByWalkingCallerChain(ex, depth + 1);
-            if (stack) {
-                return stack;
-            }
-        } catch (e) {
-            if (TraceKit.debug) {
-                throw e;
-            }
-        }
-        return {
-            'name': ex.name,
-            'message': ex.message,
-            'url': getLocationHref()
-        };
-    }
-
-    computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;
-    computeStackTrace.computeStackTraceFromStackProp = computeStackTraceFromStackProp;
-
-    return computeStackTrace;
-}());
-
-module.exports = TraceKit;
-
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"5":5}],7:[function(_dereq_,module,exports){
-'use strict';
-
-/*
+              function computeStackTrace(ex, depth) {
+                var stack = null;
+                depth = depth == null ? 0 : +depth;
+
+                try {
+                  stack = computeStackTraceFromStackProp(ex);
+                  if (stack) {
+                    return stack;
+                  }
+                } catch (e) {
+                  if (TraceKit.debug) {
+                    throw e;
+                  }
+                }
+
+                try {
+                  stack = computeStackTraceByWalkingCallerChain(ex, depth + 1);
+                  if (stack) {
+                    return stack;
+                  }
+                } catch (e) {
+                  if (TraceKit.debug) {
+                    throw e;
+                  }
+                }
+                return {
+                  name: ex.name,
+                  message: ex.message,
+                  url: getLocationHref()
+                };
+              }
+
+              computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;
+              computeStackTrace.computeStackTraceFromStackProp = computeStackTraceFromStackProp;
+
+              return computeStackTrace;
+            })();
+
+            module.exports = TraceKit;
+          }.call(
+            this,
+            typeof global !== 'undefined'
+              ? global
+              : typeof self !== 'undefined'
+                ? self
+                : typeof window !== 'undefined' ? window : {}
+          ));
+        },
+        {'5': 5}
+      ],
+      7: [
+        function(_dereq_, module, exports) {
+          /*
  json-stringify-safe
  Like JSON.stringify, but doesn't throw on circular references.
 
  Originally forked from https://github.com/isaacs/json-stringify-safe
- version 5.0.1 on 3/8/2017 and modified for IE8 compatibility.
- Tests for this are in test/vendor.
+ version 5.0.1 on 3/8/2017 and modified to handle Errors serialization
+ and IE8 compatibility. Tests for this are in test/vendor.
 
  ISC license: https://github.com/isaacs/json-stringify-safe/blob/master/LICENSE
 */
 
-exports = module.exports = stringify
-exports.getSerialize = serializer
-
-function indexOf(haystack, needle) {
-  for (var i = 0; i < haystack.length; ++i) {
-    if (haystack[i] === needle) return i;
-  }
-  return -1;
-}
-
-function stringify(obj, replacer, spaces, cycleReplacer) {
-  return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces)
-}
-
-function serializer(replacer, cycleReplacer) {
-  var stack = [], keys = []
-
-  if (cycleReplacer == null) cycleReplacer = function(key, value) {
-    if (stack[0] === value) return '[Circular ~]'
-    return '[Circular ~.' + keys.slice(0, indexOf(stack, value)).join('.') + ']'
-  }
-
-  return function(key, value) {
-    if (stack.length > 0) {
-      var thisPos = indexOf(stack, this);
-      ~thisPos ? stack.splice(thisPos + 1) : stack.push(this)
-      ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key)
-      if (~indexOf(stack, value)) value = cycleReplacer.call(this, key, value)
-    }
-    else stack.push(value)
-
-    return replacer == null ? value : replacer.call(this, key, value)
-  }
-}
-
-},{}]},{},[4])(4)
-});
\ No newline at end of file
+          exports = module.exports = stringify;
+          exports.getSerialize = serializer;
+
+          function indexOf(haystack, needle) {
+            for (var i = 0; i < haystack.length; ++i) {
+              if (haystack[i] === needle) return i;
+            }
+            return -1;
+          }
+
+          function stringify(obj, replacer, spaces, cycleReplacer) {
+            return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces);
+          }
+
+          // https://github.com/ftlabs/js-abbreviate/blob/fa709e5f139e7770a71827b1893f22418097fbda/index.js#L95-L106
+          function stringifyError(value) {
+            var err = {
+              // These properties are implemented as magical getters and don't show up in for in
+              stack: value.stack,
+              message: value.message,
+              name: value.name
+            };
+
+            for (var i in value) {
+              if (Object.prototype.hasOwnProperty.call(value, i)) {
+                err[i] = value[i];
+              }
+            }
+
+            return err;
+          }
+
+          function serializer(replacer, cycleReplacer) {
+            var stack = [];
+            var keys = [];
+
+            if (cycleReplacer == null) {
+              cycleReplacer = function(key, value) {
+                if (stack[0] === value) {
+                  return '[Circular ~]';
+                }
+                return (
+                  '[Circular ~.' + keys.slice(0, indexOf(stack, value)).join('.') + ']'
+                );
+              };
+            }
+
+            return function(key, value) {
+              if (stack.length > 0) {
+                var thisPos = indexOf(stack, this);
+                ~thisPos ? stack.splice(thisPos + 1) : stack.push(this);
+                ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key);
+
+                if (~indexOf(stack, value)) {
+                  value = cycleReplacer.call(this, key, value);
+                }
+              } else {
+                stack.push(value);
+              }
+
+              return replacer == null
+                ? value instanceof Error ? stringifyError(value) : value
+                : replacer.call(this, key, value);
+            };
+          }
+        },
+        {}
+      ]
+    },
+    {},
+    [4]
+  )(4);
+});