ravenjs-gem 1.0.7.0 → 1.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTdlOWVkODFhNGJlYjU3OTFjMGNkOWExMjllNTQ5OTY1MTA1NGI4MA==
5
+ data.tar.gz: !binary |-
6
+ OGQyMmIxMTM0NWZkZDFjYWQzYTI1OTFiZmI3NWQ4MWUzOGQ3ZTc1Yw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NGM2NWE1YTkzODg5NzJjM2IzMTg5OWU5MDliYTRjY2QyOWZlYmQzYmM1ZWIz
10
+ OTY2MGM5NGUzYjNjYWM5ZjA2MDRhMmY1NDdjMzQ0MTQ3YzA3OTMwMzRlODBl
11
+ Zjg1ZGJjZGFiNzRhMmYyYjUyMDc2NjU2ZTkxYzlkZjJhMzhmZTY=
12
+ data.tar.gz: !binary |-
13
+ ZDllNzU0NjBlZjk3NDE4ODAwNTZmMjViMTk0NGY3MjRlZDU5MmNjMGYzZDE0
14
+ MTY2MDNjMzNkNjAyZTc0YWY4MTFlZDQ2ZTNlNTA2ZjE3M2Q0MzliODUxN2Mw
15
+ N2JhYmJkOTMyNTAyZGYyMWNlNjcyMGNjNWUxZjNiYTQwZjUzYjM=
@@ -1,3 +1,3 @@
1
1
  module RavenjsGem
2
- VERSION = "1.0.7.0"
2
+ VERSION = "1.1.14"
3
3
  end
