Browse Source

Update Raven.js

Thibaut Courouble 9 years ago
parent
commit
5db1ca7cd5
1 changed files with 218 additions and 166 deletions
  1. 218 166
      assets/javascripts/vendor/raven.js

+ 218 - 166
assets/javascripts/vendor/raven.js

@@ -1,4 +1,4 @@
-/*! Raven.js 3.0.4 (0784c3c) | github.com/getsentry/raven-js */
+/*! Raven.js 3.5.1 (bef9fa7) | github.com/getsentry/raven-js */
 
 /*
  * Includes TraceKit
@@ -11,6 +11,35 @@
  */
 
 (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){
+exports = module.exports = stringify
+exports.getSerialize = serializer
+
+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, stack.indexOf(value)).join(".") + "]"
+  }
+
+  return function(key, value) {
+    if (stack.length > 0) {
+      var thisPos = stack.indexOf(this)
+      ~thisPos ? stack.splice(thisPos + 1) : stack.push(this)
+      ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key)
+      if (~stack.indexOf(value)) value = cycleReplacer.call(this, key, value)
+    }
+    else stack.push(value)
+
+    return replacer == null ? value : replacer.call(this, key, value)
+  }
+}
+
+},{}],2:[function(_dereq_,module,exports){
 'use strict';
 
 function RavenConfigError(message) {
@@ -22,7 +51,7 @@ RavenConfigError.prototype.constructor = RavenConfigError;
 
 module.exports = RavenConfigError;
 
-},{}],2:[function(_dereq_,module,exports){
+},{}],3:[function(_dereq_,module,exports){
 'use strict';
 
 var wrapMethod = function(console, level, callback) {
@@ -61,13 +90,14 @@ module.exports = {
     wrapMethod: wrapMethod
 };
 
-},{}],3:[function(_dereq_,module,exports){
+},{}],4:[function(_dereq_,module,exports){
 /*global XDomainRequest:false*/
 'use strict';
 
-var TraceKit = _dereq_(6);
-var RavenConfigError = _dereq_(1);
-var utils = _dereq_(5);
+var TraceKit = _dereq_(7);
+var RavenConfigError = _dereq_(2);
+var utils = _dereq_(6);
+var stringify = _dereq_(1);
 
 var isFunction = utils.isFunction;
 var isUndefined = utils.isUndefined;
@@ -83,8 +113,9 @@ var uuid4 = utils.uuid4;
 var htmlTreeAsString = utils.htmlTreeAsString;
 var parseUrl = utils.parseUrl;
 var isString = utils.isString;
+var fill = utils.fill;
 
-var wrapConsoleMethod = _dereq_(2).wrapMethod;
+var wrapConsoleMethod = _dereq_(3).wrapMethod;
 
 var dsnKeys = 'source protocol user pass host port path'.split(' '),
     dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
@@ -93,6 +124,7 @@ function now() {
     return +new Date();
 }
 
+
 // 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
@@ -115,7 +147,8 @@ function Raven() {
         crossOrigin: 'anonymous',
         collectWindowErrors: true,
         maxMessageLength: 0,
-        stackTraceLimit: 50
+        stackTraceLimit: 50,
+        autoBreadcrumbs: true
     };
     this._ignoreOnError = 0;
     this._isRavenInstalled = false;
@@ -128,7 +161,6 @@ function Raven() {
     this._startTime = now();
     this._wrappedBuiltIns = [];
     this._breadcrumbs = [];
-    this._breadcrumbLimit = 20;
     this._lastCapturedEvent = null;
     this._keypressTimeout;
     this._location = window.location;
@@ -150,7 +182,7 @@ Raven.prototype = {
     // 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.0.4',
+    VERSION: '3.5.1',
 
     debug: false,
 
@@ -200,6 +232,22 @@ Raven.prototype = {
         this._globalOptions.ignoreUrls = this._globalOptions.ignoreUrls.length ? joinRegExp(this._globalOptions.ignoreUrls) : false;
         this._globalOptions.whitelistUrls = this._globalOptions.whitelistUrls.length ? joinRegExp(this._globalOptions.whitelistUrls) : false;
         this._globalOptions.includePaths = joinRegExp(this._globalOptions.includePaths);
+        this._globalOptions.maxBreadcrumbs = Math.max(0, Math.min(this._globalOptions.maxBreadcrumbs || 100, 100)); // default and hard limit is 100
+
+        var autoBreadcrumbDefaults = {
+            xhr: true,
+            console: true,
+            dom: true,
+            location: true
+        };
+
+        var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
+        if ({}.toString.call(autoBreadcrumbs) === '[object Object]') {
+            autoBreadcrumbs = objectMerge(autoBreadcrumbDefaults, autoBreadcrumbs);
+        } else if (autoBreadcrumbs !== false) {
+            autoBreadcrumbs = autoBreadcrumbDefaults;
+        }
+        this._globalOptions.autoBreadcrumbs = autoBreadcrumbs;
 
         this._globalKey = uri.user;
         this._globalSecret = uri.pass && uri.pass.substr(1);
@@ -210,14 +258,6 @@ Raven.prototype = {
         this._globalEndpoint = this._globalServer +
             '/' + path + 'api/' + this._globalProject + '/store/';
 
-        if (this._globalOptions.fetchContext) {
-            TraceKit.remoteFetching = true;
-        }
-
-        if (this._globalOptions.linesOfContext) {
-            TraceKit.linesOfContext = this._globalOptions.linesOfContext;
-        }
-
         TraceKit.collectWindowErrors = !!this._globalOptions.collectWindowErrors;
 
         // return for chaining
@@ -238,7 +278,9 @@ Raven.prototype = {
             TraceKit.report.subscribe(function () {
                 self._handleOnErrorStackInfo.apply(self, arguments);
             });
-            this._wrapBuiltIns();
+            this._instrumentTryCatch();
+            if (self._globalOptions.autoBreadcrumbs)
+                this._instrumentBreadcrumbs();
 
             // Install all of the plugins
             this._drainPlugins();
@@ -429,7 +471,7 @@ Raven.prototype = {
         }, obj);
 
         this._breadcrumbs.push(crumb);
-        if (this._breadcrumbs.length > this._breadcrumbLimit) {
+        if (this._breadcrumbs.length > this._globalOptions.maxBreadcrumbs) {
             this._breadcrumbs.shift();
         }
     },
@@ -500,7 +542,20 @@ Raven.prototype = {
      */
     getContext: function() {
         // lol javascript
-        return JSON.parse(JSON.stringify(this._globalContext));
+        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;
     },
 
     /*
@@ -523,7 +578,10 @@ Raven.prototype = {
      * @return {Raven}
      */
     setDataCallback: function(callback) {
-        this._globalOptions.dataCallback = callback;
+        var original = this._globalOptions.dataCallback;
+        this._globalOptions.dataCallback = isFunction(callback)
+          ? function (data) { return callback(data, original); }
+          : callback;
 
         return this;
     },
@@ -536,7 +594,10 @@ Raven.prototype = {
      * @return {Raven}
      */
     setShouldSendCallback: function(callback) {
-        this._globalOptions.shouldSendCallback = callback;
+        var original = this._globalOptions.shouldSendCallback;
+        this._globalOptions.shouldSendCallback = isFunction(callback)
+            ? function (data) { return callback(data, original); }
+            : callback;
 
         return this;
     },
@@ -794,16 +855,10 @@ Raven.prototype = {
     /**
      * Install any queued plugins
      */
-    _wrapBuiltIns: function() {
+    _instrumentTryCatch: function() {
         var self = this;
 
-        function fill(obj, name, replacement, noUndo) {
-            var orig = obj[name];
-            obj[name] = replacement(orig);
-            if (!noUndo) {
-                self._wrappedBuiltIns.push([obj, name, orig]);
-            }
-        }
+        var wrappedBuiltIns = self._wrappedBuiltIns;
 
         function wrapTimeFn(orig) {
             return function (fn, t) { // preserve arity
@@ -829,6 +884,8 @@ Raven.prototype = {
             };
         }
 
+        var autoBreadcrumbs = this._globalOptions.autoBreadcrumbs;
+
         function wrapEventTarget(global) {
             var proto = window[global] && window[global].prototype;
             if (proto && proto.hasOwnProperty && proto.hasOwnProperty('addEventListener')) {
@@ -842,10 +899,10 @@ Raven.prototype = {
                             // can sometimes get 'Permission denied to access property "handle Event'
                         }
 
-
-                        // TODO: more than just click
+                        // More breadcrumb DOM capture ... done here and not in `_instrumentBreadcrumbs`
+                        // so that we don't have more than one wrapper function
                         var before;
-                        if (global === 'EventTarget' || global === 'Node') {
+                        if (autoBreadcrumbs && autoBreadcrumbs.dom && (global === 'EventTarget' || global === 'Node')) {
                             if (evtName === 'click'){
                                 before = self._breadcrumbEventHandler(evtName);
                             } else if (evtName === 'keypress') {
@@ -854,39 +911,24 @@ Raven.prototype = {
                         }
                         return orig.call(this, evtName, self.wrap(fn, undefined, before), capture, secure);
                     };
-                });
+                }, wrappedBuiltIns);
                 fill(proto, 'removeEventListener', function (orig) {
                     return function (evt, fn, capture, secure) {
                         fn = fn && (fn.__raven_wrapper__ ? fn.__raven_wrapper__  : fn);
                         return orig.call(this, evt, fn, capture, secure);
                     };
-                });
+                }, wrappedBuiltIns);
             }
         }
 
-        function wrapProp(prop, xhr) {
-            if (prop in xhr && isFunction(xhr[prop])) {
-                fill(xhr, prop, function (orig) {
-                    return self.wrap(orig);
-                }, true /* noUndo */); // don't track filled methods on XHR instances
-            }
-        }
-
-        fill(window, 'setTimeout', wrapTimeFn);
-        fill(window, 'setInterval', wrapTimeFn);
+        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));
                 };
-            });
-        }
-
-        // Capture breadcrubms from any click that is unhandled / bubbled up all the way
-        // to the document. Do this before we instrument addEventListener.
-        if (this._hasDocument) {
-            document.addEventListener('click', self._breadcrumbEventHandler('click'));
-            document.addEventListener('keypress', self._keypressEventHandler());
+            }, wrappedBuiltIns);
         }
 
         // event targets borrowed from bugsnag-js:
@@ -896,7 +938,41 @@ Raven.prototype = {
             wrapEventTarget(eventTargets[i]);
         }
 
-        if ('XMLHttpRequest' in window) {
+        var $ = window.jQuery || window.$;
+        if ($ && $.fn && $.fn.ready) {
+            fill($.fn, 'ready', function (orig) {
+                return function (fn) {
+                    return orig.call(this, self.wrap(fn));
+                };
+            }, wrappedBuiltIns);
+        }
+    },
+
+
+    /**
+     * 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
@@ -912,7 +988,7 @@ Raven.prototype = {
 
                     return origOpen.apply(this, arguments);
                 };
-            });
+            }, wrappedBuiltIns);
 
             fill(xhrproto, 'send', function(origSend) {
                 return function (data) { // preserve arity
@@ -941,7 +1017,7 @@ Raven.prototype = {
                     if ('onreadystatechange' in xhr && isFunction(xhr.onreadystatechange)) {
                         fill(xhr, 'onreadystatechange', function (orig) {
                             return self.wrap(orig, undefined, onreadystatechangeHandler);
-                        }, true /* noUndo */);
+                        } /* 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
@@ -950,11 +1026,31 @@ Raven.prototype = {
 
                     return origSend.apply(this, arguments);
                 };
-            });
+            }, 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
-        if ('history' in window && history.pushState) {
+        // 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 () {
@@ -969,7 +1065,7 @@ Raven.prototype = {
             fill(history, 'pushState', function (origPushState) {
                 // note history.pushState.length is 0; intentionally not declaring
                 // params to preserve 0 arity
-                return function(/* state, title, url */) {
+                return function (/* state, title, url */) {
                     var url = arguments.length > 2 ? arguments[2] : undefined;
 
                     // url argument is optional
@@ -980,32 +1076,24 @@ Raven.prototype = {
 
                     return origPushState.apply(this, arguments);
                 };
-            });
+            }, wrappedBuiltIns);
         }
 
