top of page
HOME
COACH
ABOUT US
CONTACT
TEAM WINS
PRIVATE LESSONS
CLASSES
Events
Track and manage your events here.
Upcoming
Past
No tickets or RSVPs yet
Browse events
Mrs Jackson
Follow
Following icon
More actions
Profile
Events
bottom of page
/* UTM Tracker v2.0 - first/latest touch attribution and form autofill */ (function (window, document) { "use strict"; var userConfig = window.UTM_TRACKER_CONFIG || {}; var config = { storageKey: userConfig.storageKey || "utm_attribution_v2", cookieName: userConfig.cookieName || "utm_attribution_v2", ownedDomains: Array.isArray(userConfig.ownedDomains) ? userConfig.ownedDomains : [], defaultTouch: userConfig.defaultTouch === "latest" ? "latest" : "first", cookieDays: Math.min(Number(userConfig.cookieDays) || 400, 400), linkerMinutes: Math.min(Number(userConfig.linkerMinutes) || 30, 1440), decorateLinks: userConfig.decorateLinks !== false, removeLinkerFromUrl: userConfig.removeLinkerFromUrl !== false, debug: userConfig.debug === true, canStore: typeof userConfig.canStore === "function" ? userConfig.canStore : function () { return true; } }; var PARAMS = [ "utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content", "utm_id", "utm_source_platform", "utm_creative_format", "utm_marketing_tactic", "gclid", "gbraid", "wbraid", "fbclid", "msclkid", "ttclid", "twclid", "li_fat_id", "dclid", "srsltid" ]; var META = ["landing_page", "referrer", "captured_at"]; var LINKER_PARAM = "_utm_attribution"; var MAX_VALUE_LENGTH = 2048; var memoryData = emptyData(); var observedRoots = []; var scheduled = false; function emptyData() { return { first: null, latest: null }; } function log() { if (config.debug && window.console) { window.console.log.apply(window.console, ["[UTM Tracker]"].concat([].slice.call(arguments))); } } function clean(value, max) { if (typeof value !== "string") return ""; return value.replace(/[\u0000-\u001F\u007F]/g, "").trim().slice(0, max || MAX_VALUE_LENGTH); } function parseJSON(value) { try { var parsed = JSON.parse(value); return parsed && typeof parsed === "object" ? parsed : null; } catch (_) { return null; } } function storageAllowed() { try { return config.canStore() === true; } catch (_) { return false; } } function validTouch(value) { if (!value || typeof value !== "object") return null; var result = {}; PARAMS.concat(META).forEach(function (key) { var item = clean(value[key] || "", key === "captured_at" ? 40 : MAX_VALUE_LENGTH); if (item) result[key] = item; }); return Object.keys(result).length ? result : null; } function validData(value) { return { first: validTouch(value && value.first), latest: validTouch(value && value.latest) }; } function readCookie() { var match = document.cookie.match(new RegExp("(?:^|; )" + config.cookieName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "=([^;]*)")); if (!match) return null; try { return parseJSON(decodeURIComponent(match[1])); } catch (_) { return null; } } function compactData(data) { function compactTouch(touch) { if (!touch) return null; var result = {}; PARAMS.forEach(function (key) { if (touch[key]) result[key] = clean(touch[key], 250); }); if (touch.captured_at) result.captured_at = touch.captured_at; return Object.keys(result).length ? result : null; } return { first: compactTouch(data.first), latest: compactTouch(data.latest) }; } function cookieData(data) { var compact = compactData(data); var encoded = encodeURIComponent(JSON.stringify(compact)); if (encoded.length <= 3800) return encoded; /* Stay below the practical 4 KB cookie limit by retaining values in priority order. localStorage still keeps the complete record. */ var priority = ["utm_source", "utm_medium", "utm_campaign", "utm_id", "utm_term", "utm_content", "gclid", "gbraid", "wbraid", "fbclid", "msclkid", "ttclid", "twclid", "li_fat_id", "dclid", "srsltid"]; var reduced = emptyData(); ["first", "latest"].forEach(function (touchName) { if (!compact[touchName]) return; reduced[touchName] = {}; priority.forEach(function (key) { if (!compact[touchName][key]) return; var candidate = JSON.parse(JSON.stringify(reduced)); candidate[touchName][key] = clean(compact[touchName][key], 120); var candidateEncoded = encodeURIComponent(JSON.stringify(candidate)); if (candidateEncoded.length <= 3800) reduced = candidate; }); }); return encodeURIComponent(JSON.stringify(reduced)); } function readData() { if (!storageAllowed()) return memoryData; var parsed = null; try { parsed = parseJSON(window.localStorage.getItem(config.storageKey)); } catch (_) {} if (!parsed) parsed = readCookie(); memoryData = validData(parsed || memoryData); return memoryData; } function writeData(data) { memoryData = validData(data); if (!storageAllowed()) return; try { window.localStorage.setItem(config.storageKey, JSON.stringify(memoryData)); } catch (error) { log("localStorage unavailable", error); } try { var value = cookieData(memoryData); document.cookie = config.cookieName + "=" + value + "; Path=/; Max-Age=" + Math.floor(config.cookieDays * 86400) + "; SameSite=Lax" + (location.protocol === "https:" ? "; Secure" : ""); } catch (error) { log("cookie unavailable", error); } } function allParamValues(search, key) { var values = search.getAll(key); for (var i = 0; i < values.length; i += 1) { var value = clean(values[i]); if (value) return value; } return ""; } function base64UrlEncode(value) { var bytes = new TextEncoder().encode(value), binary = ""; bytes.forEach(function (byte) { binary += String.fromCharCode(byte); }); return window.btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); } function base64UrlDecode(value) { var input = value.replace(/-/g, "+").replace(/_/g, "/"); input += "===".slice((input.length + 3) % 4); var binary = window.atob(input), bytes = new Uint8Array(binary.length); for (var i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i); return new TextDecoder().decode(bytes); } function readLinker(search) { var raw = clean(search.get(LINKER_PARAM) || "", 12000); if (!raw) return null; try { var payload = parseJSON(base64UrlDecode(raw)); if (!payload || !Number.isFinite(payload.created)) return null; if (Math.abs(Date.now() - payload.created) > config.linkerMinutes * 60000) return null; return validData(payload.data); } catch (_) { return null; } } function removeLinker() { if (!config.removeLinkerFromUrl || !window.history || !window.history.replaceState) return; try { var url = new URL(location.href); if (!url.searchParams.has(LINKER_PARAM)) return; url.searchParams.delete(LINKER_PARAM); history.replaceState(history.state, "", url.href); } catch (_) {} } function capture() { var search = new URL(location.href).searchParams; var linked = readLinker(search); var data = readData(); if (linked) { if (!data.first && linked.first) data.first = linked.first; if (linked.latest) data.latest = linked.latest; removeLinker(); } var touch = {}; PARAMS.forEach(function (key) { var value = allParamValues(search, key); if (value) touch[key] = value; }); if (Object.keys(touch).length) { touch.landing_page = clean(location.href); touch.referrer = clean(document.referrer || ""); touch.captured_at = new Date().toISOString(); if (!data.first) data.first = touch; data.latest = touch; } writeData(data); return data; } function normalizeName(field) { return clean(field.getAttribute("data-utm-field") || field.name || field.id || "", 200) .toLowerCase().replace(/\[\]$/, "").replace(/[\s.-]+/g, "_"); } function fieldInfo(field) { var name = normalizeName(field), touch = config.defaultTouch; if (/^(first_touch_|first_|original_)/.test(name)) { touch = "first"; name = name.replace(/^(first_touch_|first_|original_)/, ""); } else if (/^(latest_touch_|latest_|last_touch_|last_)/.test(name)) { touch = "latest"; name = name.replace(/^(latest_touch_|latest_|last_touch_|last_)/, ""); } var aliases = { landing_url: "landing_page", utm_landing_page: "landing_page", utm_referrer: "referrer", utm_captured_at: "captured_at" }; name = aliases[name] || name; return PARAMS.concat(META).indexOf(name) === -1 ? null : { key: name, touch: touch }; } function setNativeValue(field, value) { var prototype = field.tagName === "TEXTAREA" ? window.HTMLTextAreaElement.prototype : window.HTMLInputElement.prototype; var setter = Object.getOwnPropertyDescriptor(prototype, "value"); if (setter && setter.set) setter.set.call(field, value); else field.value = value; field.setAttribute("value", value); field.dispatchEvent(new Event("input", { bubbles: true })); field.dispatchEvent(new Event("change", { bubbles: true })); } function fillField(field, data) { if (!field || field.disabled || /^(button|submit|reset|file|checkbox|radio)$/i.test(field.type || "")) return; var info = fieldInfo(field); if (!info) return; var existing = clean(field.value || ""); if (existing && existing.toLowerCase() !== "no utm") return; var primary = data[info.touch], fallback = data[info.touch === "first" ? "latest" : "first"]; var value = (primary && primary[info.key]) || (fallback && fallback[info.key]) || ""; if (value) setNativeValue(field, value); } function scan(root) { var data = readData(), fields = []; if (root.matches && root.matches("input,textarea")) fields.push(root); if (root.querySelectorAll) fields = fields.concat([].slice.call(root.querySelectorAll("input,textarea"))); fields.forEach(function (field) { fillField(field, data); }); if (root.querySelectorAll) { [].slice.call(root.querySelectorAll("*")).forEach(function (element) { if (element.shadowRoot) observeRoot(element.shadowRoot); }); } } function scheduleScan() { if (scheduled) return; scheduled = true; (window.requestAnimationFrame || window.setTimeout)(function () { scheduled = false; scan(document); }, 0); } function observeRoot(root) { if (!root || observedRoots.indexOf(root) !== -1) return; observedRoots.push(root); scan(root); new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { [].slice.call(mutation.addedNodes).forEach(function (node) { if (node.nodeType === 1) scan(node); }); }); }).observe(root, { childList: true, subtree: true }); } function owned(hostname) { var host = hostname.toLowerCase().replace(/^www\./, ""); return config.ownedDomains.some(function (domain) { var candidate = clean(domain, 253).toLowerCase().replace(/^https?:\/\//, "").split("/")[0].replace(/^www\./, "").replace(/:\d+$/, ""); return host === candidate || host.slice(-candidate.length - 1) === "." + candidate; }); } function decorate(anchor) { if (!config.decorateLinks || !anchor || !config.ownedDomains.length) return; try { var url = new URL(anchor.href, location.href); if (!/^https?:$/.test(url.protocol) || !owned(url.hostname) || url.hostname === location.hostname || url.searchParams.has(LINKER_PARAM)) return; var data = readData(); if (!data.first && !data.latest) return; var payload = base64UrlEncode(JSON.stringify({ created: Date.now(), data: compactData(data) })); if (payload.length <= 6000) url.searchParams.set(LINKER_PARAM, payload); anchor.href = url.href; } catch (_) {} } function handleRouteChange() { window.setTimeout(function () { capture(); scheduleScan(); }, 0); } function clearData() { memoryData = emptyData(); try { window.localStorage.removeItem(config.storageKey); } catch (_) {} try { document.cookie = config.cookieName + "=; Path=/; Max-Age=0; SameSite=Lax" + (location.protocol === "https:" ? "; Secure" : ""); } catch (_) {} } function patchHistory(method) { if (!window.history || !history[method]) return; var original = history[method]; history[method] = function () { var result = original.apply(this, arguments); handleRouteChange(); return result; }; } function init() { capture(); observeRoot(document.documentElement); document.addEventListener("submit", function (event) { scan(event.target); }, true); document.addEventListener("focusin", function (event) { fillField(event.target, readData()); }, true); document.addEventListener("pointerdown", function (event) { decorate(event.target.closest && event.target.closest("a[href]")); }, true); document.addEventListener("click", function (event) { decorate(event.target.closest && event.target.closest("a[href]")); }, true); document.addEventListener("contextmenu", function (event) { decorate(event.target.closest && event.target.closest("a[href]")); }, true); document.addEventListener("keydown", function (event) { if (event.key === "Enter") decorate(event.target.closest && event.target.closest("a[href]")); }, true); window.addEventListener("popstate", handleRouteChange); patchHistory("pushState"); patchHistory("replaceState"); } /* Useful for consent managers and debugging. Call refresh() immediately after analytics/marketing consent is granted. */ window.UTMTracker = { refresh: function () { var data = capture(); scheduleScan(); return data; }, get: function () { return validData(readData()); }, clear: clearData }; if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init, { once: true }); else init(); })(window, document);