1class Etracker { 2 static URL = "/etracker/"; 3 static N_SESSION_ID = "etr_sid"; 4 static N_USER_HASH = "etr_uh"; 5 static N_LAST_ACTION_TIME = "etr_at"; 6 static N_TRAFFIC_SOURCE = "etr_trs"; 7 static N_UTM = "etr_utm"; 8 static N_DEBUG = "etr_debug"; 9 10 static sendFetch(data, command = 'run') { 11 return fetch(`${Etracker.URL}?ajax=${command}`, { 12 method : "POST", 13 body : JSON.stringify({ 14 data : data, 15 }), 16 credentials: 'include' 17 }).then(response => { 18 if (response.status >= 400) { 19 return Promise.reject(new Error(`${response.url}, ${response.status}`)); 20 } 21 return response.json().then(json => json); 22 }).then(json => { 23 if (localStorage.getItem(Etracker.N_DEBUG)) { 24 console.log('Etracker sendFetch', json); 25 } 26 return json; 27 }).catch(err => { 28 console.error('Etracker sendFetch error', err); 29 return Promise.reject(new Error(err)); 30 }); 31 } 32 33 static sendXHR(data, command = 'run', onready = null) { 34 const xhr = new XMLHttpRequest(); 35 xhr.onreadystatechange = function() { 36 if (xhr.readyState == XMLHttpRequest.DONE) { 37 const response = JSON.parse(xhr.responseText); 38 if (localStorage.getItem(Etracker.N_DEBUG)) { 39 console.log('Etracker sendXHR', response); 40 } 41 if (response.data.last_action_time) { 42 localStorage.setItem(Etracker.N_LAST_ACTION_TIME, response.data.last_action_time); 43 } 44 if (typeof onready === "function") { 45 return onready(response); 46 } 47 return true; 48 } 49 } 50 xhr.timeout = 5000; 51 xhr.open("POST", `${Etracker.URL}?ajax=${command}`); 52 xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); 53 xhr.send(JSON.stringify({ 54 data : data, 55 })); 56 } 57 58 static send(data, httpAPI = "xhr", command = 'run', onready = null) { 59 data = Object.assign({ 60 timestamp_ms: Date.now(), 61 }, this.readEtrackerData(), data); 62 63 let response = null; 64 switch (httpAPI) { 65 case "xhr": 66 response = this.sendXHR(data, command, onready); 67 break; 68 case "fetch": 69 response = this.sendFetch(data, command); 70 break; 71 default: 72 console.error(`Etracker. Unknown http API ${httpAPI}`); 73 } 74 return response; 75 } 76 77 static sessionWithDefault(data = {}) { 78 return Object.assign({ 79 topic: "sessions", 80 version: this.getDeviceType(), 81 timestamp_ms: Date.now(), 82 }, data); 83 } 84 85 static sendSession(data, httpAPI = "xhr") { 86 return this.send(this.sessionWithDefault(data), httpAPI); 87 } 88 89 static sendEvent(data, httpAPI = "xhr") { 90 data = Object.assign({ 91 topic: "events", 92 page_url: window.location.href, 93 page_type: this.getPageType() 94 }, data); 95 96 return this.send(data, httpAPI); 97 } 98 99 static sendPageview(data, httpAPI = "xhr") { 100 data = Object.assign({ 101 topic: "pageviews", 102 page_url: window.location.href, 103 page_type: this.getPageType(), 104 ab_tests: this.getABTests() 105 }, data); 106 107 return this.send(data, httpAPI); 108 } 109 110 static getCurrentTimestamp() { 111 return Math.floor(Date.now() / 1000); 112 } 113 114 static getPageType() { 115 if (typeof definePageType === "function") { 116 return definePageType(); 117 } 118 return 'other'; 119 } 120 121 static getDeviceType() { 122 let isMobile = false; 123 (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|
123sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) isMobile = true;})(navigator.userAgent||navigator.vendor||window.opera); 124 return isMobile ? 'mobile' : 'desktop'; 125 } 126 127 static getABTests() { 128 const abtests = []; 129 130 const cookies = Etracker.cookiesGetAll(); 131 for (const key in cookies) { 132 if (key.includes('ab_test_')) { 133 abtests.push({ ab_test_id: key.replace('ab_test_', ''), ab_test_value: cookies[key] }); 134 } 135 } 136 137 return abtests.length > 0 ? JSON.stringify(abtests) : null; 138 } 139 140 /* Cookies BEGIN */ 141 static cookiesGetOne(name) { 142 const matches = document.cookie.match(new RegExp( 143 "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)" 144 )); 145 return matches ? decodeURIComponent(matches[1]) : false; 146 } 147 148 static cookiesGetAll() { 149 const cookies = {}; 150 151 document.cookie.split('; ').forEach(function (cookie) { 152 const cookieMap = cookie.split('='); 153 cookies[cookieMap[0]] = cookieMap[1]; 154 }); 155 156 return cookies; 157 } 158 159 static cookiesSet(name, value, options = {}) { 160 let expires = options.expires || 24*60*60; 161 162 if (typeof expires === "number" && expires) { 163 const d = new Date(); 164 d.setTime(d.getTime() + expires * 1000); 165 expires = options.expires = d; 166 } 167 168 if (expires && expires.toUTCString) { 169 options.expires = expires.toUTCString(); 170 } 171 172 if (!options.domain) { 173 options.domain = window.location.host; 174 } 175 176 value = encodeURIComponent(value); 177 178 let updatedCookie = name + "=" + value; 179 180 for (const propName in options) { 181 updatedCookie += "; " + propName; 182 const propValue = options[propName]; 183 if (propValue !== true) { 184 updatedCookie += "=" + propValue; 185 } 186 } 187 188 document.cookie = updatedCookie; 189 } 190 191 static cookiesDelete(name, options = {}) { 192 options.expires = -1; 193 Etracker.cookiesSet(name, "", options); 194 } 195 /* Cookies END */ 196 197 static start(data = {}, onready = null) { 198 const url = new URL(window.location.href); 199 url.searchParams.forEach((value, key) => { 200 if (value) { 201 data[key] = value; 202 } 203 }); 204 data.traffic_source = document.referrer || null; 205 206 return this.send(this.sessionWithDefault(data), "xhr", "start", onready) 207 } 208 209 static readEtrackerData() { 210 return { 211 session_id: localStorage.getItem(this.N_SESSION_ID), 212 user_hash: localStorage.getItem(this.N_USER_HASH), 213 last_action_time: localStorage.getItem(this.N_LAST_ACTION_TIME) || 0, 214 }; 215 } 216 217 static writeEtrackerData(data) { 218 if (data.session_id) { 219 localStorage.setItem(this.N_SESSION_ID, data.session_id); 220 } else if (data.id) { 221 localStorage.setItem(this.N_SESSION_ID, data.id); 222 } 223 224 if (data.user_hash) { 225 localStorage.setItem(this.N_USER_HASH, data.user_hash); 226 } 227 228 if (data.last_action_time) { 229 localStorage.setItem(this.N_LAST_ACTION_TIME, data.last_action_time); 230 } 231 } 232}
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.