mixpanel-browser 2.74.0 → 2.75.0

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.
Files changed (37) hide show
  1. package/.github/workflows/unit-tests.yml +1 -1
  2. package/CHANGELOG.md +5 -0
  3. package/README.md +2 -2
  4. package/dist/mixpanel-core.cjs.js +318 -20
  5. package/dist/mixpanel-recorder.js +127 -15
  6. package/dist/mixpanel-recorder.min.js +1 -1
  7. package/dist/mixpanel-recorder.min.js.map +1 -1
  8. package/dist/mixpanel-targeting.js +2576 -0
  9. package/dist/mixpanel-targeting.min.js +2 -0
  10. package/dist/mixpanel-targeting.min.js.map +1 -0
  11. package/dist/mixpanel-with-async-modules.cjs.d.ts +522 -0
  12. package/dist/mixpanel-with-async-modules.cjs.js +9700 -0
  13. package/dist/mixpanel-with-async-recorder.cjs.js +318 -20
  14. package/dist/mixpanel-with-recorder.js +435 -26
  15. package/dist/mixpanel-with-recorder.min.js +1 -1
  16. package/dist/mixpanel.amd.js +1020 -28
  17. package/dist/mixpanel.cjs.js +1020 -28
  18. package/dist/mixpanel.globals.js +318 -20
  19. package/dist/mixpanel.min.js +179 -172
  20. package/dist/mixpanel.module.js +1020 -28
  21. package/dist/mixpanel.umd.js +1020 -28
  22. package/dist/rrweb-bundled.js +119 -5
  23. package/dist/rrweb-compiled.js +116 -5
  24. package/package.json +4 -3
  25. package/rollup.config.mjs +34 -2
  26. package/src/config.js +1 -1
  27. package/src/flags/index.js +269 -8
  28. package/src/globals.js +14 -0
  29. package/src/loaders/loader-module.js +1 -0
  30. package/src/mixpanel-core.js +12 -3
  31. package/src/recorder/index.js +2 -1
  32. package/src/targeting/event-matcher.js +97 -0
  33. package/src/targeting/index.js +11 -0
  34. package/src/targeting/loader.js +36 -0
  35. package/src/utils.js +1 -8
  36. package/.claude/settings.local.json +0 -12
  37. /package/src/loaders/{loader-module-with-async-recorder.js → loader-module-with-async-modules.js} +0 -0
