@apstal/analytics 1.0.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.
package/src/apstal.js ADDED
@@ -0,0 +1,1830 @@
1
+ // Apstal Analytics Tracker (Open Source)
2
+ // https://github.com/apstal/apstal
3
+ // Copyright (c) 2025-2026 Apstal. AGPL-3.0 License.
4
+ import * as rrweb from "rrweb";
5
+ import { gzipSync, strToU8 } from "fflate";
6
+ (function () {
7
+ "use strict";
8
+ var script = document.currentScript;
9
+ if (!script) return;
10
+ var PROJECT_ID = script.getAttribute("data-project");
11
+ if (!PROJECT_ID) {
12
+ return;
13
+ }
14
+ var scriptSrc = script.src;
15
+ var API_URL = scriptSrc.substring(0, scriptSrc.lastIndexOf("/")) + "/api/v1/m";
16
+ var customEndpoint = script.getAttribute("data-endpoint");
17
+ if (customEndpoint) API_URL = customEndpoint;
18
+ var BATCH_INTERVAL = 5e3;
19
+ var MAX_BATCH_SIZE = 25;
20
+ var MAX_PAYLOAD_CHARS = 3e4;
21
+ var DEFAULT_MAX_PAYLOAD = 3e4;
22
+ var MAX_RETRIES = 5;
23
+ var RETRY_TRACKER = {};
24
+ var EVENT_TIMERS = {};
25
+ var SCROLL_THROTTLE = 1e3;
26
+ var MUTATION_DEBOUNCE = 1e3;
27
+ var MAX_VISIBILITY_EVENTS = 20;
28
+ var FEATURES = { session_replays: false, rage_clicks: true, galactic_tracking: false };
29
+ var CONFIG_CACHE_KEY = "_apstal_cfg_" + PROJECT_ID;
30
+ var CONFIG_CACHE_TTL = 3e5;
31
+ fetchFeatureConfig();
32
+ function applyFeatures(features) {
33
+ FEATURES = features;
34
+ }
35
+ function fetchFeatureConfig() {
36
+ try {
37
+ var cached = localStorage.getItem(CONFIG_CACHE_KEY);
38
+ if (cached) {
39
+ var parsed = JSON.parse(cached);
40
+ if (parsed.ts && Date.now() - parsed.ts < CONFIG_CACHE_TTL) {
41
+ applyFeatures(parsed.features);
42
+ return;
43
+ }
44
+ }
45
+ } catch (e) {
46
+ }
47
+ var baseApiUrl = API_URL.replace(/\/v1\/m$/, "").replace(/\/event$/, "");
48
+ var CONFIG_URL = baseApiUrl + "/v1/config?project_id=" + encodeURIComponent(PROJECT_ID);
49
+ try {
50
+ var xhr = new XMLHttpRequest();
51
+ xhr.open("GET", CONFIG_URL, true);
52
+ xhr.onreadystatechange = function () {
53
+ if (xhr.readyState === 4 && xhr.status === 200) {
54
+ try {
55
+ var res = JSON.parse(xhr.responseText);
56
+ if (res.features) {
57
+ applyFeatures(res.features);
58
+ try {
59
+ localStorage.setItem(CONFIG_CACHE_KEY, JSON.stringify({
60
+ features: res.features,
61
+ ts: Date.now()
62
+ }));
63
+ } catch (e) {
64
+ }
65
+ }
66
+ } catch (e) {
67
+ }
68
+ }
69
+ };
70
+ xhr.send();
71
+ } catch (e) {
72
+ }
73
+ }
74
+ var BOT_LIST = "ahrefsbot;ahrefssiteaudit;amazonbot;amazonproductbot;applebot;archive.org_bot;awariobot;baiduspider;bingbot;bingpreview;chrome-lighthouse;facebookexternal;petalbot;pinterest;screaming frog;yahoo! slurp;yandex;adsbot-google;apis-google;duplexweb-google;feedfetcher-google;google favicon;google web preview;google-read-aloud;googlebot;googleweblight;mediapartners-google;storebot-google;gptbot;oai-searchbot;chatgpt-user;perplexitybot;headlesschrome;cypress;slackbot;linkedinbot".split(";");
75
+ function isBot() {
76
+ if (!navigator.userAgent) return false;
77
+ var ua = navigator.userAgent.toLowerCase();
78
+ for (var i = 0; i < BOT_LIST.length; i++) {
79
+ if (ua.indexOf(BOT_LIST[i]) !== -1) return true;
80
+ }
81
+ if (window._phantom || window.__nightmare || window.navigator.webdriver || window.Cypress || window.__plausible) return true;
82
+ return false;
83
+ }
84
+ if (isBot()) {
85
+ return;
86
+ }
87
+ var clickHistory = [];
88
+ var mouseHistory = { lastX: 0, lastY: 0, lastTime: 0, moves: 0, shifts: 0 };
89
+ var userInactivityTimer = null;
90
+ var INACTIVITY_THRESHOLD = 6e4;
91
+ function sntnl_matches(el, selector) {
92
+ if (!el || el.nodeType !== 1 || !selector) return false;
93
+ try {
94
+ if (el.matches) return el.matches(selector);
95
+ if (el.webkitMatchesSelector) return el.webkitMatchesSelector(selector);
96
+ if (el.msMatchesSelector) return el.msMatchesSelector(selector);
97
+ } catch (e) {
98
+ }
99
+ var chunks = selector.split(/(?=\[)|(?=\.)|(?=#)/);
100
+ for (var i = 0; i < chunks.length; i++) {
101
+ var s = chunks[i];
102
+ if (s.indexOf("#") === 0) {
103
+ if (el.id !== s.slice(1)) return false;
104
+ } else if (s.indexOf(".") === 0) {
105
+ if (!el.classList.contains(s.slice(1))) return false;
106
+ } else if (s.indexOf("[") === 0) {
107
+ var match = s.match(/^\[([a-zA-Z0-9\-_]+)\s*([~|^$*]?=)?\s*['"]?([^'"]*)['"]?\]$/);
108
+ if (match) {
109
+ var attr = match[1];
110
+ var op = match[2];
111
+ var val = match[3];
112
+ var curr = el.getAttribute(attr);
113
+ if (curr === null) return false;
114
+ if (!op) continue;
115
+ if (op === "=") {
116
+ if (curr !== val) return false;
117
+ } else if (op === "^=") {
118
+ if (curr.indexOf(val) !== 0) return false;
119
+ } else if (op === "$=") {
120
+ if (curr.indexOf(val, curr.length - val.length) === -1) return false;
121
+ } else if (op === "*=") {
122
+ if (curr.indexOf(val) === -1) return false;
123
+ } else if (op === "~=") {
124
+ if ((" " + curr + " ").indexOf(" " + val + " ") === -1) return false;
125
+ } else if (op === "|=") {
126
+ if (curr !== val && curr.indexOf(val + "-") !== 0) return false;
127
+ }
128
+ }
129
+ } else {
130
+ if (el.tagName.toLowerCase() !== s.toLowerCase()) return false;
131
+ }
132
+ }
133
+ return true;
134
+ }
135
+ var FORBIDDEN_IDS = [
136
+ "undefined",
137
+ "null",
138
+ "nan",
139
+ "na",
140
+ "guest",
141
+ "unknown",
142
+ "anonymous",
143
+ "not_authenticated",
144
+ "[object object]",
145
+ "false",
146
+ "true",
147
+ "{{email}}",
148
+ "{{user_id}}",
149
+ "{{customer.email}}",
150
+ "unique_identifier",
151
+ "0",
152
+ "NaN",
153
+ "Na",
154
+ "hashed_user_id",
155
+ '""',
156
+ "none"
157
+ ];
158
+ function validateIdentity(id) {
159
+ if (!id || typeof id !== "string") return null;
160
+ var clean = id.trim();
161
+ var lowered = clean.toLowerCase();
162
+ if (lowered.length < 2 || lowered.length > 200) return null;
163
+ if (FORBIDDEN_IDS.indexOf(lowered) !== -1) return null;
164
+ if (/^[0\?\s\-]+$/.test(lowered)) return null;
165
+ if (/^(email|none|null|undefined|guest|unknown|na)$/i.test(lowered)) return null;
166
+ return clean;
167
+ }
168
+ var SAMPLING_RATE = parseFloat(localStorage.getItem("_sn_sr") || "1.0");
169
+ var isSampledIn = (function () {
170
+ var decision = localStorage.getItem("_sn_sd");
171
+ if (decision === null) {
172
+ decision = Math.random() <= SAMPLING_RATE ? "1" : "0";
173
+ localStorage.setItem("_sn_sd", decision);
174
+ }
175
+ return decision === "1";
176
+ })();
177
+ if (!isSampledIn) {
178
+ return;
179
+ }
180
+ var PAUSE_KEY = "_sn_paused";
181
+ var PAUSE_TTL = 36e5;
182
+ var trackingPaused = false;
183
+ try {
184
+ var pausedAt = parseInt(localStorage.getItem(PAUSE_KEY) || "0", 10);
185
+ if (pausedAt && Date.now() - pausedAt < PAUSE_TTL) {
186
+ return;
187
+ } else if (pausedAt) {
188
+ localStorage.removeItem(PAUSE_KEY);
189
+ }
190
+ } catch (e) {
191
+ }
192
+ function generateId() {
193
+ return "xxxx-xxxx-xxxx".replace(/x/g, function () {
194
+ return (Math.random() * 16 | 0).toString(16);
195
+ });
196
+ }
197
+ function getOrSet(key, generator) {
198
+ try {
199
+ var val = sessionStorage.getItem(key) || localStorage.getItem(key);
200
+ if (val) return val;
201
+ val = generator();
202
+ if (key === "_apstal_sid") sessionStorage.setItem(key, val);
203
+ else localStorage.setItem(key, val);
204
+ return val;
205
+ } catch (e) {
206
+ return generator();
207
+ }
208
+ }
209
+ function hashString(str) {
210
+ var hash = 0, i, chr;
211
+ if (str.length === 0) return hash;
212
+ for (i = 0; i < str.length; i++) {
213
+ chr = str.charCodeAt(i);
214
+ hash = (hash << 5) - hash + chr;
215
+ hash |= 0;
216
+ }
217
+ return Math.abs(hash).toString(16);
218
+ }
219
+ var DEVICE_HASH = getOrSet("_sn_dh", function () {
220
+ return hashString(navigator.userAgent + screen.width + "x" + screen.height);
221
+ });
222
+ var TAB_ID = "t-" + Math.random().toString(36).substr(2, 9);
223
+ var SESSION_ID = (function () {
224
+ try {
225
+ var val = sessionStorage.getItem("_sn_sid");
226
+ if (val) return val;
227
+ val = generateId();
228
+ sessionStorage.setItem("_sn_sid", val);
229
+ return val;
230
+ } catch (e) {
231
+ return generateId();
232
+ }
233
+ })();
234
+ var VISITOR_ID = getOrSet("_sn_vid", generateId);
235
+ var pageEnteredAt = Date.now();
236
+ var detectedTags = [];
237
+ var batteryLevel = null;
238
+ var hasAdblock = false;
239
+ var gpuClassData = null;
240
+ var networkData = null;
241
+ var deviceMemoryData = null;
242
+ function runEnvDetection() {
243
+ var check = function () {
244
+ try {
245
+ if (navigator.userAgentData && navigator.userAgentData.getHighEntropyValues) {
246
+ navigator.userAgentData.getHighEntropyValues(["model", "platformVersion", "architecture", "bitness"]).then(function (hints) {
247
+ if (hints.model) detectedTags.push("Model: " + hints.model);
248
+ if (hints.platformVersion) detectedTags.push("OSv: " + hints.platformVersion);
249
+ if (hints.architecture) detectedTags.push("Arch: " + hints.architecture);
250
+ if (hints.bitness) detectedTags.push("Bits: " + hints.bitness);
251
+ }).catch(function () {
252
+ });
253
+ }
254
+ try {
255
+ var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
256
+ if (tz) detectedTags.push("TZ: " + tz.split("/")[0]);
257
+ } catch (e) {
258
+ }
259
+ try {
260
+ if (navigator.plugins && navigator.plugins.length === 0 && !/Mobile|Android|iPhone|iPad/i.test(navigator.userAgent)) {
261
+ detectedTags.push("No Plugins");
262
+ }
263
+ } catch (e) {
264
+ }
265
+ try {
266
+ if (FEATURES.galactic_tracking) {
267
+ fetch("https://www.google-analytics.com/analytics.js", { method: "HEAD", mode: "no-cors" }).catch(function () {
268
+ hasAdblock = true;
269
+ detectedTags.push("AdBlocker Active");
270
+ });
271
+ }
272
+ } catch (e) {
273
+ }
274
+ try {
275
+ var conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
276
+ if (conn) {
277
+ networkData = {
278
+ downlink: conn.downlink || null,
279
+ effectiveType: conn.effectiveType || null,
280
+ rtt: conn.rtt || null,
281
+ connectionType: conn.type || null
282
+ };
283
+ if (conn.effectiveType) detectedTags.push("Net: " + conn.effectiveType);
284
+ if (conn.type) detectedTags.push("Conn: " + conn.type);
285
+ }
286
+ } catch (e) {
287
+ }
288
+ try {
289
+ if (navigator.deviceMemory) {
290
+ var ram = navigator.deviceMemory;
291
+ var memTier = "unknown";
292
+ if (ram >= 8) memTier = "high";
293
+ else if (ram >= 4) memTier = "mid";
294
+ else if (ram >= 2) memTier = "low";
295
+ else memTier = "budget";
296
+ deviceMemoryData = {
297
+ ram,
298
+ tier: memTier
299
+ };
300
+ detectedTags.push("RAM: " + ram + "GB");
301
+ }
302
+ } catch (e) {
303
+ }
304
+ } catch (e) {
305
+ }
306
+ };
307
+ if (window.requestIdleCallback) {
308
+ window.requestIdleCallback(check);
309
+ } else {
310
+ setTimeout(check, 1e3);
311
+ }
312
+ var gpuCheck = function () {
313
+ try {
314
+ var canvas = document.createElement("canvas");
315
+ var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
316
+ if (gl) {
317
+ var maxTex = gl.getParameter(gl.MAX_TEXTURE_SIZE);
318
+ var maxRb = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
319
+ var maxVp = gl.getParameter(gl.MAX_VIEWPORT_DIMS);
320
+ var maxFragUni = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
321
+ var exts = gl.getSupportedExtensions();
322
+ var extCount = exts ? exts.length : 0;
323
+ var gpuTier = "unknown";
324
+ if (maxTex >= 32768 && extCount >= 50) gpuTier = "workstation";
325
+ else if (maxTex >= 16384 && extCount >= 40) gpuTier = "high";
326
+ else if (maxTex >= 8192 && extCount >= 25) gpuTier = "mid";
327
+ else gpuTier = "low";
328
+ gpuClassData = {
329
+ maxTexture: maxTex,
330
+ maxRenderbuffer: maxRb,
331
+ maxViewport: maxVp ? [maxVp[0], maxVp[1]] : null,
332
+ maxFragUniforms: maxFragUni,
333
+ extensions: extCount,
334
+ tier: gpuTier
335
+ };
336
+ detectedTags.push("GPU: " + gpuTier);
337
+ var ext = gl.getExtension("WEBGL_lose_context");
338
+ if (ext) ext.loseContext();
339
+ }
340
+ } catch (e) {
341
+ }
342
+ };
343
+ if (window.requestIdleCallback) {
344
+ setTimeout(function () {
345
+ window.requestIdleCallback(gpuCheck);
346
+ }, 2e3);
347
+ } else {
348
+ setTimeout(gpuCheck, 3e3);
349
+ }
350
+ }
351
+ if (document.readyState === "complete") {
352
+ runEnvDetection();
353
+ } else {
354
+ window.addEventListener("load", runEnvDetection);
355
+ }
356
+ var honeypotTriggered = false;
357
+ function setupHoneypot() {
358
+ try {
359
+ var trap = document.createElement("a");
360
+ trap.href = "/" + Math.random().toString(36).slice(2, 8);
361
+ trap.style.cssText = "opacity:0;position:absolute;top:-9999px;left:-9999px;width:1px;height:1px;overflow:hidden;pointer-events:auto;z-index:-1";
362
+ trap.setAttribute("tabindex", "-1");
363
+ trap.setAttribute("aria-hidden", "true");
364
+ trap.textContent = " ";
365
+ document.body.appendChild(trap);
366
+ trap.addEventListener("click", function (e) {
367
+ e.preventDefault();
368
+ honeypotTriggered = true;
369
+ });
370
+ } catch (e) {
371
+ }
372
+ }
373
+ if (document.readyState === "complete") {
374
+ setupHoneypot();
375
+ } else {
376
+ window.addEventListener("load", setupHoneypot);
377
+ }
378
+ var mousePoints = [];
379
+ var mouseEntropyScore = -1;
380
+ document.addEventListener("mousemove", function (e) {
381
+ if (mousePoints.length < 30) {
382
+ mousePoints.push([e.clientX, e.clientY]);
383
+ }
384
+ if (mousePoints.length === 30 && mouseEntropyScore === -1) {
385
+ mouseEntropyScore = calcMouseEntropy();
386
+ }
387
+ }, { passive: true });
388
+ function calcMouseEntropy() {
389
+ if (mousePoints.length < 10) return -1;
390
+ var angles = [];
391
+ for (var i = 1; i < mousePoints.length - 1; i++) {
392
+ var dx1 = mousePoints[i][0] - mousePoints[i - 1][0];
393
+ var dy1 = mousePoints[i][1] - mousePoints[i - 1][1];
394
+ var dx2 = mousePoints[i + 1][0] - mousePoints[i][0];
395
+ var dy2 = mousePoints[i + 1][1] - mousePoints[i][1];
396
+ if (dx1 === 0 && dy1 === 0) continue;
397
+ if (dx2 === 0 && dy2 === 0) continue;
398
+ var angle = Math.atan2(dy2, dx2) - Math.atan2(dy1, dx1);
399
+ angles.push(angle);
400
+ }
401
+ if (angles.length < 3) return 0;
402
+ var mean = 0;
403
+ for (var j = 0; j < angles.length; j++) mean += angles[j];
404
+ mean /= angles.length;
405
+ var variance = 0;
406
+ for (var j = 0; j < angles.length; j++) variance += (angles[j] - mean) * (angles[j] - mean);
407
+ variance /= angles.length;
408
+ return Math.min(100, Math.round(variance * 100));
409
+ }
410
+ function detectBrowser() {
411
+ var ua = navigator.userAgent;
412
+ var vendor = navigator.vendor || "";
413
+ var name = "Unknown";
414
+ var version = null;
415
+ if (navigator.brave && typeof navigator.brave.isBrave === "function") name = "Brave";
416
+ else if (ua.indexOf("OPR/") !== -1 || ua.indexOf("Opera") !== -1) name = "Opera";
417
+ else if (ua.indexOf("SamsungBrowser") !== -1) name = "Samsung Browser";
418
+ else if (ua.indexOf("UCBrowser") !== -1) name = "UC Browser";
419
+ else if (ua.indexOf("YaBrowser") !== -1) name = "Yandex";
420
+ else if (ua.indexOf("Firefox/") !== -1) name = "Firefox";
421
+ else if (ua.indexOf("Edg/") !== -1) name = "Edge";
422
+ else if (ua.indexOf("Chrome/") !== -1) name = "Chrome";
423
+ else if (ua.indexOf("Safari/") !== -1) name = "Safari";
424
+ var match = ua.match(/(applewebkit|rv|chrome|firefox|version|opr|edge|edg)\/([0-9\.]+)/i);
425
+ if (match && match[2]) version = match[2];
426
+ return { name, version };
427
+ }
428
+ function detectOS() {
429
+ var ua = navigator.userAgent;
430
+ if (/Windows/i.test(ua)) {
431
+ if (/Phone/.test(ua) || /WPDesktop/.test(ua)) return "Windows Phone";
432
+ return "Windows";
433
+ }
434
+ if (/(iPhone|iPad|iPod)/.test(ua)) return "iOS";
435
+ if (/Android/.test(ua)) return "Android";
436
+ if (/(BlackBerry|PlayBook|BB10)/i.test(ua)) return "BlackBerry";
437
+ if (/Mac/i.test(ua)) return "Mac OS X";
438
+ if (/Linux/.test(ua)) return "Linux";
439
+ if (/CrOS/.test(ua)) return "Chrome OS";
440
+ return "Unknown";
441
+ }
442
+ var BROWSER_INFO = detectBrowser();
443
+ var DETECTED_OS = detectOS();
444
+ var LOCK_KEY = "_sn_lck";
445
+ var LOCK_TTL = 3e3;
446
+ function isMasterTab() {
447
+ try {
448
+ var now = Date.now();
449
+ var raw = localStorage.getItem(LOCK_KEY);
450
+ if (!raw) return true;
451
+ var lock = JSON.parse(raw);
452
+ return now - lock.t > LOCK_TTL || lock.id === TAB_ID;
453
+ } catch (e) {
454
+ return true;
455
+ }
456
+ }
457
+ function refreshTabLock() {
458
+ try {
459
+ if (isMasterTab()) {
460
+ localStorage.setItem(LOCK_KEY, JSON.stringify({ t: Date.now(), id: TAB_ID }));
461
+ }
462
+ } catch (e) {
463
+ }
464
+ }
465
+ setInterval(refreshTabLock, 2e3);
466
+ var BLOCKLISTED_ATTRS = ["password", "ssn", "cvv", "card", "key", "secret", "token", "auth", "onclick", "onmouseover", "onkeydown", "style", "data-reactid", "data-v-"];
467
+ function isRedacted(el) {
468
+ try {
469
+ var curr = el;
470
+ while (curr && curr !== document.body) {
471
+ if (curr.hasAttribute("data-sntnl-redact") || curr.hasAttribute("data-heap-redact-text")) return true;
472
+ curr = curr.parentElement;
473
+ }
474
+ } catch (e) {
475
+ }
476
+ return false;
477
+ }
478
+ function scrubPII(text) {
479
+ if (!text || typeof text !== "string") return text;
480
+ var emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
481
+ var tokenRegex = /\b[a-zA-Z0-9-_]{32,}\b/g;
482
+ var cardRegex = /\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35[0-9]{3})[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12})\b/g;
483
+ var ssnRegex = /\b\d{3}-?\d{2}-?\d{4}\b/g;
484
+ return text.replace(emailRegex, "[EMAIL_REDACTED]").replace(cardRegex, "[CARD_REDACTED]").replace(ssnRegex, "[SSN_REDACTED]").replace(tokenRegex, "[TOKEN_REDACTED]");
485
+ }
486
+ function scrubURL(url) {
487
+ if (!url || typeof url !== "string") return url;
488
+ try {
489
+ var sensitiveKeys = ["token", "auth", "key", "secret", "hash", "id_token", "access_token", "refresh_token", "pwd", "password"];
490
+ var u = new URL(url);
491
+ var params = new URLSearchParams(u.search);
492
+ var hash = u.hash;
493
+ var changed = false;
494
+ params.forEach(function (val, key) {
495
+ var k = key.toLowerCase();
496
+ if (sensitiveKeys.some(function (sk) {
497
+ return k.indexOf(sk) !== -1;
498
+ })) {
499
+ params.set(key, "[REDACTED]");
500
+ changed = true;
501
+ }
502
+ });
503
+ if (hash) {
504
+ sensitiveKeys.forEach(function (sk) {
505
+ if (hash.toLowerCase().indexOf(sk) !== -1) {
506
+ hash = "#[REDACTED]";
507
+ changed = true;
508
+ }
509
+ });
510
+ }
511
+ if (!changed) return url;
512
+ u.search = params.toString();
513
+ u.hash = hash;
514
+ return u.toString();
515
+ } catch (e) {
516
+ return url;
517
+ }
518
+ }
519
+ function getSafeClassName(el) {
520
+ try {
521
+ var className = typeof el.className === "string" ? el.className : el.getAttribute("class") || "";
522
+ return className.trim().slice(0, 300);
523
+ } catch (e) {
524
+ return "";
525
+ }
526
+ }
527
+ function getHierarchy(el) {
528
+ try {
529
+ var path = [];
530
+ var current = el;
531
+ var depth = 0;
532
+ while (current && current.tagName && depth < 6) {
533
+ var tag = current.tagName.toLowerCase();
534
+ var id = current.id ? "#" + current.id : "";
535
+ if (id && (BLOCKLISTED_ATTRS.some(function (a) {
536
+ return id.indexOf(a) !== -1;
537
+ }) || id.length > 60)) {
538
+ id = "#[REDACTED]";
539
+ }
540
+ var cls = getSafeClassName(current);
541
+ var displayCls = cls ? "." + cls.split(/\s+/)[0] : "";
542
+ path.unshift(tag + id + displayCls);
543
+ current = current.parentElement;
544
+ depth++;
545
+ }
546
+ return path.join(" > ");
547
+ } catch (e) {
548
+ return null;
549
+ }
550
+ }
551
+ function extractSearchQuery(ref) {
552
+ if (!ref) return null;
553
+ try {
554
+ var url = new URL(ref);
555
+ var params = new URLSearchParams(url.search);
556
+ return params.get("q") || params.get("p") || null;
557
+ } catch (e) {
558
+ return null;
559
+ }
560
+ }
561
+ function detectTranslation() {
562
+ try {
563
+ var html = document.documentElement;
564
+ var isTranslated = html.classList.contains("translated-ltr") || html.classList.contains("translated-rtl") || !!document.querySelector(".skiptranslate") || !!document.querySelector("iframe.goog-te-menu-frame");
565
+ return isTranslated;
566
+ } catch (e) {
567
+ return false;
568
+ }
569
+ }
570
+ function captureAttribution() {
571
+ try {
572
+ var urlParams = new URLSearchParams(window.location.search);
573
+ var AD_IDS = "dclid fbclid gclid ko_click_id li_fat_id msclkid sccid ttclid twclid wbraid".split(" ");
574
+ var utm = {
575
+ source: urlParams.get("utm_source"),
576
+ medium: urlParams.get("utm_medium"),
577
+ campaign: urlParams.get("utm_campaign"),
578
+ content: urlParams.get("utm_content"),
579
+ term: urlParams.get("utm_term")
580
+ };
581
+ var clickId = null;
582
+ for (var i = 0; i < AD_IDS.length; i++) {
583
+ var val = urlParams.get(AD_IDS[i]);
584
+ if (val) {
585
+ utm[AD_IDS[i]] = val;
586
+ if (!clickId) clickId = val;
587
+ }
588
+ }
589
+ utm.click_id = clickId;
590
+ if (!utm.source && document.referrer) {
591
+ var ref = document.referrer.toLowerCase();
592
+ var engine = null;
593
+ if (ref.indexOf("google.") !== -1) engine = "google";
594
+ else if (ref.indexOf("bing.com") !== -1) engine = "bing";
595
+ else if (ref.indexOf("yahoo.com") !== -1) engine = "yahoo";
596
+ else if (ref.indexOf("duckduckgo.com") !== -1) engine = "duckduckgo";
597
+ if (engine) {
598
+ utm.source = engine;
599
+ utm.medium = "organic";
600
+ }
601
+ }
602
+ var stored = JSON.parse(localStorage.getItem("_sn_attr") || "{}");
603
+ var firstTouch = JSON.parse(localStorage.getItem("_sn_ft") || "{}");
604
+ if (!firstTouch.landing_page) {
605
+ var ft = {};
606
+ for (var k in utm) {
607
+ if (utm[k]) ft["initial_" + k] = utm[k];
608
+ }
609
+ if (!ft.initial_source && document.referrer) {
610
+ ft.initial_source = extractHostname(document.referrer);
611
+ ft.initial_medium = "referral";
612
+ }
613
+ if (!firstTouch.landing_page) {
614
+ ft.landing_page = scrubURL(location.href);
615
+ ft.initial_referrer = scrubURL(document.referrer);
616
+ localStorage.setItem("_sn_ft", JSON.stringify(ft));
617
+ }
618
+ }
619
+ var hasNewAttr = false;
620
+ for (var k in utm) {
621
+ if (utm[k]) {
622
+ stored[k] = utm[k];
623
+ hasNewAttr = true;
624
+ }
625
+ }
626
+ if (hasNewAttr) localStorage.setItem("_sn_attr", JSON.stringify(stored));
627
+ return {
628
+ current: stored,
629
+ first: JSON.parse(localStorage.getItem("_sn_ft") || "{}")
630
+ };
631
+ } catch (e) {
632
+ return { current: {}, first: {} };
633
+ }
634
+ }
635
+ function extractHostname(url) {
636
+ try {
637
+ return new URL(url).hostname;
638
+ } catch (e) {
639
+ return null;
640
+ }
641
+ }
642
+ function getPreviousUrl() {
643
+ try {
644
+ return sessionStorage.getItem("_sn_prev") || null;
645
+ } catch (e) {
646
+ return null;
647
+ }
648
+ }
649
+ function updatePreviousUrl() {
650
+ try {
651
+ sessionStorage.setItem("_sn_prev", scrubURL(location.href));
652
+ } catch (e) {
653
+ }
654
+ }
655
+ var ATTR = captureAttribution();
656
+ var CURRENT_SEARCH_QUERY = extractSearchQuery(document.referrer);
657
+ if (detectTranslation()) detectedTags.push("Translated Page");
658
+ var BUFFER_KEY = "_sn_q";
659
+ var queue = [];
660
+ function syncStorage() {
661
+ try {
662
+ var data = JSON.stringify(queue);
663
+ if (data.length > 5e4) return;
664
+ localStorage.setItem(BUFFER_KEY, data);
665
+ } catch (e) {
666
+ }
667
+ }
668
+ function loadStorage() {
669
+ try {
670
+ var stored = localStorage.getItem(BUFFER_KEY);
671
+ if (stored) {
672
+ var items = JSON.parse(stored);
673
+ if (Array.isArray(items)) {
674
+ queue = items.concat(queue);
675
+ }
676
+ }
677
+ } catch (e) {
678
+ }
679
+ }
680
+ function isOptedOut() {
681
+ try {
682
+ return localStorage.getItem("_sn_oo") === "1";
683
+ } catch (e) {
684
+ return false;
685
+ }
686
+ }
687
+ function enqueue(type, data) {
688
+ if (isOptedOut() || trackingPaused) return;
689
+ var attr = ATTR;
690
+ var evt = {
691
+ type,
692
+ url: scrubURL(location.href),
693
+ path: location.pathname,
694
+ title: document.title,
695
+ referrer: scrubURL(document.referrer),
696
+ prev_url: getPreviousUrl(),
697
+ sessionId: SESSION_ID,
698
+ visitorId: VISITOR_ID,
699
+ deviceHash: DEVICE_HASH,
700
+ viewport: window.innerWidth + "x" + window.innerHeight,
701
+ timeOnPage: Math.round((Date.now() - pageEnteredAt) / 1e3),
702
+ tags: detectedTags.join(","),
703
+ adblock: hasAdblock,
704
+ isBot: !!navigator.webdriver || honeypotTriggered || isBot() || screen.width === 400 && screen.height === 400 || mouseEntropyScore === 0,
705
+ mouseEntropy: mouseEntropyScore,
706
+ battery: batteryLevel,
707
+ detectedBrowser: BROWSER_INFO.name,
708
+ browserVersion: BROWSER_INFO.version,
709
+ detectedOS: DETECTED_OS,
710
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
711
+ customUserId: localStorage.getItem("_sn_id") || null,
712
+ searchQuery: CURRENT_SEARCH_QUERY,
713
+ // Device Intelligence
714
+ gpuClass: gpuClassData,
715
+ networkInfo: networkData,
716
+ deviceMemory: deviceMemoryData,
717
+ screenResolution: screen.width + "x" + screen.height,
718
+ pixelRatio: window.devicePixelRatio || 1,
719
+ // Marketing Attribution
720
+ utm_source: attr.current.source || null,
721
+ utm_medium: attr.current.medium || null,
722
+ utm_campaign: attr.current.campaign || null,
723
+ utm_content: attr.current.content || null,
724
+ utm_term: attr.current.term || null,
725
+ click_id: attr.current.click_id || null
726
+ };
727
+ if (attr.first) {
728
+ for (var key in attr.first) {
729
+ if (attr.first.hasOwnProperty(key)) {
730
+ evt[key] = attr.first[key];
731
+ }
732
+ }
733
+ }
734
+ updatePreviousUrl();
735
+ if (data) {
736
+ for (var k in data) {
737
+ if (data.hasOwnProperty(k)) {
738
+ var val = data[k];
739
+ if (typeof val === "string" && (k === "text" || k === "hierarchy" || k === "elClass")) {
740
+ val = scrubPII(val);
741
+ }
742
+ evt[k] = val;
743
+ }
744
+ }
745
+ }
746
+ if (EVENT_TIMERS[type]) {
747
+ var duration = (Date.now() - EVENT_TIMERS[type]) / 1e3;
748
+ evt.$duration = Math.round(duration * 1e3) / 1e3;
749
+ delete EVENT_TIMERS[type];
750
+ }
751
+ evt._id = Math.random().toString(36).substr(2, 9) + Date.now().toString(36);
752
+ evt._retries = 0;
753
+ queue.push(evt);
754
+ syncStorage();
755
+ if (queue.length >= MAX_BATCH_SIZE) {
756
+ flush();
757
+ }
758
+ }
759
+ function extractPrice(str) {
760
+ if (!str) return null;
761
+ var matches = str.match(/([0-9]{1,3}(?:[,. ][0-9]{3})*(?:[. ,][0-9]{2})?)/);
762
+ if (!matches) return null;
763
+ return parseFloat(matches[0].replace(/[ ,]/g, "").replace(",", "."));
764
+ }
765
+ function checkRevenueSignals(el) {
766
+ try {
767
+ var text = (el.innerText || el.value || "").toLowerCase();
768
+ var price = extractPrice(text);
769
+ if (price && (text.indexOf("buy") !== -1 || text.indexOf("purchase") !== -1 || text.indexOf("add to cart") !== -1 || text.indexOf("pay") !== -1)) {
770
+ return { amount: price, currency: "USD" };
771
+ }
772
+ } catch (e) {
773
+ }
774
+ return null;
775
+ }
776
+ function flush() {
777
+ if (queue.length === 0) return;
778
+ if (!isMasterTab()) return;
779
+ refreshTabLock();
780
+ while (queue.length > 0) {
781
+ var batch = [];
782
+ var currentSize = 0;
783
+ while (queue.length > 0) {
784
+ var nextEvt = queue[0];
785
+ var evtSize = JSON.stringify(nextEvt).length;
786
+ if (batch.length > 0 && currentSize + evtSize > MAX_PAYLOAD_CHARS) {
787
+ break;
788
+ }
789
+ batch.push(queue.shift());
790
+ currentSize += evtSize;
791
+ }
792
+ var payload = JSON.stringify({
793
+ projectId: PROJECT_ID,
794
+ events: batch
795
+ });
796
+ if (window.fetch) {
797
+ window.fetch(API_URL, {
798
+ method: "POST",
799
+ body: payload,
800
+ headers: { "Content-Type": "text/plain" },
801
+ keepalive: true
802
+ }).then(function (res) {
803
+ if (res.status === 413) {
804
+ MAX_PAYLOAD_CHARS = Math.max(2e3, Math.floor(MAX_PAYLOAD_CHARS / 2));
805
+ } else if (res.ok) {
806
+ res.json().then(function (body) {
807
+ if (body && body.paused) {
808
+ trackingPaused = true;
809
+ queue = [];
810
+ try {
811
+ localStorage.setItem(PAUSE_KEY, String(Date.now()));
812
+ } catch (e) {
813
+ }
814
+ try {
815
+ localStorage.removeItem(BUFFER_KEY);
816
+ } catch (e) {
817
+ }
818
+ return;
819
+ }
820
+ if (MAX_PAYLOAD_CHARS < DEFAULT_MAX_PAYLOAD) {
821
+ MAX_PAYLOAD_CHARS = Math.min(DEFAULT_MAX_PAYLOAD, MAX_PAYLOAD_CHARS + 2e3);
822
+ }
823
+ batch.forEach(function (item) {
824
+ if (item._id) delete RETRY_TRACKER[item._id];
825
+ });
826
+ }).catch(function () {
827
+ if (MAX_PAYLOAD_CHARS < DEFAULT_MAX_PAYLOAD) {
828
+ MAX_PAYLOAD_CHARS = Math.min(DEFAULT_MAX_PAYLOAD, MAX_PAYLOAD_CHARS + 2e3);
829
+ }
830
+ batch.forEach(function (item) {
831
+ if (item._id) delete RETRY_TRACKER[item._id];
832
+ });
833
+ });
834
+ } else {
835
+ handleRetry(batch);
836
+ }
837
+ }).catch(function () {
838
+ handleRetry(batch);
839
+ });
840
+ } else if (navigator.sendBeacon) {
841
+ navigator.sendBeacon(API_URL, payload);
842
+ }
843
+ syncStorage();
844
+ }
845
+ }
846
+ function handleRetry(batch) {
847
+ var toRetry = [];
848
+ batch.forEach(function (item) {
849
+ item._retries = (item._retries || 0) + 1;
850
+ if (item._retries < MAX_RETRIES) {
851
+ toRetry.push(item);
852
+ }
853
+ });
854
+ if (toRetry.length > 0) {
855
+ queue = toRetry.concat(queue);
856
+ syncStorage();
857
+ }
858
+ }
859
+ function startPulse() {
860
+ setInterval(function () {
861
+ if (document.visibilityState === "visible" && document.hasFocus()) {
862
+ updateScrollDepth();
863
+ var pageHeight = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
864
+ var scrollPerc = pageHeight ? Math.round(maxScrollDepth / pageHeight * 100) : 0;
865
+ enqueue("engagement_pulse", {
866
+ $scroll_percentage: Math.min(100, scrollPerc),
867
+ $duration_cumulative: Math.round((Date.now() - pageEnteredAt) / 1e3)
868
+ });
869
+ }
870
+ }, 1e4);
871
+ }
872
+ startPulse();
873
+ setInterval(flush, BATCH_INTERVAL);
874
+ var vitals = { fcp: null, lcp: null, cls: 0, ttfb: null };
875
+ var maxScrollDepth = 0;
876
+ function updateScrollDepth() {
877
+ var current = window.scrollY || window.pageYOffset || 0;
878
+ var depth = current + window.innerHeight;
879
+ if (depth > maxScrollDepth) maxScrollDepth = depth;
880
+ }
881
+ window.addEventListener("scroll", updateScrollDepth, { passive: true });
882
+ function sendPageLeave() {
883
+ var pageHeight = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
884
+ var foldContent = window.innerHeight;
885
+ var foldLinePerc = pageHeight ? Math.round(foldContent / pageHeight * 100) : 0;
886
+ var scrollPerc = pageHeight ? Math.round(maxScrollDepth / pageHeight * 100) : 0;
887
+ var wordsOnPage = (document.body.innerText || "").split(/\s+/).length || 0;
888
+ var wordsSeen = Math.ceil(wordsOnPage * (Math.min(100, scrollPerc) / 100));
889
+ var activeTimeSpent = Math.max(1, Math.round((Date.now() - pageEnteredAt) / 1e3) - (typeof totalAwaySeconds !== "undefined" ? totalAwaySeconds : 0));
890
+ var readingSpeed = Math.round(wordsSeen / (activeTimeSpent / 60));
891
+ enqueue("$mp_page_leave", {
892
+ $max_scroll_view_depth: Math.round(maxScrollDepth),
893
+ $scroll_height: pageHeight,
894
+ $scroll_percentage: Math.min(100, scrollPerc),
895
+ $fold_line_percentage: Math.min(100, foldLinePerc),
896
+ reading_speed_wpm: readingSpeed,
897
+ active_seconds: activeTimeSpent
898
+ });
899
+ flush();
900
+ }
901
+ var leaveSent = false;
902
+ document.addEventListener("visibilitychange", function () {
903
+ if (document.visibilityState === "hidden") {
904
+ if (!leaveSent) {
905
+ sendPageLeave();
906
+ leaveSent = true;
907
+ }
908
+ flush();
909
+ }
910
+ });
911
+ window.addEventListener("pagehide", function () {
912
+ if (!leaveSent) {
913
+ sendPageLeave();
914
+ leaveSent = true;
915
+ }
916
+ flush();
917
+ });
918
+ try {
919
+ if (performance && performance.getEntriesByType) {
920
+ var nav = performance.getEntriesByType("navigation")[0];
921
+ if (nav) vitals.ttfb = Math.round(nav.responseStart - nav.startTime);
922
+ }
923
+ } catch (e) {
924
+ }
925
+ if (window.PerformanceObserver) {
926
+ try {
927
+ var po = new PerformanceObserver(function (list) {
928
+ var entries = list.getEntries();
929
+ for (var i = 0; i < entries.length; i++) {
930
+ var entry = entries[i];
931
+ if (entry.name === "first-contentful-paint") vitals.fcp = Math.round(entry.startTime);
932
+ if (entry.entryType === "largest-contentful-paint") vitals.lcp = Math.round(entry.startTime);
933
+ if (entry.entryType === "layout-shift" && !entry.hadRecentInput) vitals.cls += entry.value;
934
+ }
935
+ });
936
+ po.observe({ type: "paint", buffered: true });
937
+ po.observe({ type: "largest-contentful-paint", buffered: true });
938
+ po.observe({ type: "layout-shift", buffered: true });
939
+ } catch (e) {
940
+ }
941
+ }
942
+ function trackPageview() {
943
+ try {
944
+ var perfData = Object.assign({}, vitals);
945
+ try {
946
+ perfData.domNodes = document.querySelectorAll("*").length;
947
+ perfData.scripts = document.querySelectorAll("script[src]").length;
948
+ } catch (e) {
949
+ }
950
+ try {
951
+ if (performance && performance.timing) {
952
+ var t = performance.timing;
953
+ perfData.loadTime = t.loadEventEnd - t.navigationStart;
954
+ if (perfData.loadTime < 0) perfData.loadTime = null;
955
+ } else if (performance && performance.getEntriesByType) {
956
+ var nav2 = performance.getEntriesByType("navigation");
957
+ if (nav2 && nav2[0]) {
958
+ perfData.loadTime = Math.round(nav2[0].loadEventEnd);
959
+ }
960
+ }
961
+ } catch (e) {
962
+ }
963
+ enqueue("pageview", perfData);
964
+ setTimeout(captureDOMMap, 1500);
965
+ } catch (e) {
966
+ }
967
+ }
968
+ loadStorage();
969
+ if (queue.length > 0) flush();
970
+ captureAttribution();
971
+ if (document.readyState === "complete") {
972
+ trackPageview();
973
+ } else {
974
+ window.addEventListener("load", function () {
975
+ trackPageview();
976
+ });
977
+ }
978
+ var lastClickTime = 0;
979
+ var lastClickTarget = null;
980
+ var lastClickPos = null;
981
+ var rapidClickCount = 0;
982
+ function getLogicalTarget(e) {
983
+ var target = e.target;
984
+ var path = e.composedPath ? e.composedPath() : [];
985
+ var selectors = ["a", "button", 'input[type="submit"]', 'input[type="button"]', '[role="button"]', "[data-sntnl]"];
986
+ for (var i = 0; i < path.length; i++) {
987
+ var el = path[i];
988
+ if (!el || el.nodeType !== 1) continue;
989
+ if (el.classList.contains("mp-no-track")) return null;
990
+ for (var j = 0; j < selectors.length; j++) {
991
+ if (sntnl_matches(el, selectors[j])) return el;
992
+ }
993
+ if (el === target) break;
994
+ }
995
+ return target;
996
+ }
997
+ document.addEventListener("click", function (e) {
998
+ var target = getLogicalTarget(e);
999
+ var el = target;
1000
+ var rect = el.getBoundingClientRect();
1001
+ var x_rel = rect.width ? (e.clientX - rect.left) / rect.width : 0;
1002
+ var y_rel = rect.height ? (e.clientY - rect.top) / rect.height : 0;
1003
+ var text = (el.innerText || el.value || el.alt || el.ariaLabel || "").slice(0, 200).trim();
1004
+ if (isRedacted(el)) {
1005
+ text = "[REDACTED_BY_USER]";
1006
+ }
1007
+ var data = {
1008
+ tag: el.tagName ? el.tagName.toLowerCase() : null,
1009
+ text,
1010
+ elId: el.id || null,
1011
+ elClass: getSafeClassName(el),
1012
+ hierarchy: getHierarchy(el),
1013
+ href: el.href || el.closest("a")?.href || null,
1014
+ position: { x: e.pageX, y: e.pageY },
1015
+ xRel: Math.round(x_rel * 1e3) / 1e3,
1016
+ yRel: Math.round(y_rel * 1e3) / 1e3
1017
+ };
1018
+ var now = Date.now();
1019
+ var JITTER_THRESHOLD = 30;
1020
+ var isNear = lastClickPos && Math.abs(e.pageX - lastClickPos.x) < JITTER_THRESHOLD && Math.abs(e.pageY - lastClickPos.y) < JITTER_THRESHOLD;
1021
+ if (now - lastClickTime < 800 && el === lastClickTarget && isNear) {
1022
+ rapidClickCount++;
1023
+ if (rapidClickCount >= 3) {
1024
+ enqueue("rage_click", data);
1025
+ rapidClickCount = 0;
1026
+ }
1027
+ } else {
1028
+ rapidClickCount = 1;
1029
+ }
1030
+ lastClickTime = now;
1031
+ lastClickTarget = el;
1032
+ lastClickPos = { x: e.pageX, y: e.pageY };
1033
+ if (el.tagName === "A" && el.href) {
1034
+ try {
1035
+ var host = new URL(el.href).hostname;
1036
+ if (host && host !== location.hostname) {
1037
+ enqueue("exit_link", {
1038
+ href: el.href,
1039
+ target_domain: host
1040
+ });
1041
+ }
1042
+ } catch (e2) {
1043
+ }
1044
+ }
1045
+ enqueue("click", data);
1046
+ }, true);
1047
+ (function (history2) {
1048
+ var pushState = history2.pushState;
1049
+ history2.pushState = function (state) {
1050
+ var ret = pushState.apply(history2, arguments);
1051
+ window.dispatchEvent(new Event("pushstate"));
1052
+ window.dispatchEvent(new Event("locationchange"));
1053
+ return ret;
1054
+ };
1055
+ var replaceState = history2.replaceState;
1056
+ history2.replaceState = function (state) {
1057
+ var ret = replaceState.apply(history2, arguments);
1058
+ window.dispatchEvent(new Event("replacestate"));
1059
+ window.dispatchEvent(new Event("locationchange"));
1060
+ return ret;
1061
+ };
1062
+ window.addEventListener("popstate", function () {
1063
+ window.dispatchEvent(new Event("locationchange"));
1064
+ });
1065
+ })(window.history);
1066
+ window.addEventListener("locationchange", function () {
1067
+ pageEnteredAt = Date.now();
1068
+ ATTR = captureAttribution();
1069
+ trackPageview();
1070
+ });
1071
+ document.addEventListener("copy", function () {
1072
+ try {
1073
+ var selection = window.getSelection().toString().trim();
1074
+ if (selection.length > 20) {
1075
+ if (detectedTags.indexOf("Aggressive Evaluator") === -1) {
1076
+ detectedTags.push("Aggressive Evaluator");
1077
+ }
1078
+ enqueue("scrape_copy", { text: selection.slice(0, 500) });
1079
+ }
1080
+ } catch (e) {
1081
+ }
1082
+ });
1083
+ var maxScroll = 0;
1084
+ var scrollTimer = null;
1085
+ var scrollMilestones = { 25: false, 50: false, 75: false, 90: false, 100: false };
1086
+ function onScroll() {
1087
+ if (scrollTimer) return;
1088
+ scrollTimer = setTimeout(function () {
1089
+ scrollTimer = null;
1090
+ var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
1091
+ var docHeight = Math.max(
1092
+ document.body.scrollHeight,
1093
+ document.documentElement.scrollHeight
1094
+ ) - window.innerHeight;
1095
+ if (docHeight <= 0) return;
1096
+ var percent = Math.min(100, Math.round(scrollTop / docHeight * 100));
1097
+ if (percent > maxScroll) {
1098
+ maxScroll = percent;
1099
+ var milestones = [25, 50, 75, 90, 100];
1100
+ for (var i = 0; i < milestones.length; i++) {
1101
+ var m = milestones[i];
1102
+ if (percent >= m && !scrollMilestones[m]) {
1103
+ scrollMilestones[m] = true;
1104
+ enqueue("scroll", { scrollDepth: m });
1105
+ }
1106
+ }
1107
+ }
1108
+ }, SCROLL_THROTTLE);
1109
+ }
1110
+ window.addEventListener("scroll", onScroll, { passive: true });
1111
+ var trackedForms = /* @__PURE__ */ new WeakSet();
1112
+ function trackForms() {
1113
+ var forms = document.querySelectorAll("form");
1114
+ for (var i = 0; i < forms.length; i++) {
1115
+ if (trackedForms.has(forms[i])) continue;
1116
+ trackedForms.add(forms[i]);
1117
+ (function (form) {
1118
+ var firstField = form.querySelector("input, textarea, select");
1119
+ if (firstField) {
1120
+ firstField.addEventListener("focus", function () {
1121
+ enqueue("form_interact", {
1122
+ tag: "form",
1123
+ elId: form.id || null,
1124
+ text: "form_start",
1125
+ elClass: form.className && typeof form.className === "string" ? form.className.slice(0, 200) : null
1126
+ });
1127
+ }, { once: true });
1128
+ }
1129
+ form.addEventListener("submit", function () {
1130
+ var emailField = form.querySelector('input[type="email"], input[name*="email"], input[id*="email"]');
1131
+ var identity = emailField ? emailField.value : null;
1132
+ enqueue("form_submit", {
1133
+ tag: "form",
1134
+ elId: form.id || null,
1135
+ text: "form_submit",
1136
+ identity,
1137
+ elClass: form.className && typeof form.className === "string" ? form.className.slice(0, 200) : null
1138
+ });
1139
+ });
1140
+ form.querySelectorAll("input").forEach(function (input) {
1141
+ input.addEventListener("blur", function () {
1142
+ if (input.value && (input.type === "email" || input.name.indexOf("email") !== -1)) {
1143
+ enqueue("identity_capture", {
1144
+ email: input.value,
1145
+ fieldName: input.name || input.id
1146
+ });
1147
+ }
1148
+ });
1149
+ });
1150
+ })(forms[i]);
1151
+ }
1152
+ }
1153
+ if (document.readyState !== "loading") {
1154
+ trackForms();
1155
+ } else {
1156
+ document.addEventListener("DOMContentLoaded", trackForms);
1157
+ }
1158
+ setInterval(trackForms, 5e3);
1159
+ window.addEventListener("error", function (e) {
1160
+ enqueue("error", {
1161
+ text: (e.message || "Unknown error").slice(0, 500),
1162
+ tag: "error",
1163
+ elId: e.filename ? e.filename.split("/").pop() : null,
1164
+ position: { x: e.lineno || 0, y: e.colno || 0 }
1165
+ });
1166
+ });
1167
+ window.addEventListener("unhandledrejection", function (e) {
1168
+ enqueue("error", {
1169
+ text: ("Unhandled Promise: " + String(e.reason || "")).slice(0, 500),
1170
+ tag: "promise_error"
1171
+ });
1172
+ });
1173
+ var clickHistory = [];
1174
+ var mouseHistory = { lastX: 0, lastY: 0, lastTime: 0, moves: 0, shifts: 0 };
1175
+ var stagnationTimer = null;
1176
+ var STAGNATION_LIMIT = 6e4;
1177
+ function checkRageClick(e) {
1178
+ var now = Date.now();
1179
+ clickHistory.push({ x: e.clientX, y: e.clientY, time: now });
1180
+ clickHistory = clickHistory.filter(function (c) {
1181
+ return now - c.time < 1e3;
1182
+ });
1183
+ if (clickHistory.length >= 4) {
1184
+ var first = clickHistory[0];
1185
+ var isCluster = clickHistory.every(function (c) {
1186
+ return Math.abs(c.x - first.x) < 50 && Math.abs(c.y - first.y) < 50;
1187
+ });
1188
+ if (isCluster) {
1189
+ enqueue("rage_click", {
1190
+ x: e.clientX,
1191
+ y: e.clientY,
1192
+ count: clickHistory.length,
1193
+ selector: sntnl_get_selector(e.target)
1194
+ });
1195
+ clickHistory = [];
1196
+ }
1197
+ }
1198
+ }
1199
+ function checkConfusion(e) {
1200
+ var now = Date.now();
1201
+ var dt = now - mouseHistory.lastTime;
1202
+ if (dt < 50) return;
1203
+ var dx = e.clientX - mouseHistory.lastX;
1204
+ var dy = e.clientY - mouseHistory.lastY;
1205
+ var distance = Math.sqrt(dx * dx + dy * dy);
1206
+ if (distance > 10) {
1207
+ mouseHistory.moves++;
1208
+ if (Math.abs(dx) > 5 && Math.abs(dy) > 5) mouseHistory.shifts++;
1209
+ if (mouseHistory.moves > 25 && mouseHistory.shifts > 15) {
1210
+ enqueue("user_confusion", { intensity: mouseHistory.shifts / mouseHistory.moves });
1211
+ mouseHistory.moves = 0;
1212
+ mouseHistory.shifts = 0;
1213
+ }
1214
+ }
1215
+ mouseHistory.lastX = e.clientX;
1216
+ mouseHistory.lastY = e.clientY;
1217
+ mouseHistory.lastTime = now;
1218
+ resetStagnation();
1219
+ }
1220
+ function resetStagnation() {
1221
+ if (stagnationTimer) clearTimeout(stagnationTimer);
1222
+ stagnationTimer = setTimeout(function () {
1223
+ enqueue("stagnant_session", { duration: STAGNATION_LIMIT });
1224
+ }, STAGNATION_LIMIT);
1225
+ }
1226
+ var exitFired = false;
1227
+ document.addEventListener("mouseleave", function (e) {
1228
+ if (exitFired) return;
1229
+ if (e.clientY < 5) {
1230
+ exitFired = true;
1231
+ enqueue("exit_intent", { scrollDepth: maxScroll });
1232
+ }
1233
+ });
1234
+ function onLeave() {
1235
+ updateScrollDepth();
1236
+ enqueue("exit", {
1237
+ scrollDepth: Math.round(maxScroll),
1238
+ timeOnPage: Math.round((Date.now() - pageEnteredAt) / 1e3)
1239
+ });
1240
+ flush();
1241
+ }
1242
+ var tabSwitches = 0;
1243
+ var lastHiddenAt = null;
1244
+ var totalAwaySeconds = 0;
1245
+ document.addEventListener("visibilitychange", function () {
1246
+ if (document.visibilityState === "hidden") {
1247
+ onLeave();
1248
+ lastHiddenAt = Date.now();
1249
+ tabSwitches++;
1250
+ enqueue("page_leave", { switchCount: tabSwitches });
1251
+ flush();
1252
+ } else if (lastHiddenAt) {
1253
+ var away = Math.round((Date.now() - lastHiddenAt) / 1e3);
1254
+ if (away >= 2) {
1255
+ totalAwaySeconds += away;
1256
+ enqueue("tab_return", {
1257
+ awaySeconds: away,
1258
+ switchCount: tabSwitches
1259
+ });
1260
+ flush();
1261
+ }
1262
+ lastHiddenAt = null;
1263
+ }
1264
+ });
1265
+ window.addEventListener("beforeunload", onLeave);
1266
+ var visibilityEventCount = 0;
1267
+ var reportedSignatures = /* @__PURE__ */ new Set();
1268
+ var mutationTimer = null;
1269
+ function setupMutationWatcher() {
1270
+ if (!window.MutationObserver) return;
1271
+ var observer = new MutationObserver(function (mutations) {
1272
+ if (mutationTimer) clearTimeout(mutationTimer);
1273
+ mutationTimer = setTimeout(function () {
1274
+ processMutations(mutations);
1275
+ }, MUTATION_DEBOUNCE);
1276
+ });
1277
+ observer.observe(document.body, {
1278
+ childList: true,
1279
+ subtree: true
1280
+ });
1281
+ }
1282
+ function processMutations(mutations) {
1283
+ if (visibilityEventCount >= MAX_VISIBILITY_EVENTS) return;
1284
+ try {
1285
+ var interestingSelectors = [
1286
+ "button",
1287
+ "a",
1288
+ "input",
1289
+ '[role="dialog"]',
1290
+ '[role="alert"]',
1291
+ ".modal",
1292
+ ".toast",
1293
+ ".popup",
1294
+ ".error-message",
1295
+ ".ai-response",
1296
+ "[data-sntnl]"
1297
+ ];
1298
+ interestingSelectors.forEach(function (selector) {
1299
+ var els = document.querySelectorAll(selector);
1300
+ for (var i = 0; i < els.length; i++) {
1301
+ var el = els[i];
1302
+ var rect = el.getBoundingClientRect();
1303
+ if (rect.width > 0 && rect.height > 0) {
1304
+ var text = (el.innerText || el.value || "").trim().slice(0, 300);
1305
+ if (text.length < 3) continue;
1306
+ if (isRedacted(el)) {
1307
+ text = "[REDACTED_BY_USER]";
1308
+ }
1309
+ var hierarchy = getHierarchy(el);
1310
+ var signature = el.tagName + ":" + text + ":" + hierarchy;
1311
+ if (!reportedSignatures.has(signature)) {
1312
+ reportedSignatures.add(signature);
1313
+ visibilityEventCount++;
1314
+ enqueue("visibility", {
1315
+ tag: el.tagName.toLowerCase(),
1316
+ text,
1317
+ hierarchy,
1318
+ elId: el.id || null,
1319
+ elClass: getSafeClassName(el)
1320
+ });
1321
+ if (visibilityEventCount >= MAX_VISIBILITY_EVENTS) break;
1322
+ }
1323
+ }
1324
+ }
1325
+ });
1326
+ } catch (e) {
1327
+ }
1328
+ }
1329
+ if (document.readyState === "complete") {
1330
+ setupMutationWatcher();
1331
+ } else {
1332
+ window.addEventListener("load", setupMutationWatcher);
1333
+ }
1334
+ var lastPathname = location.pathname;
1335
+ function checkRouteChange() {
1336
+ if (location.pathname !== lastPathname) {
1337
+ lastPathname = location.pathname;
1338
+ pageEnteredAt = Date.now();
1339
+ maxScroll = 0;
1340
+ scrollMilestones = { 25: false, 50: false, 75: false, 90: false, 100: false };
1341
+ trackPageview();
1342
+ trackForms();
1343
+ }
1344
+ }
1345
+ var origPush = history.pushState;
1346
+ var origReplace = history.replaceState;
1347
+ history.pushState = function () {
1348
+ origPush.apply(this, arguments);
1349
+ setTimeout(checkRouteChange, 50);
1350
+ };
1351
+ history.replaceState = function () {
1352
+ origReplace.apply(this, arguments);
1353
+ setTimeout(checkRouteChange, 50);
1354
+ };
1355
+ window.addEventListener("popstate", function () {
1356
+ setTimeout(checkRouteChange, 50);
1357
+ });
1358
+ function extractBrandContext() {
1359
+ try {
1360
+ var bodyStyle = window.getComputedStyle(document.body);
1361
+ var metaDescEl = document.querySelector('meta[name="description"]');
1362
+ var brandColors = [];
1363
+ document.querySelectorAll("button, a.btn, .button").forEach(function (btn) {
1364
+ var btnStyle = window.getComputedStyle(btn);
1365
+ var btnBg = btnStyle.backgroundColor;
1366
+ if (btnBg !== "rgba(0, 0, 0, 0)" && btnBg !== "transparent") {
1367
+ if (brandColors.indexOf(btnBg) === -1) brandColors.push(btnBg);
1368
+ }
1369
+ });
1370
+ return {
1371
+ title: document.title,
1372
+ description: metaDescEl ? metaDescEl.getAttribute("content") : "",
1373
+ theme: {
1374
+ background: bodyStyle.backgroundColor,
1375
+ text: bodyStyle.color,
1376
+ fontFamily: bodyStyle.fontFamily,
1377
+ accentColors: brandColors.slice(0, 3)
1378
+ }
1379
+ };
1380
+ } catch (e) {
1381
+ return null;
1382
+ }
1383
+ }
1384
+ var _replayStarted = false;
1385
+ function startSessionReplay() {
1386
+ if (!FEATURES.session_replays || _replayStarted) return;
1387
+ _replayStarted = true;
1388
+ var rrwebEvents = [];
1389
+ var baseApiUrl = API_URL.replace(/\/v1\/m$/, "").replace(/\/event$/, "");
1390
+ var sendChunk = function (events, immediate) {
1391
+ if (events.length === 0) return;
1392
+ var doSend = function () {
1393
+ try {
1394
+ var payloadStr = JSON.stringify(events);
1395
+ var compressed = gzipSync(strToU8(payloadStr), { level: 9, mem: 8 });
1396
+ var chunkIndex = Date.now();
1397
+ var INGEST_URL = baseApiUrl + "/v1/stream?pid=" + encodeURIComponent(PROJECT_ID) + "&sid=" + encodeURIComponent(SESSION_ID) + "&chunk=" + chunkIndex;
1398
+ var blob = new Blob([compressed], { type: "application/gzip" });
1399
+ if (blob.size < 6e4 && navigator.sendBeacon) {
1400
+ navigator.sendBeacon(INGEST_URL, blob);
1401
+ } else if (window.fetch) {
1402
+ window.fetch(INGEST_URL, {
1403
+ method: "POST",
1404
+ body: blob,
1405
+ keepalive: immediate && blob.size < 6e4
1406
+ }).catch(function () {
1407
+ });
1408
+ }
1409
+ } catch (e) {
1410
+ }
1411
+ };
1412
+ if (immediate) {
1413
+ doSend();
1414
+ } else {
1415
+ setTimeout(doSend, 0);
1416
+ }
1417
+ };
1418
+ var flushReplay = function (immediate) {
1419
+ if (rrwebEvents.length === 0) return;
1420
+ var batch = rrwebEvents;
1421
+ rrwebEvents = [];
1422
+ sendChunk(batch, immediate);
1423
+ };
1424
+ var mutationSpamCounter = 0;
1425
+ var lastMutationSecond = Math.floor(Date.now() / 1e3);
1426
+ rrweb.record({
1427
+ emit: function (event) {
1428
+ if (event.type === 3) {
1429
+ var currentSecond = Math.floor(Date.now() / 1e3);
1430
+ if (currentSecond === lastMutationSecond) {
1431
+ mutationSpamCounter++;
1432
+ if (mutationSpamCounter > 50) return;
1433
+ } else {
1434
+ lastMutationSecond = currentSecond;
1435
+ mutationSpamCounter = 0;
1436
+ }
1437
+ }
1438
+ rrwebEvents.push(event);
1439
+ if (event.type === 2 || event.type === 4) {
1440
+ flushReplay();
1441
+ }
1442
+ },
1443
+ inlineStylesheet: true,
1444
+ recordCanvas: false,
1445
+ recordCrossOriginIframes: false,
1446
+ slimDOMOptions: "all",
1447
+ sampling: {
1448
+ mousemove: 200,
1449
+ // 5 FPS is enough
1450
+ scroll: 150,
1451
+ media: 800,
1452
+ input: "last"
1453
+ },
1454
+ maskAllInputs: true,
1455
+ maskTextFn: function (t) {
1456
+ return scrubPII(t);
1457
+ }
1458
+ });
1459
+ setInterval(flushReplay, 15e3);
1460
+ window.addEventListener("beforeunload", function () {
1461
+ flushReplay(true);
1462
+ });
1463
+ document.addEventListener("visibilitychange", function () {
1464
+ if (document.visibilityState === "hidden") flushReplay(true);
1465
+ });
1466
+ }
1467
+ var hoverTarget = null;
1468
+ var hoverStart = 0;
1469
+ document.addEventListener("mouseover", function (e) {
1470
+ var target = e.target.closest('button, a, [role="button"], input, [data-sntnl]');
1471
+ if (target && target !== hoverTarget) {
1472
+ if (hoverTarget) {
1473
+ var duration = Date.now() - hoverStart;
1474
+ if (duration > 2e3) {
1475
+ enqueue("hover_friction", {
1476
+ tag: hoverTarget.tagName.toLowerCase(),
1477
+ text: (hoverTarget.innerText || "").slice(0, 50),
1478
+ duration
1479
+ });
1480
+ }
1481
+ }
1482
+ hoverTarget = target;
1483
+ hoverStart = Date.now();
1484
+ } else if (!target && hoverTarget) {
1485
+ var duration = Date.now() - hoverStart;
1486
+ if (duration > 2e3) {
1487
+ enqueue("hover_friction", {
1488
+ tag: hoverTarget.tagName.toLowerCase(),
1489
+ text: (hoverTarget.innerText || "").slice(0, 50),
1490
+ duration
1491
+ });
1492
+ }
1493
+ hoverTarget = null;
1494
+ }
1495
+ });
1496
+ document.addEventListener("click", function (e) {
1497
+ var target = e.target;
1498
+ var meaningful = target.closest('button, a, [role="button"], input, select, textarea, [data-sntnl]');
1499
+ if (!meaningful) {
1500
+ enqueue("click", {
1501
+ tag: target.tagName ? target.tagName.toLowerCase() : "unknown",
1502
+ dead_click: true,
1503
+ position: { x: e.pageX, y: e.pageY }
1504
+ });
1505
+ }
1506
+ }, true);
1507
+ document.addEventListener("copy", function () {
1508
+ if (!FEATURES.galactic_tracking) return;
1509
+ try {
1510
+ var selected = window.getSelection().toString();
1511
+ if (selected && selected.length > 2) {
1512
+ enqueue("copy", {
1513
+ copiedText: selected.slice(0, 150)
1514
+ });
1515
+ }
1516
+ } catch (e) {
1517
+ }
1518
+ });
1519
+ var backspaceCounts = {};
1520
+ document.addEventListener("keydown", function (e) {
1521
+ if (!FEATURES.galactic_tracking) return;
1522
+ if (e.key === "Backspace" || e.key === "Delete") {
1523
+ var target = e.target;
1524
+ if (target && target.tagName && (target.tagName.toLowerCase() === "input" || target.tagName.toLowerCase() === "textarea")) {
1525
+ if (target.type === "password" || target.name.toLowerCase().indexOf("card") !== -1) return;
1526
+ var fieldId = target.id || target.name || "unknown_field";
1527
+ backspaceCounts[fieldId] = (backspaceCounts[fieldId] || 0) + 1;
1528
+ if (backspaceCounts[fieldId] === 3) {
1529
+ enqueue("hesitation", {
1530
+ fieldType: target.type,
1531
+ fieldId,
1532
+ backspaceCount: backspaceCounts[fieldId]
1533
+ });
1534
+ }
1535
+ }
1536
+ }
1537
+ }, true);
1538
+ window.addEventListener("error", function (e) {
1539
+ if (!FEATURES.galactic_tracking) return;
1540
+ if (!e.message || typeof e.message !== "string") return;
1541
+ if (e.message.indexOf("rrweb") !== -1 || e.message.indexOf("sntnl") !== -1) return;
1542
+ enqueue("js_error", {
1543
+ errorMsg: e.message.slice(0, 200),
1544
+ source: typeof e.filename === "string" ? e.filename.split("/").pop() : "unknown",
1545
+ line: e.lineno,
1546
+ column: e.colno
1547
+ });
1548
+ });
1549
+ window.addEventListener("unhandledrejection", function (e) {
1550
+ if (!FEATURES.galactic_tracking) return;
1551
+ var msg = e.reason ? e.reason.message || e.reason.toString() : "Unknown promise rejection";
1552
+ if (msg.indexOf("rrweb") !== -1 || msg.indexOf("sntnl") !== -1) return;
1553
+ enqueue("js_error", {
1554
+ errorMsg: "Promise Rejection: " + msg.slice(0, 200)
1555
+ });
1556
+ });
1557
+ if (document.readyState === "complete") {
1558
+ setTimeout(startSessionReplay, 2e3);
1559
+ } else {
1560
+ window.addEventListener("load", function () {
1561
+ setTimeout(startSessionReplay, 2e3);
1562
+ });
1563
+ }
1564
+ function extractPrice(str) {
1565
+ if (!str) return null;
1566
+ var matches = str.match(/([0-9]{1,3}(?:[,. ][0-9]{3})*(?:[. ,][0-9]{2})?)/);
1567
+ if (!matches) return null;
1568
+ return parseFloat(matches[0].replace(/[ ,]/g, "").replace(",", "."));
1569
+ }
1570
+ function autoDetectRevenue() {
1571
+ var paths = ["/success", "/thank-you", "/confirmation", "/order-complete", "/done", "/checkout/paid"];
1572
+ var currentPath = location.pathname.toLowerCase();
1573
+ var isSuccessPage = paths.some(function (p) {
1574
+ return currentPath.indexOf(p) !== -1;
1575
+ });
1576
+ var revenue = null;
1577
+ var platform = "Generic";
1578
+ try {
1579
+ if (window.Shopify && window.Shopify.checkout) {
1580
+ revenue = window.Shopify.checkout.total_price;
1581
+ platform = "Shopify";
1582
+ } else if (window.WC_ORDER_DATA || document.querySelector(".woocommerce-thankyou-order-fixed")) {
1583
+ revenue = extractPrice(document.querySelector(".woocommerce-Price-amount")?.innerText);
1584
+ platform = "WooCommerce";
1585
+ } else if (window.dataLayer && Array.isArray(window.dataLayer)) {
1586
+ for (var i = window.dataLayer.length - 1; i >= 0; i--) {
1587
+ var dl = window.dataLayer[i];
1588
+ if (dl.ecommerce && dl.ecommerce.purchase && dl.ecommerce.purchase.actionField) {
1589
+ revenue = dl.ecommerce.purchase.actionField.revenue;
1590
+ platform = "DataLayer";
1591
+ break;
1592
+ }
1593
+ }
1594
+ }
1595
+ } catch (e) {
1596
+ }
1597
+ if (!revenue && isSuccessPage) {
1598
+ var selectors = [".total-price", ".order-total", ".amount-paid", "#total", '[class*="total"]'];
1599
+ for (var s = 0; s < selectors.length; s++) {
1600
+ var el = document.querySelector(selectors[s]);
1601
+ if (el && extractPrice(el.innerText)) {
1602
+ revenue = extractPrice(el.innerText);
1603
+ platform = "DOM-Scan";
1604
+ break;
1605
+ }
1606
+ }
1607
+ }
1608
+ if (revenue) {
1609
+ enqueue("purchase", {
1610
+ amount: parseFloat(revenue),
1611
+ platform,
1612
+ autoDetected: true,
1613
+ path: currentPath
1614
+ });
1615
+ flush();
1616
+ }
1617
+ }
1618
+ if (document.readyState === "complete") autoDetectRevenue();
1619
+ else window.addEventListener("load", autoDetectRevenue);
1620
+ setInterval(autoDetectRevenue, 1e4);
1621
+ function autoDiscover() {
1622
+ try {
1623
+ var urlParams = new URLSearchParams(window.location.search);
1624
+ var foundId = urlParams.get("email") || urlParams.get("uid") || urlParams.get("user_id");
1625
+ if (!foundId) {
1626
+ var authKeys = ["supabase.auth.token", "firebase:authUser", "ajs_user_id", "profile", "user"];
1627
+ for (var i = 0; i < authKeys.length; i++) {
1628
+ var val = localStorage.getItem(authKeys[i]);
1629
+ if (val) {
1630
+ try {
1631
+ if (val.indexOf("{") === 0) {
1632
+ var parsed = JSON.parse(val);
1633
+ foundId = parsed.email || parsed.id || parsed.user_id;
1634
+ } else {
1635
+ foundId = val;
1636
+ }
1637
+ } catch (e) {
1638
+ }
1639
+ }
1640
+ if (foundId) break;
1641
+ }
1642
+ }
1643
+ if (foundId) {
1644
+ var validId = validateIdentity(foundId);
1645
+ var current = localStorage.getItem("_sn_vid");
1646
+ if (validId && (!current || current !== validId)) {
1647
+ window.apstal.identify(validId);
1648
+ }
1649
+ }
1650
+ } catch (e) {
1651
+ }
1652
+ }
1653
+ var printFired = false;
1654
+ window.addEventListener("beforeprint", function () {
1655
+ if (printFired) return;
1656
+ printFired = true;
1657
+ enqueue("print_intent", {
1658
+ page: location.pathname,
1659
+ timeOnPage: Math.round((Date.now() - pageEnteredAt) / 1e3)
1660
+ });
1661
+ flush();
1662
+ });
1663
+ var devtoolsDetected = false;
1664
+ function checkDevTools() {
1665
+ if (devtoolsDetected) return;
1666
+ try {
1667
+ var el = new Image();
1668
+ Object.defineProperty(el, "id", {
1669
+ get: function () {
1670
+ devtoolsDetected = true;
1671
+ enqueue("devtools_open", {
1672
+ page: location.pathname,
1673
+ timeBeforeOpen: Math.round((Date.now() - pageEnteredAt) / 1e3)
1674
+ });
1675
+ }
1676
+ });
1677
+ console.log("%c", el);
1678
+ } catch (e) {
1679
+ }
1680
+ }
1681
+ setInterval(checkDevTools, 3e3);
1682
+ var lastScrollY_bi = 0;
1683
+ var scrollDirection_bi = 0;
1684
+ var scrollReversals = 0;
1685
+ window.addEventListener("scroll", function () {
1686
+ var y = window.scrollY || window.pageYOffset || 0;
1687
+ if (y === lastScrollY_bi) return;
1688
+ var dir = y > lastScrollY_bi ? 1 : -1;
1689
+ if (scrollDirection_bi !== 0 && dir !== scrollDirection_bi) {
1690
+ scrollReversals++;
1691
+ }
1692
+ scrollDirection_bi = dir;
1693
+ lastScrollY_bi = y;
1694
+ }, { passive: true });
1695
+ var sectionTimers = {};
1696
+ var sectionDwells = {};
1697
+ function setupSectionDwell() {
1698
+ if (!window.IntersectionObserver) return;
1699
+ var observer = new IntersectionObserver(function (entries) {
1700
+ for (var i2 = 0; i2 < entries.length; i2++) {
1701
+ var e = entries[i2];
1702
+ var id = e.target.id || e.target.getAttribute("data-section");
1703
+ if (!id) continue;
1704
+ if (e.isIntersecting) {
1705
+ sectionTimers[id] = Date.now();
1706
+ } else if (sectionTimers[id]) {
1707
+ var dwell = Math.round((Date.now() - sectionTimers[id]) / 1e3);
1708
+ if (dwell >= 1) sectionDwells[id] = dwell;
1709
+ delete sectionTimers[id];
1710
+ }
1711
+ }
1712
+ }, { threshold: 0.5 });
1713
+ var sections = document.querySelectorAll("section[id], [data-section], [id]");
1714
+ for (var i = 0; i < sections.length; i++) {
1715
+ var el = sections[i];
1716
+ var tag = el.tagName.toLowerCase();
1717
+ if (tag === "section" || tag === "div" || tag === "main" || tag === "article" || tag === "aside" || tag === "header" || tag === "footer" || tag === "nav") {
1718
+ observer.observe(el);
1719
+ }
1720
+ }
1721
+ }
1722
+ if (document.readyState === "complete") {
1723
+ setupSectionDwell();
1724
+ } else {
1725
+ window.addEventListener("load", setupSectionDwell);
1726
+ }
1727
+ var _origSendPageLeave = sendPageLeave;
1728
+ sendPageLeave = function () {
1729
+ var _origEnqueue = enqueue;
1730
+ enqueue = function (type, data) {
1731
+ if (type === "$mp_page_leave") {
1732
+ for (var id in sectionTimers) {
1733
+ var dwell = Math.round((Date.now() - sectionTimers[id]) / 1e3);
1734
+ if (dwell >= 1) sectionDwells[id] = dwell;
1735
+ }
1736
+ data.scroll_reversals = scrollReversals;
1737
+ if (Object.keys(sectionDwells).length > 0) {
1738
+ data.section_dwells = sectionDwells;
1739
+ }
1740
+ }
1741
+ _origEnqueue(type, data);
1742
+ };
1743
+ _origSendPageLeave();
1744
+ enqueue = _origEnqueue;
1745
+ };
1746
+ function checkBrokenAssets() {
1747
+ try {
1748
+ var images = document.querySelectorAll("img");
1749
+ var broken = [];
1750
+ for (var i = 0; i < images.length; i++) {
1751
+ var img = images[i];
1752
+ if (img.complete && img.naturalWidth === 0 && img.src) {
1753
+ broken.push(img.src.split("?")[0].split("/").pop());
1754
+ }
1755
+ }
1756
+ if (broken.length > 0) {
1757
+ enqueue("broken_assets", {
1758
+ count: broken.length,
1759
+ total: images.length,
1760
+ files: broken.slice(0, 10).join(","),
1761
+ page: location.pathname
1762
+ });
1763
+ }
1764
+ } catch (e) {
1765
+ }
1766
+ }
1767
+ if (document.readyState === "complete") {
1768
+ setTimeout(checkBrokenAssets, 2e3);
1769
+ } else {
1770
+ window.addEventListener("load", function () {
1771
+ setTimeout(checkBrokenAssets, 2e3);
1772
+ });
1773
+ }
1774
+ window.apstal = {
1775
+ trackForm: function (selector, type, data) {
1776
+ trackForm(selector, type, data);
1777
+ },
1778
+ // Block 5: Identity & Compliance
1779
+ identify: function (id) {
1780
+ if (!id) return;
1781
+ var oldId = VISITOR_ID;
1782
+ VISITOR_ID = id;
1783
+ localStorage.setItem("_sn_vid", id);
1784
+ enqueue("$identify", { $user_id: id, $anon_distinct_id: oldId });
1785
+ flush();
1786
+ },
1787
+ alias: function (alias, original) {
1788
+ original = original || VISITOR_ID;
1789
+ enqueue("$create_alias", { alias, distinct_id: original });
1790
+ flush();
1791
+ },
1792
+ timeEvent: function (name) {
1793
+ EVENT_TIMERS[name] = Date.now();
1794
+ },
1795
+ optOut: function () {
1796
+ localStorage.setItem("_sn_oo", "1");
1797
+ localStorage.removeItem("_sn_vid");
1798
+ localStorage.removeItem("_sn_sid");
1799
+ location.reload();
1800
+ },
1801
+ optIn: function () {
1802
+ localStorage.removeItem("_sn_oo");
1803
+ },
1804
+ track: function (type, data) {
1805
+ enqueue(type, data);
1806
+ flush();
1807
+ }
1808
+ };
1809
+ autoDiscover();
1810
+ var originalEnqueue = enqueue;
1811
+ enqueue = function (type, data) {
1812
+ if (type === "click" && (data.tag === "button" || data.tag === "a")) {
1813
+ var el = lastClickTarget;
1814
+ if (el) {
1815
+ var rev = checkRevenueSignals(el);
1816
+ if (rev) {
1817
+ originalEnqueue("revenue_intent", {
1818
+ amount: rev.amount,
1819
+ currency: rev.currency,
1820
+ elementText: data.text
1821
+ });
1822
+ }
1823
+ }
1824
+ }
1825
+ originalEnqueue(type, data);
1826
+ };
1827
+ document.addEventListener("click", checkRageClick, true);
1828
+ document.addEventListener("mousemove", checkConfusion, true);
1829
+ resetStagnation();
1830
+ })();