1jQuery(document).ready(async () => { 2 3 const DURATION = 3600*24*365*2; 4 const SOURCE_DURATION = 3600*24*30; 5 6 let visitor = getCookie("Visitor"); 7 let entryTimestamp = getCookie("entryTimestamp"); 8 let trackingBrowser = getCookie("TrackingBrowser"); 9 let lastPageVisited = localStorage.getItem('lastVisitedPage'); 10 const data = await fetch("/wp-json/itss/cookies"); 11 const { timestamp, identity } = await data.json(); 12 13 let domain = location.host; 14 if (domain === "www.stamps.com") { 15 domain = ".stamps.com"; 16 } 17 18 if (!visitor) { 19 const uuid = self.crypto.randomUUID(); 20 document.cookie = `Visitor=${uuid};max-age=${DURATION};path=/;domain=${domain};`; 21 visitor = uuid; 22 } 23 if (lastPageVisited) { 24 document.cookie = `lastPageVisited=${lastPageVisited};path=/;domain=${domain}`; 25 } 26 if (!entryTimestamp) { 27 const encodedTimestamp = encodeURIComponent(timestamp); 28 document.cookie = `entryTimestamp=${encodedTimestamp};path=/;domain=${domain};` 29 entryTimestamp = encodedTimestamp; 30 } 31 32 if (!trackingBrowser) { 33 document.cookie = `TrackingBrowser=${identity}.${visitor};max-age=${5 * DURATION};path=/;domain=${domain};` 34 } 35 36 window["pageData"]["VisitorId"] = visitor; 37 window["pageData"]["Timestamp"] = decodeURIComponent(entryTimestamp); 38 39 await handleSourceDetection(domain); 40 41 function gatherCookies() { 42 const cookies = {}; 43 document.cookie.split(";").forEach(c => { 44 const arr = c.split("="); 45 cookies[arr[0].trim()] = arr[1].trim(); 46 }); 47 return cookies; 48 } 49 50 function getCookie(key) { 51 return gatherCookies()[key] || null; 52 } 53 54 function setSourceCookie(value) { 55 document.cookie = `Source=${encodeURIComponent(value)};max-age=${SOURCE_DURATION};path=/;domain=${domain};secure`; 56 } 57 58 function setSubSourceCookie(value) { 59 document.cookie = `subSource=${encodeURIComponent(value)};max-age=${SOURCE_DURATION};path=/;domain=${domain};secure`; 60 } 61 62 function isInternalReferrer(hostname) { 63 return hostname === "stamps.com" 64 || hostname === "www.stamps.com" 65 || hostname.endsWith(".stamps.com"); 66 } 67 68 function getReferrerMatchCandidates(hostname) { 69 const parts = hostname.split("."); 70 if (parts.length > 3) { 71 return [parts[1], parts[2], parts[1] + "." + parts[2]]; 72 } else if (parts.length > 2) { 73 return [parts[0] + "." + parts[1], parts[0], parts[1]]; 74 } 75 return [parts[0]]; 76 } 77 78 function matchReferrer(candidates, referrerMap) { 79 for (const candidate of candidates) { 80 for (const entry of referrerMap) { 81 if (candidate === entry.domain) { 82 return entry; 83 } 84 } 85 } 86 return null; 87 } 88 89 async function getReferrerMap() { 90 const CACHE_KEY = "stamps_referrer_map"; 91 const CACHE_TTL = 3600000; 92 93 try { 94 const cached = localStorage.getItem(CACHE_KEY); 95 if (cached) { 96 const parsed = JSON.parse(cached); 97 if (Date.now() - parsed.timestamp < CACHE_TTL) { 98 return parsed.data; 99 } 100 } 101 } catch (e) {} 102 103 try { 104 const response = await fetch("/wp-json/itss/referrer-map"); 105 if (!response.ok) throw new Error(response.status); 106 const data = await response.json(); 107 if (!data || !Array.isArray(data.referrers)) throw new Error("invalid response"); 108 localStorage.setItem(CACHE_KEY, JSON.stringify({ 109 timestamp: Date.now(), 110 data: data 111 })); 112 return data; 113 } catch (e) { 114 try { 115 const cached = localStorage.getItem(CACHE_KEY); 116 if (cached) { 117 return JSON.parse(cached).data; 118 } 119 } catch (e2) {} 120 return null; 121 } 122 } 123 124 async function handleSourceDetection(domain) { 125 const params = new URLSearchParams(window.location.search); 126 const hasSourceParam = params.has("source"); 127 const hasSubsourceParam = params.has("subsource"); 128 const existingSource = getCookie("Source"); 129 130 if (hasSubsourceParam) { 131 setSubSourceCookie(params.get("subsource")); 132 } 133 134 if (hasSourceParam) { 135 setSourceCookie(params.get("source")); 136 return; 137 } 138 139 if (existingSource) { 140 return; 141 } 142 143 const referrerMap = await getReferrerMap(); 144 if (!referrerMap) { 145 return; 146 } 147 148 const referrer = document.referrer; 149 if (!referrer) { 150 if (referrerMap.default_sourceid) { 151 setSourceCookie(referrerMap.default_sourceid); 152 } 153 return; 154 } 155 156 let referrerHostname; 157 try { 158 referrerHostname = new URL(referrer).hostname; 159 } catch (e) { 160 return; 161 } 162 163 if (isInternalReferrer(referrerHostname)) { 164 return; 165 } 166 167 const candidates = getReferrerMatchCandidates(referrerHostname); 168 const match = matchReferrer(candidates, referrerMap.referrers); 169 170 if (match) { 171 setSourceCookie(match.sourceid); 172 if (match.subsourceid) { 173 setSubSourceCookie(match.subsourceid); 174 } 175 } else if (referrerMap.default_sourceid) { 176 setSourceCookie(referrerMap.default_sourceid); 177 } 178 } 179});
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.