smoke_detector 1.1.5 → 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/smoke_detector/middleware/javascript_monitors.rb +2 -1
  4. data/lib/smoke_detector/providers/js/rollbar.js +2343 -0
  5. data/lib/smoke_detector/providers/rollbar.rb +3 -2
  6. data/lib/smoke_detector/version.rb +1 -1
  7. data/spec/dummy/config/initializers/rollbar.rb +52 -0
  8. data/spec/dummy/db/test.sqlite3 +0 -0
  9. data/spec/dummy/log/development.log +0 -0
  10. data/spec/dummy/log/test.log +2004 -0
  11. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/-x18hqI9UW005FhNgtUabDb_BX9T417ldrWDmDWNPX8.cache +0 -0
  12. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/05tGgfvaIZB2WhxiwJDDsK1qSSp8q5z2w0oizhbu63g.cache +2 -0
  13. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/2P9IKzmeq2XFDLIYjg2LNFyWtCBLF-ln0JiHUCrbW0c.cache +0 -0
  14. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/3gSuQ9W4PxO4smIQPaFSvUPwbTje0ytOAk_48728k8Y.cache +0 -0
  15. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/4PHfvRiCq9kVrQqfDNAGhcaBoauNSBACR3-CAhb4GdE.cache +2 -0
  16. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/538rWEA_3I2ZHauSM8pcOJP_kWuj6FSnitAiiJbiPN0.cache +1 -0
  17. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/7o1iNT7bl-ROe5-bYVQCS28fllTA5i6Z0iyjdFvIPIg.cache +3 -0
  18. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/9SY9VqlZtb0EDo8-J83s1Qiq7pTRujc3n2WkrHriGuM.cache +1 -0
  19. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/Dz7ku8U7vd16P6NMo09ywNulRPottH7H_s-hegc2gus.cache +0 -0
  20. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/GvpVw77ArWRTSddCmX65HDkzmlE290UZLiRcyQEuSBM.cache +1 -0
  21. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/Il1yRkc2D9nqrvnlyJyxvRsqpXTMXR5OVueD15805GA.cache +1 -0
  22. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/J_G_CP7Cl7finRnUkPE3NoWigAsaYpkc0Be7CEYGFjs.cache +0 -0
  23. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/NbHl6A1212F35_idivtDkIfodWqvEXmqF2xIc5JPMx0.cache +1 -0
  24. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/O_DOE8ZL1tv6KAmcCD3FcQSefNad6Tvw2hAB-WAYxyE.cache +1 -0
  25. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/Pz8e-g6mv0m0X3uFkpVwjOTGZEjibszt85vhL5SJdNg.cache +1 -0
  26. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/SJkrF8Ralh_HhbmvfAKbq_Td3J8UflhAnpsNhon52kE.cache +0 -0
  27. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/T3VbPBrfBG_M2mtqVvjyaZMp4LETT3VvuvKxp1U56Cc.cache +0 -0
  28. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/Yt2RZ834NN6kGkm4udDJ-Wtnx2-_14ujv8hQX_OZmOc.cache +1 -0
  29. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/ZO-3opaC2Gt8QYT5nm1mzL2Jwf4zs_9gVMegU6WWfUY.cache +1 -0
  30. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/awMEDS383IkYHC7JTIqI6sXg7kzzZv2sQHwjulX0HUs.cache +2 -0
  31. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/q6b8zxMi44GVQTl-GJRWpogdyUFouWI8u09uhqHktSw.cache +0 -0
  32. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/qO4DbjTAlq45h5i51BWY4m2LXiwxyc9fqhOKcupr4uU.cache +2 -0
  33. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/sJf6s34rz4gdJxfsPCjHDaRkRGCYAp0EujRjwsRI8w0.cache +1 -0
  34. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/scElb_WiPaZv7rRpGIgZyVh9vDRRojRi_OGL3S2jnHk.cache +1 -0
  35. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/xMXJ3vour8ycAz_YitjWxbg7iWE5yqDS7ExE6YmICsE.cache +2 -0
  36. metadata +96 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c3f92f420486f2b4a31ea3163752ffd7a1b64b29
4
- data.tar.gz: 22582c3852d83a8b4709ed3fca08b129a45b4cdf
3
+ metadata.gz: 3f1851101844a7e8886196b9ff1c619e6c16a990
4
+ data.tar.gz: 69f11dcdfa6196c9c407a9467eac12c35c7372e0
5
5
  SHA512:
