PageRenderTime 1662ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs/raven.js/1.1.11/raven.js

https://github.com/ninosys/cdnjs
JavaScript | 1796 lines | 1043 code | 229 blank | 524 comment | 215 complexity | 3d3776f540aa788531f959f213e68bcd MD5 | raw file
Possible License(s): MIT, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*! Raven.js 1.1.11 (11645a0) | github.com/getsentry/raven-js */
  2. /*
  3. * Includes TraceKit
  4. * https://github.com/getsentry/TraceKit
  5. *
  6. * Copyright 2014 Matt Robenolt and other contributors
  7. * Released under the BSD license
  8. * https://github.com/getsentry/raven-js/blob/master/LICENSE
  9. *
  10. */
  11. ;(function(window, undefined){
  12. 'use strict';
  13. /*
  14. TraceKit - Cross brower stack traces - github.com/occ/TraceKit
  15. MIT license
  16. */
  17. var TraceKit = {
  18. remoteFetching: false,
  19. collectWindowErrors: true,
  20. // 3 lines before, the offending line, 3 lines after
  21. linesOfContext: 7
  22. };
  23. // global reference to slice
  24. var _slice = [].slice;
  25. var UNKNOWN_FUNCTION = '?';
  26. /**
  27. * TraceKit.wrap: Wrap any function in a TraceKit reporter
  28. * Example: func = TraceKit.wrap(func);
  29. *
  30. * @param {Function} func Function to be wrapped
  31. * @return {Function} The wrapped func
  32. */
  33. TraceKit.wrap = function traceKitWrapper(func) {
  34. function wrapped() {
  35. try {
  36. return func.apply(this, arguments);
  37. } catch (e) {
  38. TraceKit.report(e);
  39. throw e;
  40. }
  41. }
  42. return wrapped;
  43. };
  44. /**
  45. * TraceKit.report: cross-browser processing of unhandled exceptions
  46. *
  47. * Syntax:
  48. * TraceKit.report.subscribe(function(stackInfo) { ... })
  49. * TraceKit.report.unsubscribe(function(stackInfo) { ... })
  50. * TraceKit.report(exception)
  51. * try { ...code... } catch(ex) { TraceKit.report(ex); }
  52. *
  53. * Supports:
  54. * - Firefox: full stack trace with line numbers, plus column number
  55. * on top frame; column number is not guaranteed
  56. * - Opera: full stack trace with line and column numbers
  57. * - Chrome: full stack trace with line and column numbers
  58. * - Safari: line and column number for the top frame only; some frames
  59. * may be missing, and column number is not guaranteed
  60. * - IE: line and column number for the top frame only; some frames
  61. * may be missing, and column number is not guaranteed
  62. *
  63. * In theory, TraceKit should work on all of the following versions:
  64. * - IE5.5+ (only 8.0 tested)
  65. * - Firefox 0.9+ (only 3.5+ tested)
  66. * - Opera 7+ (only 10.50 tested; versions 9 and earlier may require
  67. * Exceptions Have Stacktrace to be enabled in opera:config)
  68. * - Safari 3+ (only 4+ tested)
  69. * - Chrome 1+ (only 5+ tested)
  70. * - Konqueror 3.5+ (untested)
  71. *
  72. * Requires TraceKit.computeStackTrace.
  73. *
  74. * Tries to catch all unhandled exceptions and report them to the
  75. * subscribed handlers. Please note that TraceKit.report will rethrow the
  76. * exception. This is REQUIRED in order to get a useful stack trace in IE.
  77. * If the exception does not reach the top of the browser, you will only
  78. * get a stack trace from the point where TraceKit.report was called.
  79. *
  80. * Handlers receive a stackInfo object as described in the
  81. * TraceKit.computeStackTrace docs.
  82. */
  83. TraceKit.report = (function reportModuleWrapper() {
  84. var handlers = [],
  85. lastArgs = null,
  86. lastException = null,
  87. lastExceptionStack = null;
  88. /**
  89. * Add a crash handler.
  90. * @param {Function} handler
  91. */
  92. function subscribe(handler) {
  93. installGlobalHandler();
  94. handlers.push(handler);
  95. }
  96. /**
  97. * Remove a crash handler.
  98. * @param {Function} handler
  99. */
  100. function unsubscribe(handler) {
  101. for (var i = handlers.length - 1; i >= 0; --i) {
  102. if (handlers[i] === handler) {
  103. handlers.splice(i, 1);
  104. }
  105. }
  106. }
  107. /**
  108. * Remove all crash handlers.
  109. */
  110. function unsubscribeAll() {
  111. uninstallGlobalHandler();
  112. handlers = [];
  113. }
  114. /**
  115. * Dispatch stack information to all handlers.
  116. * @param {Object.<string, *>} stack
  117. */
  118. function notifyHandlers(stack, isWindowError) {
  119. var exception = null;
  120. if (isWindowError && !TraceKit.collectWindowErrors) {
  121. return;
  122. }
  123. for (var i in handlers) {
  124. if (hasKey(handlers, i)) {
  125. try {
  126. handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2)));
  127. } catch (inner) {
  128. exception = inner;
  129. }
  130. }
  131. }
  132. if (exception) {
  133. throw exception;
  134. }
  135. }
  136. var _oldOnerrorHandler, _onErrorHandlerInstalled;
  137. /**
  138. * Ensures all global unhandled exceptions are recorded.
  139. * Supported by Gecko and IE.
  140. * @param {string} message Error message.
  141. * @param {string} url URL of script that generated the exception.
  142. * @param {(number|string)} lineNo The line number at which the error
  143. * occurred.
  144. * @param {?(number|string)} colNo The column number at which the error
  145. * occurred.
  146. * @param {?Error} ex The actual Error object.
  147. */
  148. function traceKitWindowOnError(message, url, lineNo, colNo, ex) {
  149. var stack = null;
  150. if (lastExceptionStack) {
  151. TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(lastExceptionStack, url, lineNo, message);
  152. processLastException();
  153. } else if (ex) {
  154. // New chrome and blink send along a real error object
  155. // Let's just report that like a normal error.
  156. // See: https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
  157. stack = TraceKit.computeStackTrace(ex);
  158. notifyHandlers(stack, true);
  159. } else {
  160. var location = {
  161. 'url': url,
  162. 'line': lineNo,
  163. 'column': colNo
  164. };
  165. location.func = TraceKit.computeStackTrace.guessFunctionName(location.url, location.line);
  166. location.context = TraceKit.computeStackTrace.gatherContext(location.url, location.line);
  167. stack = {
  168. 'message': message,
  169. 'url': document.location.href,
  170. 'stack': [location]
  171. };
  172. notifyHandlers(stack, true);
  173. }
  174. if (_oldOnerrorHandler) {
  175. return _oldOnerrorHandler.apply(this, arguments);
  176. }
  177. return false;
  178. }
  179. function installGlobalHandler ()
  180. {
  181. if (_onErrorHandlerInstalled) {
  182. return;
  183. }
  184. _oldOnerrorHandler = window.onerror;
  185. window.onerror = traceKitWindowOnError;
  186. _onErrorHandlerInstalled = true;
  187. }
  188. function uninstallGlobalHandler ()
  189. {
  190. if (!_onErrorHandlerInstalled) {
  191. return;
  192. }
  193. window.onerror = _oldOnerrorHandler;
  194. _onErrorHandlerInstalled = false;
  195. _oldOnerrorHandler = undefined;
  196. }
  197. function processLastException() {
  198. var _lastExceptionStack = lastExceptionStack,
  199. _lastArgs = lastArgs;
  200. lastArgs = null;
  201. lastExceptionStack = null;
  202. lastException = null;
  203. notifyHandlers.apply(null, [_lastExceptionStack, false].concat(_lastArgs));
  204. }
  205. /**
  206. * Reports an unhandled Error to TraceKit.
  207. * @param {Error} ex
  208. * @param {?boolean} rethrow If false, do not re-throw the exception.
  209. * Only used for window.onerror to not cause an infinite loop of
  210. * rethrowing.
  211. */
  212. function report(ex, rethrow) {
  213. var args = _slice.call(arguments, 1);
  214. if (lastExceptionStack) {
  215. if (lastException === ex) {
  216. return; // already caught by an inner catch block, ignore
  217. } else {
  218. processLastException();
  219. }
  220. }
  221. var stack = TraceKit.computeStackTrace(ex);
  222. lastExceptionStack = stack;
  223. lastException = ex;
  224. lastArgs = args;
  225. // If the stack trace is incomplete, wait for 2 seconds for
  226. // slow slow IE to see if onerror occurs or not before reporting
  227. // this exception; otherwise, we will end up with an incomplete
  228. // stack trace
  229. window.setTimeout(function () {
  230. if (lastException === ex) {
  231. processLastException();
  232. }
  233. }, (stack.incomplete ? 2000 : 0));
  234. if (rethrow !== false) {
  235. throw ex; // re-throw to propagate to the top level (and cause window.onerror)
  236. }
  237. }
  238. report.subscribe = subscribe;
  239. report.unsubscribe = unsubscribe;
  240. report.uninstall = unsubscribeAll;
  241. return report;
  242. }());
  243. /**
  244. * TraceKit.computeStackTrace: cross-browser stack traces in JavaScript
  245. *
  246. * Syntax:
  247. * s = TraceKit.computeStackTrace.ofCaller([depth])
  248. * s = TraceKit.computeStackTrace(exception) // consider using TraceKit.report instead (see below)
  249. * Returns:
  250. * s.name - exception name
  251. * s.message - exception message
  252. * s.stack[i].url - JavaScript or HTML file URL
  253. * s.stack[i].func - function name, or empty for anonymous functions (if guessing did not work)
  254. * s.stack[i].args - arguments passed to the function, if known
  255. * s.stack[i].line - line number, if known
  256. * s.stack[i].column - column number, if known
  257. * s.stack[i].context - an array of source code lines; the middle element corresponds to the correct line#
  258. *
  259. * Supports:
  260. * - Firefox: full stack trace with line numbers and unreliable column
  261. * number on top frame
  262. * - Opera 10: full stack trace with line and column numbers
  263. * - Opera 9-: full stack trace with line numbers
  264. * - Chrome: full stack trace with line and column numbers
  265. * - Safari: line and column number for the topmost stacktrace element
  266. * only
  267. * - IE: no line numbers whatsoever
  268. *
  269. * Tries to guess names of anonymous functions by looking for assignments
  270. * in the source code. In IE and Safari, we have to guess source file names
  271. * by searching for function bodies inside all page scripts. This will not
  272. * work for scripts that are loaded cross-domain.
  273. * Here be dragons: some function names may be guessed incorrectly, and
  274. * duplicate functions may be mismatched.
  275. *
  276. * TraceKit.computeStackTrace should only be used for tracing purposes.
  277. * Logging of unhandled exceptions should be done with TraceKit.report,
  278. * which builds on top of TraceKit.computeStackTrace and provides better
  279. * IE support by utilizing the window.onerror event to retrieve information
  280. * about the top of the stack.
  281. *
  282. * Note: In IE and Safari, no stack trace is recorded on the Error object,
  283. * so computeStackTrace instead walks its *own* chain of callers.
  284. * This means that:
  285. * * in Safari, some methods may be missing from the stack trace;
  286. * * in IE, the topmost function in the stack trace will always be the
  287. * caller of computeStackTrace.
  288. *
  289. * This is okay for tracing (because you are likely to be calling
  290. * computeStackTrace from the function you want to be the topmost element
  291. * of the stack trace anyway), but not okay for logging unhandled
  292. * exceptions (because your catch block will likely be far away from the
  293. * inner function that actually caused the exception).
  294. *
  295. * Tracing example:
  296. * function trace(message) {
  297. * var stackInfo = TraceKit.computeStackTrace.ofCaller();
  298. * var data = message + "\n";
  299. * for(var i in stackInfo.stack) {
  300. * var item = stackInfo.stack[i];
  301. * data += (item.func || '[anonymous]') + "() in " + item.url + ":" + (item.line || '0') + "\n";
  302. * }
  303. * if (window.console)
  304. * console.info(data);
  305. * else
  306. * alert(data);
  307. * }
  308. */
  309. TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
  310. var debug = false,
  311. sourceCache = {};
  312. /**
  313. * Attempts to retrieve source code via XMLHttpRequest, which is used
  314. * to look up anonymous function names.
  315. * @param {string} url URL of source code.
  316. * @return {string} Source contents.
  317. */
  318. function loadSource(url) {
  319. if (!TraceKit.remoteFetching) { //Only attempt request if remoteFetching is on.
  320. return '';
  321. }
  322. try {
  323. var getXHR = function() {
  324. try {
  325. return new window.XMLHttpRequest();
  326. } catch (e) {
  327. // explicitly bubble up the exception if not found
  328. return new window.ActiveXObject('Microsoft.XMLHTTP');
  329. }
  330. };
  331. var request = getXHR();
  332. request.open('GET', url, false);
  333. request.send('');
  334. return request.responseText;
  335. } catch (e) {
  336. return '';
  337. }
  338. }
  339. /**
  340. * Retrieves source code from the source code cache.
  341. * @param {string} url URL of source code.
  342. * @return {Array.<string>} Source contents.
  343. */
  344. function getSource(url) {
  345. if (!isString(url)) return [];
  346. if (!hasKey(sourceCache, url)) {
  347. // URL needs to be able to fetched within the acceptable domain. Otherwise,
  348. // cross-domain errors will be triggered.
  349. var source = '';
  350. if (url.indexOf(document.domain) !== -1) {
  351. source = loadSource(url);
  352. }
  353. sourceCache[url] = source ? source.split('\n') : [];
  354. }
  355. return sourceCache[url];
  356. }
  357. /**
  358. * Tries to use an externally loaded copy of source code to determine
  359. * the name of a function by looking at the name of the variable it was
  360. * assigned to, if any.
  361. * @param {string} url URL of source code.
  362. * @param {(string|number)} lineNo Line number in source code.
  363. * @return {string} The function name, if discoverable.
  364. */
  365. function guessFunctionName(url, lineNo) {
  366. var reFunctionArgNames = /function ([^(]*)\(([^)]*)\)/,
  367. reGuessFunction = /['"]?([0-9A-Za-z$_]+)['"]?\s*[:=]\s*(function|eval|new Function)/,
  368. line = '',
  369. maxLines = 10,
  370. source = getSource(url),
  371. m;
  372. if (!source.length) {
  373. return UNKNOWN_FUNCTION;
  374. }
  375. // Walk backwards from the first line in the function until we find the line which
  376. // matches the pattern above, which is the function definition
  377. for (var i = 0; i < maxLines; ++i) {
  378. line = source[lineNo - i] + line;
  379. if (!isUndefined(line)) {
  380. if ((m = reGuessFunction.exec(line))) {
  381. return m[1];
  382. } else if ((m = reFunctionArgNames.exec(line))) {
  383. return m[1];
  384. }
  385. }
  386. }
  387. return UNKNOWN_FUNCTION;
  388. }
  389. /**
  390. * Retrieves the surrounding lines from where an exception occurred.
  391. * @param {string} url URL of source code.
  392. * @param {(string|number)} line Line number in source code to centre
  393. * around for context.
  394. * @return {?Array.<string>} Lines of source code.
  395. */
  396. function gatherContext(url, line) {
  397. var source = getSource(url);
  398. if (!source.length) {
  399. return null;
  400. }
  401. var context = [],
  402. // linesBefore & linesAfter are inclusive with the offending line.
  403. // if linesOfContext is even, there will be one extra line
  404. // *before* the offending line.
  405. linesBefore = Math.floor(TraceKit.linesOfContext / 2),
  406. // Add one extra line if linesOfContext is odd
  407. linesAfter = linesBefore + (TraceKit.linesOfContext % 2),
  408. start = Math.max(0, line - linesBefore - 1),
  409. end = Math.min(source.length, line + linesAfter - 1);
  410. line -= 1; // convert to 0-based index
  411. for (var i = start; i < end; ++i) {
  412. if (!isUndefined(source[i])) {
  413. context.push(source[i]);
  414. }
  415. }
  416. return context.length > 0 ? context : null;
  417. }
  418. /**
  419. * Escapes special characters, except for whitespace, in a string to be
  420. * used inside a regular expression as a string literal.
  421. * @param {string} text The string.
  422. * @return {string} The escaped string literal.
  423. */
  424. function escapeRegExp(text) {
  425. return text.replace(/[\-\[\]{}()*+?.,\\\^$|#]/g, '\\$&');
  426. }
  427. /**
  428. * Escapes special characters in a string to be used inside a regular
  429. * expression as a string literal. Also ensures that HTML entities will
  430. * be matched the same as their literal friends.
  431. * @param {string} body The string.
  432. * @return {string} The escaped string.
  433. */
  434. function escapeCodeAsRegExpForMatchingInsideHTML(body) {
  435. return escapeRegExp(body).replace('<', '(?:<|&lt;)').replace('>', '(?:>|&gt;)').replace('&', '(?:&|&amp;)').replace('"', '(?:"|&quot;)').replace(/\s+/g, '\\s+');
  436. }
  437. /**
  438. * Determines where a code fragment occurs in the source code.
  439. * @param {RegExp} re The function definition.
  440. * @param {Array.<string>} urls A list of URLs to search.
  441. * @return {?Object.<string, (string|number)>} An object containing
  442. * the url, line, and column number of the defined function.
  443. */
  444. function findSourceInUrls(re, urls) {
  445. var source, m;
  446. for (var i = 0, j = urls.length; i < j; ++i) {
  447. // console.log('searching', urls[i]);
  448. if ((source = getSource(urls[i])).length) {
  449. source = source.join('\n');
  450. if ((m = re.exec(source))) {
  451. // console.log('Found function in ' + urls[i]);
  452. return {
  453. 'url': urls[i],
  454. 'line': source.substring(0, m.index).split('\n').length,
  455. 'column': m.index - source.lastIndexOf('\n', m.index) - 1
  456. };
  457. }
  458. }
  459. }
  460. // console.log('no match');
  461. return null;
  462. }
  463. /**
  464. * Determines at which column a code fragment occurs on a line of the
  465. * source code.
  466. * @param {string} fragment The code fragment.
  467. * @param {string} url The URL to search.
  468. * @param {(string|number)} line The line number to examine.
  469. * @return {?number} The column number.
  470. */
  471. function findSourceInLine(fragment, url, line) {
  472. var source = getSource(url),
  473. re = new RegExp('\\b' + escapeRegExp(fragment) + '\\b'),
  474. m;
  475. line -= 1;
  476. if (source && source.length > line && (m = re.exec(source[line]))) {
  477. return m.index;
  478. }
  479. return null;
  480. }
  481. /**
  482. * Determines where a function was defined within the source code.
  483. * @param {(Function|string)} func A function reference or serialized
  484. * function definition.
  485. * @return {?Object.<string, (string|number)>} An object containing
  486. * the url, line, and column number of the defined function.
  487. */
  488. function findSourceByFunctionBody(func) {
  489. var urls = [window.location.href],
  490. scripts = document.getElementsByTagName('script'),
  491. body,
  492. code = '' + func,
  493. codeRE = /^function(?:\s+([\w$]+))?\s*\(([\w\s,]*)\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/,
  494. eventRE = /^function on([\w$]+)\s*\(event\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/,
  495. re,
  496. parts,
  497. result;
  498. for (var i = 0; i < scripts.length; ++i) {
  499. var script = scripts[i];
  500. if (script.src) {
  501. urls.push(script.src);
  502. }
  503. }
  504. if (!(parts = codeRE.exec(code))) {
  505. re = new RegExp(escapeRegExp(code).replace(/\s+/g, '\\s+'));
  506. }
  507. // not sure if this is really necessary, but I don’t have a test
  508. // corpus large enough to confirm that and it was in the original.
  509. else {
  510. var name = parts[1] ? '\\s+' + parts[1] : '',
  511. args = parts[2].split(',').join('\\s*,\\s*');
  512. body = escapeRegExp(parts[3]).replace(/;$/, ';?'); // semicolon is inserted if the function ends with a comment.replace(/\s+/g, '\\s+');
  513. re = new RegExp('function' + name + '\\s*\\(\\s*' + args + '\\s*\\)\\s*{\\s*' + body + '\\s*}');
  514. }
  515. // look for a normal function definition
  516. if ((result = findSourceInUrls(re, urls))) {
  517. return result;
  518. }
  519. // look for an old-school event handler function
  520. if ((parts = eventRE.exec(code))) {
  521. var event = parts[1];
  522. body = escapeCodeAsRegExpForMatchingInsideHTML(parts[2]);
  523. // look for a function defined in HTML as an onXXX handler
  524. re = new RegExp('on' + event + '=[\\\'"]\\s*' + body + '\\s*[\\\'"]', 'i');
  525. if ((result = findSourceInUrls(re, urls[0]))) {
  526. return result;
  527. }
  528. // look for ???
  529. re = new RegExp(body);
  530. if ((result = findSourceInUrls(re, urls))) {
  531. return result;
  532. }
  533. }
  534. return null;
  535. }
  536. // Contents of Exception in various browsers.
  537. //
  538. // SAFARI:
  539. // ex.message = Can't find variable: qq
  540. // ex.line = 59
  541. // ex.sourceId = 580238192
  542. // ex.sourceURL = http://...
  543. // ex.expressionBeginOffset = 96
  544. // ex.expressionCaretOffset = 98
  545. // ex.expressionEndOffset = 98
  546. // ex.name = ReferenceError
  547. //
  548. // FIREFOX:
  549. // ex.message = qq is not defined
  550. // ex.fileName = http://...
  551. // ex.lineNumber = 59
  552. // ex.columnNumber = 69
  553. // ex.stack = ...stack trace... (see the example below)
  554. // ex.name = ReferenceError
  555. //
  556. // CHROME:
  557. // ex.message = qq is not defined
  558. // ex.name = ReferenceError
  559. // ex.type = not_defined
  560. // ex.arguments = ['aa']
  561. // ex.stack = ...stack trace...
  562. //
  563. // INTERNET EXPLORER:
  564. // ex.message = ...
  565. // ex.name = ReferenceError
  566. //
  567. // OPERA:
  568. // ex.message = ...message... (see the example below)
  569. // ex.name = ReferenceError
  570. // ex.opera#sourceloc = 11 (pretty much useless, duplicates the info in ex.message)
  571. // ex.stacktrace = n/a; see 'opera:config#UserPrefs|Exceptions Have Stacktrace'
  572. /**
  573. * Computes stack trace information from the stack property.
  574. * Chrome and Gecko use this property.
  575. * @param {Error} ex
  576. * @return {?Object.<string, *>} Stack trace information.
  577. */
  578. function computeStackTraceFromStackProp(ex) {
  579. if (!ex.stack) {
  580. return null;
  581. }
  582. var chrome = /^\s*at (?:((?:\[object object\])?\S+(?: \[as \S+\])?) )?\(?((?:file|https?):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
  583. gecko = /^\s*(\S*)(?:\((.*?)\))?@((?:file|https?).*?):(\d+)(?::(\d+))?\s*$/i,
  584. lines = ex.stack.split('\n'),
  585. stack = [],
  586. parts,
  587. element,
  588. reference = /^(.*) is undefined$/.exec(ex.message);
  589. for (var i = 0, j = lines.length; i < j; ++i) {
  590. if ((parts = gecko.exec(lines[i]))) {
  591. element = {
  592. 'url': parts[3],
  593. 'func': parts[1] || UNKNOWN_FUNCTION,
  594. 'args': parts[2] ? parts[2].split(',') : '',
  595. 'line': +parts[4],
  596. 'column': parts[5] ? +parts[5] : null
  597. };
  598. } else if ((parts = chrome.exec(lines[i]))) {
  599. element = {
  600. 'url': parts[2],
  601. 'func': parts[1] || UNKNOWN_FUNCTION,
  602. 'line': +parts[3],
  603. 'column': parts[4] ? +parts[4] : null
  604. };
  605. } else {
  606. continue;
  607. }
  608. if (!element.func && element.line) {
  609. element.func = guessFunctionName(element.url, element.line);
  610. }
  611. if (element.line) {
  612. element.context = gatherContext(element.url, element.line);
  613. }
  614. stack.push(element);
  615. }
  616. if (!stack.length) {
  617. return null;
  618. }
  619. if (stack[0].line && !stack[0].column && reference) {
  620. stack[0].column = findSourceInLine(reference[1], stack[0].url, stack[0].line);
  621. } else if (!stack[0].column && !isUndefined(ex.columnNumber)) {
  622. // FireFox uses this awesome columnNumber property for its top frame
  623. // Also note, Firefox's column number is 0-based and everything else expects 1-based,
  624. // so adding 1
  625. stack[0].column = ex.columnNumber + 1;
  626. }
  627. return {
  628. 'name': ex.name,
  629. 'message': ex.message,
  630. 'url': document.location.href,
  631. 'stack': stack
  632. };
  633. }
  634. /**
  635. * Computes stack trace information from the stacktrace property.
  636. * Opera 10 uses this property.
  637. * @param {Error} ex
  638. * @return {?Object.<string, *>} Stack trace information.
  639. */
  640. function computeStackTraceFromStacktraceProp(ex) {
  641. // Access and store the stacktrace property before doing ANYTHING
  642. // else to it because Opera is not very good at providing it
  643. // reliably in other circumstances.
  644. var stacktrace = ex.stacktrace;
  645. var testRE = / line (\d+), column (\d+) in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\) in (.*):\s*$/i,
  646. lines = stacktrace.split('\n'),
  647. stack = [],
  648. parts;
  649. for (var i = 0, j = lines.length; i < j; i += 2) {
  650. if ((parts = testRE.exec(lines[i]))) {
  651. var element = {
  652. 'line': +parts[1],
  653. 'column': +parts[2],
  654. 'func': parts[3] || parts[4],
  655. 'args': parts[5] ? parts[5].split(',') : [],
  656. 'url': parts[6]
  657. };
  658. if (!element.func && element.line) {
  659. element.func = guessFunctionName(element.url, element.line);
  660. }
  661. if (element.line) {
  662. try {
  663. element.context = gatherContext(element.url, element.line);
  664. } catch (exc) {}
  665. }
  666. if (!element.context) {
  667. element.context = [lines[i + 1]];
  668. }
  669. stack.push(element);
  670. }
  671. }
  672. if (!stack.length) {
  673. return null;
  674. }
  675. return {
  676. 'name': ex.name,
  677. 'message': ex.message,
  678. 'url': document.location.href,
  679. 'stack': stack
  680. };
  681. }
  682. /**
  683. * NOT TESTED.
  684. * Computes stack trace information from an error message that includes
  685. * the stack trace.
  686. * Opera 9 and earlier use this method if the option to show stack
  687. * traces is turned on in opera:config.
  688. * @param {Error} ex
  689. * @return {?Object.<string, *>} Stack information.
  690. */
  691. function computeStackTraceFromOperaMultiLineMessage(ex) {
  692. // Opera includes a stack trace into the exception message. An example is:
  693. //
  694. // Statement on line 3: Undefined variable: undefinedFunc
  695. // Backtrace:
  696. // Line 3 of linked script file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.js: In function zzz
  697. // undefinedFunc(a);
  698. // Line 7 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function yyy
  699. // zzz(x, y, z);
  700. // Line 3 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function xxx
  701. // yyy(a, a, a);
  702. // Line 1 of function script
  703. // try { xxx('hi'); return false; } catch(ex) { TraceKit.report(ex); }
  704. // ...
  705. var lines = ex.message.split('\n');
  706. if (lines.length < 4) {
  707. return null;
  708. }
  709. var lineRE1 = /^\s*Line (\d+) of linked script ((?:file|https?)\S+)(?:: in function (\S+))?\s*$/i,
  710. lineRE2 = /^\s*Line (\d+) of inline#(\d+) script in ((?:file|https?)\S+)(?:: in function (\S+))?\s*$/i,
  711. lineRE3 = /^\s*Line (\d+) of function script\s*$/i,
  712. stack = [],
  713. scripts = document.getElementsByTagName('script'),
  714. inlineScriptBlocks = [],
  715. parts,
  716. i,
  717. len,
  718. source;
  719. for (i in scripts) {
  720. if (hasKey(scripts, i) && !scripts[i].src) {
  721. inlineScriptBlocks.push(scripts[i]);
  722. }
  723. }
  724. for (i = 2, len = lines.length; i < len; i += 2) {
  725. var item = null;
  726. if ((parts = lineRE1.exec(lines[i]))) {
  727. item = {
  728. 'url': parts[2],
  729. 'func': parts[3],
  730. 'line': +parts[1]
  731. };
  732. } else if ((parts = lineRE2.exec(lines[i]))) {
  733. item = {
  734. 'url': parts[3],
  735. 'func': parts[4]
  736. };
  737. var relativeLine = (+parts[1]); // relative to the start of the <SCRIPT> block
  738. var script = inlineScriptBlocks[parts[2] - 1];
  739. if (script) {
  740. source = getSource(item.url);
  741. if (source) {
  742. source = source.join('\n');
  743. var pos = source.indexOf(script.innerText);
  744. if (pos >= 0) {
  745. item.line = relativeLine + source.substring(0, pos).split('\n').length;
  746. }
  747. }
  748. }
  749. } else if ((parts = lineRE3.exec(lines[i]))) {
  750. var url = window.location.href.replace(/#.*$/, ''),
  751. line = parts[1];
  752. var re = new RegExp(escapeCodeAsRegExpForMatchingInsideHTML(lines[i + 1]));
  753. source = findSourceInUrls(re, [url]);
  754. item = {
  755. 'url': url,
  756. 'line': source ? source.line : line,
  757. 'func': ''
  758. };
  759. }
  760. if (item) {
  761. if (!item.func) {
  762. item.func = guessFunctionName(item.url, item.line);
  763. }
  764. var context = gatherContext(item.url, item.line);
  765. var midline = (context ? context[Math.floor(context.length / 2)] : null);
  766. if (context && midline.replace(/^\s*/, '') === lines[i + 1].replace(/^\s*/, '')) {
  767. item.context = context;
  768. } else {
  769. // if (context) alert("Context mismatch. Correct midline:\n" + lines[i+1] + "\n\nMidline:\n" + midline + "\n\nContext:\n" + context.join("\n") + "\n\nURL:\n" + item.url);
  770. item.context = [lines[i + 1]];
  771. }
  772. stack.push(item);
  773. }
  774. }
  775. if (!stack.length) {
  776. return null; // could not parse multiline exception message as Opera stack trace
  777. }
  778. return {
  779. 'name': ex.name,
  780. 'message': lines[0],
  781. 'url': document.location.href,
  782. 'stack': stack
  783. };
  784. }
  785. /**
  786. * Adds information about the first frame to incomplete stack traces.
  787. * Safari and IE require this to get complete data on the first frame.
  788. * @param {Object.<string, *>} stackInfo Stack trace information from
  789. * one of the compute* methods.
  790. * @param {string} url The URL of the script that caused an error.
  791. * @param {(number|string)} lineNo The line number of the script that
  792. * caused an error.
  793. * @param {string=} message The error generated by the browser, which
  794. * hopefully contains the name of the object that caused the error.
  795. * @return {boolean} Whether or not the stack information was
  796. * augmented.
  797. */
  798. function augmentStackTraceWithInitialElement(stackInfo, url, lineNo, message) {
  799. var initial = {
  800. 'url': url,
  801. 'line': lineNo
  802. };
  803. if (initial.url && initial.line) {
  804. stackInfo.incomplete = false;
  805. if (!initial.func) {
  806. initial.func = guessFunctionName(initial.url, initial.line);
  807. }
  808. if (!initial.context) {
  809. initial.context = gatherContext(initial.url, initial.line);
  810. }
  811. var reference = / '([^']+)' /.exec(message);
  812. if (reference) {
  813. initial.column = findSourceInLine(reference[1], initial.url, initial.line);
  814. }
  815. if (stackInfo.stack.length > 0) {
  816. if (stackInfo.stack[0].url === initial.url) {
  817. if (stackInfo.stack[0].line === initial.line) {
  818. return false; // already in stack trace
  819. } else if (!stackInfo.stack[0].line && stackInfo.stack[0].func === initial.func) {
  820. stackInfo.stack[0].line = initial.line;
  821. stackInfo.stack[0].context = initial.context;
  822. return false;
  823. }
  824. }
  825. }
  826. stackInfo.stack.unshift(initial);
  827. stackInfo.partial = true;
  828. return true;
  829. } else {
  830. stackInfo.incomplete = true;
  831. }
  832. return false;
  833. }
  834. /**
  835. * Computes stack trace information by walking the arguments.caller
  836. * chain at the time the exception occurred. This will cause earlier
  837. * frames to be missed but is the only way to get any stack trace in
  838. * Safari and IE. The top frame is restored by
  839. * {@link augmentStackTraceWithInitialElement}.
  840. * @param {Error} ex
  841. * @return {?Object.<string, *>} Stack trace information.
  842. */
  843. function computeStackTraceByWalkingCallerChain(ex, depth) {
  844. var functionName = /function\s+([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)?\s*\(/i,
  845. stack = [],
  846. funcs = {},
  847. recursion = false,
  848. parts,
  849. item,
  850. source;
  851. for (var curr = computeStackTraceByWalkingCallerChain.caller; curr && !recursion; curr = curr.caller) {
  852. if (curr === computeStackTrace || curr === TraceKit.report) {
  853. // console.log('skipping internal function');
  854. continue;
  855. }
  856. item = {
  857. 'url': null,
  858. 'func': UNKNOWN_FUNCTION,
  859. 'line': null,
  860. 'column': null
  861. };
  862. if (curr.name) {
  863. item.func = curr.name;
  864. } else if ((parts = functionName.exec(curr.toString()))) {
  865. item.func = parts[1];
  866. }
  867. if ((source = findSourceByFunctionBody(curr))) {
  868. item.url = source.url;
  869. item.line = source.line;
  870. if (item.func === UNKNOWN_FUNCTION) {
  871. item.func = guessFunctionName(item.url, item.line);
  872. }
  873. var reference = / '([^']+)' /.exec(ex.message || ex.description);
  874. if (reference) {
  875. item.column = findSourceInLine(reference[1], source.url, source.line);
  876. }
  877. }
  878. if (funcs['' + curr]) {
  879. recursion = true;
  880. }else{
  881. funcs['' + curr] = true;
  882. }
  883. stack.push(item);
  884. }
  885. if (depth) {
  886. // console.log('depth is ' + depth);
  887. // console.log('stack is ' + stack.length);
  888. stack.splice(0, depth);
  889. }
  890. var result = {
  891. 'name': ex.name,
  892. 'message': ex.message,
  893. 'url': document.location.href,
  894. 'stack': stack
  895. };
  896. augmentStackTraceWithInitialElement(result, ex.sourceURL || ex.fileName, ex.line || ex.lineNumber, ex.message || ex.description);
  897. return result;
  898. }
  899. /**
  900. * Computes a stack trace for an exception.
  901. * @param {Error} ex
  902. * @param {(string|number)=} depth
  903. */
  904. function computeStackTrace(ex, depth) {
  905. var stack = null;
  906. depth = (depth == null ? 0 : +depth);
  907. try {
  908. // This must be tried first because Opera 10 *destroys*
  909. // its stacktrace property if you try to access the stack
  910. // property first!!
  911. stack = computeStackTraceFromStacktraceProp(ex);
  912. if (stack) {
  913. return stack;
  914. }
  915. } catch (e) {
  916. if (debug) {
  917. throw e;
  918. }
  919. }
  920. try {
  921. stack = computeStackTraceFromStackProp(ex);
  922. if (stack) {
  923. return stack;
  924. }
  925. } catch (e) {
  926. if (debug) {
  927. throw e;
  928. }
  929. }
  930. try {
  931. stack = computeStackTraceFromOperaMultiLineMessage(ex);
  932. if (stack) {
  933. return stack;
  934. }
  935. } catch (e) {
  936. if (debug) {
  937. throw e;
  938. }
  939. }
  940. try {
  941. stack = computeStackTraceByWalkingCallerChain(ex, depth + 1);
  942. if (stack) {
  943. return stack;
  944. }
  945. } catch (e) {
  946. if (debug) {
  947. throw e;
  948. }
  949. }
  950. return {};
  951. }
  952. /**
  953. * Logs a stacktrace starting from the previous call and working down.
  954. * @param {(number|string)=} depth How many frames deep to trace.
  955. * @return {Object.<string, *>} Stack trace information.
  956. */
  957. function computeStackTraceOfCaller(depth) {
  958. depth = (depth == null ? 0 : +depth) + 1; // "+ 1" because "ofCaller" should drop one frame
  959. try {
  960. throw new Error();
  961. } catch (ex) {
  962. return computeStackTrace(ex, depth + 1);
  963. }
  964. }
  965. computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;
  966. computeStackTrace.guessFunctionName = guessFunctionName;
  967. computeStackTrace.gatherContext = gatherContext;
  968. computeStackTrace.ofCaller = computeStackTraceOfCaller;
  969. return computeStackTrace;
  970. }());
  971. 'use strict';
  972. // First, check for JSON support
  973. // If there is no JSON, we no-op the core features of Raven
  974. // since JSON is required to encode the payload
  975. var _Raven = window.Raven,
  976. hasJSON = !!(window.JSON && window.JSON.stringify),
  977. lastCapturedException,
  978. lastEventId,
  979. globalServer,
  980. globalUser,
  981. globalKey,
  982. globalProject,
  983. globalOptions = {
  984. logger: 'javascript',
  985. ignoreErrors: [],
  986. ignoreUrls: [],
  987. whitelistUrls: [],
  988. includePaths: [],
  989. collectWindowErrors: true,
  990. tags: {},
  991. extra: {}
  992. };
  993. /*
  994. * The core Raven singleton
  995. *
  996. * @this {Raven}
  997. */
  998. var Raven = {
  999. VERSION: '1.1.11',
  1000. // Expose TraceKit to the Raven namespace
  1001. TraceKit: TraceKit,
  1002. /*
  1003. * Allow Raven to be configured as soon as it is loaded
  1004. * It uses a global RavenConfig = {dsn: '...', config: {}}
  1005. *
  1006. * @return undefined
  1007. */
  1008. afterLoad: function() {
  1009. var globalConfig = window.RavenConfig;
  1010. if (globalConfig) {
  1011. this.config(globalConfig.dsn, globalConfig.config).install();
  1012. }
  1013. },
  1014. /*
  1015. * Allow multiple versions of Raven to be installed.
  1016. * Strip Raven from the global context and returns the instance.
  1017. *
  1018. * @return {Raven}
  1019. */
  1020. noConflict: function() {
  1021. window.Raven = _Raven;
  1022. return Raven;
  1023. },
  1024. /*
  1025. * Configure Raven with a DSN and extra options
  1026. *
  1027. * @param {string} dsn The public Sentry DSN
  1028. * @param {object} options Optional set of of global options [optional]
  1029. * @return {Raven}
  1030. */
  1031. config: function(dsn, options) {
  1032. if (!dsn) return Raven;
  1033. var uri = parseDSN(dsn),
  1034. lastSlash = uri.path.lastIndexOf('/'),
  1035. path = uri.path.substr(1, lastSlash);
  1036. // merge in options
  1037. if (options) {
  1038. each(options, function(key, value){
  1039. globalOptions[key] = value;
  1040. });
  1041. }
  1042. // "Script error." is hard coded into browsers for errors that it can't read.
  1043. // this is the result of a script being pulled in from an external domain and CORS.
  1044. globalOptions.ignoreErrors.push('Script error.');
  1045. globalOptions.ignoreErrors.push('Script error');
  1046. // join regexp rules into one big rule
  1047. globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
  1048. globalOptions.ignoreUrls = globalOptions.ignoreUrls.length ? joinRegExp(globalOptions.ignoreUrls) : false;
  1049. globalOptions.whitelistUrls = globalOptions.whitelistUrls.length ? joinRegExp(globalOptions.whitelistUrls) : false;
  1050. globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
  1051. globalKey = uri.user;
  1052. globalProject = uri.path.substr(lastSlash + 1);
  1053. // assemble the endpoint from the uri pieces
  1054. globalServer = '//' + uri.host +
  1055. (uri.port ? ':' + uri.port : '') +
  1056. '/' + path + 'api/' + globalProject + '/store/';
  1057. if (uri.protocol) {
  1058. globalServer = uri.protocol + ':' + globalServer;
  1059. }
  1060. if (globalOptions.fetchContext) {
  1061. TraceKit.remoteFetching = true;
  1062. }
  1063. if (globalOptions.linesOfContext) {
  1064. TraceKit.linesOfContext = globalOptions.linesOfContext;
  1065. }
  1066. TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
  1067. // return for chaining
  1068. return Raven;
  1069. },
  1070. /*
  1071. * Installs a global window.onerror error handler
  1072. * to capture and report uncaught exceptions.
  1073. * At this point, install() is required to be called due
  1074. * to the way TraceKit is set up.
  1075. *
  1076. * @return {Raven}
  1077. */
  1078. install: function() {
  1079. if (isSetup()) {
  1080. TraceKit.report.subscribe(handleStackInfo);
  1081. }
  1082. return Raven;
  1083. },
  1084. /*
  1085. * Wrap code within a context so Raven can capture errors
  1086. * reliably across domains that is executed immediately.
  1087. *
  1088. * @param {object} options A specific set of options for this context [optional]
  1089. * @param {function} func The callback to be immediately executed within the context
  1090. * @param {array} args An array of arguments to be called with the callback [optional]
  1091. */
  1092. context: function(options, func, args) {
  1093. if (isFunction(options)) {
  1094. args = func || [];
  1095. func = options;
  1096. options = undefined;
  1097. }
  1098. return Raven.wrap(options, func).apply(this, args);
  1099. },
  1100. /*
  1101. * Wrap code within a context and returns back a new function to be executed
  1102. *
  1103. * @param {object} options A specific set of options for this context [optional]
  1104. * @param {function} func The function to be wrapped in a new context
  1105. * @return {function} The newly wrapped functions with a context
  1106. */
  1107. wrap: function(options, func) {
  1108. // 1 argument has been passed, and it's not a function
  1109. // so just return it
  1110. if (isUndefined(func) && !isFunction(options)) {
  1111. return options;
  1112. }
  1113. // options is optional
  1114. if (isFunction(options)) {
  1115. func = options;
  1116. options = undefined;
  1117. }
  1118. // At this point, we've passed along 2 arguments, and the second one
  1119. // is not a function either, so we'll just return the second argument.
  1120. if (!isFunction(func)) {
  1121. return func;
  1122. }
  1123. // We don't wanna wrap it twice!
  1124. if (func.__raven__) {
  1125. return func;
  1126. }
  1127. function wrapped() {
  1128. var args = [], i = arguments.length,
  1129. deep = !options || options && options.deep !== false;
  1130. // Recursively wrap all of a function's arguments that are
  1131. // functions themselves.
  1132. while(i--) args[i] = deep ? Raven.wrap(options, arguments[i]) : arguments[i];
  1133. try {
  1134. /*jshint -W040*/
  1135. return func.apply(this, args);
  1136. } catch(e) {
  1137. Raven.captureException(e, options);
  1138. throw e;
  1139. }
  1140. }
  1141. // copy over properties of the old function
  1142. for (var property in func) {
  1143. if (func.hasOwnProperty(property)) {
  1144. wrapped[property] = func[property];
  1145. }
  1146. }
  1147. // Signal that this function has been wrapped already
  1148. // for both debugging and to prevent it to being wrapped twice
  1149. wrapped.__raven__ = true;
  1150. return wrapped;
  1151. },
  1152. /*
  1153. * Uninstalls the global error handler.
  1154. *
  1155. * @return {Raven}
  1156. */
  1157. uninstall: function() {
  1158. TraceKit.report.uninstall();
  1159. return Raven;
  1160. },
  1161. /*
  1162. * Manually capture an exception and send it over to Sentry
  1163. *
  1164. * @param {error} ex An exception to be logged
  1165. * @param {object} options A specific set of options for this error [optional]
  1166. * @return {Raven}
  1167. */
  1168. captureException: function(ex, options) {
  1169. // If a string is passed through, recall as a message
  1170. if (isString(ex)) return Raven.captureMessage(ex, options);
  1171. // Store the raw exception object for potential debugging and introspection
  1172. lastCapturedException = ex;
  1173. // TraceKit.report will re-raise any exception passed to it,
  1174. // which means you have to wrap it in try/catch. Instead, we
  1175. // can wrap it here and only re-raise if TraceKit.report
  1176. // raises an exception different from the one we asked to
  1177. // report on.
  1178. try {
  1179. TraceKit.report(ex, options);
  1180. } catch(ex1) {
  1181. if(ex !== ex1) {
  1182. throw ex1;
  1183. }
  1184. }
  1185. return Raven;
  1186. },
  1187. /*
  1188. * Manually send a message to Sentry
  1189. *
  1190. * @param {string} msg A plain message to be captured in Sentry
  1191. * @param {object} options A specific set of options for this message [optional]
  1192. * @return {Raven}
  1193. */
  1194. captureMessage: function(msg, options) {
  1195. // Fire away!
  1196. send(
  1197. objectMerge({
  1198. message: msg
  1199. }, options)
  1200. );
  1201. return Raven;
  1202. },
  1203. /*
  1204. * Set/clear a user to be sent along with the payload.
  1205. *
  1206. * @param {object} user An object representing user data [optional]
  1207. * @return {Raven}
  1208. */
  1209. setUser: function(user) {
  1210. globalUser = user;
  1211. return Raven;
  1212. },
  1213. /*
  1214. * Get the latest raw exception that was captured by Raven.
  1215. *
  1216. * @return {error}
  1217. */
  1218. lastException: function() {
  1219. return lastCapturedException;
  1220. },
  1221. /*
  1222. * Get the last event id
  1223. *
  1224. * @return {string}
  1225. */
  1226. lastEventId: function() {
  1227. return lastEventId;
  1228. }
  1229. };
  1230. function triggerEvent(eventType, options) {
  1231. var event, key;
  1232. options = options || {};
  1233. eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
  1234. if (document.createEvent) {
  1235. event = document.createEvent('HTMLEvents');
  1236. event.initEvent(eventType, true, true);
  1237. } else {
  1238. event = document.createEventObject();
  1239. event.eventType = eventType;
  1240. }
  1241. for (key in options) if (options.hasOwnProperty(key)) {
  1242. event[key] = options[key];
  1243. }
  1244. if (document.createEvent) {
  1245. // IE9 if standards
  1246. document.dispatchEvent(event);
  1247. } else {
  1248. // IE8 regardless of Quirks or Standards
  1249. // IE9 if quirks
  1250. try {
  1251. document.fireEvent('on' + event.eventType.toLowerCase(), event);
  1252. } catch(e) {}
  1253. }
  1254. }
  1255. var dsnKeys = 'source protocol user pass host port path'.split(' '),
  1256. dsnPattern = /^(?:(\w+):)?\/\/(\w+)(:\w+)?@([\w\.-]+)(?::(\d+))?(\/.*)/;
  1257. function RavenConfigError(message) {
  1258. this.name = 'RavenConfigError';
  1259. this.message = message;
  1260. }
  1261. RavenConfigError.prototype = new Error();
  1262. RavenConfigError.prototype.constructor = RavenConfigError;
  1263. /**** Private functions ****/
  1264. function parseDSN(str) {
  1265. var m = dsnPattern.exec(str),
  1266. dsn = {},
  1267. i = 7;
  1268. try {
  1269. while (i--) dsn[dsnKeys[i]] = m[i] || '';
  1270. } catch(e) {
  1271. throw new RavenConfigError('Invalid DSN: ' + str);
  1272. }
  1273. if (dsn.pass)
  1274. throw new RavenConfigError('Do not specify your private key in the DSN!');
  1275. return dsn;
  1276. }
  1277. function isUndefined(what) {
  1278. return typeof what === 'undefined';
  1279. }
  1280. function isFunction(what) {
  1281. return typeof what === 'function';
  1282. }
  1283. function isString(what) {
  1284. return typeof what === 'string';
  1285. }
  1286. function isEmptyObject(what) {
  1287. for (var k in what) return false;
  1288. return true;
  1289. }
  1290. /**
  1291. * hasKey, a better form of hasOwnProperty
  1292. * Example: hasKey(MainHostObject, property) === true/false
  1293. *
  1294. * @param {Object} host object to check property
  1295. * @param {string} key to check
  1296. */
  1297. function hasKey(object, key) {
  1298. return Object.prototype.hasOwnProperty.call(object, key);
  1299. }
  1300. function each(obj, callback) {
  1301. var i, j;
  1302. if (isUndefined(obj.length)) {
  1303. for (i in obj) {
  1304. if (obj.hasOwnProperty(i)) {
  1305. callback.call(null, i, obj[i]);
  1306. }
  1307. }
  1308. } else {
  1309. j = obj.length;
  1310. if (j) {
  1311. for (i = 0; i < j; i++) {
  1312. callback.call(null, i, obj[i]);
  1313. }
  1314. }
  1315. }
  1316. }
  1317. var cachedAuth;
  1318. function getAuthQueryString() {
  1319. if (cachedAuth) return cachedAuth;
  1320. var qs = [
  1321. 'sentry_version=4',
  1322. 'sentry_client=raven-js/' + Raven.VERSION
  1323. ];
  1324. if (globalKey) {
  1325. qs.push('sentry_key=' + globalKey);
  1326. }
  1327. cachedAuth = '?' + qs.join('&');
  1328. return cachedAuth;
  1329. }
  1330. function handleStackInfo(stackInfo, options) {
  1331. var frames = [];
  1332. if (stackInfo.stack && stackInfo.stack.length) {
  1333. each(stackInfo.stack, function(i, stack) {
  1334. var frame = normalizeFrame(stack);
  1335. if (frame) {
  1336. frames.push(frame);
  1337. }
  1338. });
  1339. }
  1340. triggerEvent('handle', {
  1341. stackInfo: stackInfo,
  1342. options: opti

Large files files are truncated, but you can click here to view the full file