@@ -0,0 +1,2576 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
5
+ var win;
6
+ if (typeof(window) === 'undefined') {
7
+ var loc = {
8
+ hostname: ''
9
+ };
10
+ win = {
11
+ crypto: {randomUUID: function() {throw Error('unsupported');}},
12
+ navigator: { userAgent: '', onLine: true },
13
+ document: {
14
+ createElement: function() { return {}; },
15
+ location: loc,
16
+ referrer: ''
17
+ },
18
+ screen: { width: 0, height: 0 },
19
+ location: loc,
20
+ addEventListener: function() {},
21
+ removeEventListener: function() {},
22
+ dispatchEvent: function() {},
23
+ CustomEvent: function () {}
24
+ };
25
+ } else {
26
+ win = window;
27
+ }
28
+
29
+ /**
30
+ * Shared global window property names used across modules
31
+ */
32
+
33
+ // Targeting library global (used by flags and targeting modules)
34
+ var TARGETING_GLOBAL_NAME = '__mp_targeting';
35
+
36
+ var Config = {
37
+ LIB_VERSION: '2.75.0'
38
+ };
39
+
40
+ var setImmediate = win['setImmediate'];
41
+ var builtInProp, cycle, schedulingQueue,
42
+ ToString = Object.prototype.toString,
43
+ timer = (typeof setImmediate !== 'undefined') ?
44
+ function timer(fn) { return setImmediate(fn); } :
45
+ setTimeout;
46
+
47
+ // dammit, IE8.
48
+ try {
49
+ Object.defineProperty({},'x',{});
50
+ builtInProp = function builtInProp(obj,name,val,config) {
51
+ return Object.defineProperty(obj,name,{
52
+ value: val,
53
+ writable: true,
54
+ configurable: config !== false
55
+ });
56
+ };
57
+ }
58
+ catch (err) {
59
+ builtInProp = function builtInProp(obj,name,val) {
60
+ obj[name] = val;
61
+ return obj;
62
+ };
63
+ }
64
+
65
+ // Note: using a queue instead of array for efficiency
66
+ schedulingQueue = (function Queue() {
67
+ var first, last, item;
68
+
69
+ function Item(fn,self) {
70
+ this.fn = fn;
71
+ this.self = self;
72
+ this.next = void 0;
73
+ }
74
+
75
+ return {
76
+ add: function add(fn,self) {
77
+ item = new Item(fn,self);
78
+ if (last) {
79
+ last.next = item;
80
+ }
81
+ else {
82
+ first = item;
83
+ }
84
+ last = item;
85
+ item = void 0;
86
+ },
87
+ drain: function drain() {
88
+ var f = first;
89
+ first = last = cycle = void 0;
90
+
91
+ while (f) {
92
+ f.fn.call(f.self);
93
+ f = f.next;
94
+ }
95
+ }
96
+ };
97
+ })();
98
+
99
+ function schedule(fn,self) {
100
+ schedulingQueue.add(fn,self);
101
+ if (!cycle) {
102
+ cycle = timer(schedulingQueue.drain);
103
+ }
104
+ }
105
+
106
+ // promise duck typing
107
+ function isThenable(o) {
108
+ var _then, oType = typeof o;
109
+
110
+ if (o !== null && (oType === 'object' || oType === 'function')) {
111
+ _then = o.then;
112
+ }
113
+ return typeof _then === 'function' ? _then : false;
114
+ }
115
+
116
+ function notify() {
117
+ for (var i=0; i<this.chain.length; i++) {
118
+ notifyIsolated(
119
+ this,
120
+ (this.state === 1) ? this.chain[i].success : this.chain[i].failure,
121
+ this.chain[i]
122
+ );
123
+ }
124
+ this.chain.length = 0;
125
+ }
126
+
127
+ // NOTE: This is a separate function to isolate
128
+ // the `try..catch` so that other code can be
129
+ // optimized better
130
+ function notifyIsolated(self,cb,chain) {
131
+ var ret, _then;
132
+ try {
133
+ if (cb === false) {
134
+ chain.reject(self.msg);
135
+ }
136
+ else {
137
+ if (cb === true) {
138
+ ret = self.msg;
139
+ }
140
+ else {
141
+ ret = cb.call(void 0,self.msg);
142
+ }
143
+
144
+ if (ret === chain.promise) {
145
+ chain.reject(TypeError('Promise-chain cycle'));
146
+ }
147
+ // eslint-disable-next-line no-cond-assign
148
+ else if (_then = isThenable(ret)) {
149
+ _then.call(ret,chain.resolve,chain.reject);
150
+ }
151
+ else {
152
+ chain.resolve(ret);
153
+ }
154
+ }
155
+ }
156
+ catch (err) {
157
+ chain.reject(err);
158
+ }
159
+ }
160
+
161
+ function resolve(msg) {
162
+ var _then, self = this;
163
+
164
+ // already triggered?
165
+ if (self.triggered) { return; }
166
+
167
+ self.triggered = true;
168
+
169
+ // unwrap
170
+ if (self.def) {
171
+ self = self.def;
172
+ }
173
+
174
+ try {
175
+ // eslint-disable-next-line no-cond-assign
176
+ if (_then = isThenable(msg)) {
177
+ schedule(function(){
178
+ var defWrapper = new MakeDefWrapper(self);
179
+ try {
180
+ _then.call(msg,
181
+ function $resolve$(){ resolve.apply(defWrapper,arguments); },
182
+ function $reject$(){ reject.apply(defWrapper,arguments); }
183
+ );
184
+ }
185
+ catch (err) {
186
+ reject.call(defWrapper,err);
187
+ }
188
+ });
189
+ }
190
+ else {
191
+ self.msg = msg;
192
+ self.state = 1;
193
+ if (self.chain.length > 0) {
194
+ schedule(notify,self);
195
+ }
196
+ }
197
+ }
198
+ catch (err) {
199
+ reject.call(new MakeDefWrapper(self),err);
200
+ }
201
+ }
202
+
203
+ function reject(msg) {
204
+ var self = this;
205
+
206
+ // already triggered?
207
+ if (self.triggered) { return; }
208
+
209
+ self.triggered = true;
210
+
211
+ // unwrap
212
+ if (self.def) {
213
+ self = self.def;
214
+ }
215
+
216
+ self.msg = msg;
217
+ self.state = 2;
218
+ if (self.chain.length > 0) {
219
+ schedule(notify,self);
220
+ }
221
+ }
222
+
223
+ function iteratePromises(Constructor,arr,resolver,rejecter) {
224
+ for (var idx=0; idx<arr.length; idx++) {
225
+ (function IIFE(idx){
226
+ Constructor.resolve(arr[idx])
227
+ .then(
228
+ function $resolver$(msg){
229
+ resolver(idx,msg);
230
+ },
231
+ rejecter
232
+ );
233
+ })(idx);
234
+ }
235
+ }
236
+
237
+ function MakeDefWrapper(self) {
238
+ this.def = self;
239
+ this.triggered = false;
240
+ }
241
+
242
+ function MakeDef(self) {
243
+ this.promise = self;
244
+ this.state = 0;
245
+ this.triggered = false;
246
+ this.chain = [];
247
+ this.msg = void 0;
248
+ }
249
+
250
+ function NpoPromise(executor) {
251
+ if (typeof executor !== 'function') {
252
+ throw TypeError('Not a function');
253
+ }
254
+
255
+ if (this['__NPO__'] !== 0) {
256
+ throw TypeError('Not a promise');
257
+ }
258
+
259
+ // instance shadowing the inherited "brand"
260
+ // to signal an already "initialized" promise
261
+ this['__NPO__'] = 1;
262
+
263
+ var def = new MakeDef(this);
264
+
265
+ this['then'] = function then(success,failure) {
266
+ var o = {
267
+ success: typeof success === 'function' ? success : true,
268
+ failure: typeof failure === 'function' ? failure : false
269
+ };
270
+ // Note: `then(..)` itself can be borrowed to be used against
271
+ // a different promise constructor for making the chained promise,
272
+ // by substituting a different `this` binding.
273
+ o.promise = new this.constructor(function extractChain(resolve,reject) {
274
+ if (typeof resolve !== 'function' || typeof reject !== 'function') {
275
+ throw TypeError('Not a function');
276
+ }
277
+
278
+ o.resolve = resolve;
279
+ o.reject = reject;
280
+ });
281
+ def.chain.push(o);
282
+
283
+ if (def.state !== 0) {
284
+ schedule(notify,def);
285
+ }
286
+
287
+ return o.promise;
288
+ };
289
+ this['catch'] = function $catch$(failure) {
290
+ return this.then(void 0,failure);
291
+ };
292
+
293
+ try {
294
+ executor.call(
295
+ void 0,
296
+ function publicResolve(msg){
297
+ resolve.call(def,msg);
298
+ },
299
+ function publicReject(msg) {
300
+ reject.call(def,msg);
301
+ }
302
+ );
303
+ }
304
+ catch (err) {
305
+ reject.call(def,err);
306
+ }
307
+ }
308
+
309
+ var PromisePrototype = builtInProp({},'constructor',NpoPromise,
310
+ /*configurable=*/false
311
+ );
312
+
313
+ // Note: Android 4 cannot use `Object.defineProperty(..)` here
314
+ NpoPromise.prototype = PromisePrototype;
315
+
316
+ // built-in "brand" to signal an "uninitialized" promise
317
+ builtInProp(PromisePrototype,'__NPO__',0,
318
+ /*configurable=*/false
319
+ );
320
+
321
+ builtInProp(NpoPromise,'resolve',function Promise$resolve(msg) {
322
+ var Constructor = this;
323
+
324
+ // spec mandated checks
325
+ // note: best "isPromise" check that's practical for now
326
+ if (msg && typeof msg === 'object' && msg['__NPO__'] === 1) {
327
+ return msg;
328
+ }
329
+
330
+ return new Constructor(function executor(resolve,reject){
331
+ if (typeof resolve !== 'function' || typeof reject !== 'function') {
332
+ throw TypeError('Not a function');
333
+ }
334
+
335
+ resolve(msg);
336
+ });
337
+ });
338
+
339
+ builtInProp(NpoPromise,'reject',function Promise$reject(msg) {
340
+ return new this(function executor(resolve,reject){
341
+ if (typeof resolve !== 'function' || typeof reject !== 'function') {
342
+ throw TypeError('Not a function');
343
+ }
344
+
345
+ reject(msg);
346
+ });
347
+ });
348
+
349
+ builtInProp(NpoPromise,'all',function Promise$all(arr) {
350
+ var Constructor = this;
351
+
352
+ // spec mandated checks
353
+ if (ToString.call(arr) !== '[object Array]') {
354
+ return Constructor.reject(TypeError('Not an array'));
355
+ }
356
+ if (arr.length === 0) {
357
+ return Constructor.resolve([]);
358
+ }
359
+
360
+ return new Constructor(function executor(resolve,reject){
361
+ if (typeof resolve !== 'function' || typeof reject !== 'function') {
362
+ throw TypeError('Not a function');
363
+ }
364
+
365
+ var len = arr.length, msgs = Array(len), count = 0;
366
+
367
+ iteratePromises(Constructor,arr,function resolver(idx,msg) {
368
+ msgs[idx] = msg;
369
+ if (++count === len) {
370
+ resolve(msgs);
371
+ }
372
+ },reject);
373
+ });
374
+ });
375
+
376
+ builtInProp(NpoPromise,'race',function Promise$race(arr) {
377
+ var Constructor = this;
378
+
379
+ // spec mandated checks
380
+ if (ToString.call(arr) !== '[object Array]') {
381
+ return Constructor.reject(TypeError('Not an array'));
382
+ }
383
+
384
+ return new Constructor(function executor(resolve,reject){
385
+ if (typeof resolve !== 'function' || typeof reject !== 'function') {
386
+ throw TypeError('Not a function');
387
+ }
388
+
389
+ iteratePromises(Constructor,arr,function resolver(idx,msg){
390
+ resolve(msg);
391
+ },reject);
392
+ });
393
+ });
394
+ if (typeof Promise !== 'undefined' && Promise.toString().indexOf('[native code]') !== -1) ;
395
+
396
+ /* eslint camelcase: "off", eqeqeq: "off" */
397
+
398
+ /*
399
+ * Saved references to long variable names, so that closure compiler can
400
+ * minimize file size.
401
+ */
402
+
403
+ var ArrayProto = Array.prototype,
404
+ FuncProto = Function.prototype,
405
+ ObjProto = Object.prototype,
406
+ slice = ArrayProto.slice,
407
+ toString = ObjProto.toString,
408
+ hasOwnProperty = ObjProto.hasOwnProperty;
409
+ win.console;
410
+ var navigator = win.navigator,
411
+ document = win.document,
412
+ windowOpera = win.opera,
413
+ screen = win.screen,
414
+ userAgent = navigator.userAgent;
415
+
416
+ var nativeBind = FuncProto.bind,
417
+ nativeForEach = ArrayProto.forEach,
418
+ nativeIndexOf = ArrayProto.indexOf,
419
+ nativeMap = ArrayProto.map,
420
+ nativeIsArray = Array.isArray,
421
+ breaker = {};
422
+
423
+ var _ = {
424
+ trim: function(str) {
425
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Polyfill
426
+ return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
427
+ }
428
+ };
429
+
430
+
431
+ // UNDERSCORE
432
+ // Embed part of the Underscore Library
433
+ _.bind = function(func, context) {
434
+ var args, bound;
435
+ if (nativeBind && func.bind === nativeBind) {
436
+ return nativeBind.apply(func, slice.call(arguments, 1));
437
+ }
438
+ if (!_.isFunction(func)) {
439
+ throw new TypeError();
440
+ }
441
+ args = slice.call(arguments, 2);
442
+ bound = function() {
443
+ if (!(this instanceof bound)) {
444
+ return func.apply(context, args.concat(slice.call(arguments)));
445
+ }
446
+ var ctor = {};
447
+ ctor.prototype = func.prototype;
448
+ var self = new ctor();
449
+ ctor.prototype = null;
450
+ var result = func.apply(self, args.concat(slice.call(arguments)));
451
+ if (Object(result) === result) {
452
+ return result;
453
+ }
454
+ return self;
455
+ };
456
+ return bound;
457
+ };
458
+
459
+ /**
460
+ * @param {*=} obj
461
+ * @param {function(...*)=} iterator
462
+ * @param {Object=} context
463
+ */
464
+ _.each = function(obj, iterator, context) {
465
+ if (obj === null || obj === undefined) {
466
+ return;
467
+ }
468
+ if (nativeForEach && obj.forEach === nativeForEach) {
469
+ obj.forEach(iterator, context);
470
+ } else if (obj.length === +obj.length) {
471
+ for (var i = 0, l = obj.length; i < l; i++) {
472
+ if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) {
473
+ return;
474
+ }
475
+ }
476
+ } else {
477
+ for (var key in obj) {
478
+ if (hasOwnProperty.call(obj, key)) {
479
+ if (iterator.call(context, obj[key], key, obj) === breaker) {
480
+ return;
481
+ }
482
+ }
483
+ }
484
+ }
485
+ };
486
+
487
+ _.extend = function(obj) {
488
+ _.each(slice.call(arguments, 1), function(source) {
489
+ for (var prop in source) {
490
+ if (source[prop] !== void 0) {
491
+ obj[prop] = source[prop];
492
+ }
493
+ }
494
+ });
495
+ return obj;
496
+ };
497
+
498
+ _.isArray = nativeIsArray || function(obj) {
499
+ return toString.call(obj) === '[object Array]';
500
+ };
501
+
502
+ _.isFunction = function(f) {
503
+ return typeof f === 'function';
504
+ };
505
+
506
+ _.isArguments = function(obj) {
507
+ return !!(obj && hasOwnProperty.call(obj, 'callee'));
508
+ };
509
+
510
+ _.toArray = function(iterable) {
511
+ if (!iterable) {
512
+ return [];
513
+ }
514
+ if (iterable.toArray) {
515
+ return iterable.toArray();
516
+ }
517
+ if (_.isArray(iterable)) {
518
+ return slice.call(iterable);
519
+ }
520
+ if (_.isArguments(iterable)) {
521
+ return slice.call(iterable);
522
+ }
523
+ return _.values(iterable);
524
+ };
525
+
526
+ _.map = function(arr, callback, context) {
527
+ if (nativeMap && arr.map === nativeMap) {
528
+ return arr.map(callback, context);
529
+ } else {
530
+ var results = [];
531
+ _.each(arr, function(item) {
532
+ results.push(callback.call(context, item));
533
+ });
534
+ return results;
535
+ }
536
+ };
537
+
538
+ _.keys = function(obj) {
539
+ var results = [];
540
+ if (obj === null) {
541
+ return results;
542
+ }
543
+ _.each(obj, function(value, key) {
544
+ results[results.length] = key;
545
+ });
546
+ return results;
547
+ };
548
+
549
+ _.values = function(obj) {
550
+ var results = [];
551
+ if (obj === null) {
552
+ return results;
553
+ }
554
+ _.each(obj, function(value) {
555
+ results[results.length] = value;
556
+ });
557
+ return results;
558
+ };
559
+
560
+ _.include = function(obj, target) {
561
+ var found = false;
562
+ if (obj === null) {
563
+ return found;
564
+ }
565
+ if (nativeIndexOf && obj.indexOf === nativeIndexOf) {
566
+ return obj.indexOf(target) != -1;
567
+ }
568
+ _.each(obj, function(value) {
569
+ if (found || (found = (value === target))) {
570
+ return breaker;
571
+ }
572
+ });
573
+ return found;
574
+ };
575
+
576
+ _.includes = function(str, needle) {
577
+ return str.indexOf(needle) !== -1;
578
+ };
579
+
580
+ // Underscore Addons
581
+ _.inherit = function(subclass, superclass) {
582
+ subclass.prototype = new superclass();
583
+ subclass.prototype.constructor = subclass;
584
+ subclass.superclass = superclass.prototype;
585
+ return subclass;
586
+ };
587
+
588
+ _.isObject = function(obj) {
589
+ return (obj === Object(obj) && !_.isArray(obj));
590
+ };
591
+
592
+ _.isEmptyObject = function(obj) {
593
+ if (_.isObject(obj)) {
594
+ for (var key in obj) {
595
+ if (hasOwnProperty.call(obj, key)) {
596
+ return false;
597
+ }
598
+ }
599
+ return true;
600
+ }
601
+ return false;
602
+ };
603
+
604
+ _.isUndefined = function(obj) {
605
+ return obj === void 0;
606
+ };
607
+
608
+ _.isString = function(obj) {
609
+ return toString.call(obj) == '[object String]';
610
+ };
611
+
612
+ _.isDate = function(obj) {
613
+ return toString.call(obj) == '[object Date]';
614
+ };
615
+
616
+ _.isNumber = function(obj) {
617
+ return toString.call(obj) == '[object Number]';
618
+ };
619
+
620
+ _.isElement = function(obj) {
621
+ return !!(obj && obj.nodeType === 1);
622
+ };
623
+
624
+ _.encodeDates = function(obj) {
625
+ _.each(obj, function(v, k) {
626
+ if (_.isDate(v)) {
627
+ obj[k] = _.formatDate(v);
628
+ } else if (_.isObject(v)) {
629
+ obj[k] = _.encodeDates(v); // recurse
630
+ }
631
+ });
632
+ return obj;
633
+ };
634
+
635
+ _.timestamp = function() {
636
+ Date.now = Date.now || function() {
637
+ return +new Date;
638
+ };
639
+ return Date.now();
640
+ };
641
+
642
+ _.formatDate = function(d) {
643
+ // YYYY-MM-DDTHH:MM:SS in UTC
644
+ function pad(n) {
645
+ return n < 10 ? '0' + n : n;
646
+ }
647
+ return d.getUTCFullYear() + '-' +
648
+ pad(d.getUTCMonth() + 1) + '-' +
649
+ pad(d.getUTCDate()) + 'T' +
650
+ pad(d.getUTCHours()) + ':' +
651
+ pad(d.getUTCMinutes()) + ':' +
652
+ pad(d.getUTCSeconds());
653
+ };
654
+
655
+ _.strip_empty_properties = function(p) {
656
+ var ret = {};
657
+ _.each(p, function(v, k) {
658
+ if (_.isString(v) && v.length > 0) {
659
+ ret[k] = v;
660
+ }
661
+ });
662
+ return ret;
663
+ };
664
+
665
+ /*
666
+ * this function returns a copy of object after truncating it. If
667
+ * passed an Array or Object it will iterate through obj and
668
+ * truncate all the values recursively.
669
+ */
670
+ _.truncate = function(obj, length) {
671
+ var ret;
672
+
673
+ if (typeof(obj) === 'string') {
674
+ ret = obj.slice(0, length);
675
+ } else if (_.isArray(obj)) {
676
+ ret = [];
677
+ _.each(obj, function(val) {
678
+ ret.push(_.truncate(val, length));
679
+ });
680
+ } else if (_.isObject(obj)) {
681
+ ret = {};
682
+ _.each(obj, function(val, key) {
683
+ ret[key] = _.truncate(val, length);
684
+ });
685
+ } else {
686
+ ret = obj;
687
+ }
688
+
689
+ return ret;
690
+ };
691
+
692
+ _.JSONEncode = (function() {
693
+ return function(mixed_val) {
694
+ var value = mixed_val;
695
+ var quote = function(string) {
696
+ var escapable = /[\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; // eslint-disable-line no-control-regex
697
+ var meta = { // table of character substitutions
698
+ '\b': '\\b',
699
+ '\t': '\\t',
700
+ '\n': '\\n',
701
+ '\f': '\\f',
702
+ '\r': '\\r',
703
+ '"': '\\"',
704
+ '\\': '\\\\'
705
+ };
706
+
707
+ escapable.lastIndex = 0;
708
+ return escapable.test(string) ?
709
+ '"' + string.replace(escapable, function(a) {
710
+ var c = meta[a];
711
+ return typeof c === 'string' ? c :
712
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
713
+ }) + '"' :
714
+ '"' + string + '"';
715
+ };
716
+
717
+ var str = function(key, holder) {
718
+ var gap = '';
719
+ var indent = ' ';
720
+ var i = 0; // The loop counter.
721
+ var k = ''; // The member key.
722
+ var v = ''; // The member value.
723
+ var length = 0;
724
+ var mind = gap;
725
+ var partial = [];
726
+ var value = holder[key];
727
+
728
+ // If the value has a toJSON method, call it to obtain a replacement value.
729
+ if (value && typeof value === 'object' &&
730
+ typeof value.toJSON === 'function') {
731
+ value = value.toJSON(key);
732
+ }
733
+
734
+ // What happens next depends on the value's type.
735
+ switch (typeof value) {
736
+ case 'string':
737
+ return quote(value);
738
+
739
+ case 'number':
740
+ // JSON numbers must be finite. Encode non-finite numbers as null.
741
+ return isFinite(value) ? String(value) : 'null';
742
+
743
+ case 'boolean':
744
+ case 'null':
745
+ // If the value is a boolean or null, convert it to a string. Note:
746
+ // typeof null does not produce 'null'. The case is included here in
747
+ // the remote chance that this gets fixed someday.
748
+
749
+ return String(value);
750
+
751
+ case 'object':
752
+ // If the type is 'object', we might be dealing with an object or an array or
753
+ // null.
754
+ // Due to a specification blunder in ECMAScript, typeof null is 'object',
755
+ // so watch out for that case.
756
+ if (!value) {
757
+ return 'null';
758
+ }
759
+
760
+ // Make an array to hold the partial results of stringifying this object value.
761
+ gap += indent;
762
+ partial = [];
763
+
764
+ // Is the value an array?
765
+ if (toString.apply(value) === '[object Array]') {
766
+ // The value is an array. Stringify every element. Use null as a placeholder
767
+ // for non-JSON values.
768
+
769
+ length = value.length;
770
+ for (i = 0; i < length; i += 1) {
771
+ partial[i] = str(i, value) || 'null';
772
+ }
773
+
774
+ // Join all of the elements together, separated with commas, and wrap them in
775
+ // brackets.
776
+ v = partial.length === 0 ? '[]' :
777
+ gap ? '[\n' + gap +
778
+ partial.join(',\n' + gap) + '\n' +
779
+ mind + ']' :
780
+ '[' + partial.join(',') + ']';
781
+ gap = mind;
782
+ return v;
783
+ }
784
+
785
+ // Iterate through all of the keys in the object.
786
+ for (k in value) {
787
+ if (hasOwnProperty.call(value, k)) {
788
+ v = str(k, value);
789
+ if (v) {
790
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
791
+ }
792
+ }
793
+ }
794
+
795
+ // Join all of the member texts together, separated with commas,
796
+ // and wrap them in braces.
797
+ v = partial.length === 0 ? '{}' :
798
+ gap ? '{' + partial.join(',') + '' +
799
+ mind + '}' : '{' + partial.join(',') + '}';
800
+ gap = mind;
801
+ return v;
802
+ }
803
+ };
804
+
805
+ // Make a fake root object containing our value under the key of ''.
806
+ // Return the result of stringifying the value.
807
+ return str('', {
808
+ '': value
809
+ });
810
+ };
811
+ })();
812
+
813
+ /**
814
+ * From https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
815
+ * Slightly modified to throw a real Error rather than a POJO
816
+ */
817
+ _.JSONDecode = (function() {
818
+ var at, // The index of the current character
819
+ ch, // The current character
820
+ escapee = {
821
+ '"': '"',
822
+ '\\': '\\',
823
+ '/': '/',
824
+ 'b': '\b',
825
+ 'f': '\f',
826
+ 'n': '\n',
827
+ 'r': '\r',
828
+ 't': '\t'
829
+ },
830
+ text,
831
+ error = function(m) {
832
+ var e = new SyntaxError(m);
833
+ e.at = at;
834
+ e.text = text;
835
+ throw e;
836
+ },
837
+ next = function(c) {
838
+ // If a c parameter is provided, verify that it matches the current character.
839
+ if (c && c !== ch) {
840
+ error('Expected \'' + c + '\' instead of \'' + ch + '\'');
841
+ }
842
+ // Get the next character. When there are no more characters,
843
+ // return the empty string.
844
+ ch = text.charAt(at);
845
+ at += 1;
846
+ return ch;
847
+ },
848
+ number = function() {
849
+ // Parse a number value.
850
+ var number,
851
+ string = '';
852
+
853
+ if (ch === '-') {
854
+ string = '-';
855
+ next('-');
856
+ }
857
+ while (ch >= '0' && ch <= '9') {
858
+ string += ch;
859
+ next();
860
+ }
861
+ if (ch === '.') {
862
+ string += '.';
863
+ while (next() && ch >= '0' && ch <= '9') {
864
+ string += ch;
865
+ }
866
+ }
867
+ if (ch === 'e' || ch === 'E') {
868
+ string += ch;
869
+ next();
870
+ if (ch === '-' || ch === '+') {
871
+ string += ch;
872
+ next();
873
+ }
874
+ while (ch >= '0' && ch <= '9') {
875
+ string += ch;
876
+ next();
877
+ }
878
+ }
879
+ number = +string;
880
+ if (!isFinite(number)) {
881
+ error('Bad number');
882
+ } else {
883
+ return number;
884
+ }
885
+ },
886
+
887
+ string = function() {
888
+ // Parse a string value.
889
+ var hex,
890
+ i,
891
+ string = '',
892
+ uffff;
893
+ // When parsing for string values, we must look for " and \ characters.
894
+ if (ch === '"') {
895
+ while (next()) {
896
+ if (ch === '"') {
897
+ next();
898
+ return string;
899
+ }
900
+ if (ch === '\\') {
901
+ next();
902
+ if (ch === 'u') {
903
+ uffff = 0;
904
+ for (i = 0; i < 4; i += 1) {
905
+ hex = parseInt(next(), 16);
906
+ if (!isFinite(hex)) {
907
+ break;
908
+ }
909
+ uffff = uffff * 16 + hex;
910
+ }
911
+ string += String.fromCharCode(uffff);
912
+ } else if (typeof escapee[ch] === 'string') {
913
+ string += escapee[ch];
914
+ } else {
915
+ break;
916
+ }
917
+ } else {
918
+ string += ch;
919
+ }
920
+ }
921
+ }
922
+ error('Bad string');
923
+ },
924
+ white = function() {
925
+ // Skip whitespace.
926
+ while (ch && ch <= ' ') {
927
+ next();
928
+ }
929
+ },
930
+ word = function() {
931
+ // true, false, or null.
932
+ switch (ch) {
933
+ case 't':
934
+ next('t');
935
+ next('r');
936
+ next('u');
937
+ next('e');
938
+ return true;
939
+ case 'f':
940
+ next('f');
941
+ next('a');
942
+ next('l');
943
+ next('s');
944
+ next('e');
945
+ return false;
946
+ case 'n':
947
+ next('n');
948
+ next('u');
949
+ next('l');
950
+ next('l');
951
+ return null;
952
+ }
953
+ error('Unexpected "' + ch + '"');
954
+ },
955
+ value, // Placeholder for the value function.
956
+ array = function() {
957
+ // Parse an array value.
958
+ var array = [];
959
+
960
+ if (ch === '[') {
961
+ next('[');
962
+ white();
963
+ if (ch === ']') {
964
+ next(']');
965
+ return array; // empty array
966
+ }
967
+ while (ch) {
968
+ array.push(value());
969
+ white();
970
+ if (ch === ']') {
971
+ next(']');
972
+ return array;
973
+ }
974
+ next(',');
975
+ white();
976
+ }
977
+ }
978
+ error('Bad array');
979
+ },
980
+ object = function() {
981
+ // Parse an object value.
982
+ var key,
983
+ object = {};
984
+
985
+ if (ch === '{') {
986
+ next('{');
987
+ white();
988
+ if (ch === '}') {
989
+ next('}');
990
+ return object; // empty object
991
+ }
992
+ while (ch) {
993
+ key = string();
994
+ white();
995
+ next(':');
996
+ if (Object.hasOwnProperty.call(object, key)) {
997
+ error('Duplicate key "' + key + '"');
998
+ }
999
+ object[key] = value();
1000
+ white();
1001
+ if (ch === '}') {
1002
+ next('}');
1003
+ return object;
1004
+ }
1005
+ next(',');
1006
+ white();
1007
+ }
1008
+ }
1009
+ error('Bad object');
1010
+ };
1011
+
1012
+ value = function() {
1013
+ // Parse a JSON value. It could be an object, an array, a string,
1014
+ // a number, or a word.
1015
+ white();
1016
+ switch (ch) {
1017
+ case '{':
1018
+ return object();
1019
+ case '[':
1020
+ return array();
1021
+ case '"':
1022
+ return string();
1023
+ case '-':
1024
+ return number();
1025
+ default:
1026
+ return ch >= '0' && ch <= '9' ? number() : word();
1027
+ }
1028
+ };
1029
+
1030
+ // Return the json_parse function. It will have access to all of the
1031
+ // above functions and variables.
1032
+ return function(source) {
1033
+ var result;
1034
+
1035
+ text = source;
1036
+ at = 0;
1037
+ ch = ' ';
1038
+ result = value();
1039
+ white();
1040
+ if (ch) {
1041
+ error('Syntax error');
1042
+ }
1043
+
1044
+ return result;
1045
+ };
1046
+ })();
1047
+
1048
+ _.base64Encode = function(data) {
1049
+ var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
1050
+ var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
1051
+ ac = 0,
1052
+ enc = '',
1053
+ tmp_arr = [];
1054
+
1055
+ if (!data) {
1056
+ return data;
1057
+ }
1058
+
1059
+ data = _.utf8Encode(data);
1060
+
1061
+ do { // pack three octets into four hexets
1062
+ o1 = data.charCodeAt(i++);
1063
+ o2 = data.charCodeAt(i++);
1064
+ o3 = data.charCodeAt(i++);
1065
+
1066
+ bits = o1 << 16 | o2 << 8 | o3;
1067
+
1068
+ h1 = bits >> 18 & 0x3f;
1069
+ h2 = bits >> 12 & 0x3f;
1070
+ h3 = bits >> 6 & 0x3f;
1071
+ h4 = bits & 0x3f;
1072
+
1073
+ // use hexets to index into b64, and append result to encoded string
1074
+ tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
1075
+ } while (i < data.length);
1076
+
1077
+ enc = tmp_arr.join('');
1078
+
1079
+ switch (data.length % 3) {
1080
+ case 1:
1081
+ enc = enc.slice(0, -2) + '==';
1082
+ break;
1083
+ case 2:
1084
+ enc = enc.slice(0, -1) + '=';
1085
+ break;
1086
+ }
1087
+
1088
+ return enc;
1089
+ };
1090
+
1091
+ _.utf8Encode = function(string) {
1092
+ string = (string + '').replace(/\r\n/g, '\n').replace(/\r/g, '\n');
1093
+
1094
+ var utftext = '',
1095
+ start,
1096
+ end;
1097
+ var stringl = 0,
1098
+ n;
1099
+
1100
+ start = end = 0;
1101
+ stringl = string.length;
1102
+
1103
+ for (n = 0; n < stringl; n++) {
1104
+ var c1 = string.charCodeAt(n);
1105
+ var enc = null;
1106
+
1107
+ if (c1 < 128) {
1108
+ end++;
1109
+ } else if ((c1 > 127) && (c1 < 2048)) {
1110
+ enc = String.fromCharCode((c1 >> 6) | 192, (c1 & 63) | 128);
1111
+ } else {
1112
+ enc = String.fromCharCode((c1 >> 12) | 224, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128);
1113
+ }
1114
+ if (enc !== null) {
1115
+ if (end > start) {
1116
+ utftext += string.substring(start, end);
1117
+ }
1118
+ utftext += enc;
1119
+ start = end = n + 1;
1120
+ }
1121
+ }
1122
+
1123
+ if (end > start) {
1124
+ utftext += string.substring(start, string.length);
1125
+ }
1126
+
1127
+ return utftext;
1128
+ };
1129
+
1130
+ _.UUID = function() {
1131
+ try {
1132
+ // use native Crypto API when available
1133
+ return win['crypto']['randomUUID']();
1134
+ } catch (err) {
1135
+ // fall back to generating our own UUID
1136
+ // based on https://gist.github.com/scwood/3bff42cc005cc20ab7ec98f0d8e1d59d
1137
+ var uuid = new Array(36);
1138
+ for (var i = 0; i < 36; i++) {
1139
+ uuid[i] = Math.floor(Math.random() * 16);
1140
+ }
1141
+ uuid[14] = 4; // set bits 12-15 of time-high-and-version to 0100
1142
+ uuid[19] = uuid[19] &= -5; // set bit 6 of clock-seq-and-reserved to zero
1143
+ uuid[19] = uuid[19] |= (1 << 3); // set bit 7 of clock-seq-and-reserved to one
1144
+ uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
1145
+
1146
+ return _.map(uuid, function(x) {
1147
+ return x.toString(16);
1148
+ }).join('');
1149
+ }
1150
+ };
1151
+
1152
+ // _.isBlockedUA()
1153
+ // This is to block various web spiders from executing our JS and
1154
+ // sending false tracking data
1155
+ var BLOCKED_UA_STRS = [
1156
+ 'ahrefsbot',
1157
+ 'ahrefssiteaudit',
1158
+ 'amazonbot',
1159
+ 'baiduspider',
1160
+ 'bingbot',
1161
+ 'bingpreview',
1162
+ 'chrome-lighthouse',
1163
+ 'facebookexternal',
1164
+ 'petalbot',
1165
+ 'pinterest',
1166
+ 'screaming frog',
1167
+ 'yahoo! slurp',
1168
+ 'yandex',
1169
+
1170
+ // a whole bunch of goog-specific crawlers
1171
+ // https://developers.google.com/search/docs/advanced/crawling/overview-google-crawlers
1172
+ 'adsbot-google',
1173
+ 'apis-google',
1174
+ 'duplexweb-google',
1175
+ 'feedfetcher-google',
1176
+ 'google favicon',
1177
+ 'google web preview',
1178
+ 'google-read-aloud',
1179
+ 'googlebot',
1180
+ 'googleweblight',
1181
+ 'mediapartners-google',
1182
+ 'storebot-google'
1183
+ ];
1184
+ _.isBlockedUA = function(ua) {
1185
+ var i;
1186
+ ua = ua.toLowerCase();
1187
+ for (i = 0; i < BLOCKED_UA_STRS.length; i++) {
1188
+ if (ua.indexOf(BLOCKED_UA_STRS[i]) !== -1) {
1189
+ return true;
1190
+ }
1191
+ }
1192
+ return false;
1193
+ };
1194
+
1195
+ /**
1196
+ * @param {Object=} formdata
1197
+ * @param {string=} arg_separator
1198
+ */
1199
+ _.HTTPBuildQuery = function(formdata, arg_separator) {
1200
+ var use_val, use_key, tmp_arr = [];
1201
+
1202
+ if (_.isUndefined(arg_separator)) {
1203
+ arg_separator = '&';
1204
+ }
1205
+
1206
+ _.each(formdata, function(val, key) {
1207
+ use_val = encodeURIComponent(val.toString());
1208
+ use_key = encodeURIComponent(key);
1209
+ tmp_arr[tmp_arr.length] = use_key + '=' + use_val;
1210
+ });
1211
+
1212
+ return tmp_arr.join(arg_separator);
1213
+ };
1214
+
1215
+ _.getQueryParam = function(url, param) {
1216
+ // Expects a raw URL
1217
+
1218
+ param = param.replace(/[[]/g, '\\[').replace(/[\]]/g, '\\]');
1219
+ var regexS = '[\\?&]' + param + '=([^&#]*)',
1220
+ regex = new RegExp(regexS),
1221
+ results = regex.exec(url);
1222
+ if (results === null || (results && typeof(results[1]) !== 'string' && results[1].length)) {
1223
+ return '';
1224
+ } else {
1225
+ var result = results[1];
1226
+ try {
1227
+ result = decodeURIComponent(result);
1228
+ } catch(err) {
1229
+ }
1230
+ return result.replace(/\+/g, ' ');
1231
+ }
1232
+ };
1233
+
1234
+
1235
+ // _.cookie
1236
+ // Methods partially borrowed from quirksmode.org/js/cookies.html
1237
+ _.cookie = {
1238
+ get: function(name) {
1239
+ var nameEQ = name + '=';
1240
+ var ca = document.cookie.split(';');
1241
+ for (var i = 0; i < ca.length; i++) {
1242
+ var c = ca[i];
1243
+ while (c.charAt(0) == ' ') {
1244
+ c = c.substring(1, c.length);
1245
+ }
1246
+ if (c.indexOf(nameEQ) === 0) {
1247
+ return decodeURIComponent(c.substring(nameEQ.length, c.length));
1248
+ }
1249
+ }
1250
+ return null;
1251
+ },
1252
+
1253
+ parse: function(name) {
1254
+ var cookie;
1255
+ try {
1256
+ cookie = _.JSONDecode(_.cookie.get(name)) || {};
1257
+ } catch (err) {
1258
+ // noop
1259
+ }
1260
+ return cookie;
1261
+ },
1262
+
1263
+ set_seconds: function(name, value, seconds, is_cross_subdomain, is_secure, is_cross_site, domain_override) {
1264
+ var cdomain = '',
1265
+ expires = '',
1266
+ secure = '';
1267
+
1268
+ if (domain_override) {
1269
+ cdomain = '; domain=' + domain_override;
1270
+ } else if (is_cross_subdomain) {
1271
+ var domain = extract_domain(document.location.hostname);
1272
+ cdomain = domain ? '; domain=.' + domain : '';
1273
+ }
1274
+
1275
+ if (seconds) {
1276
+ var date = new Date();
1277
+ date.setTime(date.getTime() + (seconds * 1000));
1278
+ expires = '; expires=' + date.toGMTString();
1279
+ }
1280
+
1281
+ if (is_cross_site) {
1282
+ is_secure = true;
1283
+ secure = '; SameSite=None';
1284
+ }
1285
+ if (is_secure) {
1286
+ secure += '; secure';
1287
+ }
1288
+
1289
+ document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/' + cdomain + secure;
1290
+ },
1291
+
1292
+ set: function(name, value, days, is_cross_subdomain, is_secure, is_cross_site, domain_override) {
1293
+ var cdomain = '', expires = '', secure = '';
1294
+
1295
+ if (domain_override) {
1296
+ cdomain = '; domain=' + domain_override;
1297
+ } else if (is_cross_subdomain) {
1298
+ var domain = extract_domain(document.location.hostname);
1299
+ cdomain = domain ? '; domain=.' + domain : '';
1300
+ }
1301
+
1302
+ if (days) {
1303
+ var date = new Date();
1304
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
1305
+ expires = '; expires=' + date.toGMTString();
1306
+ }
1307
+
1308
+ if (is_cross_site) {
1309
+ is_secure = true;
1310
+ secure = '; SameSite=None';
1311
+ }
1312
+ if (is_secure) {
1313
+ secure += '; secure';
1314
+ }
1315
+
1316
+ var new_cookie_val = name + '=' + encodeURIComponent(value) + expires + '; path=/' + cdomain + secure;
1317
+ document.cookie = new_cookie_val;
1318
+ return new_cookie_val;
1319
+ },
1320
+
1321
+ remove: function(name, is_cross_subdomain, domain_override) {
1322
+ _.cookie.set(name, '', -1, is_cross_subdomain, false, false, domain_override);
1323
+ }
1324
+ };
1325
+
1326
+ var _testStorageSupported = function (storage) {
1327
+ var supported = true;
1328
+ try {
1329
+ var key = '__mplss_' + cheap_guid(8),
1330
+ val = 'xyz';
1331
+ storage.setItem(key, val);
1332
+ if (storage.getItem(key) !== val) {
1333
+ supported = false;
1334
+ }
1335
+ storage.removeItem(key);
1336
+ } catch (err) {
1337
+ supported = false;
1338
+ }
1339
+ return supported;
1340
+ };
1341
+
1342
+ var _localStorageSupported = null;
1343
+ var localStorageSupported = function(storage, forceCheck) {
1344
+ if (_localStorageSupported !== null && !forceCheck) {
1345
+ return _localStorageSupported;
1346
+ }
1347
+ return _localStorageSupported = _testStorageSupported(storage || win.localStorage);
1348
+ };
1349
+
1350
+ var _sessionStorageSupported = null;
1351
+ var sessionStorageSupported = function(storage, forceCheck) {
1352
+ if (_sessionStorageSupported !== null && !forceCheck) {
1353
+ return _sessionStorageSupported;
1354
+ }
1355
+ return _sessionStorageSupported = _testStorageSupported(storage || win.sessionStorage);
1356
+ };
1357
+
1358
+ function _storageWrapper(storage, name, is_supported_fn) {
1359
+ var log_error = function(msg) {
1360
+ };
1361
+
1362
+ return {
1363
+ is_supported: function(forceCheck) {
1364
+ var supported = is_supported_fn(storage, forceCheck);
1365
+ return supported;
1366
+ },
1367
+ error: log_error,
1368
+ get: function(key) {
1369
+ try {
1370
+ return storage.getItem(key);
1371
+ } catch (err) {
1372
+ }
1373
+ return null;
1374
+ },
1375
+ parse: function(key) {
1376
+ try {
1377
+ return _.JSONDecode(storage.getItem(key)) || {};
1378
+ } catch (err) {
1379
+ // noop
1380
+ }
1381
+ return null;
1382
+ },
1383
+ set: function(key, value) {
1384
+ try {
1385
+ storage.setItem(key, value);
1386
+ } catch (err) {
1387
+ }
1388
+ },
1389
+ remove: function(key) {
1390
+ try {
1391
+ storage.removeItem(key);
1392
+ } catch (err) {
1393
+ }
1394
+ }
1395
+ };
1396
+ }
1397
+
1398
+ // Safari errors out accessing localStorage/sessionStorage when cookies are disabled,
1399
+ // so create dummy storage wrappers that silently fail as a fallback.
1400
+ var windowLocalStorage = null, windowSessionStorage = null;
1401
+ try {
1402
+ windowLocalStorage = win.localStorage;
1403
+ windowSessionStorage = win.sessionStorage;
1404
+ // eslint-disable-next-line no-empty
1405
+ } catch (_err) {}
1406
+
1407
+ _.localStorage = _storageWrapper(windowLocalStorage, 'localStorage', localStorageSupported);
1408
+ _.sessionStorage = _storageWrapper(windowSessionStorage, 'sessionStorage', sessionStorageSupported);
1409
+
1410
+ _.register_event = (function() {
1411
+ // written by Dean Edwards, 2005
1412
+ // with input from Tino Zijdel - crisp@xs4all.nl
1413
+ // with input from Carl Sverre - mail@carlsverre.com
1414
+ // with input from Mixpanel
1415
+ // http://dean.edwards.name/weblog/2005/10/add-event/
1416
+ // https://gist.github.com/1930440
1417
+
1418
+ /**
1419
+ * @param {Object} element
1420
+ * @param {string} type
1421
+ * @param {function(...*)} handler
1422
+ * @param {boolean=} oldSchool
1423
+ * @param {boolean=} useCapture
1424
+ */
1425
+ var register_event = function(element, type, handler, oldSchool, useCapture) {
1426
+ if (!element) {
1427
+ return;
1428
+ }
1429
+
1430
+ if (element.addEventListener && !oldSchool) {
1431
+ element.addEventListener(type, handler, !!useCapture);
1432
+ } else {
1433
+ var ontype = 'on' + type;
1434
+ var old_handler = element[ontype]; // can be undefined
1435
+ element[ontype] = makeHandler(element, handler, old_handler);
1436
+ }
1437
+ };
1438
+
1439
+ function makeHandler(element, new_handler, old_handlers) {
1440
+ var handler = function(event) {
1441
+ event = event || fixEvent(win.event);
1442
+
1443
+ // this basically happens in firefox whenever another script
1444
+ // overwrites the onload callback and doesn't pass the event
1445
+ // object to previously defined callbacks. All the browsers
1446
+ // that don't define window.event implement addEventListener
1447
+ // so the dom_loaded handler will still be fired as usual.
1448
+ if (!event) {
1449
+ return undefined;
1450
+ }
1451
+
1452
+ var ret = true;
1453
+ var old_result, new_result;
1454
+
1455
+ if (_.isFunction(old_handlers)) {
1456
+ old_result = old_handlers(event);
1457
+ }
1458
+ new_result = new_handler.call(element, event);
1459
+
1460
+ if ((false === old_result) || (false === new_result)) {
1461
+ ret = false;
1462
+ }
1463
+
1464
+ return ret;
1465
+ };
1466
+
1467
+ return handler;
1468
+ }
1469
+
1470
+ function fixEvent(event) {
1471
+ if (event) {
1472
+ event.preventDefault = fixEvent.preventDefault;
1473
+ event.stopPropagation = fixEvent.stopPropagation;
1474
+ }
1475
+ return event;
1476
+ }
1477
+ fixEvent.preventDefault = function() {
1478
+ this.returnValue = false;
1479
+ };
1480
+ fixEvent.stopPropagation = function() {
1481
+ this.cancelBubble = true;
1482
+ };
1483
+
1484
+ return register_event;
1485
+ })();
1486
+
1487
+
1488
+ var TOKEN_MATCH_REGEX = new RegExp('^(\\w*)\\[(\\w+)([=~\\|\\^\\$\\*]?)=?"?([^\\]"]*)"?\\]$');
1489
+
1490
+ _.dom_query = (function() {
1491
+ /* document.getElementsBySelector(selector)
1492
+ - returns an array of element objects from the current document
1493
+ matching the CSS selector. Selectors can contain element names,
1494
+ class names and ids and can be nested. For example:
1495
+
1496
+ elements = document.getElementsBySelector('div#main p a.external')
1497
+
1498
+ Will return an array of all 'a' elements with 'external' in their
1499
+ class attribute that are contained inside 'p' elements that are
1500
+ contained inside the 'div' element which has id="main"
1501
+
1502
+ New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
1503
+ See http://www.w3.org/TR/css3-selectors/#attribute-selectors
1504
+
1505
+ Version 0.4 - Simon Willison, March 25th 2003
1506
+ -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
1507
+ -- Opera 7 fails
1508
+
1509
+ Version 0.5 - Carl Sverre, Jan 7th 2013
1510
+ -- Now uses jQuery-esque `hasClass` for testing class name
1511
+ equality. This fixes a bug related to '-' characters being
1512
+ considered not part of a 'word' in regex.
1513
+ */
1514
+
1515
+ function getAllChildren(e) {
1516
+ // Returns all children of element. Workaround required for IE5/Windows. Ugh.
1517
+ return e.all ? e.all : e.getElementsByTagName('*');
1518
+ }
1519
+
1520
+ var bad_whitespace = /[\t\r\n]/g;
1521
+
1522
+ function hasClass(elem, selector) {
1523
+ var className = ' ' + selector + ' ';
1524
+ return ((' ' + elem.className + ' ').replace(bad_whitespace, ' ').indexOf(className) >= 0);
1525
+ }
1526
+
1527
+ function getElementsBySelector(selector) {
1528
+ // Attempt to fail gracefully in lesser browsers
1529
+ if (!document.getElementsByTagName) {
1530
+ return [];
1531
+ }
1532
+ // Split selector in to tokens
1533
+ var tokens = selector.split(' ');
1534
+ var token, bits, tagName, found, foundCount, i, j, k, elements, currentContextIndex;
1535
+ var currentContext = [document];
1536
+ for (i = 0; i < tokens.length; i++) {
1537
+ token = tokens[i].replace(/^\s+/, '').replace(/\s+$/, '');
1538
+ if (token.indexOf('#') > -1) {
1539
+ // Token is an ID selector
1540
+ bits = token.split('#');
1541
+ tagName = bits[0];
1542
+ var id = bits[1];
1543
+ var element = document.getElementById(id);
1544
+ if (!element || (tagName && element.nodeName.toLowerCase() != tagName)) {
1545
+ // element not found or tag with that ID not found, return false
1546
+ return [];
1547
+ }
1548
+ // Set currentContext to contain just this element
1549
+ currentContext = [element];
1550
+ continue; // Skip to next token
1551
+ }
1552
+ if (token.indexOf('.') > -1) {
1553
+ // Token contains a class selector
1554
+ bits = token.split('.');
1555
+ tagName = bits[0];
1556
+ var className = bits[1];
1557
+ if (!tagName) {
1558
+ tagName = '*';
1559
+ }
1560
+ // Get elements matching tag, filter them for class selector
1561
+ found = [];
1562
+ foundCount = 0;
1563
+ for (j = 0; j < currentContext.length; j++) {
1564
+ if (tagName == '*') {
1565
+ elements = getAllChildren(currentContext[j]);
1566
+ } else {
1567
+ elements = currentContext[j].getElementsByTagName(tagName);
1568
+ }
1569
+ for (k = 0; k < elements.length; k++) {
1570
+ found[foundCount++] = elements[k];
1571
+ }
1572
+ }
1573
+ currentContext = [];
1574
+ currentContextIndex = 0;
1575
+ for (j = 0; j < found.length; j++) {
1576
+ if (found[j].className &&
1577
+ _.isString(found[j].className) && // some SVG elements have classNames which are not strings
1578
+ hasClass(found[j], className)
1579
+ ) {
1580
+ currentContext[currentContextIndex++] = found[j];
1581
+ }
1582
+ }
1583
+ continue; // Skip to next token
1584
+ }
1585
+ // Code to deal with attribute selectors
1586
+ var token_match = token.match(TOKEN_MATCH_REGEX);
1587
+ if (token_match) {
1588
+ tagName = token_match[1];
1589
+ var attrName = token_match[2];
1590
+ var attrOperator = token_match[3];
1591
+ var attrValue = token_match[4];
1592
+ if (!tagName) {
1593
+ tagName = '*';
1594
+ }
1595
+ // Grab all of the tagName elements within current context
1596
+ found = [];
1597
+ foundCount = 0;
1598
+ for (j = 0; j < currentContext.length; j++) {
1599
+ if (tagName == '*') {
1600
+ elements = getAllChildren(currentContext[j]);
1601
+ } else {
1602
+ elements = currentContext[j].getElementsByTagName(tagName);
1603
+ }
1604
+ for (k = 0; k < elements.length; k++) {
1605
+ found[foundCount++] = elements[k];
1606
+ }
1607
+ }
1608
+ currentContext = [];
1609
+ currentContextIndex = 0;
1610
+ var checkFunction; // This function will be used to filter the elements
1611
+ switch (attrOperator) {
1612
+ case '=': // Equality
1613
+ checkFunction = function(e) {
1614
+ return (e.getAttribute(attrName) == attrValue);
1615
+ };
1616
+ break;
1617
+ case '~': // Match one of space seperated words
1618
+ checkFunction = function(e) {
1619
+ return (e.getAttribute(attrName).match(new RegExp('\\b' + attrValue + '\\b')));
1620
+ };
1621
+ break;
1622
+ case '|': // Match start with value followed by optional hyphen
1623
+ checkFunction = function(e) {
1624
+ return (e.getAttribute(attrName).match(new RegExp('^' + attrValue + '-?')));
1625
+ };
1626
+ break;
1627
+ case '^': // Match starts with value
1628
+ checkFunction = function(e) {
1629
+ return (e.getAttribute(attrName).indexOf(attrValue) === 0);
1630
+ };
1631
+ break;
1632
+ case '$': // Match ends with value - fails with "Warning" in Opera 7
1633
+ checkFunction = function(e) {
1634
+ return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length);
1635
+ };
1636
+ break;
1637
+ case '*': // Match ends with value
1638
+ checkFunction = function(e) {
1639
+ return (e.getAttribute(attrName).indexOf(attrValue) > -1);
1640
+ };
1641
+ break;
1642
+ default:
1643
+ // Just test for existence of attribute
1644
+ checkFunction = function(e) {
1645
+ return e.getAttribute(attrName);
1646
+ };
1647
+ }
1648
+ currentContext = [];
1649
+ currentContextIndex = 0;
1650
+ for (j = 0; j < found.length; j++) {
1651
+ if (checkFunction(found[j])) {
1652
+ currentContext[currentContextIndex++] = found[j];
1653
+ }
1654
+ }
1655
+ // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
1656
+ continue; // Skip to next token
1657
+ }
1658
+ // If we get here, token is JUST an element (not a class or ID selector)
1659
+ tagName = token;
1660
+ found = [];
1661
+ foundCount = 0;
1662
+ for (j = 0; j < currentContext.length; j++) {
1663
+ elements = currentContext[j].getElementsByTagName(tagName);
1664
+ for (k = 0; k < elements.length; k++) {
1665
+ found[foundCount++] = elements[k];
1666
+ }
1667
+ }
1668
+ currentContext = found;
1669
+ }
1670
+ return currentContext;
1671
+ }
1672
+
1673
+ return function(query) {
1674
+ if (_.isElement(query)) {
1675
+ return [query];
1676
+ } else if (_.isObject(query) && !_.isUndefined(query.length)) {
1677
+ return query;
1678
+ } else {
1679
+ return getElementsBySelector.call(this, query);
1680
+ }
1681
+ };
1682
+ })();
1683
+
1684
+ var CAMPAIGN_KEYWORDS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform','utm_campaign_id', 'utm_creative_format', 'utm_marketing_tactic'];
1685
+ var CLICK_IDS = ['dclid', 'fbclid', 'gclid', 'ko_click_id', 'li_fat_id', 'msclkid', 'sccid', 'ttclid', 'twclid', 'wbraid'];
1686
+
1687
+ _.info = {
1688
+ campaignParams: function(default_value) {
1689
+ var kw = '',
1690
+ params = {};
1691
+ _.each(CAMPAIGN_KEYWORDS, function(kwkey) {
1692
+ kw = _.getQueryParam(document.URL, kwkey);
1693
+ if (kw.length) {
1694
+ params[kwkey] = kw;
1695
+ } else if (default_value !== undefined) {
1696
+ params[kwkey] = default_value;
1697
+ }
1698
+ });
1699
+
1700
+ return params;
1701
+ },
1702
+
1703
+ clickParams: function() {
1704
+ var id = '',
1705
+ params = {};
1706
+ _.each(CLICK_IDS, function(idkey) {
1707
+ id = _.getQueryParam(document.URL, idkey);
1708
+ if (id.length) {
1709
+ params[idkey] = id;
1710
+ }
1711
+ });
1712
+
1713
+ return params;
1714
+ },
1715
+
1716
+ marketingParams: function() {
1717
+ return _.extend(_.info.campaignParams(), _.info.clickParams());
1718
+ },
1719
+
1720
+ searchEngine: function(referrer) {
1721
+ if (referrer.search('https?://(.*)google.([^/?]*)') === 0) {
1722
+ return 'google';
1723
+ } else if (referrer.search('https?://(.*)bing.com') === 0) {
1724
+ return 'bing';
1725
+ } else if (referrer.search('https?://(.*)yahoo.com') === 0) {
1726
+ return 'yahoo';
1727
+ } else if (referrer.search('https?://(.*)duckduckgo.com') === 0) {
1728
+ return 'duckduckgo';
1729
+ } else {
1730
+ return null;
1731
+ }
1732
+ },
1733
+
1734
+ searchInfo: function(referrer) {
1735
+ var search = _.info.searchEngine(referrer),
1736
+ param = (search != 'yahoo') ? 'q' : 'p',
1737
+ ret = {};
1738
+
1739
+ if (search !== null) {
1740
+ ret['$search_engine'] = search;
1741
+
1742
+ var keyword = _.getQueryParam(referrer, param);
1743
+ if (keyword.length) {
1744
+ ret['mp_keyword'] = keyword;
1745
+ }
1746
+ }
1747
+
1748
+ return ret;
1749
+ },
1750
+
1751
+ /**
1752
+ * This function detects which browser is running this script.
1753
+ * The order of the checks are important since many user agents
1754
+ * include key words used in later checks.
1755
+ */
1756
+ browser: function(user_agent, vendor, opera) {
1757
+ vendor = vendor || ''; // vendor is undefined for at least IE9
1758
+ if (opera || _.includes(user_agent, ' OPR/')) {
1759
+ if (_.includes(user_agent, 'Mini')) {
1760
+ return 'Opera Mini';
1761
+ }
1762
+ return 'Opera';
1763
+ } else if (/(BlackBerry|PlayBook|BB10)/i.test(user_agent)) {
1764
+ return 'BlackBerry';
1765
+ } else if (_.includes(user_agent, 'IEMobile') || _.includes(user_agent, 'WPDesktop')) {
1766
+ return 'Internet Explorer Mobile';
1767
+ } else if (_.includes(user_agent, 'SamsungBrowser/')) {
1768
+ // https://developer.samsung.com/internet/user-agent-string-format
1769
+ return 'Samsung Internet';
1770
+ } else if (_.includes(user_agent, 'Edge') || _.includes(user_agent, 'Edg/')) {
1771
+ return 'Microsoft Edge';
1772
+ } else if (_.includes(user_agent, 'FBIOS')) {
1773
+ return 'Facebook Mobile';
1774
+ } else if (_.includes(user_agent, 'Whale/')) {
1775
+ // https://user-agents.net/browsers/whale-browser
1776
+ return 'Whale Browser';
1777
+ } else if (_.includes(user_agent, 'Chrome')) {
1778
+ return 'Chrome';
1779
+ } else if (_.includes(user_agent, 'CriOS')) {
1780
+ return 'Chrome iOS';
1781
+ } else if (_.includes(user_agent, 'UCWEB') || _.includes(user_agent, 'UCBrowser')) {
1782
+ return 'UC Browser';
1783
+ } else if (_.includes(user_agent, 'FxiOS')) {
1784
+ return 'Firefox iOS';
1785
+ } else if (_.includes(vendor, 'Apple')) {
1786
+ if (_.includes(user_agent, 'Mobile')) {
1787
+ return 'Mobile Safari';
1788
+ }
1789
+ return 'Safari';
1790
+ } else if (_.includes(user_agent, 'Android')) {
1791
+ return 'Android Mobile';
1792
+ } else if (_.includes(user_agent, 'Konqueror')) {
1793
+ return 'Konqueror';
1794
+ } else if (_.includes(user_agent, 'Firefox')) {
1795
+ return 'Firefox';
1796
+ } else if (_.includes(user_agent, 'MSIE') || _.includes(user_agent, 'Trident/')) {
1797
+ return 'Internet Explorer';
1798
+ } else if (_.includes(user_agent, 'Gecko')) {
1799
+ return 'Mozilla';
1800
+ } else {
1801
+ return '';
1802
+ }
1803
+ },
1804
+
1805
+ /**
1806
+ * This function detects which browser version is running this script,
1807
+ * parsing major and minor version (e.g., 42.1). User agent strings from:
1808
+ * http://www.useragentstring.com/pages/useragentstring.php
1809
+ */
1810
+ browserVersion: function(userAgent, vendor, opera) {
1811
+ var browser = _.info.browser(userAgent, vendor, opera);
1812
+ var versionRegexs = {
1813
+ 'Internet Explorer Mobile': /rv:(\d+(\.\d+)?)/,
1814
+ 'Microsoft Edge': /Edge?\/(\d+(\.\d+)?)/,
1815
+ 'Chrome': /Chrome\/(\d+(\.\d+)?)/,
1816
+ 'Chrome iOS': /CriOS\/(\d+(\.\d+)?)/,
1817
+ 'UC Browser' : /(UCBrowser|UCWEB)\/(\d+(\.\d+)?)/,
1818
+ 'Safari': /Version\/(\d+(\.\d+)?)/,
1819
+ 'Mobile Safari': /Version\/(\d+(\.\d+)?)/,
1820
+ 'Opera': /(Opera|OPR)\/(\d+(\.\d+)?)/,
1821
+ 'Firefox': /Firefox\/(\d+(\.\d+)?)/,
1822
+ 'Firefox iOS': /FxiOS\/(\d+(\.\d+)?)/,
1823
+ 'Konqueror': /Konqueror:(\d+(\.\d+)?)/,
1824
+ 'BlackBerry': /BlackBerry (\d+(\.\d+)?)/,
1825
+ 'Android Mobile': /android\s(\d+(\.\d+)?)/,
1826
+ 'Samsung Internet': /SamsungBrowser\/(\d+(\.\d+)?)/,
1827
+ 'Internet Explorer': /(rv:|MSIE )(\d+(\.\d+)?)/,
1828
+ 'Mozilla': /rv:(\d+(\.\d+)?)/,
1829
+ 'Whale Browser': /Whale\/(\d+(\.\d+)?)/
1830
+ };
1831
+ var regex = versionRegexs[browser];
1832
+ if (regex === undefined) {
1833
+ return null;
1834
+ }
1835
+ var matches = userAgent.match(regex);
1836
+ if (!matches) {
1837
+ return null;
1838
+ }
1839
+ return parseFloat(matches[matches.length - 2]);
1840
+ },
1841
+
1842
+ os: function() {
1843
+ var a = userAgent;
1844
+ if (/Windows/i.test(a)) {
1845
+ if (/Phone/.test(a) || /WPDesktop/.test(a)) {
1846
+ return 'Windows Phone';
1847
+ }
1848
+ return 'Windows';
1849
+ } else if (/(iPhone|iPad|iPod)/.test(a)) {
1850
+ return 'iOS';
1851
+ } else if (/Android/.test(a)) {
1852
+ return 'Android';
1853
+ } else if (/(BlackBerry|PlayBook|BB10)/i.test(a)) {
1854
+ return 'BlackBerry';
1855
+ } else if (/Mac/i.test(a)) {
1856
+ return 'Mac OS X';
1857
+ } else if (/Linux/.test(a)) {
1858
+ return 'Linux';
1859
+ } else if (/CrOS/.test(a)) {
1860
+ return 'Chrome OS';
1861
+ } else {
1862
+ return '';
1863
+ }
1864
+ },
1865
+
1866
+ device: function(user_agent) {
1867
+ if (/Windows Phone/i.test(user_agent) || /WPDesktop/.test(user_agent)) {
1868
+ return 'Windows Phone';
1869
+ } else if (/iPad/.test(user_agent)) {
1870
+ return 'iPad';
1871
+ } else if (/iPod/.test(user_agent)) {
1872
+ return 'iPod Touch';
1873
+ } else if (/iPhone/.test(user_agent)) {
1874
+ return 'iPhone';
1875
+ } else if (/(BlackBerry|PlayBook|BB10)/i.test(user_agent)) {
1876
+ return 'BlackBerry';
1877
+ } else if (/Android/.test(user_agent)) {
1878
+ return 'Android';
1879
+ } else {
1880
+ return '';
1881
+ }
1882
+ },
1883
+
1884
+ referringDomain: function(referrer) {
1885
+ var split = referrer.split('/');
1886
+ if (split.length >= 3) {
1887
+ return split[2];
1888
+ }
1889
+ return '';
1890
+ },
1891
+
1892
+ currentUrl: function() {
1893
+ return win.location.href;
1894
+ },
1895
+
1896
+ properties: function(extra_props) {
1897
+ if (typeof extra_props !== 'object') {
1898
+ extra_props = {};
1899
+ }
1900
+ return _.extend(_.strip_empty_properties({
1901
+ '$os': _.info.os(),
1902
+ '$browser': _.info.browser(userAgent, navigator.vendor, windowOpera),
1903
+ '$referrer': document.referrer,
1904
+ '$referring_domain': _.info.referringDomain(document.referrer),
1905
+ '$device': _.info.device(userAgent)
1906
+ }), {
1907
+ '$current_url': _.info.currentUrl(),
1908
+ '$browser_version': _.info.browserVersion(userAgent, navigator.vendor, windowOpera),
1909
+ '$screen_height': screen.height,
1910
+ '$screen_width': screen.width,
1911
+ 'mp_lib': 'web',
1912
+ '$lib_version': Config.LIB_VERSION,
1913
+ '$insert_id': cheap_guid(),
1914
+ 'time': _.timestamp() / 1000 // epoch time in seconds
1915
+ }, _.strip_empty_properties(extra_props));
1916
+ },
1917
+
1918
+ people_properties: function() {
1919
+ return _.extend(_.strip_empty_properties({
1920
+ '$os': _.info.os(),
1921
+ '$browser': _.info.browser(userAgent, navigator.vendor, windowOpera)
1922
+ }), {
1923
+ '$browser_version': _.info.browserVersion(userAgent, navigator.vendor, windowOpera)
1924
+ });
1925
+ },
1926
+
1927
+ mpPageViewProperties: function() {
1928
+ return _.strip_empty_properties({
1929
+ 'current_page_title': document.title,
1930
+ 'current_domain': win.location.hostname,
1931
+ 'current_url_path': win.location.pathname,
1932
+ 'current_url_protocol': win.location.protocol,
1933
+ 'current_url_search': win.location.search
1934
+ });
1935
+ }
1936
+ };
1937
+
1938
+ var cheap_guid = function(maxlen) {
1939
+ var guid = Math.random().toString(36).substring(2, 10) + Math.random().toString(36).substring(2, 10);
1940
+ return maxlen ? guid.substring(0, maxlen) : guid;
1941
+ };
1942
+
1943
+ // naive way to extract domain name (example.com) from full hostname (my.sub.example.com)
1944
+ var SIMPLE_DOMAIN_MATCH_REGEX = /[a-z0-9][a-z0-9-]*\.[a-z]+$/i;
1945
+ // this next one attempts to account for some ccSLDs, e.g. extracting oxford.ac.uk from www.oxford.ac.uk
1946
+ var DOMAIN_MATCH_REGEX = /[a-z0-9][a-z0-9-]+\.[a-z.]{2,6}$/i;
1947
+ /**
1948
+ * Attempts to extract main domain name from full hostname, using a few blunt heuristics. For
1949
+ * common TLDs like .com/.org that always have a simple SLD.TLD structure (example.com), we
1950
+ * simply extract the last two .-separated parts of the hostname (SIMPLE_DOMAIN_MATCH_REGEX).
1951
+ * For others, we attempt to account for short ccSLD+TLD combos (.ac.uk) with the legacy
1952
+ * DOMAIN_MATCH_REGEX (kept to maintain backwards compatibility with existing Mixpanel
1953
+ * integrations). The only _reliable_ way to extract domain from hostname is with an up-to-date
1954
+ * list like at https://publicsuffix.org/ so for cases that this helper fails at, the SDK
1955
+ * offers the 'cookie_domain' config option to set it explicitly.
1956
+ * @example
1957
+ * extract_domain('my.sub.example.com')
1958
+ * // 'example.com'
1959
+ */
1960
+ var extract_domain = function(hostname) {
1961
+ var domain_regex = DOMAIN_MATCH_REGEX;
1962
+ var parts = hostname.split('.');
1963
+ var tld = parts[parts.length - 1];
1964
+ if (tld.length > 4 || tld === 'com' || tld === 'org') {
1965
+ domain_regex = SIMPLE_DOMAIN_MATCH_REGEX;
1966
+ }
1967
+ var matches = hostname.match(domain_regex);
1968
+ return matches ? matches[0] : '';
1969
+ };
1970
+
1971
+ var JSONStringify = null, JSONParse = null;
1972
+ if (typeof JSON !== 'undefined') {
1973
+ JSONStringify = JSON.stringify;
1974
+ JSONParse = JSON.parse;
1975
+ }
1976
+ JSONStringify = JSONStringify || _.JSONEncode;
1977
+ JSONParse = JSONParse || _.JSONDecode;
1978
+
1979
+ // UNMINIFIED EXPORTS (for closure compiler)
1980
+ _['info'] = _.info;
1981
+ _['info']['browser'] = _.info.browser;
1982
+ _['info']['browserVersion'] = _.info.browserVersion;
1983
+ _['info']['device'] = _.info.device;
1984
+ _['info']['properties'] = _.info.properties;
1985
+ _['isBlockedUA'] = _.isBlockedUA;
1986
+ _['isEmptyObject'] = _.isEmptyObject;
1987
+ _['isObject'] = _.isObject;
1988
+ _['JSONDecode'] = _.JSONDecode;
1989
+ _['JSONEncode'] = _.JSONEncode;
1990
+ _['toArray'] = _.toArray;
1991
+ _['NPO'] = NpoPromise;
1992
+
1993
+ function getDefaultExportFromCjs (x) {
1994
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
1995
+ }
1996
+
1997
+ var logic$1 = {exports: {}};
1998
+
1999
+ /* globals define,module */
2000
+ var logic = logic$1.exports;
2001
+
2002
+ var hasRequiredLogic;
2003
+
2004
+ function requireLogic () {
2005
+ if (hasRequiredLogic) return logic$1.exports;
2006
+ hasRequiredLogic = 1;
2007
+ (function (module, exports) {
2008
+ (function(root, factory) {
2009
+ {
2010
+ module.exports = factory();
2011
+ }
2012
+ }(logic, function() {
2013
+ /* globals console:false */
2014
+
2015
+ if ( ! Array.isArray) {
2016
+ Array.isArray = function(arg) {
2017
+ return Object.prototype.toString.call(arg) === "[object Array]";
2018
+ };
2019
+ }
2020
+
2021
+ /**
2022
+ * Return an array that contains no duplicates (original not modified)
2023
+ * @param {array} array Original reference array
2024
+ * @return {array} New array with no duplicates
2025
+ */
2026
+ function arrayUnique(array) {
2027
+ var a = [];
2028
+ for (var i=0, l=array.length; i<l; i++) {
2029
+ if (a.indexOf(array[i]) === -1) {
2030
+ a.push(array[i]);
2031
+ }
2032
+ }
2033
+ return a;
2034
+ }
2035
+
2036
+ var jsonLogic = {};
2037
+ var operations = {
2038
+ "==": function(a, b) {
2039
+ return a == b;
2040
+ },
2041
+ "===": function(a, b) {
2042
+ return a === b;
2043
+ },
2044
+ "!=": function(a, b) {
2045
+ return a != b;
2046
+ },
2047
+ "!==": function(a, b) {
2048
+ return a !== b;
2049
+ },
2050
+ ">": function(a, b) {
2051
+ return a > b;
2052
+ },
2053
+ ">=": function(a, b) {
2054
+ return a >= b;
2055
+ },
2056
+ "<": function(a, b, c) {
2057
+ return (c === undefined) ? a < b : (a < b) && (b < c);
2058
+ },
2059
+ "<=": function(a, b, c) {
2060
+ return (c === undefined) ? a <= b : (a <= b) && (b <= c);
2061
+ },
2062
+ "!!": function(a) {
2063
+ return jsonLogic.truthy(a);
2064
+ },
2065
+ "!": function(a) {
2066
+ return !jsonLogic.truthy(a);
2067
+ },
2068
+ "%": function(a, b) {
2069
+ return a % b;
2070
+ },
2071
+ "log": function(a) {
2072
+ console.log(a); return a;
2073
+ },
2074
+ "in": function(a, b) {
2075
+ if (!b || typeof b.indexOf === "undefined") return false;
2076
+ return (b.indexOf(a) !== -1);
2077
+ },
2078
+ "cat": function() {
2079
+ return Array.prototype.join.call(arguments, "");
2080
+ },
2081
+ "substr": function(source, start, end) {
2082
+ if (end < 0) {
2083
+ // JavaScript doesn't support negative end, this emulates PHP behavior
2084
+ var temp = String(source).substr(start);
2085
+ return temp.substr(0, temp.length + end);
2086
+ }
2087
+ return String(source).substr(start, end);
2088
+ },
2089
+ "+": function() {
2090
+ return Array.prototype.reduce.call(arguments, function(a, b) {
2091
+ return parseFloat(a, 10) + parseFloat(b, 10);
2092
+ }, 0);
2093
+ },
2094
+ "*": function() {
2095
+ return Array.prototype.reduce.call(arguments, function(a, b) {
2096
+ return parseFloat(a, 10) * parseFloat(b, 10);
2097
+ });
2098
+ },
2099
+ "-": function(a, b) {
2100
+ if (b === undefined) {
2101
+ return -a;
2102
+ } else {
2103
+ return a - b;
2104
+ }
2105
+ },
2106
+ "/": function(a, b) {
2107
+ return a / b;
2108
+ },
2109
+ "min": function() {
2110
+ return Math.min.apply(this, arguments);
2111
+ },
2112
+ "max": function() {
2113
+ return Math.max.apply(this, arguments);
2114
+ },
2115
+ "merge": function() {
2116
+ return Array.prototype.reduce.call(arguments, function(a, b) {
2117
+ return a.concat(b);
2118
+ }, []);
2119
+ },
2120
+ "var": function(a, b) {
2121
+ var not_found = (b === undefined) ? null : b;
2122
+ var data = this;
2123
+ if (typeof a === "undefined" || a==="" || a===null) {
2124
+ return data;
2125
+ }
2126
+ var sub_props = String(a).split(".");
2127
+ for (var i = 0; i < sub_props.length; i++) {
2128
+ if (data === null || data === undefined) {
2129
+ return not_found;
2130
+ }
2131
+ // Descending into data
2132
+ data = data[sub_props[i]];
2133
+ if (data === undefined) {
2134
+ return not_found;
2135
+ }
2136
+ }
2137
+ return data;
2138
+ },
2139
+ "missing": function() {
2140
+ /*
2141
+ Missing can receive many keys as many arguments, like {"missing:[1,2]}
2142
+ Missing can also receive *one* argument that is an array of keys,
2143
+ which typically happens if it's actually acting on the output of another command
2144
+ (like 'if' or 'merge')
2145
+ */
2146
+
2147
+ var missing = [];
2148
+ var keys = Array.isArray(arguments[0]) ? arguments[0] : arguments;
2149
+
2150
+ for (var i = 0; i < keys.length; i++) {
2151
+ var key = keys[i];
2152
+ var value = jsonLogic.apply({"var": key}, this);
2153
+ if (value === null || value === "") {
2154
+ missing.push(key);
2155
+ }
2156
+ }
2157
+
2158
+ return missing;
2159
+ },
2160
+ "missing_some": function(need_count, options) {
2161
+ // missing_some takes two arguments, how many (minimum) items must be present, and an array of keys (just like 'missing') to check for presence.
2162
+ var are_missing = jsonLogic.apply({"missing": options}, this);
2163
+
2164
+ if (options.length - are_missing.length >= need_count) {
2165
+ return [];
2166
+ } else {
2167
+ return are_missing;
2168
+ }
2169
+ },
2170
+ };
2171
+
2172
+ jsonLogic.is_logic = function(logic) {
2173
+ return (
2174
+ typeof logic === "object" && // An object
2175
+ logic !== null && // but not null
2176
+ ! Array.isArray(logic) && // and not an array
2177
+ Object.keys(logic).length === 1 // with exactly one key
2178
+ );
2179
+ };
2180
+
2181
+ /*
2182
+ This helper will defer to the JsonLogic spec as a tie-breaker when different language interpreters define different behavior for the truthiness of primitives. E.g., PHP considers empty arrays to be falsy, but Javascript considers them to be truthy. JsonLogic, as an ecosystem, needs one consistent answer.
2183
+
2184
+ Spec and rationale here: http://jsonlogic.com/truthy
2185
+ */
2186
+ jsonLogic.truthy = function(value) {
2187
+ if (Array.isArray(value) && value.length === 0) {
2188
+ return false;
2189
+ }
2190
+ return !! value;
2191
+ };
2192
+
2193
+
2194
+ jsonLogic.get_operator = function(logic) {
2195
+ return Object.keys(logic)[0];
2196
+ };
2197
+
2198
+ jsonLogic.get_values = function(logic) {
2199
+ return logic[jsonLogic.get_operator(logic)];
2200
+ };
2201
+
2202
+ jsonLogic.apply = function(logic, data) {
2203
+ // Does this array contain logic? Only one way to find out.
2204
+ if (Array.isArray(logic)) {
2205
+ return logic.map(function(l) {
2206
+ return jsonLogic.apply(l, data);
2207
+ });
2208
+ }
2209
+ // You've recursed to a primitive, stop!
2210
+ if ( ! jsonLogic.is_logic(logic) ) {
2211
+ return logic;
2212
+ }
2213
+
2214
+ var op = jsonLogic.get_operator(logic);
2215
+ var values = logic[op];
2216
+ var i;
2217
+ var current;
2218
+ var scopedLogic;
2219
+ var scopedData;
2220
+ var initial;
2221
+
2222
+ // easy syntax for unary operators, like {"var" : "x"} instead of strict {"var" : ["x"]}
2223
+ if ( ! Array.isArray(values)) {
2224
+ values = [values];
2225
+ }
2226
+
2227
+ // 'if', 'and', and 'or' violate the normal rule of depth-first calculating consequents, let each manage recursion as needed.
2228
+ if (op === "if" || op == "?:") {
2229
+ /* 'if' should be called with a odd number of parameters, 3 or greater
2230
+ This works on the pattern:
2231
+ if( 0 ){ 1 }else{ 2 };
2232
+ if( 0 ){ 1 }else if( 2 ){ 3 }else{ 4 };
2233
+ if( 0 ){ 1 }else if( 2 ){ 3 }else if( 4 ){ 5 }else{ 6 };
2234
+
2235
+ The implementation is:
2236
+ For pairs of values (0,1 then 2,3 then 4,5 etc)
2237
+ If the first evaluates truthy, evaluate and return the second
2238
+ If the first evaluates falsy, jump to the next pair (e.g, 0,1 to 2,3)
2239
+ given one parameter, evaluate and return it. (it's an Else and all the If/ElseIf were false)
2240
+ given 0 parameters, return NULL (not great practice, but there was no Else)
2241
+ */
2242
+ for (i = 0; i < values.length - 1; i += 2) {
2243
+ if ( jsonLogic.truthy( jsonLogic.apply(values[i], data) ) ) {
2244
+ return jsonLogic.apply(values[i+1], data);
2245
+ }
2246
+ }
2247
+ if (values.length === i+1) {
2248
+ return jsonLogic.apply(values[i], data);
2249
+ }
2250
+ return null;
2251
+ } else if (op === "and") { // Return first falsy, or last
2252
+ for (i=0; i < values.length; i+=1) {
2253
+ current = jsonLogic.apply(values[i], data);
2254
+ if ( ! jsonLogic.truthy(current)) {
2255
+ return current;
2256
+ }
2257
+ }
2258
+ return current; // Last
2259
+ } else if (op === "or") {// Return first truthy, or last
2260
+ for (i=0; i < values.length; i+=1) {
2261
+ current = jsonLogic.apply(values[i], data);
2262
+ if ( jsonLogic.truthy(current) ) {
2263
+ return current;
2264
+ }
2265
+ }
2266
+ return current; // Last
2267
+ } else if (op === "filter") {
2268
+ scopedData = jsonLogic.apply(values[0], data);
2269
+ scopedLogic = values[1];
2270
+
2271
+ if ( ! Array.isArray(scopedData)) {
2272
+ return [];
2273
+ }
2274
+ // Return only the elements from the array in the first argument,
2275
+ // that return truthy when passed to the logic in the second argument.
2276
+ // For parity with JavaScript, reindex the returned array
2277
+ return scopedData.filter(function(datum) {
2278
+ return jsonLogic.truthy( jsonLogic.apply(scopedLogic, datum));
2279
+ });
2280
+ } else if (op === "map") {
2281
+ scopedData = jsonLogic.apply(values[0], data);
2282
+ scopedLogic = values[1];
2283
+
2284
+ if ( ! Array.isArray(scopedData)) {
2285
+ return [];
2286
+ }
2287
+
2288
+ return scopedData.map(function(datum) {
2289
+ return jsonLogic.apply(scopedLogic, datum);
2290
+ });
2291
+ } else if (op === "reduce") {
2292
+ scopedData = jsonLogic.apply(values[0], data);
2293
+ scopedLogic = values[1];
2294
+ initial = typeof values[2] !== "undefined" ? jsonLogic.apply(values[2], data) : null;
2295
+
2296
+ if ( ! Array.isArray(scopedData)) {
2297
+ return initial;
2298
+ }
2299
+
2300
+ return scopedData.reduce(
2301
+ function(accumulator, current) {
2302
+ return jsonLogic.apply(
2303
+ scopedLogic,
2304
+ {current: current, accumulator: accumulator}
2305
+ );
2306
+ },
2307
+ initial
2308
+ );
2309
+ } else if (op === "all") {
2310
+ scopedData = jsonLogic.apply(values[0], data);
2311
+ scopedLogic = values[1];
2312
+ // All of an empty set is false. Note, some and none have correct fallback after the for loop
2313
+ if ( ! Array.isArray(scopedData) || ! scopedData.length) {
2314
+ return false;
2315
+ }
2316
+ for (i=0; i < scopedData.length; i+=1) {
2317
+ if ( ! jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) {
2318
+ return false; // First falsy, short circuit
2319
+ }
2320
+ }
2321
+ return true; // All were truthy
2322
+ } else if (op === "none") {
2323
+ scopedData = jsonLogic.apply(values[0], data);
2324
+ scopedLogic = values[1];
2325
+
2326
+ if ( ! Array.isArray(scopedData) || ! scopedData.length) {
2327
+ return true;
2328
+ }
2329
+ for (i=0; i < scopedData.length; i+=1) {
2330
+ if ( jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) {
2331
+ return false; // First truthy, short circuit
2332
+ }
2333
+ }
2334
+ return true; // None were truthy
2335
+ } else if (op === "some") {
2336
+ scopedData = jsonLogic.apply(values[0], data);
2337
+ scopedLogic = values[1];
2338
+
2339
+ if ( ! Array.isArray(scopedData) || ! scopedData.length) {
2340
+ return false;
2341
+ }
2342
+ for (i=0; i < scopedData.length; i+=1) {
2343
+ if ( jsonLogic.truthy( jsonLogic.apply(scopedLogic, scopedData[i]) )) {
2344
+ return true; // First truthy, short circuit
2345
+ }
2346
+ }
2347
+ return false; // None were truthy
2348
+ }
2349
+
2350
+ // Everyone else gets immediate depth-first recursion
2351
+ values = values.map(function(val) {
2352
+ return jsonLogic.apply(val, data);
2353
+ });
2354
+
2355
+
2356
+ // The operation is called with "data" bound to its "this" and "values" passed as arguments.
2357
+ // Structured commands like % or > can name formal arguments while flexible commands (like missing or merge) can operate on the pseudo-array arguments
2358
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
2359
+ if (operations.hasOwnProperty(op) && typeof operations[op] === "function") {
2360
+ return operations[op].apply(data, values);
2361
+ } else if (op.indexOf(".") > 0) { // Contains a dot, and not in the 0th position
2362
+ var sub_ops = String(op).split(".");
2363
+ var operation = operations;
2364
+ for (i = 0; i < sub_ops.length; i++) {
2365
+ if (!operation.hasOwnProperty(sub_ops[i])) {
2366
+ throw new Error("Unrecognized operation " + op +
2367
+ " (failed at " + sub_ops.slice(0, i+1).join(".") + ")");
2368
+ }
2369
+ // Descending into operations
2370
+ operation = operation[sub_ops[i]];
2371
+ }
2372
+
2373
+ return operation.apply(data, values);
2374
+ }
2375
+
2376
+ throw new Error("Unrecognized operation " + op );
2377
+ };
2378
+
2379
+ jsonLogic.uses_data = function(logic) {
2380
+ var collection = [];
2381
+
2382
+ if (jsonLogic.is_logic(logic)) {
2383
+ var op = jsonLogic.get_operator(logic);
2384
+ var values = logic[op];
2385
+
2386
+ if ( ! Array.isArray(values)) {
2387
+ values = [values];
2388
+ }
2389
+
2390
+ if (op === "var") {
2391
+ // This doesn't cover the case where the arg to var is itself a rule.
2392
+ collection.push(values[0]);
2393
+ } else {
2394
+ // Recursion!
2395
+ values.forEach(function(val) {
2396
+ collection.push.apply(collection, jsonLogic.uses_data(val) );
2397
+ });
2398
+ }
2399
+ }
2400
+
2401
+ return arrayUnique(collection);
2402
+ };
2403
+
2404
+ jsonLogic.add_operation = function(name, code) {
2405
+ operations[name] = code;
2406
+ };
2407
+
2408
+ jsonLogic.rm_operation = function(name) {
2409
+ delete operations[name];
2410
+ };
2411
+
2412
+ jsonLogic.rule_like = function(rule, pattern) {
2413
+ // console.log("Is ". JSON.stringify(rule) . " like " . JSON.stringify(pattern) . "?");
2414
+ if (pattern === rule) {
2415
+ return true;
2416
+ } // TODO : Deep object equivalency?
2417
+ if (pattern === "@") {
2418
+ return true;
2419
+ } // Wildcard!
2420
+ if (pattern === "number") {
2421
+ return (typeof rule === "number");
2422
+ }
2423
+ if (pattern === "string") {
2424
+ return (typeof rule === "string");
2425
+ }
2426
+ if (pattern === "array") {
2427
+ // !logic test might be superfluous in JavaScript
2428
+ return Array.isArray(rule) && ! jsonLogic.is_logic(rule);
2429
+ }
2430
+
2431
+ if (jsonLogic.is_logic(pattern)) {
2432
+ if (jsonLogic.is_logic(rule)) {
2433
+ var pattern_op = jsonLogic.get_operator(pattern);
2434
+ var rule_op = jsonLogic.get_operator(rule);
2435
+
2436
+ if (pattern_op === "@" || pattern_op === rule_op) {
2437
+ // echo "\nOperators match, go deeper\n";
2438
+ return jsonLogic.rule_like(
2439
+ jsonLogic.get_values(rule, false),
2440
+ jsonLogic.get_values(pattern, false)
2441
+ );
2442
+ }
2443
+ }
2444
+ return false; // pattern is logic, rule isn't, can't be eq
2445
+ }
2446
+
2447
+ if (Array.isArray(pattern)) {
2448
+ if (Array.isArray(rule)) {
2449
+ if (pattern.length !== rule.length) {
2450
+ return false;
2451
+ }
2452
+ /*
2453
+ Note, array order MATTERS, because we're using this array test logic to consider arguments, where order can matter. (e.g., + is commutative, but '-' or 'if' or 'var' are NOT)
2454
+ */
2455
+ for (var i = 0; i < pattern.length; i += 1) {
2456
+ // If any fail, we fail
2457
+ if ( ! jsonLogic.rule_like(rule[i], pattern[i])) {
2458
+ return false;
2459
+ }
2460
+ }
2461
+ return true; // If they *all* passed, we pass
2462
+ } else {
2463
+ return false; // Pattern is array, rule isn't
2464
+ }
2465
+ }
2466
+
2467
+ // Not logic, not array, not a === match for rule.
2468
+ return false;
2469
+ };
2470
+
2471
+ return jsonLogic;
2472
+ }));
2473
+ } (logic$1));
2474
+ return logic$1.exports;
2475
+ }
2476
+
2477
+ var logicExports = requireLogic();
2478
+ var jsonLogic = /*@__PURE__*/getDefaultExportFromCjs(logicExports);
2479
+
2480
+ /**
2481
+ * Shared helper to recursively lowercase strings in nested structures
2482
+ * @param {*} obj - Value to process
2483
+ * @param {boolean} lowercaseKeys - Whether to lowercase object keys
2484
+ * @returns {*} Processed value with lowercased strings
2485
+ */
2486
+ var lowercaseJson = function(obj, lowercaseKeys) {
2487
+ if (obj === null || obj === undefined) {
2488
+ return obj;
2489
+ } else if (typeof obj === 'string') {
2490
+ return obj.toLowerCase();
2491
+ } else if (Array.isArray(obj)) {
2492
+ return obj.map(function(item) {
2493
+ return lowercaseJson(item, lowercaseKeys);
2494
+ });
2495
+ } else if (obj === Object(obj)) {
2496
+ var result = {};
2497
+ for (var key in obj) {
2498
+ if (obj.hasOwnProperty(key)) {
2499
+ var newKey = lowercaseKeys && typeof key === 'string' ? key.toLowerCase() : key;
2500
+ result[newKey] = lowercaseJson(obj[key], lowercaseKeys);
2501
+ }
2502
+ }
2503
+ return result;
2504
+ } else {
2505
+ return obj;
2506
+ }
2507
+ };
2508
+
2509
+ /**
2510
+ * Lowercase all string keys and values in a nested structure
2511
+ * @param {*} val - Value to process
2512
+ * @returns {*} Processed value with lowercased strings
2513
+ */
2514
+ var lowercaseKeysAndValues = function(val) {
2515
+ return lowercaseJson(val, true);
2516
+ };
2517
+
2518
+ /**
2519
+ * Lowercase only leaf node string values in a nested structure (keys unchanged)
2520
+ * @param {*} val - Value to process
2521
+ * @returns {*} Processed value with lowercased leaf strings
2522
+ */
2523
+ var lowercaseOnlyLeafNodes = function(val) {
2524
+ return lowercaseJson(val, false);
2525
+ };
2526
+
2527
+ /**
2528
+ * Check if an event matches the given criteria
2529
+ * @param {string} eventName - The name of the event being checked
2530
+ * @param {Object} properties - Event properties to evaluate against property filters
2531
+ * @param {Object} criteria - Criteria to match against, with:
2532
+ * - event_name: string - Required event name (case-sensitive match)
2533
+ * - property_filters: Object - Optional JsonLogic filters for properties
2534
+ * @returns {Object} Result object with:
2535
+ * - matches: boolean - Whether the event matches the criteria
2536
+ * - error: string|undefined - Error message if evaluation failed
2537
+ */
2538
+ var eventMatchesCriteria = function(eventName, properties, criteria) {
2539
+ // Check exact event name match (case-sensitive)
2540
+ if (eventName !== criteria.event_name) {
2541
+ return { matches: false };
2542
+ }
2543
+
2544
+ // Evaluate property filters using JsonLogic
2545
+ var propertyFilters = criteria.property_filters;
2546
+ var filtersMatch = true; // default to true if no filters
2547
+
2548
+ if (propertyFilters && !_.isEmptyObject(propertyFilters)) {
2549
+ try {
2550
+ // Lowercase all keys and values in event properties for case-insensitive matching
2551
+ var lowercasedProperties = lowercaseKeysAndValues(properties || {});
2552
+
2553
+ // Lowercase only leaf nodes in JsonLogic filters (keep operators intact)
2554
+ var lowercasedFilters = lowercaseOnlyLeafNodes(propertyFilters);
2555
+
2556
+ filtersMatch = jsonLogic.apply(lowercasedFilters, lowercasedProperties);
2557
+ } catch (error) {
2558
+ return {
2559
+ matches: false,
2560
+ error: error.toString()
2561
+ };
2562
+ }
2563
+ }
2564
+
2565
+ return { matches: filtersMatch };
2566
+ };
2567
+
2568
+ // Create targeting library object
2569
+ var targetingLibrary = {};
2570
+ targetingLibrary['eventMatchesCriteria'] = eventMatchesCriteria;
2571
+
2572
+ // Set global Promise (use bracket notation to prevent minification)
2573
+ // This is the ONE AND ONLY global - matches recorder pattern
2574
+ win[TARGETING_GLOBAL_NAME] = Promise.resolve(targetingLibrary);
2575
+
2576
+ })();