6
- metadata.gz: c63a0021d1433612ac87b147b917c6907a18cea2ee1557f1be61bb1766719d51fc3fb1a8c2747b4284633659736efe6ad48b39cba44c5e706196e9c6556d9456
7
- data.tar.gz: 795a60ff04979ac935ec36849f7c251bc12a7a3a4e4bb9b3091d0e3163d86ea278e3859bdf062979fd9a30a0fe6a9174eb1b6d40b3a89e8b6e159fdb10e5f20a
6
+ metadata.gz: 5a5b3b92808d08b630b466d804ef5d56b8a05296dfb7c3461b1414910c064611129873a53c5764fba4fbab59b45618cc54f38579f4d810f27a9c3bc95cd1a903
7
+ data.tar.gz: b050b01e36cab54b1f10fc9437bdf4cdd2df280d47299a81ff5731494b28ab6667d571178847358c670cad18ce4a2f652a93fcca960f353cbadc35c8aa65413c
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://travis-ci.org/lumoslabs/smoke_detector.png)](https://travis-ci.org/lumoslabs/smoke_detector)
1
+ [![Build Status](https://travis-ci.org/lumoslabs/smoke_detector.svg?branch=master)](https://travis-ci.org/lumoslabs/smoke_detector)
2
2
 
3
3
  Smoke Detector
4
4
  =============
@@ -31,7 +31,8 @@ module SmokeDetector
31
31
  end
32
32
 
33
33
  def monitor?(headers)
34
- headers["Content-Type"] =~ ACCEPTABLE_CONTENT && monitoring_code.present?
34
+ # minified code may not be UTF8 compliant, so you can't use present? reliably
35
+ headers["Content-Type"] =~ ACCEPTABLE_CONTENT && monitoring_code.size > 10
35
36
  end
36
37
  end
37
38
  end
@@ -0,0 +1,2343 @@
1
+ (function webpackUniversalModuleDefinition(root, factory) {
2
+ if(typeof exports === 'object' && typeof module === 'object')
3
+ module.exports = factory();
4
+ else if(typeof define === 'function' && define.amd)
5
+ define(factory);
6
+ else {
7
+ var a = factory();
8
+ for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
9
+ }
10
+ })(this, function() {
11
+ return /******/ (function(modules) { // webpackBootstrap
12
+ /******/ // The module cache
13
+ /******/ var installedModules = {};
14
+ /******/
15
+ /******/ // The require function
16
+ /******/ function __webpack_require__(moduleId) {
17
+ /******/
18
+ /******/ // Check if module is in cache
19
+ /******/ if(installedModules[moduleId])
20
+ /******/ return installedModules[moduleId].exports;
21
+ /******/
22
+ /******/ // Create a new module (and put it into the cache)
23
+ /******/ var module = installedModules[moduleId] = {
24
+ /******/ exports: {},
25
+ /******/ id: moduleId,
26
+ /******/ loaded: false
27
+ /******/ };
28
+ /******/
29
+ /******/ // Execute the module function
30
+ /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
31
+ /******/
32
+ /******/ // Flag the module as loaded
33
+ /******/ module.loaded = true;
34
+ /******/
35
+ /******/ // Return the exports of the module
36
+ /******/ return module.exports;
37
+ /******/ }
38
+ /******/
39
+ /******/
40
+ /******/ // expose the modules object (__webpack_modules__)
41
+ /******/ __webpack_require__.m = modules;
42
+ /******/
43
+ /******/ // expose the module cache
44
+ /******/ __webpack_require__.c = installedModules;
45
+ /******/
46
+ /******/ // __webpack_public_path__
47
+ /******/ __webpack_require__.p = "";
48
+ /******/
49
+ /******/ // Load entry module and return exports
50
+ /******/ return __webpack_require__(0);
51
+ /******/ })
52
+ /************************************************************************/
53
+ /******/ ([
54
+ /* 0 */
55
+ /***/ function(module, exports, __webpack_require__) {
56
+
57
+ module.exports = __webpack_require__(1);
58
+
59
+
60
+ /***/ },
61
+ /* 1 */
62
+ /***/ function(module, exports, __webpack_require__) {
63
+
64
+ /* globals __USE_JSON__ */
65
+ /* globals JSON */
66
+
67
+ "use strict";
68
+
69
+ var globalnotifier = __webpack_require__(2);
70
+ var notifier = __webpack_require__(3);
71
+
72
+ function setupJSON() {
73
+ var JSONObject = typeof JSON === 'undefined' ? {} : JSON;
74
+
75
+ if (true) {
76
+ // This adds the script to this context. We need it since this library
77
+ // is not a CommonJs or AMD module.
78
+ var setupCustomJSON = __webpack_require__(4);
79
+
80
+ var customJSON = {};
81
+ setupCustomJSON(customJSON);
82
+
83
+ JSONObject = customJSON;
84
+ }
85
+
86
+ globalnotifier.setupJSON(JSONObject);
87
+ }
88
+
89
+ setupJSON();
90
+
91
+ var config = window._rollbarConfig;
92
+ var alias = config && config.globalAlias || 'Rollbar';
93
+ var shimRunning = window[alias] && typeof window[alias].shimId !== 'undefined';
94
+
95
+ /* We must not initialize the full notifier here if the
96
+ * shim is loaded, snippet_callback will do that for us
97
+ */
98
+ if (!shimRunning && config) {
99
+ globalnotifier.wrapper.init(config);
100
+ } else {
101
+ window.Rollbar = globalnotifier.wrapper;
102
+ // We need to expose Notifier for the snippet
103
+ window.RollbarNotifier = notifier.Notifier;
104
+ }
105
+
106
+ module.exports = globalnotifier.wrapper;
107
+
108
+
109
+ /***/ },
110
+ /* 2 */
111
+ /***/ function(module, exports, __webpack_require__) {
112
+
113
+ "use strict";
114
+
115
+ var notifier = __webpack_require__(3);
116
+
117
+ var Notifier = notifier.Notifier;
118
+ // Stub out the wrapped error which is set
119
+ window._rollbarWrappedError = null;
120
+
121
+ function setupJSON(JSON) {
122
+ notifier.setupJSON(JSON);
123
+ }
124
+
125
+ // Global window.onerror handler
126
+ function _rollbarWindowOnError(client, old, args) {
127
+ if (!args[4] && window._rollbarWrappedError) {
128
+ args[4] = window._rollbarWrappedError;
129
+ window._rollbarWrappedError = null;
130
+ }
131
+
132
+ client.uncaughtError.apply(client, args);
133
+ if (old) {
134
+ old.apply(window, args);
135
+ }
136
+ }
137
+
138
+ function _extendListenerPrototype(client, prototype) {
139
+ if (prototype.hasOwnProperty && prototype.hasOwnProperty('addEventListener')) {
140
+ var oldAddEventListener = prototype.addEventListener;
141
+ prototype.addEventListener = function(event, callback, bubble) {
142
+ oldAddEventListener.call(this, event, client.wrap(callback), bubble);
143
+ };
144
+
145
+ var oldRemoveEventListener = prototype.removeEventListener;
146
+ prototype.removeEventListener = function(event, callback, bubble) {
147
+ oldRemoveEventListener.call(this, event, callback && callback._wrapped || callback, bubble);
148
+ };
149
+ }
150
+ }
151
+
152
+ // Add an init() method to do the same things that the shim would do
153
+ var wrapper = {};
154
+ wrapper.init = function(config, parent) {
155
+ var notifier = new Notifier(parent);
156
+ notifier.configure(config);
157
+
158
+ if (config.captureUncaught) {
159
+ // Set the global onerror handler
160
+ var old = window.onerror;
161
+
162
+ window.onerror = function() {
163
+ var args = Array.prototype.slice.call(arguments, 0);
164
+ _rollbarWindowOnError(notifier, old, args);
165
+ };
166
+
167
+ // Adapted from https://github.com/bugsnag/bugsnag-js
168
+ var globals = ['EventTarget', 'Window', 'Node', 'ApplicationCache', 'AudioTrackList', 'ChannelMergerNode', 'CryptoOperation', 'EventSource',
169
+ 'FileReader', 'HTMLUnknownElement', 'IDBDatabase', 'IDBRequest', 'IDBTransaction', 'KeyOperation', 'MediaController',
170
+ 'MessagePort', 'ModalWindow', 'Notification', 'SVGElementInstance', 'Screen', 'TextTrack', 'TextTrackCue',
171
+ 'TextTrackList', 'WebSocket', 'WebSocketWorker', 'Worker', 'XMLHttpRequest', 'XMLHttpRequestEventTarget',
172
+ 'XMLHttpRequestUpload'];
173
+
174
+ var i;
175
+ var global;
176
+ for (i = 0; i < globals.length; ++i) {
177
+ global = globals[i];
178
+
179
+ if (window[global] && window[global].prototype) {
180
+ _extendListenerPrototype(notifier, window[global].prototype);
181
+ }
182
+ }
183
+ }
184
+
185
+ window.Rollbar = notifier;
186
+ // Finally, start processing payloads using the global notifier
187
+ Notifier.processPayloads();
188
+ return notifier;
189
+ };
190
+
191
+
192
+ module.exports = {
193
+ wrapper: wrapper,
194
+ setupJSON: setupJSON
195
+ };
196
+
197
+
198
+ /***/ },
199
+ /* 3 */
200
+ /***/ function(module, exports, __webpack_require__) {
201
+
202
+ /* globals __NOTIFIER_VERSION__ */
203
+ /* globals __DEFAULT_ENDPOINT__ */
204
+ /* globals __DEFAULT_SCRUB_FIELDS__ */
205
+ /* globals __DEFAULT_LOG_LEVEL__ */
206
+ /* globals __DEFAULT_REPORT_LEVEL__ */
207
+ /* globals __DEFAULT_UNCAUGHT_ERROR_LEVEL */
208
+ /* globals __DEFAULT_ITEMS_PER_MIN__ */
209
+ /* globals __DEFAULT_MAX_ITEMS__ */
210
+ /* globals DOMException */
211
+
212
+ "use strict";
213
+
214
+ var error_parser = __webpack_require__(5);
215
+ var Util = __webpack_require__(6);
216
+ var xhr = __webpack_require__(7);
217
+
218
+ var XHR = xhr.XHR;
219
+ var RollbarJSON = null;
220
+
221
+ function setupJSON(JSON) {
222
+ RollbarJSON = JSON;
223
+ xhr.setupJSON(JSON);
224
+ }
225
+
226
+ // Updated by the build process to match package.json
227
+ Notifier.NOTIFIER_VERSION = ("1.3.0");
228
+ Notifier.DEFAULT_ENDPOINT = ("api.rollbar.com/api/1/");
229
+ Notifier.DEFAULT_SCRUB_FIELDS = (["pw","pass","passwd","password","secret","confirm_password","confirmPassword","password_confirmation","passwordConfirmation","access_token","accessToken","secret_key","secretKey","secretToken"]);
230
+ Notifier.DEFAULT_LOG_LEVEL = ("debug");
231
+ Notifier.DEFAULT_REPORT_LEVEL = ("debug");
232
+ Notifier.DEFAULT_UNCAUGHT_ERROR_LEVEL = ("warning");
233
+ Notifier.DEFAULT_ITEMS_PER_MIN = (60);
234
+ Notifier.DEFAULT_MAX_ITEMS = (0);
235
+
236
+ Notifier.LEVELS = {
237
+ debug: 0,
238
+ info: 1,
239
+ warning: 2,
240
+ error: 3,
241
+ critical: 4
242
+ };
243
+
244
+ // This is the global queue where all notifiers will put their
245
+ // payloads to be sent to Rollbar.
246
+ window._rollbarPayloadQueue = [];
247
+
248
+ // This contains global options for all Rollbar notifiers.
249
+ window._globalRollbarOptions = {
250
+ startTime: (new Date()).getTime(),
251
+ maxItems: Notifier.DEFAULT_MAX_ITEMS,
252
+ itemsPerMinute: Notifier.DEFAULT_ITEMS_PER_MIN
253
+ };
254
+
255
+ var _topLevelNotifier;
256
+
257
+ function topLevelNotifier() {
258
+ return _topLevelNotifier;
259
+ }
260
+
261
+ function Notifier(parentNotifier) {
262
+ // Save the first notifier so we can use it to send system messages like
263
+ // when the rate limit is reached.
264
+ _topLevelNotifier = _topLevelNotifier || this;
265
+
266
+ var protocol = window.location.protocol;
267
+ if (protocol.indexOf('http') !== 0) {
268
+ protocol = 'https:';
269
+ }
270
+ var endpoint = protocol + '//' + Notifier.DEFAULT_ENDPOINT;
271
+ this.options = {
272
+ enabled: true,
273
+ endpoint: endpoint,
274
+ environment: 'production',
275
+ scrubFields: Util.copy(Notifier.DEFAULT_SCRUB_FIELDS),
276
+ checkIgnore: null,
277
+ logLevel: Notifier.DEFAULT_LOG_LEVEL,
278
+ reportLevel: Notifier.DEFAULT_REPORT_LEVEL,
279
+ uncaughtErrorLevel: Notifier.DEFAULT_UNCAUGHT_ERROR_LEVEL,
280
+ payload: {}
281
+ };
282
+
283
+ this.lastError = null;
284
+ this.plugins = {};
285
+ this.parentNotifier = parentNotifier;
286
+ this.logger = function() {
287
+ if (window.console && typeof window.console.log === 'function') {
288
+ var args = ['Rollbar:'].concat(Array.prototype.slice.call(arguments, 0));
289
+ window.console.log(args);
290
+ }
291
+ };
292
+
293
+ if (parentNotifier) {
294
+ // If the parent notifier has the shimId
295
+ // property it means that it's a Rollbar shim.
296
+ if (parentNotifier.hasOwnProperty('shimId')) {
297
+ // After we set this, the shim is just a proxy to this
298
+ // Notifier instance.
299
+ parentNotifier.notifier = this;
300
+ } else {
301
+ this.logger = parentNotifier.logger;
302
+ this.configure(parentNotifier.options);
303
+ }
304
+ }
305
+ }
306
+
307
+
308
+ Notifier._generateLogFn = function(level) {
309
+ return _wrapNotifierFn(function _logFn() {
310
+ var args = this._getLogArgs(arguments);
311
+
312
+ return this._log(level || args.level || this.options.logLevel || Notifier.DEFAULT_LOG_LEVEL,
313
+ args.message, args.err, args.custom, args.callback);
314
+ });
315
+ };
316
+
317
+
318
+ /*
319
+ * Returns an Object with keys:
320
+ * {
321
+ * message: String,
322
+ * err: Error,
323
+ * custom: Object
324
+ * }
325
+ */
326
+ Notifier.prototype._getLogArgs = function(args) {
327
+ var level = this.options.logLevel || Notifier.DEFAULT_LOG_LEVEL;
328
+ var ts;
329
+ var message;
330
+ var err;
331
+ var custom;
332
+ var callback;
333
+
334
+ var argT;
335
+ var arg;
336
+ for (var i = 0; i < args.length; ++i) {
337
+ arg = args[i];
338
+ argT = typeof arg;
339
+ if (argT === 'string') {
340
+ message = arg;
341
+ } else if (argT === 'function') {
342
+ callback = _wrapNotifierFn(arg, this); // wrap the callback in a try/catch block
343
+ } else if (arg && argT === 'object') {
344
+ if (arg.constructor.name === 'Date') {
345
+ ts = arg;
346
+ } else if (arg instanceof Error ||
347
+ arg.prototype === Error.prototype ||
348
+ arg.hasOwnProperty('stack') ||
349
+ (typeof DOMException !== "undefined" && arg instanceof DOMException)) {
350
+ err = arg;
351
+ } else {
352
+ custom = arg;
353
+ }
354
+ }
355
+ }
356
+
357
+ // TODO(cory): somehow pass in timestamp too...
358
+
359
+ return {
360
+ level: level,
361
+ message: message,
362
+ err: err,
363
+ custom: custom,
364
+ callback: callback
365
+ };
366
+ };
367
+
368
+
369
+ Notifier.prototype._route = function(path) {
370
+ var endpoint = this.options.endpoint;
371
+
372
+ var endpointTrailingSlash = /\/$/.test(endpoint);
373
+ var pathBeginningSlash = /^\//.test(path);
374
+
375
+ if (endpointTrailingSlash && pathBeginningSlash) {
376
+ path = path.substring(1);
377
+ } else if (!endpointTrailingSlash && !pathBeginningSlash) {
378
+ path = '/' + path;
379
+ }
380
+
381
+ return endpoint + path;
382
+ };
383
+
384
+
385
+ /*
386
+ * Given a queue containing each call to the shim, call the
387
+ * corresponding method on this instance.
388
+ *
389
+ * shim queue contains:
390
+ *
391
+ * {shim: Rollbar, method: 'info', args: ['hello world', exc], ts: Date}
392
+ */
393
+ Notifier.prototype._processShimQueue = function(shimQueue) {
394
+ // implement me
395
+ var shim;
396
+ var obj;
397
+ var tmp;
398
+ var method;
399
+ var args;
400
+ var shimToNotifier = {};
401
+ var parentShim;
402
+ var parentNotifier;
403
+ var notifier;
404
+
405
+ // For each of the messages in the shimQueue we need to:
406
+ // 1. get/create the notifier for that shim
407
+ // 2. apply the message to the notifier
408
+ while ((obj = shimQueue.shift())) {
409
+ shim = obj.shim;
410
+ method = obj.method;
411
+ args = obj.args;
412
+ parentShim = shim.parentShim;
413
+
414
+ // Get the current notifier based on the shimId
415
+ notifier = shimToNotifier[shim.shimId];
416
+ if (!notifier) {
417
+
418
+ // If there is no notifier associated with the shimId
419
+ // Check to see if there's a parent shim
420
+ if (parentShim) {
421
+
422
+ // If there is a parent shim, get the parent notifier
423
+ // and create a new notifier for the current shim.
424
+ parentNotifier = shimToNotifier[parentShim.shimId];
425
+
426
+ // Create a new Notifier which will process all of the shim's
427
+ // messages
428
+ notifier = new Notifier(parentNotifier);
429
+ } else {
430
+ // If there is no parent, assume the shim is the top
431
+ // level shim and thus, should use this as the notifier.
432
+ notifier = this;
433
+ }
434
+
435
+ // Save off the shimId->notifier mapping
436
+ shimToNotifier[shim.shimId] = notifier;
437
+ }
438
+
439
+ if (notifier[method] && typeof notifier[method] === 'function') {
440
+ notifier[method].apply(notifier, args);
441
+ }
442
+ }
443
+ };
444
+
445
+
446
+ /*
447
+ * Builds and returns an Object that will be enqueued onto the
448
+ * window._rollbarPayloadQueue array to be sent to Rollbar.
449
+ */
450
+ Notifier.prototype._buildPayload = function(ts, level, message, stackInfo, custom) {
451
+ var accessToken = this.options.accessToken;
452
+
453
+ // NOTE(cory): DEPRECATED
454
+ // Pass in {payload: {environment: 'production'}} instead of just {environment: 'production'}
455
+ var environment = this.options.environment;
456
+
457
+ var notifierOptions = Util.copy(this.options.payload);
458
+ var uuid = Util.uuid4();
459
+
460
+ if (Notifier.LEVELS[level] === undefined) {
461
+ throw new Error('Invalid level');
462
+ }
463
+
464
+ if (!message && !stackInfo && !custom) {
465
+ throw new Error('No message, stack info or custom data');
466
+ }
467
+
468
+ var payloadData = {
469
+ environment: environment,
470
+ endpoint: this.options.endpoint,
471
+ uuid: uuid,
472
+ level: level,
473
+ platform: 'browser',
474
+ framework: 'browser-js',
475
+ language: 'javascript',
476
+ body: this._buildBody(message, stackInfo, custom),
477
+ request: {
478
+ url: window.location.href,
479
+ query_string: window.location.search,
480
+ user_ip: "$remote_ip"
481
+ },
482
+ client: {
483
+ runtime_ms: ts.getTime() - window._globalRollbarOptions.startTime,
484
+ timestamp: Math.round(ts.getTime() / 1000),
485
+ javascript: {
486
+ browser: window.navigator.userAgent,
487
+ language: window.navigator.language,
488
+ cookie_enabled: window.navigator.cookieEnabled,
489
+ screen: {
490
+ width: window.screen.width,
491
+ height: window.screen.height
492
+ },
493
+ plugins: this._getBrowserPlugins()
494
+ }
495
+ },
496
+ server: {},
497
+ notifier: {
498
+ name: 'rollbar-browser-js',
499
+ version: Notifier.NOTIFIER_VERSION
500
+ }
501
+ };
502
+
503
+ if (notifierOptions.body) {
504
+ delete notifierOptions.body;
505
+ }
506
+
507
+ // Overwrite the options from configure() with the payload
508
+ // data.
509
+ var payload = {
510
+ access_token: accessToken,
511
+ data: Util.merge(payloadData, notifierOptions)
512
+ };
513
+
514
+ // Only scrub the data section since we never want to scrub "access_token"
515
+ // even if it's in the scrub fields
516
+ this._scrub(payload.data);
517
+
518
+ return payload;
519
+ };
520
+
521
+
522
+ Notifier.prototype._buildBody = function(message, stackInfo, custom) {
523
+ var body;
524
+ if (stackInfo) {
525
+ body = this._buildPayloadBodyTrace(message, stackInfo, custom);
526
+ } else {
527
+ body = this._buildPayloadBodyMessage(message, custom);
528
+ }
529
+ return body;
530
+ };
531
+
532
+
533
+ Notifier.prototype._buildPayloadBodyMessage = function(message, custom) {
534
+ if (!message) {
535
+ if (custom) {
536
+ message = RollbarJSON.stringify(custom);
537
+ } else {
538
+ message = '';
539
+ }
540
+ }
541
+ var result = {
542
+ body: message
543
+ };
544
+
545
+ if (custom) {
546
+ result.extra = Util.copy(custom);
547
+ }
548
+
549
+ return {
550
+ message: result
551
+ };
552
+ };
553
+
554
+
555
+ Notifier.prototype._buildPayloadBodyTrace = function(description, stackInfo, custom) {
556
+ var guess = _guessErrorClass(stackInfo.message);
557
+ var className = stackInfo.name || guess[0];
558
+ var message = guess[1];
559
+ var trace = {
560
+ exception: {
561
+ 'class': className,
562
+ message: message
563
+ }
564
+ };
565
+
566
+ if (description) {
567
+ trace.exception.description = description || 'uncaught exception';
568
+ }
569
+
570
+ // Transform a TraceKit stackInfo object into a Rollbar trace
571
+ if (stackInfo.stack) {
572
+ var stackFrame;
573
+ var frame;
574
+ var code;
575
+ var pre;
576
+ var post;
577
+ var contextLength;
578
+ var i, j, mid;
579
+
580
+ trace.frames = [];
581
+ for (i = 0; i < stackInfo.stack.length; ++i) {
582
+ stackFrame = stackInfo.stack[i];
583
+ frame = {
584
+ filename: stackFrame.url ? Util.sanitizeUrl(stackFrame.url) : '(unknown)',
585
+ lineno: stackFrame.line || null,
586
+ method: (!stackFrame.func || stackFrame.func === '?') ? '[anonymous]' : stackFrame.func,
587
+ colno: stackFrame.column
588
+ };
589
+
590
+ code = pre = post = null;
591
+ contextLength = stackFrame.context ? stackFrame.context.length : 0;
592
+ if (contextLength) {
593
+ mid = Math.floor(contextLength / 2);
594
+ pre = stackFrame.context.slice(0, mid);
595
+ code = stackFrame.context[mid];
596
+ post = stackFrame.context.slice(mid);
597
+ }
598
+
599
+ if (code) {
600
+ frame.code = code;
601
+ }
602
+
603
+ if (pre || post) {
604
+ frame.context = {};
605
+ if (pre && pre.length) {
606
+ frame.context.pre = pre;
607
+ }
608
+ if (post && post.length) {
609
+ frame.context.post = post;
610
+ }
611
+ }
612
+
613
+ if (stackFrame.args) {
614
+ frame.args = stackFrame.args;
615
+ }
616
+
617
+ trace.frames.push(frame);
618
+ }
619
+
620
+ // NOTE(cory): reverse the frames since rollbar.com expects the most recent call last
621
+ trace.frames.reverse();
622
+
623
+ if (custom) {
624
+ trace.extra = Util.copy(custom);
625
+ }
626
+ return {trace: trace};
627
+ } else {
628
+ // no frames - not useful as a trace. just report as a message.
629
+ return this._buildPayloadBodyMessage(className + ': ' + message, custom);
630
+ }
631
+ };
632
+
633
+
634
+ Notifier.prototype._getBrowserPlugins = function() {
635
+ if (!this._browserPlugins) {
636
+ var navPlugins = window.navigator.plugins || [];
637
+ var cur;
638
+ var numPlugins = navPlugins.length;
639
+ var plugins = [];
640
+ var i;
641
+ for (i = 0; i < numPlugins; ++i) {
642
+ cur = navPlugins[i];
643
+ plugins.push({name: cur.name, description: cur.description});
644
+ }
645
+ this._browserPlugins = plugins;
646
+ }
647
+ return this._browserPlugins;
648
+ };
649
+
650
+
651
+ /*
652
+ * Does an in-place modification of obj such that:
653
+ * 1. All keys that match the notifier's options.scrubFields
654
+ * list will be normalized into all '*'
655
+ * 2. Any query string params that match the same criteria will have
656
+ * their values normalized as well.
657
+ */
658
+ Notifier.prototype._scrub = function(obj) {
659
+ function redactQueryParam(match, paramPart, dummy1,
660
+ dummy2, dummy3, valPart, offset, string) {
661
+ return paramPart + Util.redact(valPart);
662
+ }
663
+
664
+ function paramScrubber(v) {
665
+ var i;
666
+ if (typeof v === 'string') {
667
+ for (i = 0; i < queryRes.length; ++i) {
668
+ v = v.replace(queryRes[i], redactQueryParam);
669
+ }
670
+ }
671
+ return v;
672
+ }
673
+
674
+ function valScrubber(k, v) {
675
+ var i;
676
+ for (i = 0; i < paramRes.length; ++i) {
677
+ if (paramRes[i].test(k)) {
678
+ v = Util.redact(v);
679
+ break;
680
+ }
681
+ }
682
+ return v;
683
+ }
684
+
685
+ function scrubber(k, v) {
686
+ var tmpV = valScrubber(k, v);
687
+ if (tmpV === v) {
688
+ return paramScrubber(tmpV);
689
+ } else {
690
+ return tmpV;
691
+ }
692
+ }
693
+
694
+ var scrubFields = this.options.scrubFields;
695
+ var paramRes = this._getScrubFieldRegexs(scrubFields);
696
+ var queryRes = this._getScrubQueryParamRegexs(scrubFields);
697
+
698
+ Util.traverse(obj, scrubber);
699
+ return obj;
700
+ };
701
+
702
+
703
+ Notifier.prototype._getScrubFieldRegexs = function(scrubFields) {
704
+ var ret = [];
705
+ var pat;
706
+ for (var i = 0; i < scrubFields.length; ++i) {
707
+ pat = '\\[?(%5[bB])?' + scrubFields[i] + '\\[?(%5[bB])?\\]?(%5[dD])?';
708
+ ret.push(new RegExp(pat, 'i'));
709
+ }
710
+ return ret;
711
+ };
712
+
713
+
714
+ Notifier.prototype._getScrubQueryParamRegexs = function(scrubFields) {
715
+ var ret = [];
716
+ var pat;
717
+ for (var i = 0; i < scrubFields.length; ++i) {
718
+ pat = '\\[?(%5[bB])?' + scrubFields[i] + '\\[?(%5[bB])?\\]?(%5[dD])?';
719
+ ret.push(new RegExp('(' + pat + '=)([^&\\n]+)', 'igm'));
720
+ }
721
+ return ret;
722
+ };
723
+
724
+ Notifier.prototype._urlIsWhitelisted = function(payload){
725
+ var whitelist, trace, frame, filename, frameLength, url, listLength, urlRegex;
726
+ var i, j;
727
+
728
+ try {
729
+ whitelist = this.options.hostWhiteList;
730
+ trace = payload.data.body.trace;
731
+
732
+ if (!whitelist || whitelist.length === 0) { return true; }
733
+ if (!trace) { return true; }
734
+
735
+ listLength = whitelist.length;
736
+ frameLength = trace.frames.length;
737
+ for (i = 0; i < frameLength; i++) {
738
+ frame = trace.frames[i];
739
+ filename = frame.filename;
740
+ if (typeof filename !== "string") { return true; }
741
+ for (j = 0; j < listLength; j++) {
742
+ url = whitelist[j];
743
+ urlRegex = new RegExp(url);
744
+
745
+ if (urlRegex.test(filename)){
746
+ return true;
747
+ }
748
+ }
749
+ }
750
+ } catch (e) {
751
+ this.configure({hostWhiteList: null});
752
+ this.error("Error while reading your configuration's hostWhiteList option. Removing custom hostWhiteList.", e);
753
+ return true;
754
+ }
755
+
756
+ return false;
757
+ };
758
+
759
+ Notifier.prototype._messageIsIgnored = function(payload){
760
+ var exceptionMessage, i, ignoredMessages, len, messageIsIgnored, rIgnoredMessage, trace;
761
+ try {
762
+ messageIsIgnored = false;
763
+ ignoredMessages = this.options.ignoredMessages;
764
+ trace = payload.data.body.trace;
765
+
766
+ if(!ignoredMessages || ignoredMessages.length === 0) { return false; }
767
+ if(!trace) { return false; }
768
+ exceptionMessage = trace.exception.message;
769
+
770
+ len = ignoredMessages.length;
771
+ for(i=0; i < len; i++) {
772
+ rIgnoredMessage = new RegExp(ignoredMessages[i], "gi");
773
+ messageIsIgnored = rIgnoredMessage.test(exceptionMessage);
774
+
775
+ if(messageIsIgnored){
776
+ break;
777
+ }
778
+ }
779
+ }
780
+ catch(e) {
781
+ this.configure({ignoredMessages: null});
782
+ this.error("Error while reading your configuration's ignoredMessages option. Removing custom ignoredMessages.");
783
+ }
784
+
785
+ return messageIsIgnored;
786
+ };
787
+
788
+ Notifier.prototype._enqueuePayload = function(payload, isUncaught, callerArgs, callback) {
789
+
790
+ var payloadToSend = {
791
+ callback: callback,
792
+ accessToken: this.options.accessToken,
793
+ endpointUrl: this._route('item/'),
794
+ payload: payload
795
+ };
796
+
797
+ var ignoredCallback = function() {
798
+ if (callback) {
799
+ // If the item was ignored call the callback anyway
800
+ var msg = 'This item was not sent to Rollbar because it was ignored. ' +
801
+ 'This can happen if a custom checkIgnore() function was used ' +
802
+ 'or if the item\'s level was less than the notifier\' reportLevel. ' +
803
+ 'See https://rollbar.com/docs/notifier/rollbar.js/configuration for more details.';
804
+
805
+ callback(null, {err: 0, result: {id: null, uuid: null, message: msg}});
806
+ }
807
+ };
808
+
809
+ // Internal checkIgnore will check the level against the minimum
810
+ // report level from this.options
811
+ if (this._internalCheckIgnore(isUncaught, callerArgs, payload)) {
812
+ ignoredCallback();
813
+ return;
814
+ }
815
+
816
+ // Users can set their own ignore criteria using this.options.checkIgnore()
817
+ try {
818
+ if (this.options.checkIgnore &&
819
+ typeof this.options.checkIgnore === 'function' &&
820
+ this.options.checkIgnore(isUncaught, callerArgs, payload)) {
821
+ ignoredCallback();
822
+ return;
823
+ }
824
+ } catch (e) {
825
+ // Disable the custom checkIgnore and report errors in the checkIgnore function
826
+ this.configure({checkIgnore: null});
827
+ this.error('Error while calling custom checkIgnore() function. Removing custom checkIgnore().', e);
828
+ }
829
+
830
+ if (!this._urlIsWhitelisted(payload)) {
831
+ return;
832
+ }
833
+
834
+ if (this._messageIsIgnored(payload)) {
835
+ return;
836
+ }
837
+
838
+ if (this.options.verbose) {
839
+ if (payload.data && payload.data.body && payload.data.body.trace) {
840
+ var trace = payload.data.body.trace;
841
+ var exceptionMessage = trace.exception.message;
842
+ this.logger(exceptionMessage);
843
+ }
844
+
845
+ // FIXME: Some browsers do not output objects as json to the console, and
846
+ // instead write [object Object], so let's write the message first to ensure that is logged.
847
+ this.logger('Sending payload -', payloadToSend);
848
+ }
849
+
850
+ if (typeof this.options.logFunction === "function") {
851
+ this.options.logFunction(payloadToSend);
852
+ }
853
+
854
+ try {
855
+ if (typeof this.options.transform === 'function') {
856
+ this.options.transform(payload);
857
+ }
858
+ } catch (e) {
859
+ this.configure({transform: null});
860
+ this.error('Error while calling custom transform() function. Removing custom transform().', e);
861
+ }
862
+
863
+ if (!!this.options.enabled) {
864
+ window._rollbarPayloadQueue.push(payloadToSend);
865
+
866
+ _notifyPayloadAvailable();
867
+ }
868
+ };
869
+
870
+
871
+ Notifier.prototype._internalCheckIgnore = function(isUncaught, callerArgs, payload) {
872
+ var level = callerArgs[0];
873
+ var levelVal = Notifier.LEVELS[level] || 0;
874
+ var reportLevel = Notifier.LEVELS[this.options.reportLevel] || 0;
875
+
876
+ if (levelVal < reportLevel) {
877
+ return true;
878
+ }
879
+
880
+ var plugins = this.options ? this.options.plugins : {};
881
+ if (plugins && plugins.jquery && plugins.jquery.ignoreAjaxErrors &&
882
+ payload.body.message) {
883
+ return payload.body.messagejquery_ajax_error;
884
+ }
885
+
886
+ return false;
887
+ };
888
+
889
+
890
+ /*
891
+ * Logs stuff to Rollbar using the default
892
+ * logging level.
893
+ *
894
+ * Can be called with the following, (order doesn't matter but type does):
895
+ * - message: String
896
+ * - err: Error object, must have a .stack property or it will be
897
+ * treated as custom data
898
+ * - custom: Object containing custom data to be sent along with
899
+ * the item
900
+ * - callback: Function to call once the item is reported to Rollbar
901
+ * - isUncaught: True if this error originated from an uncaught exception handler
902
+ * - ignoreRateLimit: True if this item should be allowed despite rate limit checks
903
+ */
904
+ Notifier.prototype._log = function(level, message, err, custom, callback, isUncaught, ignoreRateLimit) {
905
+ var stackInfo = null;
906
+ if (err) {
907
+ // If we've already calculated the stack trace for the error, use it.
908
+ // This can happen for wrapped errors that don't have a "stack" property.
909
+ stackInfo = err._savedStackTrace ? err._savedStackTrace : error_parser.parse(err);
910
+
911
+ // Don't report the same error more than once
912
+ if (err === this.lastError) {
913
+ return;
914
+ }
915
+
916
+ this.lastError = err;
917
+ }
918
+
919
+ var payload = this._buildPayload(new Date(), level, message, stackInfo, custom);
920
+ if (ignoreRateLimit) {
921
+ payload.ignoreRateLimit = true;
922
+ }
923
+ this._enqueuePayload(payload, isUncaught ? true : false, [level, message, err, custom], callback);
924
+ };
925
+
926
+ Notifier.prototype.log = Notifier._generateLogFn();
927
+ Notifier.prototype.debug = Notifier._generateLogFn('debug');
928
+ Notifier.prototype.info = Notifier._generateLogFn('info');
929
+ Notifier.prototype.warn = Notifier._generateLogFn('warning'); // for console.warn() compatibility
930
+ Notifier.prototype.warning = Notifier._generateLogFn('warning');
931
+ Notifier.prototype.error = Notifier._generateLogFn('error');
932
+ Notifier.prototype.critical = Notifier._generateLogFn('critical');
933
+
934
+ // Adapted from tracekit.js
935
+ Notifier.prototype.uncaughtError = _wrapNotifierFn(function(message, url, lineNo, colNo, err, context) {
936
+ context = context || null;
937
+ if (err && err.stack) {
938
+ this._log(this.options.uncaughtErrorLevel, message, err, context, null, true);
939
+ return;
940
+ }
941
+
942
+ // NOTE(cory): sometimes users will trigger an "error" event
943
+ // on the window object directly which will result in errMsg
944
+ // being an Object instead of a string.
945
+ //
946
+ if (url && url.stack) {
947
+ this._log(this.options.uncaughtErrorLevel, message, url, context, null, true);
948
+ return;
949
+ }
950
+
951
+ var location = {
952
+ 'url': url || '',
953
+ 'line': lineNo
954
+ };
955
+ location.func = error_parser.guessFunctionName(location.url, location.line);
956
+ location.context = error_parser.gatherContext(location.url, location.line);
957
+ var stack = {
958
+ 'mode': 'onerror',
959
+ 'message': message || 'uncaught exception',
960
+ 'url': document.location.href,
961
+ 'stack': [location],
962
+ 'useragent': navigator.userAgent
963
+ };
964
+ if (err) {
965
+ stack = err._savedStackTrace || error_parser.parse(err);
966
+ }
967
+
968
+ var payload = this._buildPayload(new Date(), this.options.uncaughtErrorLevel, message, stack);
969
+ this._enqueuePayload(payload, true, [this.options.uncaughtErrorLevel, message, url, lineNo, colNo, err]);
970
+ });
971
+
972
+
973
+ Notifier.prototype.global = _wrapNotifierFn(function(options) {
974
+ options = options || {};
975
+
976
+ Util.merge(window._globalRollbarOptions, options);
977
+
978
+ if (options.maxItems !== undefined) {
979
+ rateLimitCounter = 0;
980
+ }
981
+
982
+ if (options.itemsPerMinute !== undefined) {
983
+ rateLimitPerMinCounter = 0;
984
+ }
985
+ });
986
+
987
+
988
+ Notifier.prototype.configure = _wrapNotifierFn(function(options) {
989
+ // TODO(cory): only allow non-payload keys that we understand
990
+
991
+ // Make a copy of the options object for this notifier
992
+ Util.merge(this.options, options);
993
+ this.global(options);
994
+ });
995
+
996
+ /*
997
+ * Create a new Notifier instance which has the same options
998
+ * as the current notifier + options to override them.
999
+ */
1000
+ Notifier.prototype.scope = _wrapNotifierFn(function(payloadOptions) {
1001
+ var scopedNotifier = new Notifier(this);
1002
+ Util.merge(scopedNotifier.options.payload, payloadOptions);
1003
+ return scopedNotifier;
1004
+ });
1005
+
1006
+ Notifier.prototype.wrap = function(f, context) {
1007
+ var _this = this;
1008
+ var ctxFn;
1009
+ if (typeof context === 'function') {
1010
+ ctxFn = context;
1011
+ } else {
1012
+ ctxFn = function() { return context || {}; };
1013
+ }
1014
+
1015
+ if (typeof f !== 'function') {
1016
+ return f;
1017
+ }
1018
+
1019
+ // If the given function is already a wrapped function, just
1020
+ // return it instead of wrapping twice
1021
+ if (f._isWrap) {
1022
+ return f;
1023
+ }
1024
+
1025
+ if (!f._wrapped) {
1026
+ f._wrapped = function () {
1027
+ try {
1028
+ return f.apply(this, arguments);
1029
+ } catch(e) {
1030
+ if (!e.stack) {
1031
+ e._savedStackTrace = error_parser.parse(e);
1032
+ }
1033
+ e._rollbarContext = ctxFn() || {};
1034
+ e._rollbarContext._wrappedSource = f.toString();
1035
+
1036
+ window._rollbarWrappedError = e;
1037
+ throw e;
1038
+ }
1039
+ };
1040
+
1041
+ f._wrapped._isWrap = true;
1042
+
1043
+ for (var prop in f) {
1044
+ if (f.hasOwnProperty(prop)) {
1045
+ f._wrapped[prop] = f[prop];
1046
+ }
1047
+ }
1048
+ }
1049
+
1050
+ return f._wrapped;
1051
+ };
1052
+
1053
+ /***** Misc *****/
1054
+
1055
+ function _wrapNotifierFn(fn, ctx) {
1056
+ return function() {
1057
+ var self = ctx || this;
1058
+ try {
1059
+ return fn.apply(self, arguments);
1060
+ } catch (e) {
1061
+ if (self) {
1062
+ self.logger(e);
1063
+ }
1064
+ }
1065
+ };
1066
+ }
1067
+
1068
+
1069
+ var ERR_CLASS_REGEXP = new RegExp('^(([a-zA-Z0-9-_$ ]*): *)?(Uncaught )?([a-zA-Z0-9-_$ ]*): ');
1070
+ function _guessErrorClass(errMsg) {
1071
+ if (!errMsg) {
1072
+ return ["Unknown error. There was no error message to display.", ""];
1073
+ }
1074
+ var errClassMatch = errMsg.match(ERR_CLASS_REGEXP);
1075
+ var errClass = '(unknown)';
1076
+
1077
+ if (errClassMatch) {
1078
+ errClass = errClassMatch[errClassMatch.length - 1];
1079
+ errMsg = errMsg.replace((errClassMatch[errClassMatch.length - 2] || '') + errClass + ':', '');
1080
+ errMsg = errMsg.replace(/(^[\s]+|[\s]+$)/g, '');
1081
+ }
1082
+ return [errClass, errMsg];
1083
+ }
1084
+
1085
+ /***** Payload processor *****/
1086
+
1087
+ var payloadProcessorTimeout;
1088
+ Notifier.processPayloads = function(immediate) {
1089
+ if (immediate) {
1090
+ _deferredPayloadProcess();
1091
+
1092
+ return;
1093
+ }
1094
+
1095
+ _notifyPayloadAvailable();
1096
+ };
1097
+
1098
+ function _notifyPayloadAvailable() {
1099
+ if (!payloadProcessorTimeout) {
1100
+ payloadProcessorTimeout = setTimeout(_deferredPayloadProcess, 1000);
1101
+ }
1102
+ }
1103
+
1104
+ function _deferredPayloadProcess() {
1105
+ var payloadObj;
1106
+
1107
+ try {
1108
+ while ((payloadObj = window._rollbarPayloadQueue.shift())) {
1109
+ _processPayload(payloadObj.endpointUrl, payloadObj.accessToken, payloadObj.payload, payloadObj.callback);
1110
+ }
1111
+ } finally {
1112
+ payloadProcessorTimeout = undefined;
1113
+ }
1114
+ }
1115
+
1116
+
1117
+ var rateLimitStartTime = new Date().getTime();
1118
+ var rateLimitCounter = 0;
1119
+ var rateLimitPerMinCounter = 0;
1120
+ function _processPayload(url, accessToken, payload, callback) {
1121
+ callback = callback || function cb() {};
1122
+ var now = new Date().getTime();
1123
+ if (now - rateLimitStartTime >= 60000) {
1124
+ rateLimitStartTime = now;
1125
+ rateLimitPerMinCounter = 0;
1126
+ }
1127
+
1128
+ // Check to see if we have a rate limit set or if
1129
+ // the rate limit has been met/exceeded.
1130
+ var globalRateLimit = window._globalRollbarOptions.maxItems;
1131
+ var globalRateLimitPerMin = window._globalRollbarOptions.itemsPerMinute;
1132
+ var checkOverRateLimit = function() { return !payload.ignoreRateLimit && globalRateLimit >= 1 && rateLimitCounter >= globalRateLimit; };
1133
+ var checkOverRateLimitPerMin = function() { return !payload.ignoreRateLimit && globalRateLimitPerMin >= 1 && rateLimitPerMinCounter >= globalRateLimitPerMin; };
1134
+
1135
+ if (checkOverRateLimit()) {
1136
+ callback(new Error(globalRateLimit + ' max items reached'));
1137
+ return;
1138
+ } else if (checkOverRateLimitPerMin()) {
1139
+ callback(new Error(globalRateLimitPerMin + ' items per minute reached'));
1140
+ return;
1141
+ } else {
1142
+ rateLimitCounter++;
1143
+ rateLimitPerMinCounter++;
1144
+
1145
+ // Check to see if we have just reached the rate limit. If so, notify the customer.
1146
+ if (checkOverRateLimit()) {
1147
+ _topLevelNotifier._log(_topLevelNotifier.options.uncaughtErrorLevel, //level
1148
+ 'maxItems has been hit. Ignoring errors for the remainder of the current page load.', // message
1149
+ null, // err
1150
+ {maxItems: globalRateLimit}, // custom
1151
+ null, // callback
1152
+ false, // isUncaught
1153
+ true); // ignoreRateLimit
1154
+ }
1155
+ // remove this key since it's only used for internal notifier logic
1156
+ if (payload.ignoreRateLimit) {
1157
+ delete payload.ignoreRateLimit;
1158
+ }
1159
+ }
1160
+
1161
+ // There's either no rate limit or we haven't met it yet so
1162
+ // go ahead and send it.
1163
+ XHR.post(url, accessToken, payload, function xhrCallback(err, resp) {
1164
+ if (err) {
1165
+ return callback(err);
1166
+ }
1167
+
1168
+ // TODO(cory): parse resp as JSON
1169
+ return callback(null, resp);
1170
+ });
1171
+
1172
+ }
1173
+
1174
+ module.exports = {
1175
+ Notifier: Notifier,
1176
+ setupJSON: setupJSON,
1177
+ topLevelNotifier: topLevelNotifier
1178
+ };
1179
+
1180
+
1181
+
1182
+ /***/ },
1183
+ /* 4 */
1184
+ /***/ function(module, exports, __webpack_require__) {
1185
+
1186
+ /*
1187
+ json2.js
1188
+ 2013-05-26
1189
+
1190
+ Public Domain.
1191
+
1192
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
1193
+
1194
+ See http://www.JSON.org/js.html
1195
+
1196
+
1197
+ This code should be minified before deployment.
1198
+ See http://javascript.crockford.com/jsmin.html
1199
+
1200
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
1201
+ NOT CONTROL.
1202
+
1203
+
1204
+ This file creates a global JSON object containing two methods: stringify
1205
+ and parse.
1206
+
1207
+ JSON.stringify(value, replacer, space)
1208
+ value any JavaScript value, usually an object or array.
1209
+
1210
+ replacer an optional parameter that determines how object
1211
+ values are stringified for objects. It can be a
1212
+ function or an array of strings.
1213
+
1214
+ space an optional parameter that specifies the indentation
1215
+ of nested structures. If it is omitted, the text will
1216
+ be packed without extra whitespace. If it is a number,
1217
+ it will specify the number of spaces to indent at each
1218
+ level. If it is a string (such as '\t' or '&nbsp;'),
1219
+ it contains the characters used to indent at each level.
1220
+
1221
+ This method produces a JSON text from a JavaScript value.
1222
+
1223
+ When an object value is found, if the object contains a toJSON
1224
+ method, its toJSON method will be called and the result will be
1225
+ stringified. A toJSON method does not serialize: it returns the
1226
+ value represented by the name/value pair that should be serialized,
1227
+ or undefined if nothing should be serialized. The toJSON method
1228
+ will be passed the key associated with the value, and this will be
1229
+ bound to the value
1230
+
1231
+ For example, this would serialize Dates as ISO strings.
1232
+
1233
+ Date.prototype.toJSON = function (key) {
1234
+ function f(n) {
1235
+ // Format integers to have at least two digits.
1236
+ return n < 10 ? '0' + n : n;
1237
+ }
1238
+
1239
+ return this.getUTCFullYear() + '-' +
1240
+ f(this.getUTCMonth() + 1) + '-' +
1241
+ f(this.getUTCDate()) + 'T' +
1242
+ f(this.getUTCHours()) + ':' +
1243
+ f(this.getUTCMinutes()) + ':' +
1244
+ f(this.getUTCSeconds()) + 'Z';
1245
+ };
1246
+
1247
+ You can provide an optional replacer method. It will be passed the
1248
+ key and value of each member, with this bound to the containing
1249
+ object. The value that is returned from your method will be
1250
+ serialized. If your method returns undefined, then the member will
1251
+ be excluded from the serialization.
1252
+
1253
+ If the replacer parameter is an array of strings, then it will be
1254
+ used to select the members to be serialized. It filters the results
1255
+ such that only members with keys listed in the replacer array are
1256
+ stringified.
1257
+
1258
+ Values that do not have JSON representations, such as undefined or
1259
+ functions, will not be serialized. Such values in objects will be
1260
+ dropped; in arrays they will be replaced with null. You can use
1261
+ a replacer function to replace those with JSON values.
1262
+ JSON.stringify(undefined) returns undefined.
1263
+
1264
+ The optional space parameter produces a stringification of the
1265
+ value that is filled with line breaks and indentation to make it
1266
+ easier to read.
1267
+
1268
+ If the space parameter is a non-empty string, then that string will
1269
+ be used for indentation. If the space parameter is a number, then
1270
+ the indentation will be that many spaces.
1271
+
1272
+ Example:
1273
+
1274
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
1275
+ // text is '["e",{"pluribus":"unum"}]'
1276
+
1277
+
1278
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
1279
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
1280
+
1281
+ text = JSON.stringify([new Date()], function (key, value) {
1282
+ return this[key] instanceof Date ?
1283
+ 'Date(' + this[key] + ')' : value;
1284
+ });
1285
+ // text is '["Date(---current time---)"]'
1286
+
1287
+
1288
+ JSON.parse(text, reviver)
1289
+ This method parses a JSON text to produce an object or array.
1290
+ It can throw a SyntaxError exception.
1291
+
1292
+ The optional reviver parameter is a function that can filter and
1293
+ transform the results. It receives each of the keys and values,
1294
+ and its return value is used instead of the original value.
1295
+ If it returns what it received, then the structure is not modified.
1296
+ If it returns undefined then the member is deleted.
1297
+
1298
+ Example:
1299
+
1300
+ // Parse the text. Values that look like ISO date strings will
1301
+ // be converted to Date objects.
1302
+
1303
+ myData = JSON.parse(text, function (key, value) {
1304
+ var a;
1305
+ if (typeof value === 'string') {
1306
+ a =
1307
+ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
1308
+ if (a) {
1309
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
1310
+ +a[5], +a[6]));
1311
+ }
1312
+ }
1313
+ return value;
1314
+ });
1315
+
1316
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
1317
+ var d;
1318
+ if (typeof value === 'string' &&
1319
+ value.slice(0, 5) === 'Date(' &&
1320
+ value.slice(-1) === ')') {
1321
+ d = new Date(value.slice(5, -1));
1322
+ if (d) {
1323
+ return d;
1324
+ }
1325
+ }
1326
+ return value;
1327
+ });
1328
+
1329
+
1330
+ This is a reference implementation. You are free to copy, modify, or
1331
+ redistribute.
1332
+ */
1333
+
1334
+ /*jslint evil: true, regexp: true */
1335
+
1336
+ /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
1337
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
1338
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
1339
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
1340
+ test, toJSON, toString, valueOf
1341
+ */
1342
+
1343
+ var setupCustomJSON = function(JSON) {
1344
+ function f(n) {
1345
+ // Format integers to have at least two digits.
1346
+ return n < 10 ? '0' + n : n;
1347
+ }
1348
+
1349
+ if (typeof Date.prototype.toJSON !== 'function') {
1350
+
1351
+ Date.prototype.toJSON = function () {
1352
+
1353
+ return isFinite(this.valueOf())
1354
+ ? this.getUTCFullYear() + '-' +
1355
+ f(this.getUTCMonth() + 1) + '-' +
1356
+ f(this.getUTCDate()) + 'T' +
1357
+ f(this.getUTCHours()) + ':' +
1358
+ f(this.getUTCMinutes()) + ':' +
1359
+ f(this.getUTCSeconds()) + 'Z'
1360
+ : null;
1361
+ };
1362
+
1363
+ String.prototype.toJSON =
1364
+ Number.prototype.toJSON =
1365
+ Boolean.prototype.toJSON = function () {
1366
+ return this.valueOf();
1367
+ };
1368
+ }
1369
+
1370
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
1371
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
1372
+ gap,
1373
+ indent,
1374
+ meta = { // table of character substitutions
1375
+ '\b': '\\b',
1376
+ '\t': '\\t',
1377
+ '\n': '\\n',
1378
+ '\f': '\\f',
1379
+ '\r': '\\r',
1380
+ '"' : '\\"',
1381
+ '\\': '\\\\'
1382
+ },
1383
+ rep;
1384
+
1385
+
1386
+ function quote(string) {
1387
+
1388
+ // If the string contains no control characters, no quote characters, and no
1389
+ // backslash characters, then we can safely slap some quotes around it.
1390
+ // Otherwise we must also replace the offending characters with safe escape
1391
+ // sequences.
1392
+
1393
+ escapable.lastIndex = 0;
1394
+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
1395
+ var c = meta[a];
1396
+ return typeof c === 'string'
1397
+ ? c
1398
+ : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
1399
+ }) + '"' : '"' + string + '"';
1400
+ }
1401
+
1402
+
1403
+ function str(key, holder) {
1404
+
1405
+ // Produce a string from holder[key].
1406
+
1407
+ var i, // The loop counter.
1408
+ k, // The member key.
1409
+ v, // The member value.
1410
+ length,
1411
+ mind = gap,
1412
+ partial,
1413
+ value = holder[key];
1414
+
1415
+ // If we were called with a replacer function, then call the replacer to
1416
+ // obtain a replacement value.
1417
+
1418
+ if (typeof rep === 'function') {
1419
+ value = rep.call(holder, key, value);
1420
+ }
1421
+
1422
+ // What happens next depends on the value's type.
1423
+
1424
+ switch (typeof value) {
1425
+ case 'string':
1426
+ return quote(value);
1427
+
1428
+ case 'number':
1429
+
1430
+ // JSON numbers must be finite. Encode non-finite numbers as null.
1431
+
1432
+ return isFinite(value) ? String(value) : 'null';
1433
+
1434
+ case 'boolean':
1435
+ case 'null':
1436
+
1437
+ // If the value is a boolean or null, convert it to a string. Note:
1438
+ // typeof null does not produce 'null'. The case is included here in
1439
+ // the remote chance that this gets fixed someday.
1440
+
1441
+ return String(value);
1442
+
1443
+ // If the type is 'object', we might be dealing with an object or an array or
1444
+ // null.
1445
+
1446
+ case 'object':
1447
+
1448
+ // Due to a specification blunder in ECMAScript, typeof null is 'object',
1449
+ // so watch out for that case.
1450
+
1451
+ if (!value) {
1452
+ return 'null';
1453
+ }
1454
+
1455
+ // Make an array to hold the partial results of stringifying this object value.
1456
+
1457
+ gap += indent;
1458
+ partial = [];
1459
+
1460
+ // Is the value an array?
1461
+
1462
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
1463
+
1464
+ // The value is an array. Stringify every element. Use null as a placeholder
1465
+ // for non-JSON values.
1466
+
1467
+ length = value.length;
1468
+ for (i = 0; i < length; i += 1) {
1469
+ partial[i] = str(i, value) || 'null';
1470
+ }
1471
+
1472
+ // Join all of the elements together, separated with commas, and wrap them in
1473
+ // brackets.
1474
+
1475
+ v = partial.length === 0
1476
+ ? '[]'
1477
+ : gap
1478
+ ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
1479
+ : '[' + partial.join(',') + ']';
1480
+ gap = mind;
1481
+ return v;
1482
+ }
1483
+
1484
+ // If the replacer is an array, use it to select the members to be stringified.
1485
+
1486
+ if (rep && typeof rep === 'object') {
1487
+ length = rep.length;
1488
+ for (i = 0; i < length; i += 1) {
1489
+ if (typeof rep[i] === 'string') {
1490
+ k = rep[i];
1491
+ v = str(k, value);
1492
+ if (v) {
1493
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
1494
+ }
1495
+ }
1496
+ }
1497
+ } else {
1498
+
1499
+ // Otherwise, iterate through all of the keys in the object.
1500
+
1501
+ for (k in value) {
1502
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
1503
+ v = str(k, value);
1504
+ if (v) {
1505
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
1506
+ }
1507
+ }
1508
+ }
1509
+ }
1510
+
1511
+ // Join all of the member texts together, separated with commas,
1512
+ // and wrap them in braces.
1513
+
1514
+ v = partial.length === 0
1515
+ ? '{}'
1516
+ : gap
1517
+ ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
1518
+ : '{' + partial.join(',') + '}';
1519
+ gap = mind;
1520
+ return v;
1521
+ }
1522
+ }
1523
+
1524
+ // If the JSON object does not yet have a stringify method, give it one.
1525
+
1526
+ if (typeof JSON.stringify !== 'function') {
1527
+ JSON.stringify = function (value, replacer, space) {
1528
+
1529
+ // The stringify method takes a value and an optional replacer, and an optional
1530
+ // space parameter, and returns a JSON text. The replacer can be a function
1531
+ // that can replace values, or an array of strings that will select the keys.
1532
+ // A default replacer method can be provided. Use of the space parameter can
1533
+ // produce text that is more easily readable.
1534
+
1535
+ var i;
1536
+ gap = '';
1537
+ indent = '';
1538
+
1539
+ // If the space parameter is a number, make an indent string containing that
1540
+ // many spaces.
1541
+
1542
+ if (typeof space === 'number') {
1543
+ for (i = 0; i < space; i += 1) {
1544
+ indent += ' ';
1545
+ }
1546
+
1547
+ // If the space parameter is a string, it will be used as the indent string.
1548
+
1549
+ } else if (typeof space === 'string') {
1550
+ indent = space;
1551
+ }
1552
+
1553
+ // If there is a replacer, it must be a function or an array.
1554
+ // Otherwise, throw an error.
1555
+
1556
+ rep = replacer;
1557
+ if (replacer && typeof replacer !== 'function' &&
1558
+ (typeof replacer !== 'object' ||
1559
+ typeof replacer.length !== 'number')) {
1560
+ throw new Error('JSON.stringify');
1561
+ }
1562
+
1563
+ // Make a fake root object containing our value under the key of ''.
1564
+ // Return the result of stringifying the value.
1565
+
1566
+ return str('', {'': value});
1567
+ };
1568
+ }
1569
+
1570
+
1571
+ // If the JSON object does not yet have a parse method, give it one.
1572
+
1573
+ if (typeof JSON.parse !== 'function') {
1574
+ JSON.parse = function (text, reviver) {
1575
+
1576
+ // The parse method takes a text and an optional reviver function, and returns
1577
+ // a JavaScript value if the text is a valid JSON text.
1578
+
1579
+ var j;
1580
+
1581
+ function walk(holder, key) {
1582
+
1583
+ // The walk method is used to recursively walk the resulting structure so
1584
+ // that modifications can be made.
1585
+
1586
+ var k, v, value = holder[key];
1587
+ if (value && typeof value === 'object') {
1588
+ for (k in value) {
1589
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
1590
+ v = walk(value, k);
1591
+ if (v !== undefined) {
1592
+ value[k] = v;
1593
+ } else {
1594
+ delete value[k];
1595
+ }
1596
+ }
1597
+ }
1598
+ }
1599
+ return reviver.call(holder, key, value);
1600
+ }
1601
+
1602
+
1603
+ // Parsing happens in four stages. In the first stage, we replace certain
1604
+ // Unicode characters with escape sequences. JavaScript handles many characters
1605
+ // incorrectly, either silently deleting them, or treating them as line endings.
1606
+
1607
+ text = String(text);
1608
+ cx.lastIndex = 0;
1609
+ if (cx.test(text)) {
1610
+ text = text.replace(cx, function (a) {
1611
+ return '\\u' +
1612
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
1613
+ });
1614
+ }
1615
+
1616
+ // In the second stage, we run the text against regular expressions that look
1617
+ // for non-JSON patterns. We are especially concerned with '()' and 'new'
1618
+ // because they can cause invocation, and '=' because it can cause mutation.
1619
+ // But just to be safe, we want to reject all unexpected forms.
1620
+
1621
+ // We split the second stage into 4 regexp operations in order to work around
1622
+ // crippling inefficiencies in IE's and Safari's regexp engines. First we
1623
+ // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
1624
+ // replace all simple value tokens with ']' characters. Third, we delete all
1625
+ // open brackets that follow a colon or comma or that begin the text. Finally,
1626
+ // we look to see that the remaining characters are only whitespace or ']' or
1627
+ // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
1628
+
1629
+ if (/^[\],:{}\s]*$/
1630
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
1631
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
1632
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
1633
+
1634
+ // In the third stage we use the eval function to compile the text into a
1635
+ // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
1636
+ // in JavaScript: it can begin a block or an object literal. We wrap the text
1637
+ // in parens to eliminate the ambiguity.
1638
+
1639
+ j = eval('(' + text + ')');
1640
+
1641
+ // In the optional fourth stage, we recursively walk the new structure, passing
1642
+ // each name/value pair to a reviver function for possible transformation.
1643
+
1644
+ return typeof reviver === 'function'
1645
+ ? walk({'': j}, '')
1646
+ : j;
1647
+ }
1648
+
1649
+ // If the text is not JSON parseable, then a SyntaxError is thrown.
1650
+
1651
+ throw new SyntaxError('JSON.parse');
1652
+ };
1653
+ }
1654
+ }
1655
+
1656
+ module.exports = setupCustomJSON;
1657
+
1658
+
1659
+ /***/ },
1660
+ /* 5 */
1661
+ /***/ function(module, exports, __webpack_require__) {
1662
+
1663
+ "use strict";
1664
+
1665
+ var ErrorStackParser = __webpack_require__(8);
1666
+
1667
+ var UNKNOWN_FUNCTION = '?';
1668
+
1669
+
1670
+ function guessFunctionName(url, line) {
1671
+ return UNKNOWN_FUNCTION;
1672
+ }
1673
+
1674
+ function gatherContext(url, line) {
1675
+ return null;
1676
+ }
1677
+
1678
+ function Frame(stackFrame) {
1679
+ var data = {};
1680
+
1681
+ data._stackFrame = stackFrame;
1682
+
1683
+ data.url = stackFrame.fileName;
1684
+ data.line = stackFrame.lineNumber;
1685
+ data.func = stackFrame.functionName;
1686
+ data.column = stackFrame.columnNumber;
1687
+ data.args = stackFrame.args;
1688
+
1689
+ data.context = gatherContext(data.url, data.line);
1690
+
1691
+ return data;
1692
+ }
1693
+
1694
+ function Stack(exception) {
1695
+ function getStack() {
1696
+ var parserStack = [];
1697
+
1698
+ try {
1699
+ parserStack = ErrorStackParser.parse(exception);
1700
+ } catch(e) {
1701
+ parserStack = [];
1702
+ }
1703
+
1704
+ var stack = [];
1705
+
1706
+ for (var i = 0; i < parserStack.length; i++) {
1707
+ stack.push(new Frame(parserStack[i]));
1708
+ }
1709
+
1710
+ return stack;
1711
+ }
1712
+
1713
+ return {
1714
+ stack: getStack(),
1715
+ message: exception.message,
1716
+ name: exception.name
1717
+ };
1718
+ }
1719
+
1720
+ function parse(e) {
1721
+ return new Stack(e);
1722
+ }
1723
+
1724
+ module.exports = {
1725
+ guessFunctionName: guessFunctionName,
1726
+ gatherContext: gatherContext,
1727
+ parse: parse,
1728
+ Stack: Stack,
1729
+ Frame: Frame
1730
+ };
1731
+
1732
+
1733
+ /***/ },
1734
+ /* 6 */
1735
+ /***/ function(module, exports, __webpack_require__) {
1736
+
1737
+ "use strict";
1738
+
1739
+ var Util = {
1740
+ // modified from https://github.com/jquery/jquery/blob/master/src/core.js#L127
1741
+ merge: function() {
1742
+ var options, name, src, copy, copyIsArray, clone,
1743
+ target = arguments[0] || {},
1744
+ i = 1,
1745
+ length = arguments.length,
1746
+ deep = true;
1747
+
1748
+ // Handle case when target is a string or something (possible in deep copy)
1749
+ if (typeof target !== "object" && typeof target !== 'function') {
1750
+ target = {};
1751
+ }
1752
+
1753
+ for (; i < length; i++) {
1754
+ // Only deal with non-null/undefined values
1755
+ if ((options = arguments[i]) !== null) {
1756
+ // Extend the base object
1757
+ for (name in options) {
1758
+ // IE8 will iterate over properties of objects like "indexOf"
1759
+ if (!options.hasOwnProperty(name)) {
1760
+ continue;
1761
+ }
1762
+
1763
+ src = target[name];
1764
+ copy = options[name];
1765
+
1766
+ // Prevent never-ending loop
1767
+ if (target === copy) {
1768
+ continue;
1769
+ }
1770
+
1771
+ // Recurse if we're merging plain objects or arrays
1772
+ if (deep && copy && (copy.constructor === Object || (copyIsArray = (copy.constructor === Array)))) {
1773
+ if (copyIsArray) {
1774
+ copyIsArray = false;
1775
+ // Overwrite the source with a copy of the array to merge in
1776
+ clone = [];
1777
+ } else {
1778
+ clone = src && src.constructor === Object ? src : {};
1779
+ }
1780
+
1781
+ // Never move original objects, clone them
1782
+ target[name] = Util.merge(clone, copy);
1783
+
1784
+ // Don't bring in undefined values
1785
+ } else if (copy !== undefined) {
1786
+ target[name] = copy;
1787
+ }
1788
+ }
1789
+ }
1790
+ }
1791
+
1792
+ // Return the modified object
1793
+ return target;
1794
+ },
1795
+
1796
+ copy: function(obj) {
1797
+ var dest;
1798
+ if (typeof obj === 'object') {
1799
+ if (obj.constructor === Object) {
1800
+ dest = {};
1801
+ } else if (obj.constructor === Array) {
1802
+ dest = [];
1803
+ }
1804
+ }
1805
+
1806
+ Util.merge(dest, obj);
1807
+ return dest;
1808
+ },
1809
+
1810
+ parseUriOptions: {
1811
+ strictMode: false,
1812
+ key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
1813
+ q: {
1814
+ name: "queryKey",
1815
+ parser: /(?:^|&)([^&=]*)=?([^&]*)/g
1816
+ },
1817
+ parser: {
1818
+ strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
1819
+ loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
1820
+ }
1821
+ },
1822
+
1823
+ parseUri: function(str) {
1824
+ if (!str || (typeof str !== 'string' && !(str instanceof String))) {
1825
+ throw new Error('Util.parseUri() received invalid input');
1826
+ }
1827
+
1828
+ var o = Util.parseUriOptions;
1829
+ var m = o.parser[o.strictMode ? "strict" : "loose"].exec(str);
1830
+ var uri = {};
1831
+ var i = 14;
1832
+
1833
+ while (i--) {
1834
+ uri[o.key[i]] = m[i] || "";
1835
+ }
1836
+
1837
+ uri[o.q.name] = {};
1838
+ uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
1839
+ if ($1) {
1840
+ uri[o.q.name][$1] = $2;
1841
+ }
1842
+ });
1843
+
1844
+ return uri;
1845
+ },
1846
+
1847
+ sanitizeUrl: function(url) {
1848
+ if (!url || (typeof url !== 'string' && !(url instanceof String))) {
1849
+ throw new Error('Util.sanitizeUrl() received invalid input');
1850
+ }
1851
+
1852
+ var baseUrlParts = Util.parseUri(url);
1853
+ // remove a trailing # if there is no anchor
1854
+ if (baseUrlParts.anchor === '') {
1855
+ baseUrlParts.source = baseUrlParts.source.replace('#', '');
1856
+ }
1857
+
1858
+ url = baseUrlParts.source.replace('?' + baseUrlParts.query, '');
1859
+ return url;
1860
+ },
1861
+
1862
+ traverse: function(obj, func) {
1863
+ var k;
1864
+ var v;
1865
+ var i;
1866
+ var isObj = typeof obj === 'object';
1867
+ var keys = [];
1868
+
1869
+ if (isObj) {
1870
+ if (obj.constructor === Object) {
1871
+ for (k in obj) {
1872
+ if (obj.hasOwnProperty(k)) {
1873
+ keys.push(k);
1874
+ }
1875
+ }
1876
+ } else if (obj.constructor === Array) {
1877
+ for (i = 0; i < obj.length; ++i) {
1878
+ keys.push(i);
1879
+ }
1880
+ }
1881
+ }
1882
+
1883
+ for (i = 0; i < keys.length; ++i) {
1884
+ k = keys[i];
1885
+ v = obj[k];
1886
+ isObj = typeof v === 'object';
1887
+ if (isObj) {
1888
+ if (v === null) {
1889
+ obj[k] = func(k, v);
1890
+ } else if (v.constructor === Object) {
1891
+ obj[k] = Util.traverse(v, func);
1892
+ } else if (v.constructor === Array) {
1893
+ obj[k] = Util.traverse(v, func);
1894
+ } else {
1895
+ obj[k] = func(k, v);
1896
+ }
1897
+ } else {
1898
+ obj[k] = func(k, v);
1899
+ }
1900
+ }
1901
+
1902
+ return obj;
1903
+
1904
+ },
1905
+
1906
+ redact: function(val) {
1907
+ val = String(val);
1908
+ return new Array(val.length + 1).join('*');
1909
+ },
1910
+
1911
+ // from http://stackoverflow.com/a/8809472/1138191
1912
+ uuid4: function() {
1913
+ var d = new Date().getTime();
1914
+ var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
1915
+ var r = (d + Math.random() * 16) % 16 | 0;
1916
+ d = Math.floor(d / 16);
1917
+ return (c === 'x' ? r : (r & 0x7 | 0x8)).toString(16);
1918
+ });
1919
+ return uuid;
1920
+ }
1921
+ };
1922
+
1923
+ module.exports = Util;
1924
+
1925
+
1926
+ /***/ },
1927
+ /* 7 */
1928
+ /***/ function(module, exports, __webpack_require__) {
1929
+
1930
+ /* globals ActiveXObject */
1931
+
1932
+ "use strict";
1933
+
1934
+ var RollbarJSON = null;
1935
+
1936
+ function setupJSON(JSON) {
1937
+ RollbarJSON = JSON;
1938
+ }
1939
+
1940
+ var XHR = {
1941
+ XMLHttpFactories: [
1942
+ function () {return new XMLHttpRequest();},
1943
+ function () {return new ActiveXObject("Msxml2.XMLHTTP");},
1944
+ function () {return new ActiveXObject("Msxml3.XMLHTTP");},
1945
+ function () {return new ActiveXObject("Microsoft.XMLHTTP");}
1946
+ ],
1947
+ createXMLHTTPObject: function() {
1948
+ var xmlhttp = false;
1949
+ var factories = XHR.XMLHttpFactories;
1950
+ var i;
1951
+ var numFactories = factories.length;
1952
+ for (i = 0; i < numFactories; i++) {
1953
+ try {
1954
+ xmlhttp = factories[i]();
1955
+ break;
1956
+ } catch (e) {
1957
+ // pass
1958
+ }
1959
+ }
1960
+ return xmlhttp;
1961
+ },
1962
+ post: function(url, accessToken, payload, callback) {
1963
+ if (typeof payload !== 'object') {
1964
+ throw new Error('Expected an object to POST');
1965
+ }
1966
+ payload = RollbarJSON.stringify(payload);
1967
+ callback = callback || function() {};
1968
+ var request = XHR.createXMLHTTPObject();
1969
+ if (request) {
1970
+ try {
1971
+ try {
1972
+ var onreadystatechange = function(args) {
1973
+ try {
1974
+ if (onreadystatechange && request.readyState === 4) {
1975
+ onreadystatechange = undefined;
1976
+
1977
+ // TODO(cory): have the notifier log an internal error on non-200 response codes
1978
+ if (request.status === 200) {
1979
+ callback(null, RollbarJSON.parse(request.responseText));
1980
+ } else if (typeof request.status === "number" &&
1981
+ request.status >= 400 && request.status < 600) {
1982
+ // return valid http status codes
1983
+ callback(new Error(request.status.toString()));
1984
+ } else {
1985
+ // IE will return a status 12000+ on some sort of connection failure,
1986
+ // so we return a blank error
1987
+ // http://msdn.microsoft.com/en-us/library/aa383770%28VS.85%29.aspx
1988
+ callback(new Error());
1989
+ }
1990
+ }
1991
+ } catch (ex) {
1992
+ //jquery source mentions firefox may error out while accessing the
1993
+ //request members if there is a network error
1994
+ //https://github.com/jquery/jquery/blob/a938d7b1282fc0e5c52502c225ae8f0cef219f0a/src/ajax/xhr.js#L111
1995
+ var exc;
1996
+ if (typeof ex === 'object' && ex.stack) {
1997
+ exc = ex;
1998
+ } else {
1999
+ exc = new Error(ex);
2000
+ }
2001
+ callback(exc);
2002
+ }
2003
+ };
2004
+
2005
+ request.open('POST', url, true);
2006
+ if (request.setRequestHeader) {
2007
+ request.setRequestHeader('Content-Type', 'application/json');
2008
+ request.setRequestHeader('X-Rollbar-Access-Token', accessToken);
2009
+ }
2010
+ request.onreadystatechange = onreadystatechange;
2011
+ request.send(payload);
2012
+ } catch (e1) {
2013
+ // Sending using the normal xmlhttprequest object didn't work, try XDomainRequest
2014
+ if (typeof XDomainRequest !== "undefined") {
2015
+ var ontimeout = function(args) {
2016
+ callback(new Error());
2017
+ };
2018
+
2019
+ var onerror = function(args) {
2020
+ callback(new Error());
2021
+ };
2022
+
2023
+ var onload = function(args) {
2024
+ callback(null, RollbarJSON.parse(request.responseText));
2025
+ };
2026
+
2027
+ request = new XDomainRequest();
2028
+ request.onprogress = function() {};
2029
+ request.ontimeout = ontimeout;
2030
+ request.onerror = onerror;
2031
+ request.onload = onload;
2032
+ request.open('POST', url, true);
2033
+ request.send(payload);
2034
+ }
2035
+ }
2036
+ } catch (e2) {
2037
+ callback(e2);
2038
+ }
2039
+ }
2040
+ }
2041
+ };
2042
+
2043
+ module.exports = {
2044
+ XHR: XHR,
2045
+ setupJSON: setupJSON
2046
+ };
2047
+
2048
+
2049
+ /***/ },
2050
+ /* 8 */
2051
+ /***/ function(module, exports, __webpack_require__) {
2052
+
2053
+ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (root, factory) {
2054
+ 'use strict';
2055
+ // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.
2056
+ if (true) {
2057
+ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(9)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
2058
+ } else if (typeof exports === 'object') {
2059
+ module.exports = factory(require('stackframe'));
2060
+ } else {
2061
+ root.ErrorStackParser = factory(root.StackFrame);
2062
+ }
2063
+ }(this, function ErrorStackParser(StackFrame) {
2064
+ 'use strict';
2065
+
2066
+ var FIREFOX_SAFARI_STACK_REGEXP = /\S+\:\d+/;
2067
+ var CHROME_IE_STACK_REGEXP = /\s+at /;
2068
+ var map, filter;
2069
+
2070
+ if (Array.prototype.map) {
2071
+ map = function (arr, fn) {
2072
+ return arr.map(fn);
2073
+ };
2074
+ } else {
2075
+ map = function (arr, fn) {
2076
+ var i;
2077
+ var len = arr.length;
2078
+ var ret = [];
2079
+
2080
+ for (i = 0; i < len; ++i) {
2081
+ ret.push(fn(arr[i]));
2082
+ }
2083
+ return ret;
2084
+ };
2085
+ }
2086
+
2087
+ if (Array.prototype.filter) {
2088
+ filter = function (arr, fn) {
2089
+ return arr.filter(fn);
2090
+ };
2091
+ } else {
2092
+ filter = function (arr, fn) {
2093
+ var i;
2094
+ var len = arr.length;
2095
+ var ret = [];
2096
+ for (i = 0; i < len; ++i) {
2097
+ if (fn(arr[i])) {
2098
+ ret.push(arr[i]);
2099
+ }
2100
+ }
2101
+ return ret;
2102
+ };
2103
+ }
2104
+
2105
+ return {
2106
+ /**
2107
+ * Given an Error object, extract the most information from it.
2108
+ * @param error {Error}
2109
+ * @return Array[StackFrame]
2110
+ */
2111
+ parse: function ErrorStackParser$$parse(error) {
2112
+ if (typeof error.stacktrace !== 'undefined' || typeof error['opera#sourceloc'] !== 'undefined') {
2113
+ return this.parseOpera(error);
2114
+ } else if (error.stack && error.stack.match(CHROME_IE_STACK_REGEXP)) {
2115
+ return this.parseV8OrIE(error);
2116
+ } else if (error.stack && error.stack.match(FIREFOX_SAFARI_STACK_REGEXP)) {
2117
+ return this.parseFFOrSafari(error);
2118
+ } else {
2119
+ throw new Error('Cannot parse given Error object');
2120
+ }
2121
+ },
2122
+
2123
+ /**
2124
+ * Separate line and column numbers from a URL-like string.
2125
+ * @param urlLike String
2126
+ * @return Array[String]
2127
+ */
2128
+ extractLocation: function ErrorStackParser$$extractLocation(urlLike) {
2129
+ // Fail-fast but return locations like "(native)"
2130
+ if (urlLike.indexOf(':') === -1) {
2131
+ return [urlLike];
2132
+ }
2133
+
2134
+ var locationParts = urlLike.replace(/[\(\)\s]/g, '').split(':');
2135
+ var lastNumber = locationParts.pop();
2136
+ var possibleNumber = locationParts[locationParts.length - 1];
2137
+ if (!isNaN(parseFloat(possibleNumber)) && isFinite(possibleNumber)) {
2138
+ var lineNumber = locationParts.pop();
2139
+ return [locationParts.join(':'), lineNumber, lastNumber];
2140
+ } else {
2141
+ return [locationParts.join(':'), lastNumber, undefined];
2142
+ }
2143
+ },
2144
+
2145
+ parseV8OrIE: function ErrorStackParser$$parseV8OrIE(error) {
2146
+ var extractLocation = this.extractLocation;
2147
+ var mapped = map(error.stack.split('\n').slice(1), function (line) {
2148
+ var tokens = line.replace(/^\s+/, '').split(/\s+/).slice(1);
2149
+ var locationParts = extractLocation(tokens.pop());
2150
+ var functionName = (!tokens[0] || tokens[0] === 'Anonymous') ? undefined : tokens[0];
2151
+ return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2]);
2152
+ });
2153
+ return mapped;
2154
+ },
2155
+
2156
+ parseFFOrSafari: function ErrorStackParser$$parseFFOrSafari(error) {
2157
+ var filtered = filter(error.stack.split('\n'), function (line) {
2158
+ return !!line.match(FIREFOX_SAFARI_STACK_REGEXP);
2159
+ });
2160
+ var extractLocation = this.extractLocation;
2161
+ var mapped = map(filtered, function (line) {
2162
+ var tokens = line.split('@');
2163
+ var locationParts = extractLocation(tokens.pop());
2164
+ var functionName = tokens.shift() || undefined;
2165
+ return new StackFrame(functionName, undefined, locationParts[0], locationParts[1], locationParts[2]);
2166
+ });
2167
+ return mapped;
2168
+ },
2169
+
2170
+ parseOpera: function ErrorStackParser$$parseOpera(e) {
2171
+ if (!e.stacktrace || (e.message.indexOf('\n') > -1 &&
2172
+ e.message.split('\n').length > e.stacktrace.split('\n').length)) {
2173
+ return this.parseOpera9(e);
2174
+ } else if (!e.stack) {
2175
+ return this.parseOpera10(e);
2176
+ } else {
2177
+ return this.parseOpera11(e);
2178
+ }
2179
+ },
2180
+
2181
+ parseOpera9: function ErrorStackParser$$parseOpera9(e) {
2182
+ var lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
2183
+ var lines = e.message.split('\n');
2184
+ var result = [];
2185
+
2186
+ for (var i = 2, len = lines.length; i < len; i += 2) {
2187
+ var match = lineRE.exec(lines[i]);
2188
+ if (match) {
2189
+ result.push(new StackFrame(undefined, undefined, match[2], match[1]));
2190
+ }
2191
+ }
2192
+
2193
+ return result;
2194
+ },
2195
+
2196
+ parseOpera10: function ErrorStackParser$$parseOpera10(e) {
2197
+ var lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
2198
+ var lines = e.stacktrace.split('\n');
2199
+ var result = [];
2200
+
2201
+ for (var i = 0, len = lines.length; i < len; i += 2) {
2202
+ var match = lineRE.exec(lines[i]);
2203
+ if (match) {
2204
+ result.push(new StackFrame(match[3] || undefined, undefined, match[2], match[1]));
2205
+ }
2206
+ }
2207
+
2208
+ return result;
2209
+ },
2210
+
2211
+ // Opera 10.65+ Error.stack very similar to FF/Safari
2212
+ parseOpera11: function ErrorStackParser$$parseOpera11(error) {
2213
+ var filtered = filter(error.stack.split('\n'), function (line) {
2214
+ return !!line.match(FIREFOX_SAFARI_STACK_REGEXP) && !line.match(/^Error created at/);
2215
+ });
2216
+ var extractLocation = this.extractLocation;
2217
+ var mapped = map(filtered, function (line) {
2218
+ var tokens = line.split('@');
2219
+ var locationParts = extractLocation(tokens.pop());
2220
+ var functionCall = (tokens.shift() || '');
2221
+ var functionName = functionCall
2222
+ .replace(/<anonymous function(: (\w+))?>/, '$2')
2223
+ .replace(/\([^\)]*\)/g, '') || undefined;
2224
+ var argsRaw;
2225
+ if (functionCall.match(/\(([^\)]*)\)/)) {
2226
+ argsRaw = functionCall.replace(/^[^\(]+\(([^\)]*)\)$/, '$1');
2227
+ }
2228
+ var args = (argsRaw === undefined || argsRaw === '[arguments not available]') ? undefined : argsRaw.split(',');
2229
+ return new StackFrame(functionName, args, locationParts[0], locationParts[1], locationParts[2]);
2230
+ });
2231
+ return mapped;
2232
+ }
2233
+ };
2234
+ }));
2235
+
2236
+
2237
+
2238
+ /***/ },
2239
+ /* 9 */
2240
+ /***/ function(module, exports, __webpack_require__) {
2241
+
2242
+ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (root, factory) {
2243
+ 'use strict';
2244
+ // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, Rhino, and browsers.
2245
+ if (true) {
2246
+ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
2247
+ } else if (typeof exports === 'object') {
2248
+ module.exports = factory();
2249
+ } else {
2250
+ root.StackFrame = factory();
2251
+ }
2252
+ }(this, function () {
2253
+ 'use strict';
2254
+ function _isNumber(n) {
2255
+ return !isNaN(parseFloat(n)) && isFinite(n);
2256
+ }
2257
+
2258
+ function StackFrame(functionName, args, fileName, lineNumber, columnNumber) {
2259
+ if (functionName !== undefined) {
2260
+ this.setFunctionName(functionName);
2261
+ }
2262
+ if (args !== undefined) {
2263
+ this.setArgs(args);
2264
+ }
2265
+ if (fileName !== undefined) {
2266
+ this.setFileName(fileName);
2267
+ }
2268
+ if (lineNumber !== undefined) {
2269
+ this.setLineNumber(lineNumber);
2270
+ }
2271
+ if (columnNumber !== undefined) {
2272
+ this.setColumnNumber(columnNumber);
2273
+ }
2274
+ }
2275
+
2276
+ StackFrame.prototype = {
2277
+ getFunctionName: function () {
2278
+ return this.functionName;
2279
+ },
2280
+ setFunctionName: function (v) {
2281
+ this.functionName = String(v);
2282
+ },
2283
+
2284
+ getArgs: function () {
2285
+ return this.args;
2286
+ },
2287
+ setArgs: function (v) {
2288
+ if (Object.prototype.toString.call(v) !== '[object Array]') {
2289
+ throw new TypeError('Args must be an Array');
2290
+ }
2291
+ this.args = v;
2292
+ },
2293
+
2294
+ // NOTE: Property name may be misleading as it includes the path,
2295
+ // but it somewhat mirrors V8's JavaScriptStackTraceApi
2296
+ // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi and Gecko's
2297
+ // http://mxr.mozilla.org/mozilla-central/source/xpcom/base/nsIException.idl#14
2298
+ getFileName: function () {
2299
+ return this.fileName;
2300
+ },
2301
+ setFileName: function (v) {
2302
+ this.fileName = String(v);
2303
+ },
2304
+
2305
+ getLineNumber: function () {
2306
+ return this.lineNumber;
2307
+ },
2308
+ setLineNumber: function (v) {
2309
+ if (!_isNumber(v)) {
2310
+ throw new TypeError('Line Number must be a Number');
2311
+ }
2312
+ this.lineNumber = Number(v);
2313
+ },
2314
+
2315
+ getColumnNumber: function () {
2316
+ return this.columnNumber;
2317
+ },
2318
+ setColumnNumber: function (v) {
2319
+ if (!_isNumber(v)) {
2320
+ throw new TypeError('Column Number must be a Number');
2321
+ }
2322
+ this.columnNumber = Number(v);
2323
+ },
2324
+
2325
+ toString: function() {
2326
+ var functionName = this.getFunctionName() || '{anonymous}';
2327
+ var args = '(' + (this.getArgs() || []).join(',') + ')';
2328
+ var fileName = this.getFileName() ? ('@' + this.getFileName()) : '';
2329
+ var lineNumber = _isNumber(this.getLineNumber()) ? (':' + this.getLineNumber()) : '';
2330
+ var columnNumber = _isNumber(this.getColumnNumber()) ? (':' + this.getColumnNumber()) : '';
2331
+ return functionName + args + fileName + lineNumber + columnNumber;
2332
+ }
2333
+ };
2334
+
2335
+ return StackFrame;
2336
+ }));
2337
+
2338
+
2339
+ /***/ }
2340
+ /******/ ])
2341
+ });
2342
+ ;
2343
+ //# sourceMappingURL=rollbar.umd.js.map