-        // console
-        var consoleMethodCallback = function (msg, data) {
-            self.captureBreadcrumb({
-                message: msg,
-                level: data.level,
-                category: 'console'
-            });
-        };
+        if (autoBreadcrumbs.console && 'console' in window && console.log) {
+            // console
+            var consoleMethodCallback = function (msg, data) {
+                self.captureBreadcrumb({
+                    message: msg,
+                    level: data.level,
+                    category: 'console'
+                });
+            };
 
-        if ('console' in window && console.log) {
             each(['debug', 'info', 'warn', 'error', 'log'], function (_, level) {
                 wrapConsoleMethod(console, level, consoleMethodCallback);
             });
         }
 
-        var $ = window.jQuery || window.$;
-        if ($ && $.fn && $.fn.ready) {
-            fill($.fn, 'ready', function (orig) {
-                return function (fn) {
-                    return orig.call(this, self.wrap(fn));
-                };
-            });
-        }
     },
 
     _restoreBuiltIns: function () {
@@ -1106,13 +1194,7 @@ Raven.prototype = {
             lineno:     frame.line,
             colno:      frame.column,
             'function': frame.func || '?'
-        }, context = this._extractContextFromFrame(frame), i;
-
-        if (context) {
-            var keys = ['pre_context', 'context_line', 'post_context'];
-            i = 3;
-            while (i--) normalized[keys[i]] = context[i];
-        }
+        };
 
         normalized.in_app = !( // determine if an exception came from outside of our app
             // first we check the global includePaths list.
@@ -1126,55 +1208,12 @@ Raven.prototype = {
         return normalized;
     },
 
-    _extractContextFromFrame: function(frame) {
-        // immediately check if we should even attempt to parse a context
-        if (!frame.context || !this._globalOptions.fetchContext) return;
-
-        var context = frame.context,
-            pivot = ~~(context.length / 2),
-            i = context.length, isMinified = false;
-
-        while (i--) {
-            // We're making a guess to see if the source is minified or not.
-            // To do that, we make the assumption if *any* of the lines passed
-            // in are greater than 300 characters long, we bail.
-            // Sentry will see that there isn't a context
-            if (context[i].length > 300) {
-                isMinified = true;
-                break;
-            }
-        }
-
-        if (isMinified) {
-            // The source is minified and we don't know which column. Fuck it.
-            if (isUndefined(frame.column)) return;
-
-            // If the source is minified and has a frame column
-            // we take a chunk of the offending line to hopefully shed some light
-            return [
-                [],  // no pre_context
-                context[pivot].substr(frame.column, 50), // grab 50 characters, starting at the offending column
-                []   // no post_context
-            ];
-        }
-
-        return [
-            context.slice(0, pivot),    // pre_context
-            context[pivot],             // context_line
-            context.slice(pivot + 1)    // post_context
-        ];
-    },
-
     _processException: function(type, message, fileurl, lineno, frames, options) {
-        var stacktrace, fullMessage;
+        var stacktrace;
 
         if (!!this._globalOptions.ignoreErrors.test && this._globalOptions.ignoreErrors.test(message)) return;
 
         message += '';
-        message = truncate(message, this._globalOptions.maxMessageLength);
-
-        fullMessage = (type ? type + ': ' : '') + message;
-        fullMessage = truncate(fullMessage, this._globalOptions.maxMessageLength);
 
         if (frames && frames.length) {
             fileurl = frames[0].filename || fileurl;
@@ -1204,8 +1243,7 @@ Raven.prototype = {
                     stacktrace: stacktrace
                 }]
             },
-            culprit: fileurl,
-            message: fullMessage
+            culprit: fileurl
         }, options);
 
         // Fire away!
