demo/dist/demo.js
function computeStackTraceFromStackProp(ex) {
	    if (typeof ex.stack === 'undefined' || !ex.stack) return;
	    var chrome = /^\s*at (?:(.*?) ?\()?((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|[a-z]:|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
	    var winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx(?:-web)|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i; // NOTE: blob urls are now supposed to always have an origin, therefore it's format
	    // which is `blob:http://url/path/with-some-uuid`, is matched by `blob.*?:\/` as well

	    var gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|moz-extension).*?:\/.*?|\[native code\]|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i; // Used to additionally parse URL/line/column from eval frames

	    var geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
	    var chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/;
	    var lines = ex.stack.split('\n');
	    var stack = [];
	    var submatch;
	    var parts;
	    var element;
	    var 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;
	      }

	      if (element.url && element.url.substr(0, 5) === 'blob:') {
	        // Special case for handling JavaScript loaded into a blob.
	        // We use a synchronous AJAX request here as a blob is already in
	        // memory - it's not making a network request.  This will generate a warning
	        // in the browser console, but there has already been an error so that's not
	        // that much of an issue.
	        var xhr = new XMLHttpRequest();
	        xhr.open('GET', element.url, false);
	        xhr.send(null); // If we failed to download the source, skip this patch

	        if (xhr.status === 200) {
	          var source = xhr.responseText || ''; // We trim the source down to the last 300 characters as sourceMappingURL is always at the end of the file.
	          // Why 300? To be in line with: https://github.com/getsentry/sentry/blob/4af29e8f2350e20c28a6933354e4f42437b4ba42/src/sentry/lang/javascript/processor.py#L164-L175

	          source = source.slice(-300); // Now we dig out the source map URL

	          var sourceMaps = source.match(/\/\/# sourceMappingURL=(.*)$/); // If we don't find a source map comment or we find more than one, continue on to the next element.

	          if (sourceMaps) {
	            var sourceMapAddress = sourceMaps[1]; // Now we check to see if it's a relative URL.
	            // If it is, convert it to an absolute one.

	            if (sourceMapAddress.charAt(0) === '~') {
	              sourceMapAddress = getLocationOrigin() + sourceMapAddress.slice(1);
	            } // Now we strip the '.map' off of the end of the URL and update the
	            // element so that Sentry can match the map to the blob.


	            element.url = sourceMapAddress.slice(0, -4);
	          }
	        }
	      }

	      stack.push(element);
	    }

	    if (!stack.length) {
	      return null;
	    }

	    return {
	      name: ex.name,
	      message: ex.message,
	      url: getLocationHref(),
	      stack: stack
	    };
	  }
function computeStackTraceFromStackProp(ex) {
	    if (typeof ex.stack === 'undefined' || !ex.stack) return;
	    var chrome = /^\s*at (?:(.*?) ?\()?((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|[a-z]:|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
	    var winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx(?:-web)|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i; // NOTE: blob urls are now supposed to always have an origin, therefore it's format
	    // which is `blob:http://url/path/with-some-uuid`, is matched by `blob.*?:\/` as well

	    var gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|moz-extension).*?:\/.*?|\[native code\]|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i; // Used to additionally parse URL/line/column from eval frames

	    var geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
	    var chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/;
	    var lines = ex.stack.split('\n');
	    var stack = [];
	    var submatch;
	    var parts;
	    var element;
	    var 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;
	      }

	      if (element.url && element.url.substr(0, 5) === 'blob:') {
	        // Special case for handling JavaScript loaded into a blob.
	        // We use a synchronous AJAX request here as a blob is already in
	        // memory - it's not making a network request.  This will generate a warning
	        // in the browser console, but there has already been an error so that's not
	        // that much of an issue.
	        var xhr = new XMLHttpRequest();
	        xhr.open('GET', element.url, false);
	        xhr.send(null); // If we failed to download the source, skip this patch

	        if (xhr.status === 200) {
	          var source = xhr.responseText || ''; // We trim the source down to the last 300 characters as sourceMappingURL is always at the end of the file.
	          // Why 300? To be in line with: https://github.com/getsentry/sentry/blob/4af29e8f2350e20c28a6933354e4f42437b4ba42/src/sentry/lang/javascript/processor.py#L164-L175

	          source = source.slice(-300); // Now we dig out the source map URL

	          var sourceMaps = source.match(/\/\/# sourceMappingURL=(.*)$/); // If we don't find a source map comment or we find more than one, continue on to the next element.

	          if (sourceMaps) {
	            var sourceMapAddress = sourceMaps[1]; // Now we check to see if it's a relative URL.
	            // If it is, convert it to an absolute one.

	            if (sourceMapAddress.charAt(0) === '~') {
	              sourceMapAddress = getLocationOrigin() + sourceMapAddress.slice(1);
	            } // Now we strip the '.map' off of the end of the URL and update the
	            // element so that Sentry can match the map to the blob.


	            element.url = sourceMapAddress.slice(0, -4);
	          }
	        }
	      }

	      stack.push(element);
	    }

	    if (!stack.length) {
	      return null;
	    }

	    return {
	      name: ex.name,
	      message: ex.message,
	      url: getLocationHref(),
	      stack: stack
	    };
	  }
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.