PageSourceSearch

https://zippykind.com/assets/front/v3/assets/js/zk-track.js?ver=2.1.8

js zippykind.com collected 2026-10-01 23:52:14 UTC 34,747 bytes, 941 lines download raw bytes

1/*! Zippykind LLC - Proprietary and confidential. Copyright (c) Zippykind LLC. All rights reserved.
2 *  zk-signature: sha256=c9b203059df1191f46324da617a7ad50d4caf6c4a802b8fe0abba8b8d3372eb6 file=zk-track.js by=Zippykind LLC
3 */
4/* fe-1054 */
5;(function(){var s="Zippykind LLC|zk-signature|sha256=c9b203059df1191f46324da617a7ad50d4caf6c4a802b8fe0abba8b8d3372eb6|file=zk-track.js";return s;})();
6(function (w, d) {
7  "use strict";
8
9  // fe-1055
10  var SEND = true;
11  // fe-1056
12  var ENDPOINT = "/ajaxfront/track";
13  // fe-1057
14  var IX_ENDPOINT = "/ajaxfront/behavior";
15  // fe-1058
16  var SEND_IX = true;
17  // fe-1059
18  var BEACON_TYPE = "text/plain;charset=UTF-8";
19
20  var UTM = ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term", "zkref"];
21
22  // fe-1060
23  var AFF_PARAMS = ["zkref", "zka", "aff"];
24  var AFF_CAMPAIGN_PARAM = "zkcid";
25  var AFF_MAX = 64;
26
27  // fe-1061
28  var DWELL_MIN_MS = 1000;        // fe-1062
29  var SECTION_RATIO = 0.3;        // fe-1063
30  var HOVER_MS = 400;             // fe-1064
31  var SEARCH_DEBOUNCE_MS = 1200;
32  var SELECT_DEBOUNCE_MS = 900;
33  var IDLE_MS = 30000;            // fe-1065
34  var FLUSH_MS = 30000;
35  var IX_CAP = 200;               // fe-1066
36  var TEXT_CAP = 50;              // fe-1067
37  var SELECT_CAP = 200;
38  var QUERY_CAP = 100;
39
40  // fe-1068
41  var STEPS = {
42    // fe-1069
43    page_view:      "any page load",
44    // fe-1070
45    qo_hover:       "industry cell hovered/focused, capture panel shown",
46    qo_dismiss:     "capture panel closed without a submit",
47    qo_submit:      "email submitted from the capture panel",
48    qo_sent:        "verification email queued (server side once ported)",
49    qo_resend:      "resend link clicked",
50    qo_verified:    "verification link followed, landed on quick start",
51    qo_choice:      "the two-option modal was shown",
52    qo_peek:        "chose Peek at an Active Account",
53    qo_tour_tools:  "chose Tour The Tools That Will Make Your Life Easier",
54    qo_tour_step1:  "tour step 1 shown (Take Tour button)",
55    qo_tour_step2:  "tour step 2 shown (Dashboard Demo switch)",
56    qo_tour_done:   "tour finished or skipped",
57    qo_demo_load:   "dashboard demo loaded (props.demo = operator|admin)",
58    // fe-1071
59    qo_signup_click: "clicked through to signup -- the zk_vid handoff to the app",
60    // fe-1072
61    ix_batch:       "batched interaction records (see zkTrack.ix)",
62    cv_contact:     "contact form submitted",
63    cv_demo:        "book-a-demo form submitted (qualified)",
64    cv_newsletter:  "footer email capture submitted",
65    cv_login_click: "clicked through to /app/login",
66    cv_phone_click: "clicked a tel: link",
67    // fe-1073
68    how_it_works_status: "how-it-works status pill clicked (zk-flow.js)",
69    video_play:     "inline video opened in the lightbox (zk-video.js)",
70    // fe-1074
71    qo_signup:      "account created (SERVER SIDE)",
72    qo_paid:        "first payment taken (SERVER SIDE)"
73  };
74
75  // fe-1075
76  var CONVERSIONS = {
77    contact:      "cv_contact",
78    demo:         "cv_demo",
79    newsletter:   "cv_newsletter",
80    signup_click: "qo_signup_click",
81    login_click:  "cv_login_click",
82    phone_click:  "cv_phone_click"
83  };
84  // fe-1076
85
86  // fe-1077
87  function get(store, k) {
88    try { return w[store].getItem(k); } catch (e) { return null; }
89  }
90  function set(store, k, v) {
91    try { w[store].setItem(k, v); } catch (e) { /* fe-1078 */ }
92  }
93  function getJSON(store, k) {
94    var raw = get(store, k);
95    if (!raw) return null;
96    try { return JSON.parse(raw); } catch (e) { return null; }
97  }
98  function setJSON(store, k, v) { set(store, k, JSON.stringify(v)); }
99
100  // fe-1079
101  function cookieDomain() {
102    var h = (w.location.hostname || "").toLowerCase();
103    if (h === "zippykind.com" || h.slice(-14) === ".zippykind.com") return ".zippykind.com";
104    return "";  // fe-1080
105  }
106  function getCookie(k) {
107    try {
108      var parts = ("; " + (d.cookie || "")).split("; " + k + "=");
109      return parts.length < 2 ? null : decodeURIComponent(parts.pop().split(";").shift());
110    } catch (e) { return null; }
111  }
112  function setCookie(k, v, days) {
113    try {
114      var dom = cookieDomain();
115      var exp = new Date(Date.now() + days * 86400000).toUTCString();
116      d.cookie = k + "=" + encodeURIComponent(v) +
117                 ";expires=" + exp + ";path=/" +
118                 (dom ? ";domain=" + dom : "") +
119                 ";SameSite=Lax" +
120                 (w.location.protocol === "https:" ? ";Secure" : "");
121    } catch (e) { /* fe-1081 */ }
122  }
123
124  function rid() {
125    // fe-1082
126    return Date.now().toString(36) + "-" + Math.random().toString(36).slice(2, 10);
127  }
128
129  function params() {
130    var out = {};
131    var q = w.location.search;
132    if (!q || q.length < 2) return out;
133    q.slice(1).split("&").forEach(function (pair) {
134      if (!pair) return;
135      var i = pair.indexOf("=");
136      var k = decodeURIComponent(i < 0 ? pair : pair.slice(0, i)
136).replace(/\+/g, " ");
137      var v = i < 0 ? "" : decodeURIComponent(pair.slice(i + 1).replace(/\+/g, " "));
138      out[k] = v;
139    });
140    return out;
141  }
142
143  var Q = params();
144  var CFG = w.ZK_TRACK_CFG || {};      // fe-1083
145
146  function campaignFromUrl() {
147    var c = null;
148    UTM.forEach(function (k) {
149      if (Q[k]) { c = c || {}; c[k] = Q[k].slice(0, 255); }
150    });
151    if (c) {
152      c.landing = w.location.pathname.split("/").pop() || "index.html";
153      c.referrer = (d.referrer || "").slice(0, 512);
154      c.ts = new Date().toISOString();
155    }
156    return c;
157  }
158
159  // fe-1084
160  if (w.ZKConsent && w.ZKConsent.optedOut("analytics")) {
161    var stub = function () {};
162    w.zkTrack = function () {};
163    w.zkTrack.link = function (href) { return href; };
164    w.zkTrack.steps = STEPS;
165    w.zkTrack.param = function (k) { return Q[k] || ""; };
166    w.zkTrack.vid = function () { return ""; };
167    w.zkTrack.campaign = function () { return { first: null, last: null }; };
168    w.zkTrack.conversion = stub;
169    w.zkTrack.conversions = CONVERSIONS;
170    w.zkTrack.ix = stub;
171    w.zkTrack.flush = stub;
172    w.zkTrack.arrival = function () { return { session: null, first: null }; };
173    w.zkTrack.affiliate = function () { return null; };
174    w.zkTrack.visitor = function () { return { type: "unknown", confidence: "assumed", signals: [] }; };
175    w.zkTrack.rescan = stub;
176    return;
177  }
178
179  // fe-1085
180  var vid = getCookie("zk_vid") || get("localStorage", "zk_vid");
181  if (!vid) { vid = rid(); }
182  vid = String(vid).slice(0, 40);
183  set("localStorage", "zk_vid", vid);
184  setCookie("zk_vid", vid, 730);
185
186  var sid = get("sessionStorage", "zk_sid");
187  if (!sid) { sid = rid(); set("sessionStorage", "zk_sid", sid); }
188
189  var fromUrl = campaignFromUrl();
190  var first = getJSON("localStorage", "zk_campaign_first");
191  if (!first && fromUrl) { first = fromUrl; set("localStorage", "zk_campaign_first", JSON.stringify(first)); }
192  var last = fromUrl || getJSON("sessionStorage", "zk_campaign_last");
193  if (fromUrl) set("sessionStorage", "zk_campaign_last", JSON.stringify(fromUrl));
194
195  // fe-1086
196  if (first) {
197    setCookie("zk_camp", [
198      (first.utm_source || "").slice(0, 60),
199      (first.utm_medium || "").slice(0, 40),
200      (first.utm_campaign || "").slice(0, 80)
201    ].join("|"), 365);
202  }
203
204  // fe-1087
205  var AI_HOSTS = [
206    ["chatgpt.com", "chatgpt"], ["chat.openai.com", "chatgpt"], ["openai.com", "chatgpt"],
207    ["perplexity.ai", "perplexity"],
208    ["claude.ai", "claude"], ["anthropic.com", "claude"],
209    ["gemini.google.com", "gemini"], ["bard.google.com", "gemini"],
210    ["copilot.microsoft.com", "copilot"], ["edgeservices.bing.com", "copilot"],
211    ["you.com", "you"], ["phind.com", "phind"], ["poe.com", "poe"],
212    ["meta.ai", "meta_ai"], ["grok.com", "grok"], ["x.ai", "grok"],
213    ["deepseek.com", "deepseek"], ["mistral.ai", "mistral"], ["kagi.com", "kagi"]
214  ];
215  var SOCIAL_HOSTS = [
216    ["instagram.com", "instagram"],
217    ["facebook.com", "facebook"], ["fb.com", "facebook"], ["fb.me", "facebook"],
218    ["linkedin.com", "linkedin"], ["lnkd.in", "linkedin"],
219    ["x.com", "x"], ["twitter.com", "x"], ["t.co", "x"],
220    ["youtube.com", "youtube"], ["youtu.be", "youtube"],
221    ["tiktok.com", "tiktok"], ["pinterest.", "pinterest"],
222    ["threads.net", "threads"], ["threads.com", "threads"],
223    ["reddit.com", "reddit"], ["quora.com", "quora"], ["nextdoor.com", "nextdoor"]
224  ];
225  var SEARCH_HOSTS = [
226    ["google.", "google"], ["bing.com", "bing"], ["yahoo.", "yahoo"],
227    ["duckduckgo.com", "duckduckgo"], ["ecosia.org", "ecosia"],
228    ["search.brave.com", "brave"], ["startpage.com", "startpage"],
229    ["yandex.", "yandex"], ["baidu.com", "baidu"], ["ask.com", "ask"]
230  ];
231  var MAIL_HOSTS = [
232    ["mail.google.com", "email"], ["outlook.", "email"], ["mail.
232yahoo.com", "email"],
233    ["mail.proton.me", "email"], ["superhuman.com", "email"]
234  ];
235  // fe-1088
236  var SRC_MAP = {
237    "google": "google", "google ads": "google", "googleads": "google", "adwords": "google",
238    "bing": "bing", "microsoft": "bing", "msn": "bing", "yahoo": "yahoo",
239    "duckduckgo": "duckduckgo", "ddg": "duckduckgo",
240    "chatgpt": "chatgpt", "chatgpt.com": "chatgpt", "openai": "chatgpt",
241    "perplexity": "perplexity", "perplexity.ai": "perplexity",
242    "claude": "claude", "claude.ai": "claude",
243    "gemini": "gemini", "bard": "gemini", "copilot": "copilot",
244    "ig": "instagram", "instagram": "instagram",
245    "fb": "facebook", "facebook": "facebook", "meta": "facebook",
246    "li": "linkedin", "linkedin": "linkedin",
247    "x": "x", "twitter": "x",
248    "yt": "youtube", "youtube": "youtube",
249    "tiktok": "tiktok", "pinterest": "pinterest", "reddit": "reddit",
250    "email": "email", "sendgrid": "email", "newsletter": "email"
251  };
252  var AI_CHANNELS = { chatgpt: 1, perplexity: 1, claude: 1, gemini: 1, copilot: 1,
253                      you: 1, phind: 1, poe: 1, meta_ai: 1, grok: 1, deepseek: 1,
254                      mistral: 1, kagi: 1 };
255  var SEARCH_CHANNELS = { google: 1, bing: 1, yahoo: 1, duckduckgo: 1, ecosia: 1,
256                          brave: 1, startpage: 1, yandex: 1, baidu: 1, ask: 1 };
257  var SOCIAL_CHANNELS = { instagram: 1, facebook: 1, linkedin: 1, x: 1, youtube: 1,
258                          tiktok: 1, pinterest: 1, threads: 1, reddit: 1, quora: 1,
259                          nextdoor: 1 };
260  // fe-1089
261  var CLICK_IDS = [["gclid", "google"], ["gbraid", "google"], ["wbraid", "google"],
262                   ["dclid", "google"], ["msclkid", "bing"], ["fbclid", "facebook"],
263                   ["igshid", "instagram"], ["li_fat_id", "linkedin"],
264                   ["ttclid", "tiktok"], ["twclid", "x"], ["epik", "pinterest"]];
265  var PAID_MEDIUMS = { cpc: 1, ppc: 1, paid: 1, paidsocial: 1, paid_social: 1,
266                       "paid-social": 1, display: 1, banner: 1, retargeting: 1 };
267
268  function hostOf(url) {
269    if (!url) return "";
270    try {
271      var a = d.createElement("a");
272      a.href = url;
273      return (a.hostname || "").toLowerCase();
274    } catch (e) { return ""; }
275  }
276  function matchHost(host, table) {
277    for (var i = 0; i < table.length; i++) {
278      if (host.indexOf(table[i][0]) > -1) return table[i][1];
279    }
280    return "";
281  }
282  function typeOf(channel) {
283    if (AI_CHANNELS[channel]) return "ai";
284    if (SEARCH_CHANNELS[channel]) return "search";
285    if (SOCIAL_CHANNELS[channel]) return "social";
286    if (channel === "email") return "email";
287    if (channel === "direct" || channel === "internal" || channel === "referral") return channel;
288    return "referral";
289  }
290  // fe-1090
291  function refQuery(ref) {
292    if (!ref || ref.indexOf("?") < 0) return "";
293    var qs = ref.slice(ref.indexOf("?") + 1).split("&");
294    var keys = { q: 1, query: 1, p: 1, wd: 1, text: 1 };
295    for (var i = 0; i < qs.length; i++) {
296      var kv = qs[i].split("=");
297      if (keys[decodeURIComponent(kv[0] || "").toLowerCase()] && kv[1]) {
298        try { return decodeURIComponent(kv[1].replace(/\+/g, " ")).slice(0, 120); }
299        catch (e) { return ""; }
300      }
301    }
302    return "";
303  }
304
305  function resolveArrival() {
306    var ref = (d.referrer || "");
307    var refHost = hostOf(ref);
308    var here = (w.location.hostname || "").toLowerCase();
309    var internal = !!refHost && (refHost === here || refHost === "zippykind.com" ||
310                                 refHost.slice(-14) === ".zippykind.com");
311    var src = (Q.utm_source || "").toLowerCase().trim();
312    var medium = (Q.utm_medium || "").toLowerCase().trim();
313    var channel = "";
314    var how = "";
315    var i;
316
317    if (src && SRC_MAP[src]) { channel = SRC_MAP[src]; how = "utm_source"; }
318    if (!channel) {
319      for (i = 0; i < CLICK_IDS.length; i++) {
320        if (Q[CLICK_IDS[i][0]]) { channel = CLICK_IDS[i][1]; how = CLICK_IDS[i][0]; break; }
321      }
322    }
323    if (!channel && refHost && !internal) {
324      channel = matchHost(refHost, AI_HOSTS);
325      if (channel) how = "referrer_ai";
326      if (!channel) { channel = matchHost(refHost, SOCIAL_HOSTS); if (channel) how = "referrer_social"; }
327      if (!channel) { channel = matchHost(refHost, SEARCH_HOSTS); if (channel) how = "referrer_search"; }
328      if (!channel) { channel = matchHost(refHost, MAIL_HOSTS); if (channel) how = "referrer_mail"; }
329    }
330    if (!channel && (medium === "email" || src === "email")) { channel = "email"; how = "utm_medium"; }
331    if (!channel && internal) { channel = "internal"; how = "referrer_internal"; }
332    if (!channel && refHost) { channel = "referral"; how = "referrer_other"; }
333    if (!channel) { channel = "direct"; how = (src || medium) ? "utm_only" : "no_referrer"; }
334
335    var paid = !!PAID_MEDIUMS[medium];
336    for (i = 0; i < CLICK_IDS.length && !paid; i++) { if (Q[CLICK_IDS[i][0]]) paid = true; }
337
338    return {
339      channel: channel,
340      channel_type: typeOf(channel),
341      paid: paid,
342      resolved_by: how,
343      referrer_host: refHost.slice(0, 120),
344      referrer: ref.slice(0, 512),
345      ref_query: refQuery(ref),
346      landing: w.location.pathname.split("/").pop() || "index.html",
347      landing_path: w.location.pathname.slice(0, 255),
348      landing_host: here.slice(0, 120),
349      utm_source: (Q.utm_source || "").slice(0, 255),
350      utm_medium: (Q.utm_medium || "").slice(0, 255),
351      utm_campaign: (Q.utm_campaign || "").slice(0, 255),
352      ts: new Date().toISOString()
353    };
354  }
355
356  // fe-1091
357  var arrival = getJSON("sessionStorage", "zk_arrival");
358  if (!arrival) {
359    arrival = resolveArrival();
360    setJSON("sessionStorage", "zk_arrival", arrival);
361  }
362  var arrivalFirst = getJSON("localStorage", "zk_arrival_first");
363  if (!arrivalFirst) { arrivalFirst = arrival; setJSON("localStorage", "zk_arrival_first", arrival); }
364
365  // fe-1092
366  var UA = (w.navigator && w.navigator.userAgent) || "";
367  // fe-1093
368  var UA_AI = /(GPTBot|OAI-SearchBot|ChatGPT-User|ClaudeBot|Claude-User|Claude-SearchBot|anthropic-ai|PerplexityBot|Perplexity-User|Google-Extended|GoogleOther|Applebot-Extended|Bytespider|CCBot|meta-externalagent|meta-externalfetcher|FacebookBot|cohere-ai|Diffbot|YouBot|DuckAssistBot|Amazonbot|Ai2Bot|PanguBot|ImagesiftBot|Timpibot|omgili|AndiBot|MistralAI-User|DeepSeekBot)/i;
369  // fe-1094
370  var UA_BOT = /(bot\b|bot\/|crawl|spider|slurp|headless|phantomjs|puppeteer|playwright|selenium|python-requests|curl\/|wget|httpclient|axios\/|node-fetch|go-http-client|java\/|scrapy|libwww|okhttp|lighthouse|pagespeed|gtmetrix|pingdom|uptimerobot)/i;
371
372  function classifyVisitor() {
373    var signals = [];
374    var type = "human";
375    var confidence = "assumed";   // fe-1095
376    var nav = w.navigator || {};
377
378    if (UA_AI.test(UA)) { type = "ai_agent"; confidence = "declared"; signals.push("ua_ai"); }
379    else if (UA_BOT.test(UA)) { type = "bot"; confidence = "declared"; signals.push("ua_bot"); }
380
381    if (nav.webdriver === true) {
382      signals.push("webdriver");
383      if (type === "human") { type = "automation"; confidence = "strong"; }
384    }
385    if (/HeadlessChrome/i.test(UA)) {
386      signals.push("headless_ua");
387      if (type === "human") { type = "automation"; confidence = "strong"; }
388    }
389    // fe-1096
390    if (!nav.languages || !nav.languages.length) signals.push("no_languages");
391    if (nav.plugins && nav.plugins.length === 0 && !/Mobi|Android|iPhone|iPad/i.test(UA)) {
392      signals.push("no_plugins");
393    }
394    if (type === "human" && signals.length >= 2) confidence = "weak";
395    return { type: type, confidence: confidence, signals: signals };
396  }
397  var visitor = classifyVisitor();
398
399  // fe-1097
400  var sawHumanInput = false;
401  function noteHumanInput() { sawHumanInput = true; }
402
403  // fe-1098
404  function cleanCode(v) {
405    if (!v) return "";
406    // fe-1099
407    return String(v).replace(/[^A-Za-z0-9_.\-]/g, "").slice(0, AFF_MAX);
408  }
409
410  function affFromUrl() {
411    var code = "";
412    var param = "";
413    for (var i = 0; i < AFF_PARAMS.length && !code; i++) {
414      code = cleanCode(Q[AFF_PARAMS[i]]);
415      if (code) param = AFF_PARAMS[i];
416    }
417    if (!code) return null;
418    return {
419      code: code,
420      campaign_id: cleanCode(Q[AFF_CAMPAIGN_PARAM]),
421      param: param,
422      landing: w.location.pathname.split("/").pop() || "index.html",
423      referrer: (d.referrer || "").slice(0, 512),
424      channel: arrival.channel,
425      channel_type: arrival.channel_type,
426      ts: new Date().toISOString()
427    };
428  }
429
430  var affUrl = affFromUrl();
431  var affFirst = getJSON("localStorage", "zk_aff_first");
432  // fe-1100
433  if (!affFirst) {
434    var ck = getCookie("zk_aff");
435    if (ck) {
436      var bits = ck.split("|");
437      if (cleanCode(bits[0])) {
438        affFirst = { code: cleanCode(bits[0]), campaign_id: cleanCode(bits[1]),
439                     param: "cookie", landing: "", referrer: "", channel: "",
440                     channel_type: "", ts: "" };
441        setJSON("localStorage", "zk_aff_first", affFirst);
442      }
443    }
444  }
445  // fe-1101
446  if (!affFirst && affUrl) {
447    affFirst = affUrl;
448    setJSON("localStorage", "zk_aff_first", affFirst);
449  }
450  if (affFirst && affFirst.code) {
451    setCookie("zk_aff", affFirst.code + "|" + (affFirst.campaign_id || ""), 365);
452  }
453  var affLast = affUrl || getJSON("sessionStorage", "zk_aff_last");
454  if (affUrl) setJSON("sessionStorage", "zk_aff_last", affUrl);
455
456  function affiliateBlock() {
457    if (!affFirst && !affLast) return null;
458    var f = affFirst || {};
459    var l = affLast || {};
460    return {
461      // fe-1102
462      code: f.code || "",
463      campaign_id: f.campaign_id || "",
464      first_ts: f.ts || "",
465      first_landing: f.landing || "",
466      first_param: f.param || "",
467      // fe-1103
468      last_code: l.code || "",
469      last_ts: l.ts || "",
470      contested: !!(f.code && l.code && f.code !== l.code),
471      // fe-1104
472      term_days: null,
473      term_note: "365d default, starts at referred-party signup, computed server side"
474    };
475  }
476
477  // fe-1105
478  w.dataLayer = w.dataLayer || [];
479  w.zkTrackLog = w.zkTrackLog || [];
480
481  function baseEvent(step, props) {
482    return {
483      event: "zk_" + step,               // fe-1106
484      ev: "zk",
485      step: step,
486      ts: new Date().toISOString(),
487      vid: vid,
488      sid: sid,
489      // fe-1107
490      ysid: CFG.ysid || "",
491      uid: CFG.uid || "",
492      page: w.location.pathname.split("/").pop() || "index.html",
493      href: w.location.href.slice(0, 512),
494      campaign_first: first || null,
495      campaign_last: last || null,
496      // fe-1108
497      arrival: arrival,
498      arrival_first: (arrivalFirst && arrivalFirst.ts !== arrival.ts) ? arrivalFirst : null,
499      affiliate: affiliateBlock(),
500      vt: visitor.type,
501      vt_confidence: visitor.confidence,
502      props: props || {}
503    };
504  }
505
506  function send(url, ev) {
507    if (!SEND) {
508      console.debug("[zk-track] STUBBED (nothing sent):", ev.step, ev.props);
509      return;
510    }
511    // fe-1109
512    if (url === IX_ENDPOINT && !SEND_IX) {
513      console.debug("[zk-track] ix_batch held (SEND_IX off):", ev.step);
514      return;
515    }
516    // fe-1110
517    try {
518      var body = JSON.stringify(ev);
519      if (w.navigator && w.navigator.sendBeacon) {
520        w.navigator.sendBeacon(url, new Blob([body], { type: BEACON_TYPE }));
521      } else {
522        fetch(url, {
523          method: "POST",
524          headers: { "Content-Type": BEACON_TYPE },
525          body: body,
526          keepalive: true
527        })["catch"](function () {});
528      }
529    } catch (e) { /* fe-1111 */ }
530  }
531
532  function track(step, props) {
533    if (!STEPS[step]) {
534      // fe-1112
535      console.warn("[zk-track] unknown step id: " + step + " (add it to STEPS in zk-track.js)");
536    }
537    var ev = baseEvent(step, props);
538    w.dataLayer.push(ev);
539    w.zkTrackLog.push(ev);
540    send(ENDPOINT, ev);
541  }
542
543  // fe-1113
544  function conversion(kind, props) {
545    var step = CONVERSIONS[kind];
546    if (!step) {
547      console.warn("[zk-track] unknown conversion kind: " + kind + " (add it to CONVERSIONS)");
548      return;
549    }
550    var p = props || {};
551    p.conversion_kind = kind;
552    var ev = baseEvent(step, p);
553    ev.conversion = true;
554    w.dataLayer.push(ev);
555    w.zkTrackLog.push(ev);
556    send(ENDPOINT, ev);
557    // fe-1114
558    flush("conversion");
559  }
560
561  // fe-1115
562  function link(href, step, extra) {
563    var base = href.split("#")[0];
564    var hash = href.indexOf("#") > -1 ? href.slice(href.indexOf("#")) : "";
565    var qs = [];
566    var sawRef = false;
567    if (step) qs.push("zkc=" + encodeURIComponent(step));
568    qs.push("zk_vid=" + encodeURIComponent(vid));
569    UTM.forEach(function (k) {
570      var v = (last && last[k]) || (first && first[k]);
571      if (v) { qs.push(k + "=" + encodeURIComponent(v)); if (k === "zkref") sawRef = true; }
572    });
573    // fe-1116
574    if (!sawRef && affFirst && affFirst.code) {
575      qs.push("zkref=" + encodeURIComponent(affFirst.code));
576    }
577    if (affFirst && affFirst.campaign_id) {
578      qs.push(AFF_CAMPAIGN_PARAM + "=" + encodeURIComponent(affFirst.campaign_id));
579    }
580    if (extra) {
581      Object.keys(extra).forEach(function (k) {
582        if (extra[k] !== undefined && extra[k] !== null && extra[k] !== "") {
583          qs.push(encodeURIComponent(k) + "=" + encodeURIComponent(extra[k]));
584        }
585      });
586    }
587    return base + (base.indexOf("?") > -1 ? "&" : "?") + qs.join("&") + hash;
588  }
589
590  // fe-1117
591  var buf = [];
592  var dropped = 0;
593  var engagedMs = 0;
594  var maxScroll = 0;
595  var lastActivity = Date.now();
596  var obs = null;
597
598  function sectionOf(el) {
599    if (!el) return "global";
600    // fe-1118
601    if (el.nodeType === 3) el = el.parentElement;
602    if (!el || !el.closest) return "global";
603    // fe-1119
604    var s = el.closest("[data-zk-section]") || el.closest("[data-section]");
605    if (!s) return "global";
606    return (s.getAttribute("data-zk-section") || s.getAttribute("data-section") || "global").slice(0, 60);
607  }
608
609  function noTrack(el) {
610    if (!el) return false;
611    if (el.nodeType === 3) el = el.parentElement;
612    return !!(el && el.closest && el.closest("[data-zk-notrack]"));
613  }
614
615  function ix(kind, data) {
616    var rec = data || {};
617    rec.k = kind;
618    rec.t = Date.now();
619    rec.p = w.location.pathname.split("/").pop() || "index.html";
620    if (buf.length >= IX_CAP) { buf.shift(); dropped++; }
621    buf.push(rec);
622  }
623
624  // fe-1120
625  var openAt = {};    // fe-1121
626  var dwell = {};     // fe-1122
627  var enters = {};    // fe-1123
628
629  function closeOpenSections() {
630    var now = Date.now();
631    Object.keys(openAt).forEach(function (name) {
632      var ms = now - openAt[name];
633      if (ms >= DWELL_MIN_MS) dwell[name] = (dwell[name] || 0) + ms;
634      openAt[name] = now;   // fe-1124
635    });
636    Object.keys(dwell).forEach(function (name) {
637      ix("view", { s: name, ms: Math.round(dwell[name]), n: enters[name] || 1 });
638      delete dwell[name];
639    });
640  }
641
642  function flush(reason) {
643    // fe-1125
644    closeOpenSections();
645    if (!buf.length && !engagedMs) return;
646    var ev = baseEvent("ix_batch", {
647      reason: reason || "",
648      records: buf.slice(0),
649      dropped: dropped,
650      meta: {
651        engaged_s: Math.round(engagedMs / 1000),
652        max_scroll_pct: maxScroll,
653        viewport: (w.innerWidth || 0) + "x" + (w.innerHeight || 0),
654        screen: (w.screen ? w.screen.width : 0) + "x" + (w.screen ? w.screen.height : 0),
655        dpr: w.devicePixelRatio || 1,
656        // fe-1126
657        ua: UA.slice(0, 255),
658        vt_signals: visitor.signals.join(","),
659        human_input: sawHumanInput
660      }
661    });
662    w.dataLayer.push(ev);
663    w.zkTrackLog.push(ev);
664    send(IX_ENDPOINT, ev);
665    buf = [];
666    dropped = 0;
667    engagedMs = 0;
668  }
669
670  if (w.IntersectionObserver) {
671    obs = new w.IntersectionObserver(function (entries) {
672      var now = Date.now();
673      entries.forEach(function (e) {
674        var name = (e.target.getAttribute("data-zk-section") ||
675                    e.target.getAttribute("data-section") || "").slice(0, 60);
676        if (!name) return;
677        if (e.isIntersecting && e.intersectionRatio >= SECTION_RATIO) {
678          if (!openAt[name]) { openAt[name] = now; enters[name] = (enters[name] || 0) + 1; }
679        } else if (openAt[name]) {
680          var ms = now - openAt[name];
681          if (ms >= DWELL_MIN_MS) dwell[name] = (dwell[name] || 0) + ms;
682          delete openAt[name];
683        }
684      });
685    }, { root: null, threshold: [0, SECTION_RATIO] });
686  }
687
688  // fe-1127
689  function observeSections() {
690    if (!obs) return;
691    var nodes = d.querySelectorAll("[data-zk-section],[data-section]");
692    for (var i = 0; i < nodes.length; i++) {
693      if (nodes[i].getAttribute("data-zk-observed")) continue;
694      nodes[i].setAttribute("data-zk-observed", "1");
695      if (nodes[i].hasAttribute && nodes[i].hasAttribute("data-zk-nodwell")) continue;
696      obs.observe(nodes[i]);
697    }
698  }
699
700  // fe-1128
701  var scrollQueued = false;
702  var hitDepth = {};
703  function measureScroll() {
704    scrollQueued = false;
705    var doc = d.documentElement;
706    var h = Math.max(doc.scrollHeight || 0, d.body ? (d.body.scrollHeight || 0) : 0);
707    if (h <= 0) return;
708    var pct = Math.min(100, Math.round((((w.pageYOffset || doc.scrollTop || 0) + (w.innerHeight || 0)) / h) * 100));
709    if (pct > maxScroll) maxScroll = pct;
710    [25, 50, 75, 100].forEach(function (m) {
711      if (pct >= m && !hitDepth[m]) { hitDepth[m] = 1; ix("scroll", { pct: m }); }
712    });
713  }
714  w.addEventListener("scroll", function () {
715    lastActivity = Date.now();
716    if (scrollQueued) return;
717    scrollQueued = true;
718    (w.requestAnimationFrame || function (f) { setTimeout(f, 60); })(measureScroll);
719  }, { passive: true });
720
721  // fe-1129
722  d.addEventListener("click", function (e) {
723    lastActivity = Date.now();
724    var t = e.target;
725    if (!t || noTrack(t)) return;
726    var el = t.nodeType === 3 ? t.parentElement : t;
727    if (!el || !el.closest) return;
728    var a = el.closest("a[href],button,[role=button],input[type=submit]");
729    var node = a || el;
730    var section = sectionOf(el);
731    // fe-1130
732    if (section === "global" && !a) return;
733    var href = (a && a.getAttribute) ? (a.getAttribute("href") || "") : "";
734    var text = "";
735    try {
736      text = (node.innerText || node.textContent || node.value || "")
737             .replace(/\s+/g, " ").trim().slice(0, TEXT_CAP);
738    } catch (err) { /* fe-1131 */ }
739    ix("click", {
740      s: section,
741      tag: (node.tagName || "").toLowerCase(),
742      id: (node.id || "").slice(0, 60),
743      cls: ((node.className && String(node.className)) || "").split(/\s+/)[0].slice(0, 40),
744      txt: text,
745      href: href.slice(0, 255),
746      out: /^(https?:)?\/\//i.test(href) && href.indexOf(w.location.host) < 0
747    });
748  }, true);
749
750  // fe-1132
751  var HOVERABLE = "a[href],button,[data-zk-hover],.zk-plan,.zk-price-box,.zkq-cell,[data-key]";
752  var hoverTimer = null;
753  var hovered = {};
754  var canHover = !w.matchMedia || w.matchMedia("(hover: hover)").matches;
755  if (canHover) {
756    d.addEventListener("mouseover", function (e) {
757      var el = e.target;
758      if (!el || el.nodeType === 3) el = el && el.parentElement;
759      if (!el || !el.closest || noTrack(el)) return;
760      var node = el.closest(HOVERABLE);
761      if (!node) return;
762      var label = (node.innerText || "").replace(/\s+/g, " ").trim().slice(0, 30);
763      var key = sectionOf(node) + "|" + (node.id || "") + "|" + label;
764      if (hovered[key]) return;
765      if (hoverTimer) clearTimeout(hoverTimer);
766      hoverTimer = setTimeout(function () {
767        hovered[key] = 1;
768        ix("hover", {
769          s: sectionOf(node),
770          tag: (node.tagName || "").toLowerCase(),
771          id: (node.id || "").slice(0, 60),
772          txt: label,
773          ms: HOVER_MS
774        });
775      }, HOVER_MS);
776    }, true);
777    d.addEventListener("mouseout", function () {
778      if (hoverTimer) { clearTimeout(hoverTimer); hoverTimer = null; }
779    }, true);
780  }
781
782  // fe-1133
783  var selTimer = null;
784  var seenSel = {};
785  d.addEventListener("selectionchange", function () {
786    if (selTimer) clearTimeout(selTimer);
787    selTimer = setTimeout(function () {
788      var sel = w.getSelection ? w.getSelection() : null;
789      if (!sel) return;
790      var txt = String(sel).replace(/\s+/g, " ").trim();
791      if (txt.length < 5) return;
792      var node = sel.anchorNode;
793      if (noTrack(node)) return;
794      var short = txt.slice(0, SELECT_CAP);
795      if (seenSel[short]) return;
796      seenSel[short] = 1;
797      ix("select", { s: sectionOf(node), txt: short, len: txt.length });
798    }, SELECT_DEBOUNCE_MS);
799  });
800
801  // fe-1134
802  function videoEvent(e, action) {
803    var v = e.target;
804    if (!v || (v.tagName || "").toLowerCase() !== "video" || noTrack(v)) return;
805    ix("video", {
806      s: sectionOf(v),
807      act: action,
808      src: (v.currentSrc || v.getAttribute("src") || "").split("/").pop().slice(0, 120),
809      id: (v.id || "").slice(0, 60),
810      at: Math.round(v.currentTime || 0),
811      dur: Math.round(v.duration || 0)
812    });
813  }
814  d.addEventListener("play", function (e) { videoEvent(e, "play"); }, true);
815  d.addEventListener("pause", function (e) { if (!e.target.ended) videoEvent(e, "pause"); }, true);
816  d.addEventListener("ended", function (e) { videoEvent(e, "ended"); }, true);
817
818  // fe-1135
819  var searchTimer = null;
820  d.addEventListener("input", function (e) {
821    lastActivity = Date.now();
822    var t = e.target;
823    if (!t || noTrack(t)) return;
824    var name = (t.name || "").toLowerCase();
825    var id = (t.id || "").toLowerCase();
826    if (!(t.type === "search" || id.indexOf("search") > -1 || name.indexOf("search") > -1)) return;
827    if (searchTimer) clearTimeout(searchTimer);
828    searchTimer = setTimeout(function () {
829      var q = (t.value || "").trim();
830      if (q.length < 2) return;
831      ix("search", { s: sectionOf(t), id: (t.id || "").slice(0, 60), q: q.slice(0, QUERY_CAP) });
832    }, SEARCH_DEBOUNCE_MS);
833  }, true);
834
835  // fe-1136
836  function stampForm(f) {
837    if (!f || !f.querySelectorAll) return;
838    var pairs = [["[data-zk-vid]", vid],
839                 ["[data-zk-aff]", (affFirst && affFirst.code) || ""],
840                 ["[data-zk-cid]", (affFirst && affFirst.campaign_id) || ""],
841                 ["[data-zk-chan]", arrival.channel + "/" + arrival.channel_type]];
842    pairs.forEach(function (pair) {
843      var nodes = f.querySelectorAll(pair[0]);
844      for (var i = 0; i < nodes.length; i++) { nodes[i].value = pair[1]; }
845    });
846  }
847  function stampAllForms() {
848    var forms = d.querySelectorAll("form");
849    for (var i = 0; i < forms.length; i++) { stampForm(forms[i]); }
850  }
851
852  // fe-1137
853  d.addEventListener("submit", function (e) {
854    var f = e.target;
855    if (!f || noTrack(f)) return;
856    var kind = f.getAttribute ? (f.getAttribute("data-zk-conv") || "") : "";
857    stampForm(f);
858    // fe-1138
859    var valid = !f.checkValidity || f.checkValidity();
860    if (kind && valid) {
861      conversion(kind, { s: sectionOf(f), form: String(f.id || f.className || "").slice(0, 60) });
862      return;
863    }
864    ix("form", { s: sectionOf(f), id: (f.id || "").slice(0, 60),
865                 act: (f.getAttribute("action") || "").slice(0, 255),
866                 conv: kind, invalid: !valid });
867    flush("submit");
868  }, true);
869
870  // fe-1139
871  ["mousemove", "keydown", "touchstart", "wheel", "pointerdown"].forEach(function (n) {
872    w.addEventListener(n, function () { lastActivity = Date.now(); noteHumanInput(); }, { passive: true });
873  });
874  setInterval(function () {
875    if (d.visibilityState === "hidden") return;
876    if (Date.now() - lastActivity > IDLE_MS) return;
877    engagedMs += 1000;
878  }, 1000);
879
880  // fe-1140
881  d.addEventListener("visibilitychange", function () {
882    if (d.visibilityState === "hidden") flush("hidden");
883  });
884  w.addEventListener("pagehide", function () { flush("pagehide"); });
885  setInterval(function () { if (buf.length) flush("interval"); }, FLUSH_MS);
886
887  // fe-1141
888  w.zkTrack = track;
889  w.zkTrack.link = link;
890  w.zkTrack.steps = STEPS;
891  w.zkTrack.param = function (k) { return Q[k] || ""; };
892  w.zkTrack.vid = function () { return vid; };
893  w.zkTrack.campaign = function () { return { first: first || null, last: last || null }; };
894  // fe-1142
895  w.zkTrack.conversion = conversion;
896  w.zkTrack.conversions = CONVERSIONS;
897  w.zkTrack.ix = ix;
898  w.zkTrack.flush = flush;
899  w.zkTrack.arrival = function () { return { session: arrival, first: arrivalFirst }; };
900  w.zkTrack.affiliate = affiliateBlock;
901  w.zkTrack.visitor = function () { return visitor; };
902  // fe-1143
903  w.zkTrack.rescan = function () { observeSections(); stampAllForms(); };
904
905  // fe-1144
906  track("page_view", {
907    from_step: Q.zkc || "",
908    entry: !d.referrer,
909    channel: arrival.channel,
910    channel_type: arrival.channel_type,
911    paid: arrival.paid,
912    landing: arrival.landing,
913    campaign_link: !!(fromUrl || affUrl),
914    affiliate_code: (affFirst && affFirst.code) || ""
915  });
916
917  if (d.readyState === "loading") {
918    d.addEventListener("DOMContentLoaded", function () { observeSections(); stampAllForms(); });
919  } else {
920    observeSections();
921    stampAllForms();
922  }
923
924  // fe-1145
925  d.addEventListener("click", function (e) {
926    var a = e.target && e.target.closest ? e.target.closest("a[href]") : null;
927    if (!a || a.getAttribute("data-zkc-linked")) return;
928    var href = a.getAttribute("href") || "";
929    if (href.slice(0, 4) === "tel:") { conversion("phone_click", { href: href.slice(0, 60) }); return; }
930    var isSignup = href.indexOf("signup.html") > -1 || href.indexOf("/signup") > -1;
931    var isLogin = href.indexOf("/app/login") > -1 || href.indexOf("/login") > -1;
932    if (!isSignup && !isLogin) return;
933    if (/^(https?:)?\/\//i.test(href) && href.indexOf(w.location.host) < 0) return;  // fe-1146
934    a.setAttribute("data-zkc-linked", "1");
935    a.href = link(href, isSignup ? "qo_signup_click" : "cv_login_click");
936    conversion(isSignup ? "signup_click" : "login_click",
937               { from: w.location.pathname.split("/").pop() || "index.html" });
938  }, true);
939
940  /* fe-1147 */
941})(window, document);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.