ravenjs-gem 1.1.14 → 1.1.16

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YTdlOWVkODFhNGJlYjU3OTFjMGNkOWExMjllNTQ5OTY1MTA1NGI4MA==
4
+ YzM2M2JmYjQwMDdlZDkxZGFjOTQxMjVhNDY1OTMzODY2NzY3MWNkMA==
5
5
  data.tar.gz: !binary |-
6
- OGQyMmIxMTM0NWZkZDFjYWQzYTI1OTFiZmI3NWQ4MWUzOGQ3ZTc1Yw==
6
+ Mjg0ODI4MjE2ODA0NjUyMWM1MWE0ZWEyMGMxNTZjMjUzOWNkNDVmOA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NGM2NWE1YTkzODg5NzJjM2IzMTg5OWU5MDliYTRjY2QyOWZlYmQzYmM1ZWIz
10
- OTY2MGM5NGUzYjNjYWM5ZjA2MDRhMmY1NDdjMzQ0MTQ3YzA3OTMwMzRlODBl
11
- Zjg1ZGJjZGFiNzRhMmYyYjUyMDc2NjU2ZTkxYzlkZjJhMzhmZTY=
9
+ NjE5NTAxN2Y2MWY2NmNlZDhkMDZjYTJmNjBkNWZjYjVmZmM0ODUzYzJkODIy
10
+ MjJjYmMzOGExMmRhMmI3OWEzOTkxYTQ3NTY2Mzk3YjlhNTZmMjBmYmQwOTk5
11
+ MDJjMmE0MzE0ZTk0YjA2Yjk5NDM1NGQxMWM5NTY5ZmFjZmNjNDA=
12
12
  data.tar.gz: !binary |-