@@ -0,0 +1,1825 @@
1
+ /*! Raven.js 1.1.14 (f9803bd) | github.com/getsentry/raven-js */
2
+
3
+ /*
4
+ * Includes TraceKit
5
+ * https://github.com/getsentry/TraceKit
6
+ *
7
+ * Copyright 2014 Matt Robenolt and other contributors
8
+ * Released under the BSD license
9
+ * https://github.com/getsentry/raven-js/blob/master/LICENSE
10
+ *
11
+ */
12
+ ;(function(window, undefined){
13
+ 'use strict';
14
+
15
+ /*
16
+ TraceKit - Cross brower stack traces - github.com/occ/TraceKit
17
+ MIT license
18
+ */
19
+
20
+ var TraceKit = {
21
+ remoteFetching: false,
22
+ collectWindowErrors: true,
23
+ // 3 lines before, the offending line, 3 lines after
24
+ linesOfContext: 7
25
+ };
26
+
27
+ // global reference to slice
28
+ var _slice = [].slice;
29
+ var UNKNOWN_FUNCTION = '?';
30
+
31
+
32
+ /**
33
+ * TraceKit.wrap: Wrap any function in a TraceKit reporter
34
+ * Example: func = TraceKit.wrap(func);
35
+ *
36
+ * @param {Function} func Function to be wrapped
37
+ * @return {Function} The wrapped func
38
+ */
39
+ TraceKit.wrap = function traceKitWrapper(func) {
40
+ function wrapped() {
41
+ try {
42
+ return func.apply(this, arguments);
43
+ } catch (e) {
44
+ TraceKit.report(e);
45
+ throw e;
46
+ }
47
+ }
48
+ return wrapped;
49
+ };
50
+
51
+ /**
52
+ * TraceKit.report: cross-browser processing of unhandled exceptions
53
+ *
54
+ * Syntax:
55
+ * TraceKit.report.subscribe(function(stackInfo) { ... })
56
+ * TraceKit.report.unsubscribe(function(stackInfo) { ... })
57
+ * TraceKit.report(exception)
58
+ * try { ...code... } catch(ex) { TraceKit.report(ex); }
59
+ *
60
+ * Supports:
61
+ * - Firefox: full stack trace with line numbers, plus column number
62
+ * on top frame; column number is not guaranteed
63
+ * - Opera: full stack trace with line and column numbers
64
+ * - Chrome: full stack trace with line and column numbers
65
+ * - Safari: line and column number for the top frame only; some frames
66
+ * may be missing, and column number is not guaranteed
67
+ * - IE: line and column number for the top frame only; some frames
68
+ * may be missing, and column number is not guaranteed
69
+ *
70
+ * In theory, TraceKit should work on all of the following versions:
71
+ * - IE5.5+ (only 8.0 tested)
72
+ * - Firefox 0.9+ (only 3.5+ tested)
73
+ * - Opera 7+ (only 10.50 tested; versions 9 and earlier may require
74
+ * Exceptions Have Stacktrace to be enabled in opera:config)
75
+ * - Safari 3+ (only 4+ tested)
76
+ * - Chrome 1+ (only 5+ tested)
77
+ * - Konqueror 3.5+ (untested)
78
+ *
79
+ * Requires TraceKit.computeStackTrace.
80
+ *
81
+ * Tries to catch all unhandled exceptions and report them to the
82
+ * subscribed handlers. Please note that TraceKit.report will rethrow the
83
+ * exception. This is REQUIRED in order to get a useful stack trace in IE.
84
+ * If the exception does not reach the top of the browser, you will only
85
+ * get a stack trace from the point where TraceKit.report was called.
86
+ *
87
+ * Handlers receive a stackInfo object as described in the
88
+ * TraceKit.computeStackTrace docs.
89
+ */
90
+ TraceKit.report = (function reportModuleWrapper() {
91
+ var handlers = [],
92
+ lastArgs = null,
93
+ lastException = null,
94
+ lastExceptionStack = null;
95
+
96
+ /**
97
+ * Add a crash handler.
98
+ * @param {Function} handler
99
+ */
100
+ function subscribe(handler) {
101
+ installGlobalHandler();
102
+ handlers.push(handler);
103
+ }
104
+
105
+ /**
106
+ * Remove a crash handler.
107
+ * @param {Function} handler
108
+ */
109
+ function unsubscribe(handler) {
110
+ for (var i = handlers.length - 1; i >= 0; --i) {
111
+ if (handlers[i] === handler) {
112
+ handlers.splice(i, 1);
113
+ }
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Remove all crash handlers.
119
+ */
120
+ function unsubscribeAll() {
121
+ uninstallGlobalHandler();
122
+ handlers = [];
123
+ }
124
+
125
+ /**
126
+ * Dispatch stack information to all handlers.
127
+ * @param {Object.<string, *>} stack
128
+ */
129
+ function notifyHandlers(stack, isWindowError) {
130
+ var exception = null;
131
+ if (isWindowError && !TraceKit.collectWindowErrors) {
132
+ return;
133
+ }
134
+ for (var i in handlers) {
135
+ if (hasKey(handlers, i)) {
136
+ try {
137
+ handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2)));
138
+ } catch (inner) {
139
+ exception = inner;
140
+ }
141
+ }
142
+ }
143
+
144
+ if (exception) {
145
+ throw exception;
146
+ }
147
+ }
148
+
149
+ var _oldOnerrorHandler, _onErrorHandlerInstalled;
150
+
151
+ /**
152
+ * Ensures all global unhandled exceptions are recorded.
153
+ * Supported by Gecko and IE.
154
+ * @param {string} message Error message.
155
+ * @param {string} url URL of script that generated the exception.
156
+ * @param {(number|string)} lineNo The line number at which the error
157
+ * occurred.
158
+ * @param {?(number|string)} colNo The column number at which the error
159
+ * occurred.
160
+ * @param {?Error} ex The actual Error object.
161
+ */
162
+ function traceKitWindowOnError(message, url, lineNo, colNo, ex) {
163
+ var stack = null;
164
+
165
+ if (lastExceptionStack) {
166
+ TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(lastExceptionStack, url, lineNo, message);
167
+ processLastException();
168
+ } else if (ex) {
169
+ // New chrome and blink send along a real error object
170
+ // Let's just report that like a normal error.
171
+ // See: https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
172
+ stack = TraceKit.computeStackTrace(ex);
173
+ notifyHandlers(stack, true);
174
+ } else {
175
+ var location = {
176
+ 'url': url,
177
+ 'line': lineNo,
178
+ 'column': colNo
179
+ };
180
+ location.func = TraceKit.computeStackTrace.guessFunctionName(location.url, location.line);
181
+ location.context = TraceKit.computeStackTrace.gatherContext(location.url, location.line);
182
+ stack = {
183
+ 'message': message,
184
+ 'url': document.location.href,
185
+ 'stack': [location]
186
+ };
187
+ notifyHandlers(stack, true);
188
+ }
189
+
190
+ if (_oldOnerrorHandler) {
191
+ return _oldOnerrorHandler.apply(this, arguments);
192
+ }
193
+
194
+ return false;
195
+ }
196
+
197
+ function installGlobalHandler ()
198
+ {
199
+ if (_onErrorHandlerInstalled) {
200
+ return;
201
+ }
202
+ _oldOnerrorHandler = window.onerror;
203
+ window.onerror = traceKitWindowOnError;
204
+ _onErrorHandlerInstalled = true;
205
+ }
206
+
207
+ function uninstallGlobalHandler ()
208
+ {
209
+ if (!_onErrorHandlerInstalled) {
210
+ return;
211
+ }
212
+ window.onerror = _oldOnerrorHandler;
213
+ _onErrorHandlerInstalled = false;
214
+ _oldOnerrorHandler = undefined;
215
+ }
216
+
217
+ function processLastException() {
218
+ var _lastExceptionStack = lastExceptionStack,
219
+ _lastArgs = lastArgs;
220
+ lastArgs = null;
221
+ lastExceptionStack = null;
222
+ lastException = null;
223
+ notifyHandlers.apply(null, [_lastExceptionStack, false].concat(_lastArgs));
224
+ }
225
+
226
+ /**
227
+ * Reports an unhandled Error to TraceKit.
228
+ * @param {Error} ex
229
+ * @param {?boolean} rethrow If false, do not re-throw the exception.
230
+ * Only used for window.onerror to not cause an infinite loop of
231
+ * rethrowing.
232
+ */
233
+ function report(ex, rethrow) {
234
+ var args = _slice.call(arguments, 1);
235
+ if (lastExceptionStack) {
236
+ if (lastException === ex) {
237
+ return; // already caught by an inner catch block, ignore
238
+ } else {
239
+ processLastException();
240
+ }
241
+ }
242
+
243
+ var stack = TraceKit.computeStackTrace(ex);
244
+ lastExceptionStack = stack;
245
+ lastException = ex;
246
+ lastArgs = args;
247
+
248
+ // If the stack trace is incomplete, wait for 2 seconds for
249
+ // slow slow IE to see if onerror occurs or not before reporting
250
+ // this exception; otherwise, we will end up with an incomplete
251
+ // stack trace
252
+ window.setTimeout(function () {
253
+ if (lastException === ex) {
254
+ processLastException();
255
+ }
256
+ }, (stack.incomplete ? 2000 : 0));
257
+
258
+ if (rethrow !== false) {
259
+ throw ex; // re-throw to propagate to the top level (and cause window.onerror)
260
+ }
261
+ }
262
+
263
+ report.subscribe = subscribe;
264
+ report.unsubscribe = unsubscribe;
265
+ report.uninstall = unsubscribeAll;
266
+ return report;
267
+ }());
268
+
269
+ /**
270
+ * TraceKit.computeStackTrace: cross-browser stack traces in JavaScript
271
+ *
272
+ * Syntax:
273
+ * s = TraceKit.computeStackTrace.ofCaller([depth])
274
+ * s = TraceKit.computeStackTrace(exception) // consider using TraceKit.report instead (see below)
275
+ * Returns:
276
+ * s.name - exception name
277
+ * s.message - exception message
278
+ * s.stack[i].url - JavaScript or HTML file URL
279
+ * s.stack[i].func - function name, or empty for anonymous functions (if guessing did not work)
280
+ * s.stack[i].args - arguments passed to the function, if known
281
+ * s.stack[i].line - line number, if known
282
+ * s.stack[i].column - column number, if known
283
+ * s.stack[i].context - an array of source code lines; the middle element corresponds to the correct line#
284
+ *
285
+ * Supports:
286
+ * - Firefox: full stack trace with line numbers and unreliable column
287
+ * number on top frame
288
+ * - Opera 10: full stack trace with line and column numbers
289
+ * - Opera 9-: full stack trace with line numbers
290
+ * - Chrome: full stack trace with line and column numbers
291
+ * - Safari: line and column number for the topmost stacktrace element
292
+ * only
293
+ * - IE: no line numbers whatsoever
294
+ *
295
+ * Tries to guess names of anonymous functions by looking for assignments
296
+ * in the source code. In IE and Safari, we have to guess source file names
297
+ * by searching for function bodies inside all page scripts. This will not
298
+ * work for scripts that are loaded cross-domain.
299
+ * Here be dragons: some function names may be guessed incorrectly, and
300
+ * duplicate functions may be mismatched.
301
+ *
302
+ * TraceKit.computeStackTrace should only be used for tracing purposes.
303
+ * Logging of unhandled exceptions should be done with TraceKit.report,
304
+ * which builds on top of TraceKit.computeStackTrace and provides better
305
+ * IE support by utilizing the window.onerror event to retrieve information
306
+ * about the top of the stack.
307
+ *
308
+ * Note: In IE and Safari, no stack trace is recorded on the Error object,
309
+ * so computeStackTrace instead walks its *own* chain of callers.
310
+ * This means that:
311
+ * * in Safari, some methods may be missing from the stack trace;
312
+ * * in IE, the topmost function in the stack trace will always be the
313
+ * caller of computeStackTrace.
314
+ *
315
+ * This is okay for tracing (because you are likely to be calling
316
+ * computeStackTrace from the function you want to be the topmost element
317
+ * of the stack trace anyway), but not okay for logging unhandled
318
+ * exceptions (because your catch block will likely be far away from the
319
+ * inner function that actually caused the exception).
320
+ *
321
+ * Tracing example:
322
+ * function trace(message) {
323
+ * var stackInfo = TraceKit.computeStackTrace.ofCaller();
324
+ * var data = message + "\n";
325
+ * for(var i in stackInfo.stack) {
326
+ * var item = stackInfo.stack[i];
327
+ * data += (item.func || '[anonymous]') + "() in " + item.url + ":" + (item.line || '0') + "\n";
328
+ * }
329
+ * if (window.console)
330
+ * console.info(data);
331
+ * else
332
+ * alert(data);
333
+ * }
334
+ */
335
+ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
336
+ var debug = false,
337
+ sourceCache = {};
338
+
339
+ /**
340
+ * Attempts to retrieve source code via XMLHttpRequest, which is used
341
+ * to look up anonymous function names.
342
+ * @param {string} url URL of source code.
343
+ * @return {string} Source contents.
344
+ */
345
+ function loadSource(url) {
346
+ if (!TraceKit.remoteFetching) { //Only attempt request if remoteFetching is on.
347
+ return '';
348
+ }
349
+ try {
350
+ var getXHR = function() {
351
+ try {
352
+ return new window.XMLHttpRequest();
353
+ } catch (e) {
354
+ // explicitly bubble up the exception if not found
355
+ return new window.ActiveXObject('Microsoft.XMLHTTP');
356
+ }
357
+ };
358
+
359
+ var request = getXHR();
360
+ request.open('GET', url, false);
361
+ request.send('');
362
+ return request.responseText;
363
+ } catch (e) {
364
+ return '';
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Retrieves source code from the source code cache.
370
+ * @param {string} url URL of source code.
371
+ * @return {Array.<string>} Source contents.
372
+ */
373
+ function getSource(url) {
374
+ if (!isString(url)) return [];
375
+ if (!hasKey(sourceCache, url)) {
376
+ // URL needs to be able to fetched within the acceptable domain. Otherwise,
377
+ // cross-domain errors will be triggered.
378
+ var source = '';
379
+ if (url.indexOf(document.domain) !== -1) {
380
+ source = loadSource(url);
381
+ }
382
+ sourceCache[url] = source ? source.split('\n') : [];
383
+ }
384
+
385
+ return sourceCache[url];
386
+ }
387
+
388
+ /**
389
+ * Tries to use an externally loaded copy of source code to determine
390
+ * the name of a function by looking at the name of the variable it was
391
+ * assigned to, if any.
392
+ * @param {string} url URL of source code.
393
+ * @param {(string|number)} lineNo Line number in source code.
394
+ * @return {string} The function name, if discoverable.
395
+ */
396
+ function guessFunctionName(url, lineNo) {
397
+ var reFunctionArgNames = /function ([^(]*)\(([^)]*)\)/,
398
+ reGuessFunction = /['"]?([0-9A-Za-z$_]+)['"]?\s*[:=]\s*(function|eval|new Function)/,
399
+ line = '',
400
+ maxLines = 10,
401
+ source = getSource(url),
402
+ m;
403
+
404
+ if (!source.length) {
405
+ return UNKNOWN_FUNCTION;
406
+ }
407
+
408
+ // Walk backwards from the first line in the function until we find the line which
409
+ // matches the pattern above, which is the function definition
410
+ for (var i = 0; i < maxLines; ++i) {
411
+ line = source[lineNo - i] + line;
412
+
413
+ if (!isUndefined(line)) {
414
+ if ((m = reGuessFunction.exec(line))) {
415
+ return m[1];
416
+ } else if ((m = reFunctionArgNames.exec(line))) {
417
+ return m[1];
418
+ }
419
+ }
420
+ }
421
+
422
+ return UNKNOWN_FUNCTION;
423
+ }
424
+
425
+ /**
426
+ * Retrieves the surrounding lines from where an exception occurred.
427
+ * @param {string} url URL of source code.
428
+ * @param {(string|number)} line Line number in source code to centre
429
+ * around for context.
430
+ * @return {?Array.<string>} Lines of source code.
431
+ */
432
+ function gatherContext(url, line) {
433
+ var source = getSource(url);
434
+
435
+ if (!source.length) {
436
+ return null;
437
+ }
438
+
439
+ var context = [],
440
+ // linesBefore & linesAfter are inclusive with the offending line.
441
+ // if linesOfContext is even, there will be one extra line
442
+ // *before* the offending line.
443
+ linesBefore = Math.floor(TraceKit.linesOfContext / 2),
444
+ // Add one extra line if linesOfContext is odd
445
+ linesAfter = linesBefore + (TraceKit.linesOfContext % 2),
446
+ start = Math.max(0, line - linesBefore - 1),
447
+ end = Math.min(source.length, line + linesAfter - 1);
448
+
449
+ line -= 1; // convert to 0-based index
450
+
451
+ for (var i = start; i < end; ++i) {
452
+ if (!isUndefined(source[i])) {
453
+ context.push(source[i]);
454
+ }
455
+ }
456
+
457
+ return context.length > 0 ? context : null;
458
+ }
459
+
460
+ /**
461
+ * Escapes special characters, except for whitespace, in a string to be
462
+ * used inside a regular expression as a string literal.
463
+ * @param {string} text The string.
464
+ * @return {string} The escaped string literal.
465
+ */
466
+ function escapeRegExp(text) {
467
+ return text.replace(/[\-\[\]{}()*+?.,\\\^$|#]/g, '\\$&');
468
+ }
469
+
470
+ /**
471
+ * Escapes special characters in a string to be used inside a regular
472
+ * expression as a string literal. Also ensures that HTML entities will
473
+ * be matched the same as their literal friends.
474
+ * @param {string} body The string.
475
+ * @return {string} The escaped string.
476
+ */
477
+ function escapeCodeAsRegExpForMatchingInsideHTML(body) {
478
+ return escapeRegExp(body).replace('<', '(?:<|&lt;)').replace('>', '(?:>|&gt;)').replace('&', '(?:&|&amp;)').replace('"', '(?:"|&quot;)').replace(/\s+/g, '\\s+');
479
+ }
480
+
481
+ /**
482
+ * Determines where a code fragment occurs in the source code.
483
+ * @param {RegExp} re The function definition.
484
+ * @param {Array.<string>} urls A list of URLs to search.
485
+ * @return {?Object.<string, (string|number)>} An object containing
486
+ * the url, line, and column number of the defined function.
487
+ */
488
+ function findSourceInUrls(re, urls) {
489
+ var source, m;
490
+ for (var i = 0, j = urls.length; i < j; ++i) {
491
+ // console.log('searching', urls[i]);
492
+ if ((source = getSource(urls[i])).length) {
493
+ source = source.join('\n');
494
+ if ((m = re.exec(source))) {
495
+ // console.log('Found function in ' + urls[i]);
496
+
497
+ return {
498
+ 'url': urls[i],
499
+ 'line': source.substring(0, m.index).split('\n').length,
500
+ 'column': m.index - source.lastIndexOf('\n', m.index) - 1
501
+ };
502
+ }
503
+ }
504
+ }
505
+
506
+ // console.log('no match');
507
+
508
+ return null;
509
+ }
510
+
511
+ /**
512
+ * Determines at which column a code fragment occurs on a line of the
513
+ * source code.
514
+ * @param {string} fragment The code fragment.
515
+ * @param {string} url The URL to search.
516
+ * @param {(string|number)} line The line number to examine.
517
+ * @return {?number} The column number.
518
+ */
519
+ function findSourceInLine(fragment, url, line) {
520
+ var source = getSource(url),
521
+ re = new RegExp('\\b' + escapeRegExp(fragment) + '\\b'),
522
+ m;
523
+
524
+ line -= 1;
525
+
526
+ if (source && source.length > line && (m = re.exec(source[line]))) {
527
+ return m.index;
528
+ }
529
+
530
+ return null;
531
+ }
532
+
533
+ /**
534
+ * Determines where a function was defined within the source code.
535
+ * @param {(Function|string)} func A function reference or serialized
536
+ * function definition.
537
+ * @return {?Object.<string, (string|number)>} An object containing
538
+ * the url, line, and column number of the defined function.
539
+ */
540
+ function findSourceByFunctionBody(func) {
541
+ var urls = [window.location.href],
542
+ scripts = document.getElementsByTagName('script'),
543
+ body,
544
+ code = '' + func,
545
+ codeRE = /^function(?:\s+([\w$]+))?\s*\(([\w\s,]*)\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/,
546
+ eventRE = /^function on([\w$]+)\s*\(event\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/,
547
+ re,
548
+ parts,
549
+ result;
550
+
551
+ for (var i = 0; i < scripts.length; ++i) {
552
+ var script = scripts[i];
553
+ if (script.src) {
554
+ urls.push(script.src);
555
+ }
556
+ }
557
+
558
+ if (!(parts = codeRE.exec(code))) {
559
+ re = new RegExp(escapeRegExp(code).replace(/\s+/g, '\\s+'));
560
+ }
561
+
562
+ // not sure if this is really necessary, but I don’t have a test
563
+ // corpus large enough to confirm that and it was in the original.
564
+ else {
565
+ var name = parts[1] ? '\\s+' + parts[1] : '',
566
+ args = parts[2].split(',').join('\\s*,\\s*');
567
+
568
+ body = escapeRegExp(parts[3]).replace(/;$/, ';?'); // semicolon is inserted if the function ends with a comment.replace(/\s+/g, '\\s+');
569
+ re = new RegExp('function' + name + '\\s*\\(\\s*' + args + '\\s*\\)\\s*{\\s*' + body + '\\s*}');
570
+ }
571
+
572
+ // look for a normal function definition
573
+ if ((result = findSourceInUrls(re, urls))) {
574
+ return result;
575
+ }
576
+
577
+ // look for an old-school event handler function
578
+ if ((parts = eventRE.exec(code))) {
579
+ var event = parts[1];
580
+ body = escapeCodeAsRegExpForMatchingInsideHTML(parts[2]);
581
+
582
+ // look for a function defined in HTML as an onXXX handler
583
+ re = new RegExp('on' + event + '=[\\\'"]\\s*' + body + '\\s*[\\\'"]', 'i');
584
+
585
+ if ((result = findSourceInUrls(re, urls[0]))) {
586
+ return result;
587
+ }
588
+
589
+ // look for ???
590
+ re = new RegExp(body);
591
+
592
+ if ((result = findSourceInUrls(re, urls))) {
593
+ return result;
594
+ }
595
+ }
596
+
597
+ return null;
598
+ }
599
+
600
+ // Contents of Exception in various browsers.
601
+ //
602
+ // SAFARI:
603
+ // ex.message = Can't find variable: qq
604
+ // ex.line = 59
605
+ // ex.sourceId = 580238192
606
+ // ex.sourceURL = http://...
607
+ // ex.expressionBeginOffset = 96
608
+ // ex.expressionCaretOffset = 98
609
+ // ex.expressionEndOffset = 98
610
+ // ex.name = ReferenceError
611
+ //
612
+ // FIREFOX:
613
+ // ex.message = qq is not defined
614
+ // ex.fileName = http://...
615
+ // ex.lineNumber = 59
616
+ // ex.columnNumber = 69
617
+ // ex.stack = ...stack trace... (see the example below)
618
+ // ex.name = ReferenceError
619
+ //
620
+ // CHROME:
621
+ // ex.message = qq is not defined
622
+ // ex.name = ReferenceError
623
+ // ex.type = not_defined
624
+ // ex.arguments = ['aa']
625
+ // ex.stack = ...stack trace...
626
+ //
627
+ // INTERNET EXPLORER:
628
+ // ex.message = ...
629
+ // ex.name = ReferenceError
630
+ //
631
+ // OPERA:
632
+ // ex.message = ...message... (see the example below)
633
+ // ex.name = ReferenceError
634
+ // ex.opera#sourceloc = 11 (pretty much useless, duplicates the info in ex.message)
635
+ // ex.stacktrace = n/a; see 'opera:config#UserPrefs|Exceptions Have Stacktrace'
636
+
637
+ /**
638
+ * Computes stack trace information from the stack property.
639
+ * Chrome and Gecko use this property.
640
+ * @param {Error} ex
641
+ * @return {?Object.<string, *>} Stack trace information.
642
+ */
643
+ function computeStackTraceFromStackProp(ex) {
644
+ if (!ex.stack) {
645
+ return null;
646
+ }
647
+
648
+ var chrome = /^\s*at (?:((?:\[object object\])?\S+(?: \[as \S+\])?) )?\(?((?:file|https?):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
649
+ gecko = /^\s*(\S*)(?:\((.*?)\))?@((?:file|https?).*?):(\d+)(?::(\d+))?\s*$/i,
650
+ lines = ex.stack.split('\n'),
651
+ stack = [],
652
+ parts,
653
+ element,
654
+ reference = /^(.*) is undefined$/.exec(ex.message);
655
+
656
+ for (var i = 0, j = lines.length; i < j; ++i) {
657
+ if ((parts = gecko.exec(lines[i]))) {
658
+ element = {
659
+ 'url': parts[3],
660
+ 'func': parts[1] || UNKNOWN_FUNCTION,
661
+ 'args': parts[2] ? parts[2].split(',') : '',
662
+ 'line': +parts[4],
663
+ 'column': parts[5] ? +parts[5] : null
664
+ };
665
+ } else if ((parts = chrome.exec(lines[i]))) {
666
+ element = {
667
+ 'url': parts[2],
668
+ 'func': parts[1] || UNKNOWN_FUNCTION,
669
+ 'line': +parts[3],
670
+ 'column': parts[4] ? +parts[4] : null
671
+ };
672
+ } else {
673
+ continue;
674
+ }
675
+
676
+ if (!element.func && element.line) {
677
+ element.func = guessFunctionName(element.url, element.line);
678
+ }
679
+
680
+ if (element.line) {
681
+ element.context = gatherContext(element.url, element.line);
682
+ }
683
+
684
+ stack.push(element);
685
+ }
686
+
687
+ if (!stack.length) {
688
+ return null;
689
+ }
690
+
691
+ if (stack[0].line && !stack[0].column && reference) {
692
+ stack[0].column = findSourceInLine(reference[1], stack[0].url, stack[0].line);
693
+ } else if (!stack[0].column && !isUndefined(ex.columnNumber)) {
694
+ // FireFox uses this awesome columnNumber property for its top frame
695
+ // Also note, Firefox's column number is 0-based and everything else expects 1-based,
696
+ // so adding 1
697
+ stack[0].column = ex.columnNumber + 1;
698
+ }
699
+
700
+ return {
701
+ 'name': ex.name,
702
+ 'message': ex.message,
703
+ 'url': document.location.href,
704
+ 'stack': stack
705
+ };
706
+ }
707
+
708
+ /**
709
+ * Computes stack trace information from the stacktrace property.
710
+ * Opera 10 uses this property.
711
+ * @param {Error} ex
712
+ * @return {?Object.<string, *>} Stack trace information.
713
+ */
714
+ function computeStackTraceFromStacktraceProp(ex) {
715
+ // Access and store the stacktrace property before doing ANYTHING
716
+ // else to it because Opera is not very good at providing it
717
+ // reliably in other circumstances.
718
+ var stacktrace = ex.stacktrace;
719
+
720
+ var testRE = / line (\d+), column (\d+) in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\) in (.*):\s*$/i,
721
+ lines = stacktrace.split('\n'),
722
+ stack = [],
723
+ parts;
724
+
725
+ for (var i = 0, j = lines.length; i < j; i += 2) {
726
+ if ((parts = testRE.exec(lines[i]))) {
727
+ var element = {
728
+ 'line': +parts[1],
729
+ 'column': +parts[2],
730
+ 'func': parts[3] || parts[4],
731
+ 'args': parts[5] ? parts[5].split(',') : [],
732
+ 'url': parts[6]
733
+ };
734
+
735
+ if (!element.func && element.line) {
736
+ element.func = guessFunctionName(element.url, element.line);
737
+ }
738
+ if (element.line) {
739
+ try {
740
+ element.context = gatherContext(element.url, element.line);
741
+ } catch (exc) {}
742
+ }
743
+
744
+ if (!element.context) {
745
+ element.context = [lines[i + 1]];
746
+ }
747
+
748
+ stack.push(element);
749
+ }
750
+ }
751
+
752
+ if (!stack.length) {
753
+ return null;
754
+ }
755
+
756
+ return {
757
+ 'name': ex.name,
758
+ 'message': ex.message,
759
+ 'url': document.location.href,
760
+ 'stack': stack
761
+ };
762
+ }
763
+
764
+ /**
765
+ * NOT TESTED.
766
+ * Computes stack trace information from an error message that includes
767
+ * the stack trace.
768
+ * Opera 9 and earlier use this method if the option to show stack
769
+ * traces is turned on in opera:config.
770
+ * @param {Error} ex
771
+ * @return {?Object.<string, *>} Stack information.
772
+ */
773
+ function computeStackTraceFromOperaMultiLineMessage(ex) {
774
+ // Opera includes a stack trace into the exception message. An example is:
775
+ //
776
+ // Statement on line 3: Undefined variable: undefinedFunc
777
+ // Backtrace:
778
+ // Line 3 of linked script file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.js: In function zzz
779
+ // undefinedFunc(a);
780
+ // Line 7 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function yyy
781
+ // zzz(x, y, z);
782
+ // Line 3 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function xxx
783
+ // yyy(a, a, a);
784
+ // Line 1 of function script
785
+ // try { xxx('hi'); return false; } catch(ex) { TraceKit.report(ex); }
786
+ // ...
787
+
788
+ var lines = ex.message.split('\n');
789
+ if (lines.length < 4) {
790
+ return null;
791
+ }
792
+
793
+ var lineRE1 = /^\s*Line (\d+) of linked script ((?:file|https?)\S+)(?:: in function (\S+))?\s*$/i,
794
+ lineRE2 = /^\s*Line (\d+) of inline#(\d+) script in ((?:file|https?)\S+)(?:: in function (\S+))?\s*$/i,
795
+ lineRE3 = /^\s*Line (\d+) of function script\s*$/i,
796
+ stack = [],
797
+ scripts = document.getElementsByTagName('script'),
798
+ inlineScriptBlocks = [],
799
+ parts,
800
+ i,
801
+ len,
802
+ source;
803
+
804
+ for (i in scripts) {
805
+ if (hasKey(scripts, i) && !scripts[i].src) {
806
+ inlineScriptBlocks.push(scripts[i]);
807
+ }
808
+ }
809
+
810
+ for (i = 2, len = lines.length; i < len; i += 2) {
811
+ var item = null;
812
+ if ((parts = lineRE1.exec(lines[i]))) {
813
+ item = {
814
+ 'url': parts[2],
815
+ 'func': parts[3],
816
+ 'line': +parts[1]
817
+ };
818
+ } else if ((parts = lineRE2.exec(lines[i]))) {
819
+ item = {
820
+ 'url': parts[3],
821
+ 'func': parts[4]
822
+ };
823
+ var relativeLine = (+parts[1]); // relative to the start of the <SCRIPT> block
824
+ var script = inlineScriptBlocks[parts[2] - 1];
825
+ if (script) {
826
+ source = getSource(item.url);
827
+ if (source) {
828
+ source = source.join('\n');
829
+ var pos = source.indexOf(script.innerText);
830
+ if (pos >= 0) {
831
+ item.line = relativeLine + source.substring(0, pos).split('\n').length;
832
+ }
833
+ }
834
+ }
835
+ } else if ((parts = lineRE3.exec(lines[i]))) {
836
+ var url = window.location.href.replace(/#.*$/, ''),
837
+ line = parts[1];
838
+ var re = new RegExp(escapeCodeAsRegExpForMatchingInsideHTML(lines[i + 1]));
839
+ source = findSourceInUrls(re, [url]);
840
+ item = {
841
+ 'url': url,
842
+ 'line': source ? source.line : line,
843
+ 'func': ''
844
+ };
845
+ }
846
+
847
+ if (item) {
848
+ if (!item.func) {
849
+ item.func = guessFunctionName(item.url, item.line);
850
+ }
851
+ var context = gatherContext(item.url, item.line);
852
+ var midline = (context ? context[Math.floor(context.length / 2)] : null);
853
+ if (context && midline.replace(/^\s*/, '') === lines[i + 1].replace(/^\s*/, '')) {
854
+ item.context = context;
855
+ } else {
856
+ // 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);
857
+ item.context = [lines[i + 1]];
858
+ }
859
+ stack.push(item);
860
+ }
861
+ }
862
+ if (!stack.length) {
863
+ return null; // could not parse multiline exception message as Opera stack trace
864
+ }
865
+
866
+ return {
867
+ 'name': ex.name,
868
+ 'message': lines[0],
869
+ 'url': document.location.href,
870
+ 'stack': stack
871
+ };
872
+ }
873
+
874
+ /**
875
+ * Adds information about the first frame to incomplete stack traces.
876
+ * Safari and IE require this to get complete data on the first frame.
877
+ * @param {Object.<string, *>} stackInfo Stack trace information from
878
+ * one of the compute* methods.
879
+ * @param {string} url The URL of the script that caused an error.
880
+ * @param {(number|string)} lineNo The line number of the script that
881
+ * caused an error.
882
+ * @param {string=} message The error generated by the browser, which
883
+ * hopefully contains the name of the object that caused the error.
884
+ * @return {boolean} Whether or not the stack information was
885
+ * augmented.
886
+ */
887
+ function augmentStackTraceWithInitialElement(stackInfo, url, lineNo, message) {
888
+ var initial = {
889
+ 'url': url,
890
+ 'line': lineNo
891
+ };
892
+
893
+ if (initial.url && initial.line) {
894
+ stackInfo.incomplete = false;
895
+
896
+ if (!initial.func) {
897
+ initial.func = guessFunctionName(initial.url, initial.line);
898
+ }
899
+
900
+ if (!initial.context) {
901
+ initial.context = gatherContext(initial.url, initial.line);
902
+ }
903
+
904
+ var reference = / '([^']+)' /.exec(message);
905
+ if (reference) {
906
+ initial.column = findSourceInLine(reference[1], initial.url, initial.line);
907
+ }
908
+
909
+ if (stackInfo.stack.length > 0) {
910
+ if (stackInfo.stack[0].url === initial.url) {
911
+ if (stackInfo.stack[0].line === initial.line) {
912
+ return false; // already in stack trace
913
+ } else if (!stackInfo.stack[0].line && stackInfo.stack[0].func === initial.func) {
914
+ stackInfo.stack[0].line = initial.line;
915
+ stackInfo.stack[0].context = initial.context;
916
+ return false;
917
+ }
918
+ }
919
+ }
920
+
921
+ stackInfo.stack.unshift(initial);
922
+ stackInfo.partial = true;
923
+ return true;
924
+ } else {
925
+ stackInfo.incomplete = true;
926
+ }
927
+
928
+ return false;
929
+ }
930
+
931
+ /**
932
+ * Computes stack trace information by walking the arguments.caller
933
+ * chain at the time the exception occurred. This will cause earlier
934
+ * frames to be missed but is the only way to get any stack trace in
935
+ * Safari and IE. The top frame is restored by
936
+ * {@link augmentStackTraceWithInitialElement}.
937
+ * @param {Error} ex
938
+ * @return {?Object.<string, *>} Stack trace information.
939
+ */
940
+ function computeStackTraceByWalkingCallerChain(ex, depth) {
941
+ var functionName = /function\s+([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)?\s*\(/i,
942
+ stack = [],
943
+ funcs = {},
944
+ recursion = false,
945
+ parts,
946
+ item,
947
+ source;
948
+
949
+ for (var curr = computeStackTraceByWalkingCallerChain.caller; curr && !recursion; curr = curr.caller) {
950
+ if (curr === computeStackTrace || curr === TraceKit.report) {
951
+ // console.log('skipping internal function');
952
+ continue;
953
+ }
954
+
955
+ item = {
956
+ 'url': null,
957
+ 'func': UNKNOWN_FUNCTION,
958
+ 'line': null,
959
+ 'column': null
960
+ };
961
+
962
+ if (curr.name) {
963
+ item.func = curr.name;
964
+ } else if ((parts = functionName.exec(curr.toString()))) {
965
+ item.func = parts[1];
966
+ }
967
+
968
+ if ((source = findSourceByFunctionBody(curr))) {
969
+ item.url = source.url;
970
+ item.line = source.line;
971
+
972
+ if (item.func === UNKNOWN_FUNCTION) {
973
+ item.func = guessFunctionName(item.url, item.line);
974
+ }
975
+
976
+ var reference = / '([^']+)' /.exec(ex.message || ex.description);
977
+ if (reference) {
978
+ item.column = findSourceInLine(reference[1], source.url, source.line);
979
+ }
980
+ }
981
+
982
+ if (funcs['' + curr]) {
983
+ recursion = true;
984
+ }else{
985
+ funcs['' + curr] = true;
986
+ }
987
+
988
+ stack.push(item);
989
+ }
990
+
991
+ if (depth) {
992
+ // console.log('depth is ' + depth);
993
+ // console.log('stack is ' + stack.length);
994
+ stack.splice(0, depth);
995
+ }
996
+
997
+ var result = {
998
+ 'name': ex.name,
999
+ 'message': ex.message,
1000
+ 'url': document.location.href,
1001
+ 'stack': stack
1002
+ };
1003
+ augmentStackTraceWithInitialElement(result, ex.sourceURL || ex.fileName, ex.line || ex.lineNumber, ex.message || ex.description);
1004
+ return result;
1005
+ }
1006
+
1007
+ /**
1008
+ * Computes a stack trace for an exception.
1009
+ * @param {Error} ex
1010
+ * @param {(string|number)=} depth
1011
+ */
1012
+ function computeStackTrace(ex, depth) {
1013
+ var stack = null;
1014
+ depth = (depth == null ? 0 : +depth);
1015
+
1016
+ try {
1017
+ // This must be tried first because Opera 10 *destroys*
1018
+ // its stacktrace property if you try to access the stack
1019
+ // property first!!
1020
+ stack = computeStackTraceFromStacktraceProp(ex);
1021
+ if (stack) {
1022
+ return stack;
1023
+ }
1024
+ } catch (e) {
1025
+ if (debug) {
1026
+ throw e;
1027
+ }
1028
+ }
1029
+
1030
+ try {
1031
+ stack = computeStackTraceFromStackProp(ex);
1032
+ if (stack) {
1033
+ return stack;
1034
+ }
1035
+ } catch (e) {
1036
+ if (debug) {
1037
+ throw e;
1038
+ }
1039
+ }
1040
+
1041
+ try {
1042
+ stack = computeStackTraceFromOperaMultiLineMessage(ex);
1043
+ if (stack) {
1044
+ return stack;
1045
+ }
1046
+ } catch (e) {
1047
+ if (debug) {
1048
+ throw e;
1049
+ }
1050
+ }
1051
+
1052
+ try {
1053
+ stack = computeStackTraceByWalkingCallerChain(ex, depth + 1);
1054
+ if (stack) {
1055
+ return stack;
1056
+ }
1057
+ } catch (e) {
1058
+ if (debug) {
1059
+ throw e;
1060
+ }
1061
+ }
1062
+
1063
+ return {};
1064
+ }
1065
+
1066
+ /**
1067
+ * Logs a stacktrace starting from the previous call and working down.
1068
+ * @param {(number|string)=} depth How many frames deep to trace.
1069
+ * @return {Object.<string, *>} Stack trace information.
1070
+ */
1071
+ function computeStackTraceOfCaller(depth) {
1072
+ depth = (depth == null ? 0 : +depth) + 1; // "+ 1" because "ofCaller" should drop one frame
1073
+ try {
1074
+ throw new Error();
1075
+ } catch (ex) {
1076
+ return computeStackTrace(ex, depth + 1);
1077
+ }
1078
+ }
1079
+
1080
+ computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;
1081
+ computeStackTrace.guessFunctionName = guessFunctionName;
1082
+ computeStackTrace.gatherContext = gatherContext;
1083
+ computeStackTrace.ofCaller = computeStackTraceOfCaller;
1084
+
1085
+ return computeStackTrace;
1086
+ }());
1087
+
1088
+ 'use strict';
1089
+
1090
+ // First, check for JSON support
1091
+ // If there is no JSON, we no-op the core features of Raven
1092
+ // since JSON is required to encode the payload
1093
+ var _Raven = window.Raven,
1094
+ hasJSON = !!(window.JSON && window.JSON.stringify),
1095
+ lastCapturedException,
1096
+ lastEventId,
1097
+ globalServer,
1098
+ globalUser,
1099
+ globalKey,
1100
+ globalProject,
1101
+ globalOptions = {
1102
+ logger: 'javascript',
1103
+ ignoreErrors: [],
1104
+ ignoreUrls: [],
1105
+ whitelistUrls: [],
1106
+ includePaths: [],
1107
+ collectWindowErrors: true,
1108
+ tags: {},
1109
+ extra: {}
1110
+ },
1111
+ authQueryString;
1112
+
1113
+ /*
1114
+ * The core Raven singleton
1115
+ *
1116
+ * @this {Raven}
1117
+ */
1118
+ var Raven = {
1119
+ VERSION: '1.1.14',
1120
+
1121
+ /*
1122
+ * Allow multiple versions of Raven to be installed.
1123
+ * Strip Raven from the global context and returns the instance.
1124
+ *
1125
+ * @return {Raven}
1126
+ */
1127
+ noConflict: function() {
1128
+ window.Raven = _Raven;
1129
+ return Raven;
1130
+ },
1131
+
1132
+ /*
1133
+ * Configure Raven with a DSN and extra options
1134
+ *
1135
+ * @param {string} dsn The public Sentry DSN
1136
+ * @param {object} options Optional set of of global options [optional]
1137
+ * @return {Raven}
1138
+ */
1139
+ config: function(dsn, options) {
1140
+ if (!dsn) return Raven;
1141
+
1142
+ var uri = parseDSN(dsn),
1143
+ lastSlash = uri.path.lastIndexOf('/'),
1144
+ path = uri.path.substr(1, lastSlash);
1145
+
1146
+ // merge in options
1147
+ if (options) {
1148
+ each(options, function(key, value){
1149
+ globalOptions[key] = value;
1150
+ });
1151
+ }
1152
+
1153
+ // "Script error." is hard coded into browsers for errors that it can't read.
1154
+ // this is the result of a script being pulled in from an external domain and CORS.
1155
+ globalOptions.ignoreErrors.push('Script error.');
1156
+ globalOptions.ignoreErrors.push('Script error');
1157
+
1158
+ // join regexp rules into one big rule
1159
+ globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
1160
+ globalOptions.ignoreUrls = globalOptions.ignoreUrls.length ? joinRegExp(globalOptions.ignoreUrls) : false;
1161
+ globalOptions.whitelistUrls = globalOptions.whitelistUrls.length ? joinRegExp(globalOptions.whitelistUrls) : false;
1162
+ globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
1163
+
1164
+ globalKey = uri.user;
1165
+ globalProject = uri.path.substr(lastSlash + 1);
1166
+
1167
+ // assemble the endpoint from the uri pieces
1168
+ globalServer = '//' + uri.host +
1169
+ (uri.port ? ':' + uri.port : '') +
1170
+ '/' + path + 'api/' + globalProject + '/store/';
1171
+
1172
+ if (uri.protocol) {
1173
+ globalServer = uri.protocol + ':' + globalServer;
1174
+ }
1175
+
1176
+ if (globalOptions.fetchContext) {
1177
+ TraceKit.remoteFetching = true;
1178
+ }
1179
+
1180
+ if (globalOptions.linesOfContext) {
1181
+ TraceKit.linesOfContext = globalOptions.linesOfContext;
1182
+ }
1183
+
1184
+ TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
1185
+
1186
+ setAuthQueryString();
1187
+
1188
+ // return for chaining
1189
+ return Raven;
1190
+ },
1191
+
1192
+ /*
1193
+ * Installs a global window.onerror error handler
1194
+ * to capture and report uncaught exceptions.
1195
+ * At this point, install() is required to be called due
1196
+ * to the way TraceKit is set up.
1197
+ *
1198
+ * @return {Raven}
1199
+ */
1200
+ install: function() {
1201
+ if (isSetup()) {
1202
+ TraceKit.report.subscribe(handleStackInfo);
1203
+ }
1204
+
1205
+ return Raven;
1206
+ },
1207
+
1208
+ /*
1209
+ * Wrap code within a context so Raven can capture errors
1210
+ * reliably across domains that is executed immediately.
1211
+ *
1212
+ * @param {object} options A specific set of options for this context [optional]
1213
+ * @param {function} func The callback to be immediately executed within the context
1214
+ * @param {array} args An array of arguments to be called with the callback [optional]
1215
+ */
1216
+ context: function(options, func, args) {
1217
+ if (isFunction(options)) {
1218
+ args = func || [];
1219
+ func = options;
1220
+ options = undefined;
1221
+ }
1222
+
1223
+ return Raven.wrap(options, func).apply(this, args);
1224
+ },
1225
+
1226
+ /*
1227
+ * Wrap code within a context and returns back a new function to be executed
1228
+ *
1229
+ * @param {object} options A specific set of options for this context [optional]
1230
+ * @param {function} func The function to be wrapped in a new context
1231
+ * @return {function} The newly wrapped functions with a context
1232
+ */
1233
+ wrap: function(options, func) {
1234
+ // 1 argument has been passed, and it's not a function
1235
+ // so just return it
1236
+ if (isUndefined(func) && !isFunction(options)) {
1237
+ return options;
1238
+ }
1239
+
1240
+ // options is optional
1241
+ if (isFunction(options)) {
1242
+ func = options;
1243
+ options = undefined;
1244
+ }
1245
+
1246
+ // At this point, we've passed along 2 arguments, and the second one
1247
+ // is not a function either, so we'll just return the second argument.
1248
+ if (!isFunction(func)) {
1249
+ return func;
1250
+ }
1251
+
1252
+ // We don't wanna wrap it twice!
1253
+ if (func.__raven__) {
1254
+ return func;
1255
+ }
1256
+
1257
+ function wrapped() {
1258
+ var args = [], i = arguments.length,
1259
+ deep = !options || options && options.deep !== false;
1260
+ // Recursively wrap all of a function's arguments that are
1261
+ // functions themselves.
1262
+
1263
+ while(i--) args[i] = deep ? Raven.wrap(options, arguments[i]) : arguments[i];
1264
+
1265
+ try {
1266
+ /*jshint -W040*/
1267
+ return func.apply(this, args);
1268
+ } catch(e) {
1269
+ Raven.captureException(e, options);
1270
+ throw e;
1271
+ }
1272
+ }
1273
+
1274
+ // copy over properties of the old function
1275
+ for (var property in func) {
1276
+ if (func.hasOwnProperty(property)) {
1277
+ wrapped[property] = func[property];
1278
+ }
1279
+ }
1280
+
1281
+ // Signal that this function has been wrapped already
1282
+ // for both debugging and to prevent it to being wrapped twice
1283
+ wrapped.__raven__ = true;
1284
+ wrapped.__inner__ = func;
1285
+
1286
+ return wrapped;
1287
+ },
1288
+
1289
+ /*
1290
+ * Uninstalls the global error handler.
1291
+ *
1292
+ * @return {Raven}
1293
+ */
1294
+ uninstall: function() {
1295
+ TraceKit.report.uninstall();
1296
+
1297
+ return Raven;
1298
+ },
1299
+
1300
+ /*
1301
+ * Manually capture an exception and send it over to Sentry
1302
+ *
1303
+ * @param {error} ex An exception to be logged
1304
+ * @param {object} options A specific set of options for this error [optional]
1305
+ * @return {Raven}
1306
+ */
1307
+ captureException: function(ex, options) {
1308
+ // If a string is passed through, recall as a message
1309
+ if (isString(ex)) return Raven.captureMessage(ex, options);
1310
+
1311
+ // Store the raw exception object for potential debugging and introspection
1312
+ lastCapturedException = ex;
1313
+
1314
+ // TraceKit.report will re-raise any exception passed to it,
1315
+ // which means you have to wrap it in try/catch. Instead, we
1316
+ // can wrap it here and only re-raise if TraceKit.report
1317
+ // raises an exception different from the one we asked to
1318
+ // report on.
1319
+ try {
1320
+ TraceKit.report(ex, options);
1321
+ } catch(ex1) {
1322
+ if(ex !== ex1) {
1323
+ throw ex1;
1324
+ }
1325
+ }
1326
+
1327
+ return Raven;
1328
+ },
1329
+
1330
+ /*
1331
+ * Manually send a message to Sentry
1332
+ *
1333
+ * @param {string} msg A plain message to be captured in Sentry
1334
+ * @param {object} options A specific set of options for this message [optional]
1335
+ * @return {Raven}
1336
+ */
1337
+ captureMessage: function(msg, options) {
1338
+ // Fire away!
1339
+ send(
1340
+ objectMerge({
1341
+ message: msg
1342
+ }, options)
1343
+ );
1344
+
1345
+ return Raven;
1346
+ },
1347
+
1348
+ /*
1349
+ * Set/clear a user to be sent along with the payload.
1350
+ *
1351
+ * @param {object} user An object representing user data [optional]
1352
+ * @return {Raven}
1353
+ */
1354
+ setUser: function(user) {
1355
+ globalUser = user;
1356
+
1357
+ return Raven;
1358
+ },
1359
+
1360
+ /*
1361
+ * Get the latest raw exception that was captured by Raven.
1362
+ *
1363
+ * @return {error}
1364
+ */
1365
+ lastException: function() {
1366
+ return lastCapturedException;
1367
+ },
1368
+
1369
+ /*
1370
+ * Get the last event id
1371
+ *
1372
+ * @return {string}
1373
+ */
1374
+ lastEventId: function() {
1375
+ return lastEventId;
1376
+ }
1377
+ };
1378
+
1379
+ function triggerEvent(eventType, options) {
1380
+ var event, key;
1381
+
1382
+ options = options || {};
1383
+
1384
+ eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
1385
+
1386
+ if (document.createEvent) {
1387
+ event = document.createEvent('HTMLEvents');
1388
+ event.initEvent(eventType, true, true);
1389
+ } else {
1390
+ event = document.createEventObject();
1391
+ event.eventType = eventType;
1392
+ }
1393
+
1394
+ for (key in options) if (options.hasOwnProperty(key)) {
1395
+ event[key] = options[key];
1396
+ }
1397
+
1398
+ if (document.createEvent) {
1399
+ // IE9 if standards
1400
+ document.dispatchEvent(event);
1401
+ } else {
1402
+ // IE8 regardless of Quirks or Standards
1403
+ // IE9 if quirks
1404
+ try {
1405
+ document.fireEvent('on' + event.eventType.toLowerCase(), event);
1406
+ } catch(e) {}
1407
+ }
1408
+ }
1409
+
1410
+ var dsnKeys = 'source protocol user pass host port path'.split(' '),
1411
+ dsnPattern = /^(?:(\w+):)?\/\/(\w+)(:\w+)?@([\w\.-]+)(?::(\d+))?(\/.*)/;
1412
+
1413
+ function RavenConfigError(message) {
1414
+ this.name = 'RavenConfigError';
1415
+ this.message = message;
1416
+ }
1417
+ RavenConfigError.prototype = new Error();
1418
+ RavenConfigError.prototype.constructor = RavenConfigError;
1419
+
1420
+ /**** Private functions ****/
1421
+ function parseDSN(str) {
1422
+ var m = dsnPattern.exec(str),
1423
+ dsn = {},
1424
+ i = 7;
1425
+
1426
+ try {
1427
+ while (i--) dsn[dsnKeys[i]] = m[i] || '';
1428
+ } catch(e) {
1429
+ throw new RavenConfigError('Invalid DSN: ' + str);
1430
+ }
1431
+
1432
+ if (dsn.pass)
1433
+ throw new RavenConfigError('Do not specify your private key in the DSN!');
1434
+
1435
+ return dsn;
1436
+ }
1437
+
1438
+ function isUndefined(what) {
1439
+ return typeof what === 'undefined';
1440
+ }
1441
+
1442
+ function isFunction(what) {
1443
+ return typeof what === 'function';
1444
+ }
1445
+
1446
+ function isString(what) {
1447
+ return typeof what === 'string';
1448
+ }
1449
+
1450
+ function isEmptyObject(what) {
1451
+ for (var k in what) return false;
1452
+ return true;
1453
+ }
1454
+
1455
+ /**
1456
+ * hasKey, a better form of hasOwnProperty
1457
+ * Example: hasKey(MainHostObject, property) === true/false
1458
+ *
1459
+ * @param {Object} host object to check property
1460
+ * @param {string} key to check
1461
+ */
1462
+ function hasKey(object, key) {
1463
+ return Object.prototype.hasOwnProperty.call(object, key);
1464
+ }
1465
+
1466
+ function each(obj, callback) {
1467
+ var i, j;
1468
+
1469
+ if (isUndefined(obj.length)) {
1470
+ for (i in obj) {
1471
+ if (obj.hasOwnProperty(i)) {
1472
+ callback.call(null, i, obj[i]);
1473
+ }
1474
+ }
1475
+ } else {
1476
+ j = obj.length;
1477
+ if (j) {
1478
+ for (i = 0; i < j; i++) {
1479
+ callback.call(null, i, obj[i]);
1480
+ }
1481
+ }
1482
+ }
1483
+ }
1484
+
1485
+
1486
+ function setAuthQueryString() {
1487
+ authQueryString =
1488
+ '?sentry_version=4' +
1489
+ '&sentry_client=raven-js/' + Raven.VERSION +
1490
+ '&sentry_key=' + globalKey;
1491
+ }
1492
+
1493
+
1494
+ function handleStackInfo(stackInfo, options) {
1495
+ var frames = [];
1496
+
1497
+ if (stackInfo.stack && stackInfo.stack.length) {
1498
+ each(stackInfo.stack, function(i, stack) {
1499
+ var frame = normalizeFrame(stack);
1500
+ if (frame) {
1501
+ frames.push(frame);
1502
+ }
1503
+ });
1504
+ }
1505
+
1506
+ triggerEvent('handle', {
1507
+ stackInfo: stackInfo,
1508
+ options: options
1509
+ });
1510
+
1511
+ processException(
1512
+ stackInfo.name,
1513
+ stackInfo.message,
1514
+ stackInfo.url,
1515
+ stackInfo.lineno,
1516
+ frames,
1517
+ options
1518
+ );
1519
+ }
1520
+
1521
+ function normalizeFrame(frame) {
1522
+ if (!frame.url) return;
1523
+
1524
+ // normalize the frames data
1525
+ var normalized = {
1526
+ filename: frame.url,
1527
+ lineno: frame.line,
1528
+ colno: frame.column,
1529
+ 'function': frame.func || '?'
1530
+ }, context = extractContextFromFrame(frame), i;
1531
+
1532
+ if (context) {
1533
+ var keys = ['pre_context', 'context_line', 'post_context'];
1534
+ i = 3;
1535
+ while (i--) normalized[keys[i]] = context[i];
1536
+ }
1537
+
1538
+ normalized.in_app = !( // determine if an exception came from outside of our app
1539
+ // first we check the global includePaths list.
1540
+ !globalOptions.includePaths.test(normalized.filename) ||
1541
+ // Now we check for fun, if the function name is Raven or TraceKit
1542
+ /(Raven|TraceKit)\./.test(normalized['function']) ||
1543
+ // finally, we do a last ditch effort and check for raven.min.js
1544
+ /raven\.(min\.)js$/.test(normalized.filename)
1545
+ );
1546
+
1547
+ return normalized;
1548
+ }
1549
+
1550
+ function extractContextFromFrame(frame) {
1551
+ // immediately check if we should even attempt to parse a context
1552
+ if (!frame.context || !globalOptions.fetchContext) return;
1553
+
1554
+ var context = frame.context,
1555
+ pivot = ~~(context.length / 2),
1556
+ i = context.length, isMinified = false;
1557
+
1558
+ while (i--) {
1559
+ // We're making a guess to see if the source is minified or not.
1560
+ // To do that, we make the assumption if *any* of the lines passed
1561
+ // in are greater than 300 characters long, we bail.
1562
+ // Sentry will see that there isn't a context
1563
+ if (context[i].length > 300) {
1564
+ isMinified = true;
1565
+ break;
1566
+ }
1567
+ }
1568
+
1569
+ if (isMinified) {
1570
+ // The source is minified and we don't know which column. Fuck it.
1571
+ if (isUndefined(frame.column)) return;
1572
+
1573
+ // If the source is minified and has a frame column
1574
+ // we take a chunk of the offending line to hopefully shed some light
1575
+ return [
1576
+ [], // no pre_context
1577
+ context[pivot].substr(frame.column, 50), // grab 50 characters, starting at the offending column
1578
+ [] // no post_context
1579
+ ];
1580
+ }
1581
+
1582
+ return [
1583
+ context.slice(0, pivot), // pre_context
1584
+ context[pivot], // context_line
1585
+ context.slice(pivot + 1) // post_context
1586
+ ];
1587
+ }
1588
+
1589
+ function processException(type, message, fileurl, lineno, frames, options) {
1590
+ var stacktrace, label, i;
1591
+
1592
+ // Sometimes an exception is getting logged in Sentry as
1593
+ // <no message value>
1594
+ // This can only mean that the message was falsey since this value
1595
+ // is hardcoded into Sentry itself.
1596
+ // At this point, if the message is falsey, we bail since it's useless
1597
+ if (type === 'Error' && !message) return;
1598
+
1599
+ if (globalOptions.ignoreErrors.test(message)) return;
1600
+
1601
+ if (frames && frames.length) {
1602
+ fileurl = frames[0].filename || fileurl;
1603
+ // Sentry expects frames oldest to newest
1604
+ // and JS sends them as newest to oldest
1605
+ frames.reverse();
1606
+ stacktrace = {frames: frames};
1607
+ } else if (fileurl) {
1608
+ stacktrace = {
1609
+ frames: [{
1610
+ filename: fileurl,
1611
+ lineno: lineno,
1612
+ in_app: true
1613
+ }]
1614
+ };
1615
+ }
1616
+
1617
+ // Truncate the message to a max of characters
1618
+ message = truncate(message, 100);
1619
+
1620
+ if (globalOptions.ignoreUrls && globalOptions.ignoreUrls.test(fileurl)) return;
1621
+ if (globalOptions.whitelistUrls && !globalOptions.whitelistUrls.test(fileurl)) return;
1622
+
1623
+ label = lineno ? message + ' at ' + lineno : message;
1624
+
1625
+ // Fire away!
1626
+ send(
1627
+ objectMerge({
1628
+ // sentry.interfaces.Exception
1629
+ exception: {
1630
+ type: type,
1631
+ value: message
1632
+ },
1633
+ // sentry.interfaces.Stacktrace
1634
+ stacktrace: stacktrace,
1635
+ culprit: fileurl,
1636
+ message: label
1637
+ }, options)
1638
+ );
1639
+ }
1640
+
1641
+ function objectMerge(obj1, obj2) {
1642
+ if (!obj2) {
1643
+ return obj1;
1644
+ }
1645
+ each(obj2, function(key, value){
1646
+ obj1[key] = value;
1647
+ });
1648
+ return obj1;
1649
+ }
1650
+
1651
+ function truncate(str, max) {
1652
+ return str.length <= max ? str : str.substr(0, max) + '\u2026';
1653
+ }
1654
+
1655
+ function getHttpData() {
1656
+ var http = {
1657
+ url: document.location.href,
1658
+ headers: {
1659
+ 'User-Agent': navigator.userAgent
1660
+ }
1661
+ };
1662
+
1663
+ if (document.referrer) {
1664
+ http.headers.Referer = document.referrer;
1665
+ }
1666
+
1667
+ return http;
1668
+ }
1669
+
1670
+ function send(data) {
1671
+ if (!isSetup()) return;
1672
+
1673
+ data = objectMerge({
1674
+ project: globalProject,
1675
+ logger: globalOptions.logger,
1676
+ site: globalOptions.site,
1677
+ platform: 'javascript',
1678
+ // sentry.interfaces.Http
1679
+ request: getHttpData()
1680
+ }, data);
1681
+
1682
+ // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
1683
+ data.tags = objectMerge(globalOptions.tags, data.tags);
1684
+ data.extra = objectMerge(globalOptions.extra, data.extra);
1685
+
1686
+ // If there are no tags/extra, strip the key from the payload alltogther.
1687
+ if (isEmptyObject(data.tags)) delete data.tags;
1688
+ if (isEmptyObject(data.extra)) delete data.extra;
1689
+
1690
+ if (globalUser) {
1691
+ // sentry.interfaces.User
1692
+ data.user = globalUser;
1693
+ }
1694
+
1695
+ if (isFunction(globalOptions.dataCallback)) {
1696
+ data = globalOptions.dataCallback(data);
1697
+ }
1698
+
1699
+ // Check if the request should be filtered or not
1700
+ if (isFunction(globalOptions.shouldSendCallback) && !globalOptions.shouldSendCallback(data)) {
1701
+ return;
1702
+ }
1703
+
1704
+ // Send along an event_id if not explicitly passed.
1705
+ // This event_id can be used to reference the error within Sentry itself.
1706
+ // Set lastEventId after we know the error should actually be sent
1707
+ lastEventId = data.event_id || (data.event_id = uuid4());
1708
+
1709
+ makeRequest(data);
1710
+ }
1711
+
1712
+
1713
+ function makeRequest(data) {
1714
+ var img = new Image(),
1715
+ src = globalServer + authQueryString + '&sentry_data=' + encodeURIComponent(JSON.stringify(data));
1716
+
1717
+ img.onload = function success() {
1718
+ triggerEvent('success', {
1719
+ data: data,
1720
+ src: src
1721
+ });
1722
+ };
1723
+ img.onerror = img.onabort = function failure() {
1724
+ triggerEvent('failure', {
1725
+ data: data,
1726
+ src: src
1727
+ });
1728
+ };
1729
+ img.src = src;
1730
+ }
1731
+
1732
+ function isSetup() {
1733
+ if (!hasJSON) return false; // needs JSON support
1734
+ if (!globalServer) {
1735
+ if (window.console && console.error) {
1736
+ console.error("Error: Raven has not been configured.");
1737
+ }
1738
+ return false;
1739
+ }
1740
+ return true;
1741
+ }
1742
+
1743
+ function joinRegExp(patterns) {
1744
+ // Combine an array of regular expressions and strings into one large regexp
1745
+ // Be mad.
1746
+ var sources = [],
1747
+ i = 0, len = patterns.length,
1748
+ pattern;
1749
+
1750
+ for (; i < len; i++) {
1751
+ pattern = patterns[i];
1752
+ if (isString(pattern)) {
1753
+ // If it's a string, we need to escape it
1754
+ // Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
1755
+ sources.push(pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"));
1756
+ } else if (pattern && pattern.source) {
1757
+ // If it's a regexp already, we want to extract the source
1758
+ sources.push(pattern.source);
1759
+ }
1760
+ // Intentionally skip other cases
1761
+ }
1762
+ return new RegExp(sources.join('|'), 'i');
1763
+ }
1764
+
1765
+ // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
1766
+ function uuid4() {
1767
+ return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
1768
+ var r = Math.random()*16|0,
1769
+ v = c == 'x' ? r : (r&0x3|0x8);
1770
+ return v.toString(16);
1771
+ });
1772
+ }
1773
+
1774
+ function afterLoad() {
1775
+ // Attempt to initialize Raven on load
1776
+ var RavenConfig = window.RavenConfig;
1777
+ if (RavenConfig) {
1778
+ Raven.config(RavenConfig.dsn, RavenConfig.config).install();
1779
+ }
1780
+ }
1781
+ afterLoad();
1782
+
1783
+ // Expose Raven to the world
1784
+ window.Raven = Raven;
1785
+
1786
+ // AMD
1787
+ if (typeof define === 'function' && define.amd) {
1788
+ define('raven', [], function() { return Raven; });
1789
+ }
1790
+
1791
+ })(this);
1792
+
1793
+ /**
1794
+ * native plugin
1795
+ *
1796
+ * Extends support for global error handling for asynchronous browser
1797
+ * functions. Adopted from Closure Library's errorhandler.js
1798
+ */
1799
+ ;(function extendToAsynchronousCallbacks(window, Raven) {
1800
+ "use strict";
1801
+
1802
+ var _helper = function _helper(fnName) {
1803
+ var originalFn = window[fnName];
1804
+ window[fnName] = function ravenAsyncExtension() {
1805
+ // Make a copy of the arguments
1806
+ var args = [].slice.call(arguments);
1807
+ var originalCallback = args[0];
1808
+ if (typeof (originalCallback) === 'function') {
1809
+ args[0] = Raven.wrap(originalCallback);
1810
+ }
1811
+ // IE < 9 doesn't support .call/.apply on setInterval/etTimeout, but it
1812
+ // also only supports 2 argument and doesn't care what this" is, so we
1813
+ // can just call the original function directly.
1814
+ if (originalFn.apply) {
1815
+ return originalFn.apply(this, args);
1816
+ } else {
1817
+ return originalFn(args[0], args[1]);
1818
+ }
1819
+ };
1820
+ };
1821
+
1822
+ _helper('setTimeout');
1823
+ _helper('setInterval');
1824
+
1825
+ }(this, Raven));