1/* 2 * thePlus.so analytics beacon 3 * 4 * Cerez kullanmiyor, localStorage'a kimlik yazmiyor. Oturum kimligi yalnizca 5 * sekme omru boyunca sessionStorage'da duruyor ve sunucuda tuzlanip 6 * hashleniyor, yani geri cozulemiyor. 7 * 8 * Gonderdigi: yol, yonlendiren, ekran genisligi, sayfada gecen sure, 9 * tiklanan dugmeler, fiyat sayfasinda inilen derinlik. 10 * Gondermedigi: ham IP, cerez, parmak izi, kisisel hicbir sey. 11 */ 12(function () { 13 'use strict'; 14 15 var EP = '/admin/api/hit'; 16 17 // Do Not Track ve Global Privacy Control saygi goruyor 18 if (navigator.doNotTrack === '1' || window.doNotTrack === '1' || 19 navigator.globalPrivacyControl === true) { return; } 20 21 // onizleme ve mola sayfalarini sayma 22 if (location.search.indexOf('datecontrol=') !== -1) { return; } 23 if (location.pathname.indexOf('/pause') === 0) { return; } 24 25 var SK = 'tp_sid'; 26 var sid, fresh = false; 27 try { 28 sid = sessionStorage.getItem(SK); 29 if (!sid) { 30 sid = Math.random().toString(36).slice(2) + Date.now().toString(36); 31 sessionStorage.setItem(SK, sid); 32 fresh = true; 33 } 34 } catch (e) { sid = 'nostore'; } 35 36 function send(body, keep) { 37 try { 38 var s = JSON.stringify(body); 39 if (keep && navigator.sendBeacon) { 40 navigator.sendBeacon(EP, new Blob([s], { type: 'application/json' })); 41 } else { 42 fetch(EP, { method: 'POST', body: s, keepalive: !!keep, 43 headers: { 'Content-Type': 'application/json' } }).catch(function () {}); 44 } 45 } catch (e) {} 46 } 47 48 var t0 = Date.now(); 49 var path = location.pathname + location.search; 50 51 send({ 52 p: path, 53 r: document.referrer || '', 54 n: fresh ? 1 : 0, 55 sid: sid, 56 w: window.screen ? window.screen.width : null 57 }); 58 59 // Sayfa disi olay bildirmek icin: tpEvent('signup') ya da tpEvent('purchase', 149) 60 window.tpEvent = function (name, value, meta) { 61 send({ e: String(name).slice(0, 60), v: value, m: meta, p: path, sid: sid }, true); 62 }; 63 64 // Ayrilirken sayfada gecen sureyi bildir. visibilitychange, pagehide'dan 65 // daha guvenilir: mobil tarayicilar pagehide'i her zaman tetiklemiyor. 66 var sent = false; 67 function bye() { 68 if (sent) { return; } 69 sent = true; 70 send({ p: path, sid: sid, u: 1, d: Math.round((Date.now() - t0) / 1000) }, true); 71 } 72 document.addEventListener('visibilitychange', function () { 73 if (document.visibilityState === 'hidden') { bye(); } 74 }); 75 window.addEventListener('pagehide', bye); 76 77 /* ââ hatalar âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 78 * Ziyaretcinin tarayicisinda patlayan JavaScript hatalari. Asil soru 79 * "kac hata var" degil, "kac kisi bundan etkilendi"; panel oran olarak 80 * gosteriyor. Ayni hata ayni sayfada bir kez bildirilir, yoksa dongu 81 * icindeki bir hata butun sayilari bozar. */ 82 var errSeen = {}; 83 function reportErr(msg, src, line) { 84 var key = String(msg || '').slice(0, 180); 85 if (!key || errSeen[key]) { return; } 86 errSeen[key] = 1; 87 send({ x: key, xs: String(src || '').slice(0, 180), xl: line || 0, p: path, sid: sid }, true); 88 } 89 window.addEventListener('error', function (e) { 90 if (!e) { return; } 91 if (e.message) { reportErr(e.message, e.filename, e.lineno); } 92 else if (e.target && e.target.src) { 93 // resim, betik gibi bir kaynak yuklenemedi 94 reportErr('Failed to load ' + (e.target.tagName || '').toLowerCase(), e.target.src, 0); 95 } 96 }, true); 97 window.addEventListener('unhandledrejection', function (e) { 98 var r = e && e.reason; 99 reportErr('Unhandled promise: ' + (r && r.message ? r.message : String(r)), '', 0); 100 }); 101 102 /* ââ tiklamalar ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 103 * Sitede zaten yuzden fazla data-track isareti var ama bugune kadar hicbir 104 * sey onlari dinlemiyordu. Artik dinliyoruz. 105 * 106 * Fiyat sayfasinda ayrica isaretsiz dugme ve baglantilari da yaziyoruz, 107 * cunku orada neyin tiklandigini bilmek dogrudan para demek. Etiket olarak 108 * gorunen yazi kullaniliyor, kirkbir karakterde kesiliyor. */ 109 var onPricing = /^\/(pricing|upgrade)\/?$/.test(location.pathname); 110 111 function label(el) { 112 var t = (el.textContent || '').replace(/\s+/g, ' ').trim(); 113 if (!t) { t = el.getAttribute('aria-label') || el.getAttribute('title') || ''; } 114 if (!t) { t = (el.getAttribute('href') || '').slice(0, 40); } 115 return t.slice(0, 40); 116 } 117 118 document.addEventListener('click', function (ev) { 119 var el = ev.target && ev.target.closest ? ev.target.closest('[data-track],a,button') : null; 120 if (!el) { return; } 121 122 var tracked = el.getAttribute('data-track'); 123 if (tracked) { 124 window.tpEvent('click:' + tracked.slice(0, 50)); 125 return; 126 } 127 if (!onPricing) { return; } 128 129 // Fiyat sayfasi: neye basildigini bilmek istiyoruz 130 var href = el.getAttribute('href') || ''; 131 var kind = /lemonsqueezy|checkout|buy/i.test(href) ? 'checkout' 132 : /membership|signup|register/i.test(href) ? 'signup' 133 : el.tagName === 'BUTTON' ? 'button' : 'link'; 134 window.tpEvent('pricing:' + kind + ':' + label(el)); 135 }, true); 136 137 /* ââ fiyat sayfasinda inilen derinlik ââââââââââââââââââââââââââââââââââââ 138 * Hangi bolume kadar bakiliyor sorusunun cevabi. Her esik bir
138kez bildirilir. */ 139 if (onPricing) { 140 var marks = [25, 50, 75, 100], hit = {}; 141 var depth = function () { 142 var h = document.documentElement; 143 var total = Math.max(h.scrollHeight - h.clientHeight, 1); 144 var p = Math.min(100, Math.round((window.scrollY || h.scrollTop) / total * 100)); 145 for (var i = 0; i < marks.length; i++) { 146 if (p >= marks[i] && !hit[marks[i]]) { 147 hit[marks[i]] = 1; 148 window.tpEvent('pricing:depth:' + marks[i]); 149 } 150 } 151 }; 152 var tick = null; 153 window.addEventListener('scroll', function () { 154 if (tick) { return; } 155 tick = setTimeout(function () { tick = null; depth(); }, 400); 156 }, { passive: true }); 157 depth(); 158 } 159 160 /* --------------------------------------------------------------- 161 * Fiyat sayfasi derin olcumu 162 * 163 * Yalnizca /pricing ve /upgrade uzerinde calisir. Cerez kullanmaz, 164 * ham koordinat gondermez: imlec ve tiklamalar 12 sutun x %5'lik 165 * satirlara yuvarlanir, yani veri dogasi geregi topludur. 166 * ------------------------------------------------------------- */ 167 if (onPricing) { 168 var KOL = 12; // yatay hucre sayisi 169 var SATIR_YUZDE = 5; // her satir sayfanin %5'i 170 var tpHeat = {}; // "tip|kol|satir" -> sayac 171 172 function hucre(tip, x, yMutlak) { 173 var w = Math.max(document.documentElement.clientWidth, 1); 174 var h = Math.max(document.documentElement.scrollHeight, 1); 175 var kol = Math.min(KOL - 1, Math.max(0, Math.floor(x / w * KOL))); 176 var satir = Math.min(Math.floor(100 / SATIR_YUZDE) - 1, 177 Math.max(0, Math.floor(yMutlak / h * (100 / SATIR_YUZDE)))); 178 var k = tip + '|' + kol + '|' + satir; 179 tpHeat[k] = (tpHeat[k] || 0) + 1; 180 } 181 182 /* imleci saniyede iki kez ornekle, surekli dinleyip islem yapma */ 183 var sonX = null, sonY = null; 184 document.addEventListener('mousemove', function (ev) { 185 sonX = ev.clientX; sonY = ev.clientY + (window.scrollY || 0); 186 }, { passive: true }); 187 setInterval(function () { 188 if (sonX === null) { return; } 189 hucre('m', sonX, sonY); 190 sonX = null; 191 }, 500); 192 193 document.addEventListener('click', function (ev) { 194 hucre('c', ev.clientX, ev.clientY + (window.scrollY || 0)); 195 }, { passive: true }); 196 197 /* bolum gorunurlugu ve kart dikkati */ 198 var gorulen = {}, dikkat = {}, girdi = {}; 199 if (window.IntersectionObserver) { 200 var io = new IntersectionObserver(function (girisler) { 201 for (var i = 0; i < girisler.length; i++) { 202 var g = girisler[i]; 203 var ad = g.target.getAttribute('data-sec') 204 || g.target.getAttribute('data-card') || ''; 205 if (!ad) { continue; } 206 if (g.isIntersecting) { 207 if (!gorulen[ad]) { gorulen[ad] = 1; window.tpEvent('pricing:seen:' + ad); } 208 girdi[ad] = Date.now(); 209 } else if (girdi[ad]) { 210 dikkat[ad] = (dikkat[ad] || 0) + (Date.now() - girdi[ad]); 211 girdi[ad] = 0; 212 } 213 } 214 }, { threshold: 0.5 }); 215 var hedefler = document.querySelectorAll('[data-sec],[data-card]'); 216 for (var j = 0; j < hedefler.length; j++) { io.observe(hedefler[j]); } 217 } 218 219 /* sayfadan cikarken toplu gonder */ 220 function tpHeatGonder() { 221 var liste = []; 222 for (var k in tpHeat) { 223 if (!Object.prototype.hasOwnProperty.call(tpHeat, k)) { continue; } 224 var p = k.split('|'); 225 liste.push([p[0], +p[1], +p[2], tpHeat[k]]); 226 } 227 /* acik kalan kartlarin suresini kapat */ 228 for (var ad in girdi) { 229 if (girdi[ad]) { dikkat[ad] = (dikkat[ad] || 0) + (Date.now() - girdi[ad]); girdi[ad] = 0; } 230 } 231 var sure = []; 232 for (var a in dikkat) { 233 if (dikkat[a] > 800) { sure.push([a, Math.round(dikkat[a] / 1000)]); } 234 } 235 if (!liste.length && !sure.length) { return; } 236 send({ p: path, h: liste, a: sure }, true); 237 } 238 window.addEventListener('pagehide', tpHeatGonder); 239 document.addEventListener('visibilitychange', function () { 240 if (document.visibilityState === 'hidden') { tpHeatGonder(); } 241 }); 242 } 243})();
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.