13
- ZDllNzU0NjBlZjk3NDE4ODAwNTZmMjViMTk0NGY3MjRlZDU5MmNjMGYzZDE0
14
- MTY2MDNjMzNkNjAyZTc0YWY4MTFlZDQ2ZTNlNTA2ZjE3M2Q0MzliODUxN2Mw
15
- N2JhYmJkOTMyNTAyZGYyMWNlNjcyMGNjNWUxZjNiYTQwZjUzYjM=
13
+ MjU3ODZmOTZjYjY2NmY5ODk4MzE3ZTg5YjU4MWEwOTMyMDVlMDE0NTQ0NjA0
14
+ NzhiMmYyYzNjNWIyZTJjYjMxODk1N2VlNTI2OWU5Mzk2ZTc2MzlhODUzM2U5
15
+ Mjg5MjlhYmU5OWUxOTcwYjBlMjkzMTliYWE3ZmE4YTNjZTM2MmM=
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Raven.js Gem
2
- [![Gem Version](https://badge.fury.io/rb/ravenjs-gem.png)](http://badge.fury.io/rb/ravenjs-gem) [![Dependency Status](https://gemnasium.com/ets-berkeley-edu/ravenjs-gem.png)](https://gemnasium.com/ets-berkeley-edu/ravenjs-gem) [![Code Climate](https://codeclimate.com/github/ets-berkeley-edu/ravenjs-gem.png)](https://codeclimate.com/github/ets-berkeley-edu/ravenjs-gem)
2
+ [![Gem Version](https://badge.fury.io/rb/ravenjs-gem.svg)](http://badge.fury.io/rb/ravenjs-gem) [![Dependency Status](https://gemnasium.com/ets-berkeley-edu/ravenjs-gem.svg)](https://gemnasium.com/ets-berkeley-edu/ravenjs-gem) [![Code Climate](http://img.shields.io/codeclimate/github/ets-berkeley-edu/ravenjs-gem.svg)](https://codeclimate.com/github/ets-berkeley-edu/ravenjs-gem)
3
3
 
4
4
  [Raven.js][ravenjs] as a Ruby gem.
5
5
 
@@ -41,8 +41,8 @@ If you would like to update this gem you should take the following steps:
41
41
  Then the maintainer of the gem will need to do the following steps:
42
42
 
43
43
  1. Update the version [lib/ravenjs-gem/version.rb](lib/ravenjs-gem/version.rb)
44
- 1. Run ``gem build ravenjs-gem.gemspec`` to package the gem
44
+ 1. Run `gem build ravenjs-gem.gemspec` to package the gem
45
45
  1. Once satisfied, push the gem up to RubyGems.org with ``gem push ravenjs-gem-<VERSION>.gem``
46
46
  1. Update [the changelog](CHANGELOG.md)
47
47
 
48
- [ravenjs]: https://github.com/getsentry/raven-js
48
+ [ravenjs]: https://github.com/getsentry/raven-js
data/Rakefile CHANGED
@@ -64,15 +64,15 @@ task :download do |t|
64
64
  create_dir dir_js, get_version
65
65
 
66
66
  # Download the right files
67
- url_root = 'https://raw.github.com/getsentry/raven-js/' + commit + '/dist/' + get_version + '/'
67
+ url_root = 'https://raw.github.com/getsentry/raven-js/' + commit + '/dist/'
68
68
  url_js = url_root + 'raven.js'
69
69
  url_js_min = url_root + 'raven.min.js'
70
70
  url_js_map = url_root + 'raven.min.map'
71
71
 
72
72
  puts "Downloading... \n"
73
73
  download_file url_js, dir_js, 'raven.js', get_version
74
- download_file url_js_min, dir_js, 'raven.min.js', get_version
75
- download_file url_js_map, dir_js, 'raven.min.map', get_version
74
+ # download_file url_js_min, dir_js, 'raven.min.js', get_version
75
+ # download_file url_js_map, dir_js, 'raven.min.map', get_version
76
76
 
77
77
  end
78
78
 
@@ -1,3 +1,3 @@
1
1
  module RavenjsGem
2
- VERSION = "1.1.14"
2
+ VERSION = "1.1.16"
3
3
  end
@@ -0,0 +1,1838 @@
1
+ /*! Raven.js 1.1.16 (463f68f) | 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?|chrome-extension):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
649
+ gecko = /^\s*(\S*)(?:\((.*?)\))?@((?:file|https?|chrome).*?):(\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
+ isRavenInstalled = false;
1113
+
1114
+ /*
1115
+ * The core Raven singleton
1116
+ *
1117
+ * @this {Raven}
1118
+ */
1119
+ var Raven = {
1120
+ VERSION: '1.1.16',
1121
+
1122
+ debug: true,
1123
+
1124
+ /*
1125
+ * Allow multiple versions of Raven to be installed.
1126
+ * Strip Raven from the global context and returns the instance.
1127
+ *
1128
+ * @return {Raven}
1129
+ */
1130
+ noConflict: function() {
1131
+ window.Raven = _Raven;
1132
+ return Raven;
1133
+ },
1134
+
1135
+ /*
1136
+ * Configure Raven with a DSN and extra options
1137
+ *
1138
+ * @param {string} dsn The public Sentry DSN
1139
+ * @param {object} options Optional set of of global options [optional]
1140
+ * @return {Raven}
1141
+ */
1142
+ config: function(dsn, options) {
1143
+ if (globalServer) {
1144
+ logDebug('error', 'Error: Raven has already been configured');
1145
+ return Raven;
1146
+ }
1147
+ if (!dsn) return Raven;
1148
+
1149
+ var uri = parseDSN(dsn),
1150
+ lastSlash = uri.path.lastIndexOf('/'),
1151
+ path = uri.path.substr(1, lastSlash);
1152
+
1153
+ // merge in options
1154
+ if (options) {
1155
+ each(options, function(key, value){
1156
+ globalOptions[key] = value;
1157
+ });
1158
+ }
1159
+
1160
+ // "Script error." is hard coded into browsers for errors that it can't read.
1161
+ // this is the result of a script being pulled in from an external domain and CORS.
1162
+ globalOptions.ignoreErrors.push('Script error.');
1163
+ globalOptions.ignoreErrors.push('Script error');
1164
+
1165
+ // Other variants of external script errors:
1166
+ globalOptions.ignoreErrors.push('Javascript error: Script error on line 0');
1167
+ globalOptions.ignoreErrors.push('Javascript error: Script error. on line 0');
1168
+
1169
+ // join regexp rules into one big rule
1170
+ globalOptions.ignoreErrors = joinRegExp(globalOptions.ignoreErrors);
1171
+ globalOptions.ignoreUrls = globalOptions.ignoreUrls.length ? joinRegExp(globalOptions.ignoreUrls) : false;
1172
+ globalOptions.whitelistUrls = globalOptions.whitelistUrls.length ? joinRegExp(globalOptions.whitelistUrls) : false;
1173
+ globalOptions.includePaths = joinRegExp(globalOptions.includePaths);
1174
+
1175
+ globalKey = uri.user;
1176
+ globalProject = uri.path.substr(lastSlash + 1);
1177
+
1178
+ // assemble the endpoint from the uri pieces
1179
+ globalServer = '//' + uri.host +
1180
+ (uri.port ? ':' + uri.port : '') +
1181
+ '/' + path + 'api/' + globalProject + '/store/';
1182
+
1183
+ if (uri.protocol) {
1184
+ globalServer = uri.protocol + ':' + globalServer;
1185
+ }
1186
+
1187
+ if (globalOptions.fetchContext) {
1188
+ TraceKit.remoteFetching = true;
1189
+ }
1190
+
1191
+ if (globalOptions.linesOfContext) {
1192
+ TraceKit.linesOfContext = globalOptions.linesOfContext;
1193
+ }
1194
+
1195
+ TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
1196
+
1197
+ setAuthQueryString();
1198
+
1199
+ // return for chaining
1200
+ return Raven;
1201
+ },
1202
+
1203
+ /*
1204
+ * Installs a global window.onerror error handler
1205
+ * to capture and report uncaught exceptions.
1206
+ * At this point, install() is required to be called due
1207
+ * to the way TraceKit is set up.
1208
+ *
1209
+ * @return {Raven}
1210
+ */
1211
+ install: function() {
1212
+ if (isSetup() && !isRavenInstalled) {
1213
+ TraceKit.report.subscribe(handleStackInfo);
1214
+ isRavenInstalled = true;
1215
+ }
1216
+
1217
+ return Raven;
1218
+ },
1219
+
1220
+ /*
1221
+ * Wrap code within a context so Raven can capture errors
1222
+ * reliably across domains that is executed immediately.
1223
+ *
1224
+ * @param {object} options A specific set of options for this context [optional]
1225
+ * @param {function} func The callback to be immediately executed within the context
1226
+ * @param {array} args An array of arguments to be called with the callback [optional]
1227
+ */
1228
+ context: function(options, func, args) {
1229
+ if (isFunction(options)) {
1230
+ args = func || [];
1231
+ func = options;
1232
+ options = undefined;
1233
+ }
1234
+
1235
+ return Raven.wrap(options, func).apply(this, args);
1236
+ },
1237
+
1238
+ /*
1239
+ * Wrap code within a context and returns back a new function to be executed
1240
+ *
1241
+ * @param {object} options A specific set of options for this context [optional]
1242
+ * @param {function} func The function to be wrapped in a new context
1243
+ * @return {function} The newly wrapped functions with a context
1244
+ */
1245
+ wrap: function(options, func) {
1246
+ // 1 argument has been passed, and it's not a function
1247
+ // so just return it
1248
+ if (isUndefined(func) && !isFunction(options)) {
1249
+ return options;
1250
+ }
1251
+
1252
+ // options is optional
1253
+ if (isFunction(options)) {
1254
+ func = options;
1255
+ options = undefined;
1256
+ }
1257
+
1258
+ // At this point, we've passed along 2 arguments, and the second one
1259
+ // is not a function either, so we'll just return the second argument.
1260
+ if (!isFunction(func)) {
1261
+ return func;
1262
+ }
1263
+
1264
+ // We don't wanna wrap it twice!
1265
+ if (func.__raven__) {
1266
+ return func;
1267
+ }
1268
+
1269
+ function wrapped() {
1270
+ var args = [], i = arguments.length,
1271
+ deep = !options || options && options.deep !== false;
1272
+ // Recursively wrap all of a function's arguments that are
1273
+ // functions themselves.
1274
+
1275
+ while(i--) args[i] = deep ? Raven.wrap(options, arguments[i]) : arguments[i];
1276
+
1277
+ try {
1278
+ /*jshint -W040*/
1279
+ return func.apply(this, args);
1280
+ } catch(e) {
1281
+ Raven.captureException(e, options);
1282
+ throw e;
1283
+ }
1284
+ }
1285
+
1286
+ // copy over properties of the old function
1287
+ for (var property in func) {
1288
+ if (hasKey(func, property)) {
1289
+ wrapped[property] = func[property];
1290
+ }
1291
+ }
1292
+
1293
+ // Signal that this function has been wrapped already
1294
+ // for both debugging and to prevent it to being wrapped twice
1295
+ wrapped.__raven__ = true;
1296
+ wrapped.__inner__ = func;
1297
+
1298
+ return wrapped;
1299
+ },
1300
+
1301
+ /*
1302
+ * Uninstalls the global error handler.
1303
+ *
1304
+ * @return {Raven}
1305
+ */
1306
+ uninstall: function() {
1307
+ TraceKit.report.uninstall();
1308
+ isRavenInstalled = false;
1309
+
1310
+ return Raven;
1311
+ },
1312
+
1313
+ /*
1314
+ * Manually capture an exception and send it over to Sentry
1315
+ *
1316
+ * @param {error} ex An exception to be logged
1317
+ * @param {object} options A specific set of options for this error [optional]
1318
+ * @return {Raven}
1319
+ */
1320
+ captureException: function(ex, options) {
1321
+ // If not an Error is passed through, recall as a message instead
1322
+ if (!(ex instanceof Error)) return Raven.captureMessage(ex, options);
1323
+
1324
+ // Store the raw exception object for potential debugging and introspection
1325
+ lastCapturedException = ex;
1326
+
1327
+ // TraceKit.report will re-raise any exception passed to it,
1328
+ // which means you have to wrap it in try/catch. Instead, we
1329
+ // can wrap it here and only re-raise if TraceKit.report
1330
+ // raises an exception different from the one we asked to
1331
+ // report on.
1332
+ try {
1333
+ TraceKit.report(ex, options);
1334
+ } catch(ex1) {
1335
+ if(ex !== ex1) {
1336
+ throw ex1;
1337
+ }
1338
+ }
1339
+
1340
+ return Raven;
1341
+ },
1342
+
1343
+ /*
1344
+ * Manually send a message to Sentry
1345
+ *
1346
+ * @param {string} msg A plain message to be captured in Sentry
1347
+ * @param {object} options A specific set of options for this message [optional]
1348
+ * @return {Raven}
1349
+ */
1350
+ captureMessage: function(msg, options) {
1351
+ // Fire away!
1352
+ send(
1353
+ objectMerge({
1354
+ message: msg + '' // Make sure it's actually a string
1355
+ }, options)
1356
+ );
1357
+
1358
+ return Raven;
1359
+ },
1360
+
1361
+ /*
1362
+ * Set/clear a user to be sent along with the payload.
1363
+ *
1364
+ * @param {object} user An object representing user data [optional]
1365
+ * @return {Raven}
1366
+ */
1367
+ setUserContext: function(user) {
1368
+ globalUser = user;
1369
+
1370
+ return Raven;
1371
+ },
1372
+
1373
+ /*
1374
+ * Set extra attributes to be sent along with the payload.
1375
+ *
1376
+ * @param {object} extra An object representing extra data [optional]
1377
+ * @return {Raven}
1378
+ */
1379
+ setExtraContext: function(extra) {
1380
+ globalOptions.extra = extra || {};
1381
+
1382
+ return Raven;
1383
+ },
1384
+
1385
+ /*
1386
+ * Set tags to be sent along with the payload.
1387
+ *
1388
+ * @param {object} tags An object representing tags [optional]
1389
+ * @return {Raven}
1390
+ */
1391
+ setTagsContext: function(tags) {
1392
+ globalOptions.tags = tags || {};
1393
+
1394
+ return Raven;
1395
+ },
1396
+
1397
+ /*
1398
+ * Get the latest raw exception that was captured by Raven.
1399
+ *
1400
+ * @return {error}
1401
+ */
1402
+ lastException: function() {
1403
+ return lastCapturedException;
1404
+ },
1405
+
1406
+ /*
1407
+ * Get the last event id
1408
+ *
1409
+ * @return {string}
1410
+ */
1411
+ lastEventId: function() {
1412
+ return lastEventId;
1413
+ }
1414
+ };
1415
+
1416
+ Raven.setUser = Raven.setUserContext; // To be deprecated
1417
+
1418
+ function triggerEvent(eventType, options) {
1419
+ var event, key;
1420
+
1421
+ options = options || {};
1422
+
1423
+ eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
1424
+
1425
+ if (document.createEvent) {
1426
+ event = document.createEvent('HTMLEvents');
1427
+ event.initEvent(eventType, true, true);
1428
+ } else {
1429
+ event = document.createEventObject();
1430
+ event.eventType = eventType;
1431
+ }
1432
+
1433
+ for (key in options) if (hasKey(options, key)) {
1434
+ event[key] = options[key];
1435
+ }
1436
+
1437
+ if (document.createEvent) {
1438
+ // IE9 if standards
1439
+ document.dispatchEvent(event);
1440
+ } else {
1441
+ // IE8 regardless of Quirks or Standards
1442
+ // IE9 if quirks
1443
+ try {
1444
+ document.fireEvent('on' + event.eventType.toLowerCase(), event);
1445
+ } catch(e) {}
1446
+ }
1447
+ }
1448
+
1449
+ var dsnKeys = 'source protocol user pass host port path'.split(' '),
1450
+ dsnPattern = /^(?:(\w+):)?\/\/(\w+)(:\w+)?@([\w\.-]+)(?::(\d+))?(\/.*)/;
1451
+
1452
+ function RavenConfigError(message) {
1453
+ this.name = 'RavenConfigError';
1454
+ this.message = message;
1455
+ }
1456
+ RavenConfigError.prototype = new Error();
1457
+ RavenConfigError.prototype.constructor = RavenConfigError;
1458
+
1459
+ /**** Private functions ****/
1460
+ function parseDSN(str) {
1461
+ var m = dsnPattern.exec(str),
1462
+ dsn = {},
1463
+ i = 7;
1464
+
1465
+ try {
1466
+ while (i--) dsn[dsnKeys[i]] = m[i] || '';
1467
+ } catch(e) {
1468
+ throw new RavenConfigError('Invalid DSN: ' + str);
1469
+ }
1470
+
1471
+ if (dsn.pass)
1472
+ throw new RavenConfigError('Do not specify your private key in the DSN!');
1473
+
1474
+ return dsn;
1475
+ }
1476
+
1477
+ function isUndefined(what) {
1478
+ return typeof what === 'undefined';
1479
+ }
1480
+
1481
+ function isFunction(what) {
1482
+ return typeof what === 'function';
1483
+ }
1484
+
1485
+ function isString(what) {
1486
+ return typeof what === 'string';
1487
+ }
1488
+
1489
+ function isEmptyObject(what) {
1490
+ for (var k in what) return false;
1491
+ return true;
1492
+ }
1493
+
1494
+ /**
1495
+ * hasKey, a better form of hasOwnProperty
1496
+ * Example: hasKey(MainHostObject, property) === true/false
1497
+ *
1498
+ * @param {Object} host object to check property
1499
+ * @param {string} key to check
1500
+ */
1501
+ function hasKey(object, key) {
1502
+ return Object.prototype.hasOwnProperty.call(object, key);
1503
+ }
1504
+
1505
+ function each(obj, callback) {
1506
+ var i, j;
1507
+
1508
+ if (isUndefined(obj.length)) {
1509
+ for (i in obj) {
1510
+ if (hasKey(obj, i)) {
1511
+ callback.call(null, i, obj[i]);
1512
+ }
1513
+ }
1514
+ } else {
1515
+ j = obj.length;
1516
+ if (j) {
1517
+ for (i = 0; i < j; i++) {
1518
+ callback.call(null, i, obj[i]);
1519
+ }
1520
+ }
1521
+ }
1522
+ }
1523
+
1524
+
1525
+ function setAuthQueryString() {
1526
+ authQueryString =
1527
+ '?sentry_version=4' +
1528
+ '&sentry_client=raven-js/' + Raven.VERSION +
1529
+ '&sentry_key=' + globalKey;
1530
+ }
1531
+
1532
+
1533
+ function handleStackInfo(stackInfo, options) {
1534
+ var frames = [];
1535
+
1536
+ if (stackInfo.stack && stackInfo.stack.length) {
1537
+ each(stackInfo.stack, function(i, stack) {
1538
+ var frame = normalizeFrame(stack);
1539
+ if (frame) {
1540
+ frames.push(frame);
1541
+ }
1542
+ });
1543
+ }
1544
+
1545
+ triggerEvent('handle', {
1546
+ stackInfo: stackInfo,
1547
+ options: options
1548
+ });
1549
+
1550
+ processException(
1551
+ stackInfo.name,
1552
+ stackInfo.message,
1553
+ stackInfo.url,
1554
+ stackInfo.lineno,
1555
+ frames,
1556
+ options
1557
+ );
1558
+ }
1559
+
1560
+ function normalizeFrame(frame) {
1561
+ if (!frame.url) return;
1562
+
1563
+ // normalize the frames data
1564
+ var normalized = {
1565
+ filename: frame.url,
1566
+ lineno: frame.line,
1567
+ colno: frame.column,
1568
+ 'function': frame.func || '?'
1569
+ }, context = extractContextFromFrame(frame), i;
1570
+
1571
+ if (context) {
1572
+ var keys = ['pre_context', 'context_line', 'post_context'];
1573
+ i = 3;
1574
+ while (i--) normalized[keys[i]] = context[i];
1575
+ }
1576
+
1577
+ normalized.in_app = !( // determine if an exception came from outside of our app
1578
+ // first we check the global includePaths list.
1579
+ !globalOptions.includePaths.test(normalized.filename) ||
1580
+ // Now we check for fun, if the function name is Raven or TraceKit
1581
+ /(Raven|TraceKit)\./.test(normalized['function']) ||
1582
+ // finally, we do a last ditch effort and check for raven.min.js
1583
+ /raven\.(min\.)?js$/.test(normalized.filename)
1584
+ );
1585
+
1586
+ return normalized;
1587
+ }
1588
+
1589
+ function extractContextFromFrame(frame) {
1590
+ // immediately check if we should even attempt to parse a context
1591
+ if (!frame.context || !globalOptions.fetchContext) return;
1592
+
1593
+ var context = frame.context,
1594
+ pivot = ~~(context.length / 2),
1595
+ i = context.length, isMinified = false;
1596
+
1597
+ while (i--) {
1598
+ // We're making a guess to see if the source is minified or not.
1599
+ // To do that, we make the assumption if *any* of the lines passed
1600
+ // in are greater than 300 characters long, we bail.
1601
+ // Sentry will see that there isn't a context
1602
+ if (context[i].length > 300) {
1603
+ isMinified = true;
1604
+ break;
1605
+ }
1606
+ }
1607
+
1608
+ if (isMinified) {
1609
+ // The source is minified and we don't know which column. Fuck it.
1610
+ if (isUndefined(frame.column)) return;
1611
+
1612
+ // If the source is minified and has a frame column
1613
+ // we take a chunk of the offending line to hopefully shed some light
1614
+ return [
1615
+ [], // no pre_context
1616
+ context[pivot].substr(frame.column, 50), // grab 50 characters, starting at the offending column
1617
+ [] // no post_context
1618
+ ];
1619
+ }
1620
+
1621
+ return [
1622
+ context.slice(0, pivot), // pre_context
1623
+ context[pivot], // context_line
1624
+ context.slice(pivot + 1) // post_context
1625
+ ];
1626
+ }
1627
+
1628
+ function processException(type, message, fileurl, lineno, frames, options) {
1629
+ var stacktrace, label, i;
1630
+
1631
+ // In some instances message is not actually a string, no idea why,
1632
+ // so we want to always coerce it to one.
1633
+ message += '';
1634
+
1635
+ // Sometimes an exception is getting logged in Sentry as
1636
+ // <no message value>
1637
+ // This can only mean that the message was falsey since this value
1638
+ // is hardcoded into Sentry itself.
1639
+ // At this point, if the message is falsey, we bail since it's useless
1640
+ if (type === 'Error' && !message) return;
1641
+
1642
+ if (globalOptions.ignoreErrors.test(message)) return;
1643
+
1644
+ if (frames && frames.length) {
1645
+ fileurl = frames[0].filename || fileurl;
1646
+ // Sentry expects frames oldest to newest
1647
+ // and JS sends them as newest to oldest
1648
+ frames.reverse();
1649
+ stacktrace = {frames: frames};
1650
+ } else if (fileurl) {
1651
+ stacktrace = {
1652
+ frames: [{
1653
+ filename: fileurl,
1654
+ lineno: lineno,
1655
+ in_app: true
1656
+ }]
1657
+ };
1658
+ }
1659
+
1660
+ // Truncate the message to a max of characters
1661
+ message = truncate(message, 100);
1662
+
1663
+ if (globalOptions.ignoreUrls && globalOptions.ignoreUrls.test(fileurl)) return;
1664
+ if (globalOptions.whitelistUrls && !globalOptions.whitelistUrls.test(fileurl)) return;
1665
+
1666
+ label = lineno ? message + ' at ' + lineno : message;
1667
+
1668
+ // Fire away!
1669
+ send(
1670
+ objectMerge({
1671
+ // sentry.interfaces.Exception
1672
+ exception: {
1673
+ type: type,
1674
+ value: message
1675
+ },
1676
+ // sentry.interfaces.Stacktrace
1677
+ stacktrace: stacktrace,
1678
+ culprit: fileurl,
1679
+ message: label
1680
+ }, options)
1681
+ );
1682
+ }
1683
+
1684
+ function objectMerge(obj1, obj2) {
1685
+ if (!obj2) {
1686
+ return obj1;
1687
+ }
1688
+ each(obj2, function(key, value){
1689
+ obj1[key] = value;
1690
+ });
1691
+ return obj1;
1692
+ }
1693
+
1694
+ function truncate(str, max) {
1695
+ return str.length <= max ? str : str.substr(0, max) + '\u2026';
1696
+ }
1697
+
1698
+ function getHttpData() {
1699
+ var http = {
1700
+ url: document.location.href,
1701
+ headers: {
1702
+ 'User-Agent': navigator.userAgent
1703
+ }
1704
+ };
1705
+
1706
+ if (document.referrer) {
1707
+ http.headers.Referer = document.referrer;
1708
+ }
1709
+
1710
+ return http;
1711
+ }
1712
+
1713
+ function send(data) {
1714
+ if (!isSetup()) return;
1715
+
1716
+ data = objectMerge({
1717
+ project: globalProject,
1718
+ logger: globalOptions.logger,
1719
+ site: globalOptions.site,
1720
+ platform: 'javascript',
1721
+ // sentry.interfaces.Http
1722
+ request: getHttpData()
1723
+ }, data);
1724
+
1725
+ // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
1726
+ data.tags = objectMerge(globalOptions.tags, data.tags);
1727
+ data.extra = objectMerge(globalOptions.extra, data.extra);
1728
+
1729
+ // If there are no tags/extra, strip the key from the payload alltogther.
1730
+ if (isEmptyObject(data.tags)) delete data.tags;
1731
+ if (isEmptyObject(data.extra)) delete data.extra;
1732
+
1733
+ if (globalUser) {
1734
+ // sentry.interfaces.User
1735
+ data.user = globalUser;
1736
+ }
1737
+
1738
+ if (isFunction(globalOptions.dataCallback)) {
1739
+ data = globalOptions.dataCallback(data);
1740
+ }
1741
+
1742
+ // Check if the request should be filtered or not
1743
+ if (isFunction(globalOptions.shouldSendCallback) && !globalOptions.shouldSendCallback(data)) {
1744
+ return;
1745
+ }
1746
+
1747
+ // Send along an event_id if not explicitly passed.
1748
+ // This event_id can be used to reference the error within Sentry itself.
1749
+ // Set lastEventId after we know the error should actually be sent
1750
+ lastEventId = data.event_id || (data.event_id = uuid4());
1751
+
1752
+ makeRequest(data);
1753
+ }
1754
+
1755
+
1756
+ function makeRequest(data) {
1757
+ var img = new Image(),
1758
+ src = globalServer + authQueryString + '&sentry_data=' + encodeURIComponent(JSON.stringify(data));
1759
+
1760
+ img.onload = function success() {
1761
+ triggerEvent('success', {
1762
+ data: data,
1763
+ src: src
1764
+ });
1765
+ };
1766
+ img.onerror = img.onabort = function failure() {
1767
+ triggerEvent('failure', {
1768
+ data: data,
1769
+ src: src
1770
+ });
1771
+ };
1772
+ img.src = src;
1773
+ }
1774
+
1775
+ function isSetup() {
1776
+ if (!hasJSON) return false; // needs JSON support
1777
+ if (!globalServer) {
1778
+ logDebug('error', 'Error: Raven has not been configured.');
1779
+ return false;
1780
+ }
1781
+ return true;
1782
+ }
1783
+
1784
+ function joinRegExp(patterns) {
1785
+ // Combine an array of regular expressions and strings into one large regexp
1786
+ // Be mad.
1787
+ var sources = [],
1788
+ i = 0, len = patterns.length,
1789
+ pattern;
1790
+
1791
+ for (; i < len; i++) {
1792
+ pattern = patterns[i];
1793
+ if (isString(pattern)) {
1794
+ // If it's a string, we need to escape it
1795
+ // Taken from: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
1796
+ sources.push(pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"));
1797
+ } else if (pattern && pattern.source) {
1798
+ // If it's a regexp already, we want to extract the source
1799
+ sources.push(pattern.source);
1800
+ }
1801
+ // Intentionally skip other cases
1802
+ }
1803
+ return new RegExp(sources.join('|'), 'i');
1804
+ }
1805
+
1806
+ // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
1807
+ function uuid4() {
1808
+ return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
1809
+ var r = Math.random()*16|0,
1810
+ v = c == 'x' ? r : (r&0x3|0x8);
1811
+ return v.toString(16);
1812
+ });
1813
+ }
1814
+
1815
+ function logDebug(level, message) {
1816
+ if (window.console && console[level] && Raven.debug) {
1817
+ console[level](message);
1818
+ }
1819
+ }
1820
+
1821
+ function afterLoad() {
1822
+ // Attempt to initialize Raven on load
1823
+ var RavenConfig = window.RavenConfig;
1824
+ if (RavenConfig) {
1825
+ Raven.config(RavenConfig.dsn, RavenConfig.config).install();
1826
+ }
1827
+ }
1828
+ afterLoad();
1829
+
1830
+ // Expose Raven to the world
1831
+ window.Raven = Raven;
1832
+
1833
+ // AMD
1834
+ if (typeof define === 'function' && define.amd) {
1835
+ define('raven', [], function() { return Raven; });
1836
+ }
1837
+
1838
+ })(this);