@@ -1216,7 +1254,9 @@ Raven.prototype = {
         // 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;
-        data.message = truncate(data.message, max);
+        if (data.message) {
+            data.message = truncate(data.message, max);
+        }
         if (data.exception) {
             var exception = data.exception.values[0];
             exception.value = truncate(exception.value, max);
@@ -1247,8 +1287,6 @@ Raven.prototype = {
 
 
     _send: function(data) {
-        var self = this;
-
         var globalOptions = this._globalOptions;
 
         var baseData = {
@@ -1286,6 +1324,9 @@ Raven.prototype = {
             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;
 
@@ -1306,6 +1347,13 @@ Raven.prototype = {
             return;
         }
 
+        this._sendProcessedPayload(data);
+    },
+
+    _sendProcessedPayload: function(data, callback) {
+        var self = this;
+        var globalOptions = this._globalOptions;
+
         // 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
@@ -1327,10 +1375,14 @@ Raven.prototype = {
             auth.sentry_secret = this._globalSecret;
         }
 
+        var exception = data.exception && data.exception.values[0];
         this.captureBreadcrumb({
             category: 'sentry',
-            message: data.message,
-            event_id: data.event_id
+            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;
@@ -1344,12 +1396,15 @@ Raven.prototype = {
                     data: data,
                     src: url
                 });
+                callback && callback();
             },
-            onError: function failure() {
+            onError: function failure(error) {
                 self._triggerEvent('failure', {
                     data: data,
                     src: url
                 });
+                error = error || new Error('Raven send failed (no additional details provided)');
+                callback && callback(error);
             }
         });
     },
@@ -1371,7 +1426,7 @@ Raven.prototype = {
                     opts.onSuccess();
                 }
             } else if (opts.onError) {
-                opts.onError();
+                opts.onError(new Error('Sentry error code: ' + request.status));
             }
         }
 
@@ -1395,14 +1450,7 @@ Raven.prototype = {
         // 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(JSON.stringify(opts.data));
-    },
-
-    // Note: this is shitty, but I can't figure out how to get
-    // sinon to stub document.createElement without breaking everything
-    // so this wrapper is just so I can stub it for tests.
-    _newImage: function() {
-        return document.createElement('img');
+        request.send(stringify(opts.data));
     },
 
     _logDebug: function(level) {
@@ -1431,7 +1479,7 @@ Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
 
 module.exports = Raven;
 
-},{"1":1,"2":2,"5":5,"6":6}],4:[function(_dereq_,module,exports){
+},{"1":1,"2":2,"3":3,"6":6,"7":7}],5:[function(_dereq_,module,exports){
 /**
  * Enforces a single instance of the Raven client, and the
  * main entry point for Raven. If you are a consumer of the
@@ -1440,7 +1488,7 @@ module.exports = Raven;
 
 'use strict';
 
-var RavenConstructor = _dereq_(3);
+var RavenConstructor = _dereq_(4);
 
 var _Raven = window.Raven;
 
@@ -1461,7 +1509,7 @@ Raven.afterLoad();
 
 module.exports = Raven;
 
-},{"3":3}],5:[function(_dereq_,module,exports){
+},{"4":4}],6:[function(_dereq_,module,exports){
 /*eslint no-extra-parens:0*/
 'use strict';
 
@@ -1700,6 +1748,21 @@ function htmlElementAsString(elem) {
     return out.join('');
 }
 
+/**
+ * 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]);
+    }
+}
+
 module.exports = {
     isUndefined: isUndefined,
     isFunction: isFunction,
@@ -1716,13 +1779,14 @@ module.exports = {
     uuid4: uuid4,
     htmlTreeAsString: htmlTreeAsString,
     htmlElementAsString: htmlElementAsString,
-    parseUrl: parseUrl
+    parseUrl: parseUrl,
+    fill: fill
 };
 
-},{}],6:[function(_dereq_,module,exports){
+},{}],7:[function(_dereq_,module,exports){
 'use strict';
 
-var utils = _dereq_(5);
+var utils = _dereq_(6);
 
 var hasKey = utils.hasKey;
 var isString = utils.isString;
@@ -1734,10 +1798,7 @@ var isUndefined = utils.isUndefined;
 */
 
 var TraceKit = {
-    remoteFetching: false,
     collectWindowErrors: true,
-    // 3 lines before, the offending line, 3 lines after
-    linesOfContext: 7,
     debug: false
 };
 
@@ -1897,7 +1958,6 @@ TraceKit.report = (function reportModuleWrapper() {
             }
 
             location.func = UNKNOWN_FUNCTION;
-            location.context = null;
 
             stack = {
                 'name': name,
@@ -2000,7 +2060,6 @@ TraceKit.report = (function reportModuleWrapper() {
  *   s.stack[i].args     - arguments passed to the function, if known
  *   s.stack[i].line     - line number, if known
  *   s.stack[i].column   - column number, if known
- *   s.stack[i].context  - an array of source code lines; the middle element corresponds to the correct line#
  *
  * Supports:
  *   - Firefox:  full stack trace with line numbers and unreliable column
@@ -2109,7 +2168,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
 
         var chrome = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|<anonymous>).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,
             gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|\[native).*?)(?::(\d+))?(?::(\d+))?\s*$/i,
-            winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:ms-appx|https?|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
+            winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
             lines = ex.stack.split('\n'),
             stack = [],
             parts,
@@ -2150,10 +2209,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
                 element.func = UNKNOWN_FUNCTION;
             }
 
-            if (element.line) {
-                element.context = null;
-            }
-
             stack.push(element);
         }
 
@@ -2219,7 +2274,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
                 if (!element.func && element.line) {
                     element.func = UNKNOWN_FUNCTION;
                 }
-                element.context = [lines[line + 1]];
 
                 stack.push(element);
             }
@@ -2307,7 +2361,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
                 if (!item.func) {
                     item.func = UNKNOWN_FUNCTION;
                 }
-                item.context = [lines[line + 1]];
 
                 stack.push(item);
             }
@@ -2357,7 +2410,6 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
                         return false; // already in stack trace
                     } else if (!stackInfo.stack[0].line && stackInfo.stack[0].func === initial.func) {
                         stackInfo.stack[0].line = initial.line;
-                        stackInfo.stack[0].context = initial.context;
                         return false;
                     }
                 }
@@ -2512,5 +2564,5 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
 
 module.exports = TraceKit;
 
-},{"5":5}]},{},[4])(4)
+},{"6":6}]},{},[5])(5)
 });