1(function () { 2 window._ptg = window._ptg || {}; 3 4 var cookieNames = { 5 visitorId: '_pc_vis', 6 sessionId: '_pc_ses', 7 visitorIdHistory: '_pc_vis_h' 8 }; 9 10 // see http://clubmate.fi/setting-and-reading-cookies-with-javascript/ 11 var Cookie = { 12 set: function (name, value, days) { 13 var expires; 14 if (days) { 15 var date = new Date(); 16 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 17 expires = "; expires=" + date.toGMTString(); 18 } 19 else { 20 expires = ""; 21 } 22 23 document.cookie = name + "=" + value + expires + "; path=/"; 24 }, 25 26 get: function (name) { 27 var nameEQ = name + "="; 28 var ca = document.cookie.split(';'); 29 for (var i = 0; i < ca.length; i++) { 30 var c = ca[i]; 31 while (c.charAt(0) === ' ') { 32 c = c.substring(1, c.length); 33 } 34 if (c.indexOf(nameEQ) === 0) { 35 return c.substring(nameEQ.length, c.length); 36 } 37 } 38 39 return null; 40 } 41 }; 42 43 var util = { 44 merge: function () { 45 if (arguments.length === 0) { 46 return {}; 47 } 48 49 var result = arguments[0], 50 obj, prop; 51 52 for (var i = 1; i < arguments.length; i++) { 53 obj = arguments[i]; 54 55 for (prop in obj) { 56 if (obj.hasOwnProperty(prop)) { 57 result[prop] = obj[prop]; 58 } 59 } 60 } 61 62 return result; 63 }, 64 65 featureDetect: (function () { 66 // most tests come from to modernizr (MIT license) 67 // https://github.com/Modernizr/Modernizr/tree/master/feature-detects 68 var tests = { 69 localStorage: function () { 70 var v = 'test'; 71 72 try { 73 localStorage.setItem(v, v); 74 localStorage.removeItem(v); 75 76 return true; 77 } catch (e) { 78 return false; 79 } 80 }, 81 82 sessionStorage: function () { 83 var v = 'test'; 84 85 try { 86 sessionStorage.setItem(v, v); 87 sessionStorage.removeItem(v); 88 89 return true; 90 } catch (e) { 91 return false; 92 } 93 }, 94 95 json: function () { 96 return 'JSON' in window && 'parse' in JSON && 'stringify' in JSON; 97 }, 98 99 geolocation: function () { 100 return 'geolocation' in navigator; 101 } 102 }; 103 104 var results = {}; 105 106 return function (type) { 107 if ('undefined' === typeof tests[type]) { 108 throw new Error('Test ' + type + ' is not defined'); 109 } 110 111 if ('undefined' === typeof results[type]) { 112 results[type] = tests[type].call(); 113 } 114 115 return results[type]; 116 }; 117 }()), 118 119 logger: { 120 canLog: function (type) { 121 if (!_ptg.options.log) { 122 return false; 123 } 124 125 if ('undefined' === typeof type) { 126 type = 'log'; 127 } 128 129 return ('undefined' !== typeof window.console && 'function' === typeof window.console[type]); 130 } 131 }, 132 133 listen: function (elem, evnt, func) { 134 if (elem.addEventListener) { // W3C DOM 135 elem.addEventListener(evnt, func, false); 136 } else if (elem.attachEvent) { // IE DOM 137 return elem.attachEvent("on" + evnt, func); 138 } 139 }, 140 141 contentLoaded: function (win, fn) { 142 var done = false, top = true, 143 144 doc = win.document, root = doc.documentElement, 145 146 add = doc.addEventListener ? 'addEventListener' : 'attachEvent', 147 rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent', 148 pre = doc.addEventListener ? '' : 'on', 149 150 init = function (e) { 151 if (e.type === 'readystatechange' && doc.readyState !== 'complete') { 152 return; 153 } 154 (e.type === 'load' ? win : doc)[rem](pre + e.type, init, false); 155 if (!done && (done = true)) { 156 fn.call(win, e.type || e); 157 } 158 }, 159 160 poll = function () { 161 try { 162 root.doScroll('left'); 163 } catch (e) { 164 setTimeout(poll, 50); 165 return; 166 } 167 init('poll'); 168 }; 169 170 if (doc.readyState === 'complete') { 171 fn.call(win, 'lazy'); 172 } else { 173 if (doc.createEventObject && root.doScroll) { 174 try { 175 top = !win.frameElement; 176 } catch (e) { 177 } 178 if (top) { 179 poll(); 180 } 181 } 182 doc[add](pre + 'DOMContentLoaded', init, false); 183 doc[add](pre + 'readystatechange', init, false); 184 win[add](pre + 'load', init, false); 185 } 186 } 187 }; 188 189 var User = (function () { 190 var generateVisitorId = function (length) { 191 var chars = '0123456789abcdef'; 192 193 var result = ''; 194 for (var i = length; i > 0; --i) { 195 result += chars[Math.floor(Math.random() * chars.length)]; 196 } 197 198 return result; 199 }; 200 201 var User = function () { 202 this.data = { 203 sessionId: null, 204 visitorId: null, 205 visitorIds: [], 206 activityLog: [] 207 }; 208 209 this.load(); 210 211 if (!this.data.visitorId) { 212 this.setVisitorId(generateVisitorId(16)); 213 this.save(); 214 } 215 }; 216 217 User.prototype.setVisitorId = function (id) { 218 if (!id) { 219 return; 220 } 221 222 if (this.data.visitorId) { 223 // don't do anything if ID is already set 224 if (id === this.data.visitorId) { 225 return; 226 } else { 227 // store last visitor ID in list 228 this.data.visitorIds.push(this.data.visitorId); 229 } 230 } 231 232 util.logger.canLog('info') && console.info('[TARGETING] Setting visitor ID to', id); 233 234 this.data.visitorId = id; 235 }; 236 237 User.prototype.addActivityLog = function (data) { 238 data.sessionId = this.data.sessionId; 239 data.visitorId = this.data.visitorId; 240 data.timestamp = (new Date()).getTime(); 241 242 util.logger.canLog('info') && console.info('[TARGETING] Track activity', data, this); 243 244 this.data.activityLog.push(data); 245 246 return this; 247 }; 248 249 User.prototype.load = function () { 250 var data = {}; 251 252 if (util.featureDetect('localStorage')) { 253 var storedData = localStorage.getItem("_ptg.user"); 254 data = JSON.parse(storedData); 255 } 256 257 if (data) { 258 for (var key in data) { 259 if (data.hasOwnProperty(key)) { 260 this.data[key] = data[key]; 261 } 262 } 263 } 264 265 var cookieVisitorId = Cookie.get(cookieNames.visitorId); 266 if (cookieVisitorId) { 267 this.setVisitorId(cookieVisitorId); 268 } 269 270 // check / generate sessionId 271 var nowTimestamp = (new Date()).getTime(); 272 273 if (0 === this.data.activityLog.length) { 274 this.data.sessionId = nowTimestamp; 275 util.logger.canLog('info') && console.info("[TARGETING] No previous activity. New sessionId: " + this.data.sessionId); 276 } else { 277 var lastActivity = this.data.activityLog.slice(-1)[0]; 278 279 var sessionLength = _ptg.options.sessionLength; 280 if (!sessionLength) { 281 sessionLength = 30; 282 } 283 284 if (lastActivity.timestamp < (nowTimestamp - (sessionLength * 60 * 1000))) { 285 this.data.sessionId = nowTimestamp; // session expired 286 util.logger.canLog('info') && console.info("[TARGETING] Previous session expired. New sessionId: " + this.data.sessionId); 287 } else { 288 this.data.sessionId = lastActivity.sessionId; 289 util.logger.canLog('info') && console.info("[TARGETING] SessionId present: " + this.data.sessionId); 290 } 291 } 292 }; 293 294 User.prototype.save = function () { 295 if (util.featureDetect('localStorage')) { 296 localStorage.setItem("_ptg.user", JSON.stringify(this.data)); 297 } 298 299 // set visitor ID cookie 300 if (this.data.visitorId) { 301 Cookie.set(cookieNames.visitorId, this.data.visitorId, 365); 302 } 303 304 // set session ID cookie 305 if (this.data.sessionId) { 306 Cookie.set(cookieNames.sessionId, this.data.sessionId); 307 } 308 309 // set cookie with last 10 visitor IDs 310 if (this.data.visitorIds.length > 0) { 311 Cookie.set(cookieNames.visitorIdHistory, this.data.visitorIds.slice(-5), 365); 312 } 313 }; 314 315 return User; 316 }()); 317 318 var dataProviders = { 319 geolocation: function () { 320 util.logger.canLog('info') && console.info('[TARGETING] Loading geolocation'); 321 322 if (!util.featureDetect('geolocation') || !util.featureDetect('json') || !util.featureDetect('sessionStorage')) { 323 return; 324 } 325 326 var cookieName = '_pc_tgl'; 327 328 var location; 329 if (location = sessionStorage.getItem(cookieName)) { 330 Cookie.set(cookieName, location); 331 } else { 332 navigator.geolocation.getCurrentPosition(function (position) { 333 var serialized = JSON.stringify({ 334 lat: position.coords.latitude, 335 long: position.coords.longitude, 336 alt: position.coords.altitude 337 }); 338 339 Cookie.set(cookieName, serialized); 340 sessionStorage.setItem(cookieName, serialized); // store to session storage for further usage 341 }, function (error) { 342 util.logger.canLog('error') && console.error('[TARGETING] Failed to load geolocation', error); 343 }); 344 } 345 } 346 }; 347 348 _ptg.options = util.merge({ 349 log: false, 350 sessionLength: 30 351 }, _ptg.options || {}); 352 353 // merge core data providers with custom ones 354 _ptg.dataProviders = util.merge(dataProviders, _ptg.dataProviders || {}); 355 356 var user = new User(); 357 358 _ptg.api = { 359 setVisitorId: function (id) { 360 user.setVisitorId(id); 361 user.save(); 362 } 363 }; 364 365 (function () { 366 if (_ptg.dataProviderKeys && _ptg.dataProviderKeys.length > 0) { 367 for (var dp = 0; dp < _ptg.dataProviderKeys.length; dp++) { 368 if (_ptg.dataProviders.hasOwnProperty(_ptg.dataProviderKeys[dp])) { 369 util.logger.canLog('info') && console.info("[TARGETING] Loading data from provider " + _ptg.dataProviderKeys[dp]); 370 _ptg.dataProviders[_ptg.dataProviderKeys[dp]].apply(this); 371 } 372 } 373 } 374 }()); 375 376 util.contentLoaded(window, function () { 377 // track page views 378 user.addActivityLog({ 379 type: "pageView", 380 url: location.href 381 }).save(); 382 383 // track links 384 try { 385 var linkElements = document.querySelectorAll("a"); 386 var linkClickHandler = function (ev) { 387 var el = ev.target ? ev.target : ev.srcElement; 388 var href = el.getAttribute("href"); 389 390 if (href) { 391 user.addActivityLog({ 392 type: "linkClicked", 393 href: href 394 }).save(); 395 } 396 }; 397 398 for (var le = 0; le < linkElements.length; le++) { 399 util.listen(linkElements[le], "click", linkClickHandler); 400 } 401 } catch (e) { 402 util.logger.canLog('error') && console.error(e); 403 } 404 }); 405}());
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.