Last active
March 20, 2020 06:16
-
-
Save zhangmx/0927215b4cb4dc3ee1d8ddc81af2a3a3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
//统计请求的地址 | |
var iAnalyseBaseURL = 'www.google-analytics.com'; | |
//脚本加载的地址 | |
var iScriptBaseURL = 'www.google-analytics.com'; | |
//Ad脚本地址 | |
var iAdBaseURL = 'stats.g.doubleclick.net'; | |
//Inpage 脚本地址 | |
var iInpageURL = 'https://www.google.com/analytics/web/inpage/pub/inpage.js?'; | |
//GTM 地址 | |
/** | |
* 获取GA请求源的地址 | |
* | |
* 统计代码的地址 | |
* | |
* | |
* | |
*/ | |
var getGAOriginUrl = function () { | |
//TODO change URL | |
return (forceHTTPS || isHTTPS() ? "https:" : "http:") + "//" + iAnalyseBaseURL | |
}; | |
/** | |
* 记录方法使用情况的类 | |
* @param {Array.<boolean>} umMap 初始的使用情况 | |
*/ | |
var UsageManager = function (umMap) { | |
this.w = umMap || [] | |
}; | |
/** | |
* 记录新的使用情况 | |
* @param {number} idx 特殊代码,指定某一种方法或情形的被调用或触发 | |
*/ | |
UsageManager.prototype.set = function (idx) { | |
this.w[idx] = !0 | |
}; | |
/** | |
* 生成代表使用情况的字符串传给后端 | |
* @return {string} | |
*/ | |
UsageManager.prototype.encode = function () { | |
for (var a = [], b = 0; b < this.w.length; b++) | |
this.w[b] && (a[Math.floor(b / 6)] ^= 1 << b % 6); | |
for (b = 0; b < a.length; b++) | |
a[b] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".charAt(a[b] || 0); | |
return a.join("") + "~" | |
}; | |
/** | |
* 解码的函数,是mmzhou所写,非GA源码 | |
* @param {string} um | |
* @return {Array.<number>} | |
*/ | |
//$c.prototype.decode = function(um) { | |
// um = um.slice(0, -1); | |
// var key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; | |
// var code; | |
// var binaryCode; | |
// var reversedbinaryCode; | |
// var codes = []; | |
// for (var i = 0; i < um.length; i++) { | |
// code = key.indexOf(um.charAt(i)); | |
// binaryCode = code.toString(2); | |
// reversedbinaryCode = binaryCode.split('').reverse(); | |
// // console.log(i + '=' + code + '=' + binaryCode + '=reverse(' + reversedbinaryCode + ')'); | |
// for (var j = 0; j < reversedbinaryCode.length; j++) { | |
// if (reversedbinaryCode[j] === '1') { | |
// codes.push(j + 6 * i); | |
// } | |
// } | |
// } | |
// return codes; | |
//}; | |
/** | |
* 全局的记录方法使用情况的对象 | |
*/ | |
var globalUM = new UsageManager; | |
/** | |
* 快捷的记录使用情况的方法 | |
* @return {string} | |
*/ | |
function reg(num) { | |
globalUM.set(num) | |
} | |
/** | |
* 更新传入配置的 USAGE_MANAGER | |
*/ | |
var setModelUM = function (model, idx) { | |
var um = new UsageManager(getCurUM(model)); | |
um.set(idx); | |
model.set(USAGE_MANAGER, um.w) | |
}; | |
/** | |
* 获取指定model里面的 USAGE_MANAGER 值,然后和全局的 globalUM 合并,然后encode | |
* @return {string} | |
*/ | |
var mergeAndEncodeUM = function (model) { | |
var umArray = getCurUM(model); | |
var modelUM = new UsageManager(umArray); | |
for (var globalUMCopy = globalUM.w.slice(), i = 0; i < modelUM.w.length; i++) | |
globalUMCopy[i] = globalUMCopy[i] || modelUM.w[i]; | |
return (new UsageManager(globalUMCopy)).encode() | |
}; | |
/** | |
* 获取配置中的USAGE_MANAGER,如果没有则返回空数组 | |
*/ | |
var getCurUM = function (model) { | |
var umArray = model.get(USAGE_MANAGER); | |
isArray(umArray) || (umArray = []); | |
return umArray | |
}; | |
/** | |
* isFunction | |
* */ | |
var isFunction = function (tarIsFunction) { | |
return "function" == typeof tarIsFunction | |
}; | |
/** | |
* isArray | |
*/ | |
var isArray = function (ar) { | |
return "[object Array]" == Object.prototype.toString.call(Object(ar)) | |
}; | |
/** | |
* isString | |
*/ | |
var isString = function (tarIsString) { | |
return void 0 != tarIsString && -1 < (tarIsString.constructor + "").indexOf("String") | |
}; | |
/** | |
* startWith | |
* | |
* @return {boolean} | |
*/ | |
var startWith = function (str, tar) { | |
return 0 == str.indexOf(tar) | |
}; | |
/** | |
* filter a with space trim | |
*/ | |
var trim = function (str) { | |
return str ? str.replace(/^[\s\xa0]+|[\s\xa0]+$/g, "") : "" | |
}; | |
/** | |
* create 1*1 img createImg | |
*/ | |
var createImg = function (imgLink) { | |
var b = idoc.createElement("img"); | |
b.width = 1; | |
b.height = 1; | |
b.src = imgLink; | |
return b | |
}; | |
/** | |
* empty function | |
* emptyFunction | |
*/ | |
var emptyFunction = function () { | |
}; | |
/** | |
* | |
* Encodes a text string as a valid component of a Uniform Resource Identifier (URI). | |
* | |
* iEncodeURIComponent | |
* | |
*/ | |
var iEncodeURIComponent = function (uri) { | |
if (encodeURIComponent instanceof Function) | |
return encodeURIComponent(uri); | |
reg(28); | |
return uri | |
}; | |
/** | |
* 为a添加一个b事件的c方法回调 | |
* | |
* iAddEventListener | |
* | |
*/ | |
var iAddEventListener = function (element, eName, callback, d) { | |
try { | |
element.addEventListener ? element.addEventListener(eName, callback, !!d) : element.attachEvent && element.attachEvent("on" + eName, callback) | |
} catch (e) { | |
reg(27) | |
} | |
}; | |
/** | |
* reg | |
*/ | |
var f = /^[\w\-:/.?=&%!]+$/; | |
/** | |
* 创建一个脚本在页面上 g.js | |
* | |
* loadScript | |
* url,id,script | |
*/ | |
var loadScript = function (url, id, c) { | |
url && (c ? | |
( | |
c = "", | |
id && f.test(id) && (c = ' id="' + id + '"'), | |
f.test(url) && idoc.write("<script" + c + ' src="' + url + '">\x3c/script>') | |
) : | |
( | |
c = idoc.createElement("script"), | |
c.type = "text/javascript", | |
c.async = !0, | |
c.src = url, | |
id && (c.id = id), | |
url = idoc.getElementsByTagName("script")[0], | |
url.parentNode.insertBefore(c, url) | |
) | |
) | |
}; | |
/** | |
* check protocol is or not https | |
* | |
* isHTTPS | |
*/ | |
var isHTTPS = function () { | |
return "https:" == idoc.location.protocol | |
}; | |
/** | |
* 返回url中name参数对应的值 | |
* @param url | |
* @param name | |
* @returns {string} | |
*/ | |
var getUrlParamVal = function (url, name) { | |
var matched = url.match("(?:&|#|\\?)" + iEncodeURIComponent(name).replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1") + "=([^&#]*)"); | |
return matched && 2 == matched.length ? matched[1] : "" | |
}; | |
/** | |
* 不带 www的域名 | |
* getHostname | |
*/ | |
var getHostName = function () { | |
var a = "" + idoc.location.hostname; | |
return 0 == a.indexOf("www.") ? a.substring(4) : a | |
}; | |
/** | |
* get referrer page | |
* | |
* getReferrer | |
*/ | |
var getReferrer = function (a) { | |
var b = idoc.referrer; | |
if (/^https?:\/\//i.test(b)) { | |
if (a) | |
return b; | |
a = "//" + idoc.location.hostname; | |
var c = b.indexOf(a); | |
if (5 == c || 6 == c) | |
if (a = b.charAt(c + a.length), | |
"/" == a || "?" == a || "" == a || ":" == a) | |
return; | |
return b | |
} | |
}; | |
/** | |
* 这个函数用于将其他函数的输入转换成一个对象,这个规则适用于GA所有对外的接口API | |
* transformInput(['a', 'b', 'c'], [1, 2, 3]); | |
* ==> {a: 1, b: 2, c: 3} | |
* transformInput(['a', 'b', 'c'], [1, 2, {c: 3, d: 4}]); | |
* ==> {a: 1, b: 2, c: 3, d: 4} | |
* | |
* transformInput | |
* | |
* paramNames, args | |
*/ | |
var transformInput = function (paramNames, args) { | |
if (1 == args.length && null != args[0] && "object" === typeof args[0]) | |
return args[0]; | |
for (var obj = {}, d = Math.min(paramNames.length + 1, args.length), i = 0; i < d; i++) | |
if ("object" === typeof args[i]) { | |
for (var arg in args[i]) | |
args[i].hasOwnProperty(arg) && (obj[arg] = args[i][arg]); | |
break | |
} else | |
i < paramNames.length && (obj[paramNames[i]] = args[i]); | |
return obj | |
}; | |
/** | |
* MAP 数据类,被模型类所使用 | |
*/ | |
var iMAP = function () { | |
this.keys = []; | |
this.values = {}; | |
this.m = {} | |
}; | |
iMAP.prototype.set = function (key, val, isFunc) { | |
this.keys.push(key); | |
isFunc ? this.m[":" + key] = val : this.values[":" + key] = val | |
}; | |
iMAP.prototype.get = function (key) { | |
return this.m.hasOwnProperty(":" + key) ? this.m[":" + key] : this.values[":" + key] | |
}; | |
iMAP.prototype.map = function (callback) { | |
for (var i = 0; i < this.keys.length; i++) { | |
var key = this.keys[i] | |
, val = this.get(key); | |
val && callback(key, val) | |
} | |
}; | |
var iwin = window | |
, idoc = document; | |
var fwin = window; | |
/** | |
* window 中的 ga-disable- 前缀的变量 | |
* Google 开发了一系列插件,安装后可以关掉GA的追踪 | |
* 这里就是获取这些插件的配置,如果开启了,这个函数返回false | |
* https://tools.google.com/dlpage/gaoptout | |
*/ | |
var checkGaUserPrefs = function (plugin) { | |
var gaUserPref = fwin._gaUserPrefs; | |
if (gaUserPref && gaUserPref.ioo && gaUserPref.ioo() || plugin && !0 === fwin["ga-disable-" + plugin]) | |
return !0; | |
try { | |
var c = fwin.external; | |
if (c && c._gaUserPrefs && "oo" == c._gaUserPrefs) | |
return !0 | |
} catch (d) { | |
} | |
return !1 | |
}; | |
/** | |
* 从google的cookie中取内容 | |
* | |
* 获取指定名字的cookie | |
* 返回的是一个数组 | |
*/ | |
var getCookie = function (key) { | |
var cookie = [] | |
, cookies = idoc.cookie.split(";"); | |
var keyReg = new RegExp("^\\s*" + key + "=\\s*(.*?)\\s*$"); | |
for (var i = 0; i < cookies.length; i++) { | |
var e = cookies[i].match(keyReg); | |
e && cookie.push(e[1]) | |
} | |
return cookie | |
}; | |
/** | |
* set cookie | |
* | |
* cookieName, cookieValue, cookiePath, cookieDomain, trackingId, cookieExpires | |
* | |
* 返回成功与否 | |
*/ | |
var setCookie = function (cookieName, cookieValue, cookiePath, cookieDomain, trackingId, cookieExpires) { | |
// 如果用户安装了google的禁止统计的插件,或者在doubleclick页面,或者在google首页 | |
// 那么都是false | |
trackingId = checkGaUserPrefs(trackingId) ? !1 : doubleclickURLreg.test(idoc.location.hostname) || "/" == cookiePath && googleURLreg.test(cookieDomain) ? !1 : !0; | |
if (!trackingId) | |
return !1; | |
cookieValue && 1200 < cookieValue.length && (cookieValue = cookieValue.substring(0, 1200), | |
reg(24)); | |
cookiePath = cookieName + "=" + cookieValue + "; path=" + cookiePath + "; "; | |
cookieExpires && (cookiePath += "expires=" + (new Date((new Date).getTime() + cookieExpires)).toGMTString() + "; "); | |
cookieDomain && "none" != cookieDomain && (cookiePath += "domain=" + cookieDomain + ";"); | |
cookieDomain = idoc.cookie; | |
idoc.cookie = cookiePath; | |
if (!(cookieDomain = cookieDomain != idoc.cookie)) | |
a: { | |
cookieName = getCookie(cookieName); | |
for (cookieDomain = 0; cookieDomain < cookieName.length; cookieDomain++) | |
if (cookieValue == cookieName[cookieDomain]) { | |
cookieDomain = !0; | |
break a | |
} | |
cookieDomain = !1 | |
} | |
return cookieDomain | |
}; | |
/** | |
* 将a中的内容的 ()转义成 URI 格式 | |
* | |
*/ | |
var encodeURIComponentWithBrackets = function (a) { | |
return iEncodeURIComponent(a).replace(/\(/g, "%28").replace(/\)/g, "%29") | |
}; | |
//googleURLreg | |
var googleURLreg = /^(www\.)?google(\.com?)?(\.[a-z]{2})?$/; | |
//doubleclickURLreg | |
var doubleclickURLreg = /(^|\.)doubleclick\.net$/i; | |
/** | |
* 请求长度过长的错误类 | |
*/ | |
var OverLengthError = function (a) { | |
this.name = "len"; | |
this.message = a + "-8192" | |
}; | |
/** | |
* 智能ga请求,依据请求的长度和浏览器特性来决定使用哪种请求方式 | |
* | |
* 发起 collection 请求 | |
*/ | |
var smartPing = function (a, b, c) { | |
c = c || emptyFunction; | |
if (2036 >= b.length) | |
imgPing(a, b, c); | |
else if (8192 >= b.length) | |
beaconPing(a, b, c) || xhrPing(a, b, c) || imgPing(a, b, c); | |
else | |
throw errorPing("len", b.length), | |
new OverLengthError(b.length); | |
}; | |
/** | |
* 设置 请求图片的回调方法 | |
*/ | |
var imgPing = function (imgBaseLink, paramstr, callback) { | |
var d = createImg(imgBaseLink + "?" + paramstr); | |
var rnd_id = "_img_" + Math.random(); | |
window[rnd_id] = d; | |
d.onload = d.onerror = function () { | |
d.onload = null; | |
d.onerror = null; | |
window[rnd_id] = null; | |
callback(); | |
} | |
}; | |
/** | |
* 使用跨域xhr来发请求 | |
* Post data by ajax | |
*/ | |
var xhrPing = function (url, data, callback) { | |
var d = iwin.XMLHttpRequest; | |
if (!d) | |
return !1; | |
var e = new d; | |
if (!("withCredentials" in e)) | |
return !1; | |
e.open("POST", url, !0); | |
e.withCredentials = !0; | |
e.setRequestHeader("Content-Type", "text/plain"); | |
e.onreadystatechange = function () { | |
4 == e.readyState && (callback(), | |
e = null ) | |
} | |
; | |
e.send(data); | |
return !0 | |
}; | |
/** | |
* 当图片的参数长度超过2036使用下面的方式发起请求 | |
* | |
* 使用sendBeacon方法来发请求 | |
* | |
* http://kaifage.com/notes/76/navigator-sendBeacon.html | |
*/ | |
var beaconPing = function (a, b, c) { | |
return iwin.navigator.sendBeacon ? iwin.navigator.sendBeacon(a, b) ? (c(), | |
!0) : !1 : !1 | |
}; | |
/** | |
* 如果统计信息发送失败,上报错误 | |
* | |
* errorType 为 len 或 exc | |
* len 表示请求长度超长 | |
* exc 表示内部执行出错 | |
* | |
*/ | |
var errorPing = function (errorType, method, detail) { | |
1 <= 100 * Math.random() || checkGaUserPrefs("?") || (errorType = ["t=error", "_e=" + errorType, "_v=j47", "sr=1"], | |
method && errorType.push("_f=" + method), | |
detail && errorType.push("_m=" + iEncodeURIComponent(detail.substring(0, 100))), | |
errorType.push("aip=1"), | |
errorType.push("z=" + _uuid()), | |
imgPing(getGAOriginUrl() + "/collect", errorType.join("&"), emptyFunction)) | |
}; | |
/** | |
* 返回 hitcount 点击统计 | |
* | |
*/ | |
var getHitCountFromBrowser = function (trackId) { | |
var collectedData = iwin.gaData = iwin.gaData || {}; | |
return collectedData[trackId] = collectedData[trackId] || {} | |
}; | |
/** | |
* 函数的名字队列类 | |
*/ | |
var Queue = function () { | |
this.M = [] | |
}; | |
Queue.prototype.add = function (name) { | |
this.M.push(name) | |
}; | |
/** | |
* | |
* 执行队列里面的名字指定的函数 | |
* 从model里面拿到名字对应的函数 | |
* 最后会执行hitCallback对应的函数 | |
* | |
* | |
* Queue.prototype.exec | |
* | |
* model | |
*/ | |
Queue.prototype.D = function (model) { | |
try { | |
for (var i = 0; i < this.M.length; i++) { | |
var c = model.get(this.M[i]); | |
c && isFunction(c) && c.call(iwin, model) | |
} | |
} catch (d) { | |
} | |
var hitCallback = model.get(HIT_CALLBACK); | |
hitCallback != emptyFunction && | |
isFunction(hitCallback) && | |
( | |
model.set(HIT_CALLBACK, emptyFunction, !0), | |
setTimeout(hitCallback, 10) | |
) | |
}; | |
/** | |
* 判断的是否进行ga的采样 | |
* | |
* samplerTaskFunc | |
* | |
*/ | |
function samplerTaskFunc(model) { | |
if (100 != model.get(SAMPLE_RATE) && str2Num(getAttrToStr(model, CLIENT_ID)) % 1E4 >= 100 * getAttrToInt(model, SAMPLE_RATE)) | |
throw "abort"; | |
} | |
/** | |
* isGAPrefsAllowed | |
*/ | |
function isGAPrefsAllowed(model) { | |
if (checkGaUserPrefs(getAttrToStr(model, TRACKING_ID))) | |
throw "abort"; | |
} | |
/** | |
* check url is not http request | |
* | |
* notHTTP | |
*/ | |
function checkProtocol() { | |
var pro = idoc.location.protocol; | |
if ("http:" != pro && "https:" != pro) | |
throw "abort"; | |
} | |
/** | |
* | |
* | |
* buildHitTaskFunc | |
* | |
* model | |
* | |
*/ | |
function buildHitTaskFunc(model) { | |
try { | |
iwin.navigator.sendBeacon ? reg(42) : iwin.XMLHttpRequest && "withCredentials" in new iwin.XMLHttpRequest && reg(40) | |
} catch (c) { | |
} | |
model.set(USAGE, mergeAndEncodeUM(model), !0); | |
model.set(_S, getAttrToInt(model, _S) + 1); | |
var b = []; | |
hookMap.map(function (c, hook) { | |
if (hook.F) { | |
var e = model.get(c); | |
// 不为空、不是默认值的键值对,才会被上传 // boolean类型转换成数字 | |
void 0 != e && e != hook.defaultValue && ("boolean" == typeof e && (e *= 1), | |
b.push(hook.F + "=" + iEncodeURIComponent("" + e))) | |
} | |
}); | |
b.push("z=" + uuid()); | |
model.set(HIT_PAYLOAD, b.join("&"), !0) | |
} | |
/** | |
* 发送任务的任务 | |
* | |
* | |
* sendHitTaskFunc(model) | |
*/ | |
function sendHitTaskFunc(model) { | |
var url = getAttrToStr(model, TRANSPORT_URL) || getGAOriginUrl() + "/collect" | |
, c = getAttrToStr(model, TRANSPORT); | |
!c && model.get(USE_BEACON) && (c = "beacon"); | |
if (c) { | |
var d = getAttrToStr(model, HIT_PAYLOAD) | |
, e = model.get(HIT_CALLBACK) | |
, e = e || emptyFunction; | |
"image" == c ? imgPing(url, d, e) : "xhr" == c && xhrPing(url, d, e) || "beacon" == c && beaconPing(url, d, e) || smartPing(url, d, e) | |
} else | |
smartPing(url, getAttrToStr(model, HIT_PAYLOAD), model.get(HIT_CALLBACK)); | |
// | |
var trackId = model.get(TRACKING_ID); | |
var gaBrowserData = getHitCountFromBrowser(trackId); | |
c = gaBrowserData.hitcount; | |
gaBrowserData.hitcount = c ? c + 1 : 1; | |
trackId = model.get(TRACKING_ID); | |
delete getHitCountFromBrowser(trackId).pending_experiments; | |
model.set(HIT_CALLBACK, emptyFunction, !0) | |
} | |
/** | |
* | |
* 从全局的 gaData 里面获取 expVar 和 expId 的值 | |
* | |
* ceTaskFunc(model) | |
*/ | |
function ceTaskFunc(model) { | |
(iwin.gaData = iwin.gaData || {}).expId && model.set(EXP_ID, (iwin.gaData = iwin.gaData || {}).expId); | |
(iwin.gaData = iwin.gaData || {}).expVar && model.set(EXP_VAR, (iwin.gaData = iwin.gaData || {}).expVar); | |
var b; | |
var c = model.get(TRACKING_ID); | |
if (c = getHitCountFromBrowser(c).pending_experiments) { | |
var d = []; | |
for (b in c) | |
c.hasOwnProperty(b) && c[b] && d.push(encodeURIComponent(b) + "." + encodeURIComponent(c[b])); | |
b = d.join("!") | |
} else | |
b = void 0; | |
b && model.set(EXPm, b, !0) | |
} | |
/** | |
* cd | |
* isPreviewLoad() | |
*/ | |
function isPreviewLoad() { | |
if (iwin.navigator && "preview" == iwin.navigator.loadPurpose) | |
throw "abort"; | |
} | |
/** | |
* 从全局的 gaDevIds 里面获取 did 的值 | |
* | |
* devIdTaskFunc(model) | |
*/ | |
function devIdTaskFunc(model) { | |
var devIds = iwin.gaDevIds; | |
isArray(devIds) && 0 != devIds.length && model.set("&did", devIds.join(","), !0) | |
} | |
/** | |
* | |
* 验证trackingId是否正确的任务 | |
* | |
* validationTaskFunc(model) | |
*/ | |
function validationTaskFunc(model) { | |
if (!model.get(TRACKING_ID)) | |
throw "abort"; | |
} | |
/** | |
* 基本的uuid方法 | |
* _uuid | |
*/ | |
var _uuid = function () { | |
return Math.round(2147483647 * Math.random()) | |
}; | |
/** | |
* 优先使用crypto API来生成uuid | |
* | |
* uuid | |
*/ | |
var uuid = function () { | |
try { | |
//an array of 32-bit unsigned integers in the platform byte order | |
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array | |
var ar = new Uint32Array(1); | |
iwin.crypto.getRandomValues(ar); | |
return ar[0] & 2147483647 | |
} catch (b) { | |
return _uuid() | |
} | |
}; | |
/** | |
* 这个 task 用于限制发送的频率 | |
* | |
* 每个 analytics.js 跟踪器对象从 20 次可发送额度开始,并以每秒 2 次额度的速度获得补充。适用于除电子商务(商品或交易)之外的所有匹配 | |
* rtlTaskFunc(model) | |
*/ | |
function rtlTaskFunc(model) { | |
// 当前页面的发送总数 | |
var b = getAttrToInt(model, HIT_COUNT); | |
// 超过500记录下 | |
500 <= b && reg(15); | |
var c = getAttrToStr(model, HIT_TYPE); | |
if ("transaction" != c && "item" != c) { | |
var c = getAttrToInt(model, AVAILABLE_COUNT) | |
, d = (new Date).getTime() | |
, e = getAttrToInt(model, LAST_SEND_TIME); | |
0 == e && model.set(LAST_SEND_TIME, d); | |
// 每秒 2 次额度的速度获得补充 | |
e = Math.round(2 * (d - e) / 1E3); | |
// 最多 20 次额度 | |
0 < e && (c = Math.min(c + e, 20), | |
model.set(LAST_SEND_TIME, d)); | |
// 额度用完,此次发送取消 | |
if (0 >= c) | |
throw "abort"; | |
// 每次发送消耗掉 | |
model.set(AVAILABLE_COUNT, --c) | |
} | |
model.set(HIT_COUNT, ++b) | |
} | |
/** | |
* 全局的Hook配置 | |
* 配置的值是Hook类的对象 | |
* | |
* hookMap | |
*/ | |
var hookMap = new iMAP; | |
// 有些配置的值的计算有特殊方法,这里存储计算规则 | |
// [/^contentGroup([0-9]+)$/, generateFunction] | |
// generateFunction输入是正则的exec执行结果,输出是Hook类的对象 | |
// 执行结果会被放到hookMap | |
// specialHooks | |
var specialHooks = []; | |
/** | |
* 模型类 | |
* https://developers.google.com/analytics/devguides/collection/analyticsjs/model-object-reference?hl=zh-cn | |
*/ | |
var iModel = function () { | |
this.data = new iMAP | |
}; | |
/** | |
* 获取模型中存储的一个字段值。 | |
*/ | |
iModel.prototype.get = function (key) { | |
var hook = getHook(key) | |
, c = this.data.get(key); | |
//// 如果没有则使用默认值 | |
hook && void 0 == c && (c = isFunction(hook.defaultValue) ? hook.defaultValue() : hook.defaultValue); | |
// 如果有getter,则使用getter来转换 | |
// hook && hook.getter ? hook.getter(this, fieldName, value) : value | |
return hook && hook.Z ? hook.Z(this, key, c) : c | |
}; | |
/** | |
* 在模型上设置一个或一组字段/值对 | |
* 可以传map进去 | |
* temporary 布尔值 默认为否。如果为 true,则在模型上仅对当前匹配设置值。 | |
* | |
* fieldName, fieldValue, temporary | |
*/ | |
iModel.prototype.set = function (fieldName, fieldValue, temporary) { | |
if (fieldName) | |
if ("object" == typeof fieldName) | |
for (var d in fieldName) | |
fieldName.hasOwnProperty(d) && _modelSet(this, d, fieldName[d], temporary); | |
else | |
_modelSet(this, fieldName, fieldValue, temporary) | |
}; | |
/** | |
* 讲数据模型对应的值初始化为字符串 | |
* | |
* @param model | |
* @param key | |
* @returns {string} | |
*/ | |
var getAttrToStr = function (model, key) { | |
var c = model.get(key); | |
return void 0 == c ? "" : "" + c | |
}; | |
/** | |
* 讲数据模型对应的值初始化为整数 | |
* | |
* @param model | |
* @param key | |
* @returns {int} | |
*/ | |
var getAttrToInt = function (model, key) { | |
var c = model.get(key); | |
return void 0 == c || "" === c ? 0 : 1 * c | |
}; | |
/** | |
* | |
* var _modelSet = function(model, fieldName, fieldValue, temporary) { | |
* | |
* | |
* | |
*/ | |
var _modelSet = function (model, fieldName, fieldValue, temporary) { | |
if (void 0 != fieldValue) | |
switch (fieldName) { | |
case TRACKING_ID: | |
gaClientIdReg.test(fieldValue) | |
} | |
var e = getHook(fieldName); | |
// 如果有特殊规则,则使用特定规则设置 // 否则设置到模型的data上 | |
e && e.o ? e.o(model, fieldName, fieldValue, temporary) : model.data.set(fieldName, fieldValue, temporary) | |
}; | |
/** | |
* Hook类 | |
* | |
* 设置指定字段相关的hook对象 | |
* | |
* | |
* var Hook = function(name, paramName, defaultValue, getter, setter) { | |
* | |
*/ | |
var Hook = function (name, paramName, defaultValue, getter, setter) { | |
this.name = name; // 字段名 | |
this.F = paramName;// F 字段的参数名(传给后端时候的参数名) | |
this.Z = getter;// Z 获取时候的hook函数 | |
this.o = setter;// o 设置时候的hook函数 | |
this.defaultValue = defaultValue; // 默认值 | |
}; | |
/** | |
* 获取hookMap中的配置,如果配置不存在,则使用specialHooks中的规则生成 | |
*/ | |
var getHook = function (fieldName) { | |
var value = hookMap.get(fieldName); | |
if (!value) | |
for (var i = 0; i < specialHooks.length; i++) { | |
var hook = specialHooks[i] | |
, e = hook[0].exec(fieldName); | |
if (e) { | |
value = hook[1](e); | |
// 生成结果会被放到hookMap中缓存下来 | |
hookMap.set(value.name, value); | |
break | |
} | |
} | |
return value | |
}; | |
/** | |
* | |
* @param key | |
* @returns {*} | |
*/ | |
var getHookFromGlobal = function (key) { | |
var hook; | |
hookMap.map(function (c, tarHook) { | |
tarHook.F == key && (hook = tarHook) | |
}); | |
return hook && hook.name | |
}; | |
/** | |
* 添加hook到hookMap的函数 | |
* | |
* | |
* var addHook = function(name, paramName, defaultValue, getter, setter) { | |
* | |
*/ | |
var S = function (name, paramName, defaultValue, getter, setter) { | |
var hook = new Hook(name, paramName, defaultValue, getter, setter); | |
hookMap.set(hook.name, hook); | |
return hook.name | |
}; | |
/** | |
* 把正则表达式 和目标 string 放入Za 数组 | |
*/ | |
var putHookToQ = function (regStr, callback) { | |
specialHooks.push([new RegExp("^" + regStr + "$"), callback]) | |
}; | |
/** | |
* 添加只读的hook到hookMap的函数 | |
*/ | |
var T = function (name, paramName, defaultValue) { | |
return S(name, paramName, defaultValue, void 0, emptyFunction2) | |
}; | |
/** | |
* 空方法 | |
*/ | |
var emptyFunction2 = function () { | |
}; | |
//GA_HOOK | |
var GA_HOOK = isString(window.GoogleAnalyticsObject) && trim(window.GoogleAnalyticsObject) || "ga" | |
, forceHTTPS = !1 //forceHTTPS | |
, API_VERSION = T("apiVersion", "v") //API_VERSION | |
, CLIENT_VERSION = T("clientVersion", "_v"); //CLIENT_VERSION | |
S("anonymizeIp", "aip"); | |
//const AD_SENSE_ID = addHook('adSenseId', 'a'); | |
var AD_SENSE_ID = S("adSenseId", "a") //AD_SENSE_ID | |
, HIT_TYPE = S("hitType", "t") //HIT_TYPE | |
, HIT_CALLBACK = S("hitCallback") //HIT_CALLBACK | |
, HIT_PAYLOAD = S("hitPayload"); //HIT_PAYLOAD | |
S("nonInteraction", "ni"); | |
S("currencyCode", "cu"); | |
S("dataSource", "ds"); | |
var USE_BEACON = S("useBeacon", void 0, !1) //USE_BEACON | |
, TRANSPORT = S("transport"); //TRANSPORT | |
S("sessionControl", "sc", ""); | |
S("sessionGroup", "sg"); | |
S("queueTime", "qt"); | |
var _S = S("_s", "_s"); | |
S("screenName", "cd"); | |
var LOCATION = S("location", "dl", "") //LOCATION | |
, REFERRER = S("referrer", "dr") //REFERRER | |
, PAGE = S("page", "dp", ""); //PAGE | |
S("hostname", "dh"); | |
var LANGUAGE = S("language", "ul") //LANGUAGE | |
, ENCODING = S("encoding", "de"); //ENCODING | |
S("title", "dt", function () { | |
return idoc.title || void 0 | |
}); | |
putHookToQ("contentGroup([0-9]+)", function (a) { | |
return new Hook(a[0], "cg" + a[1]) | |
}); | |
var SCREEN_COLORS = S("screenColors", "sd") //SCREEN_COLORS | |
, SCREEN_RESOLUTION = S("screenResolution", "sr") //SCREEN_RESOLUTION | |
, VIEWPORT_SIZE = S("viewportSize", "vp") //VIEWPORT_SIZE | |
, JAVA_ENABLED = S("javaEnabled", "je") //JAVA_ENABLED | |
, FLASH_VERSION = S("flashVersion", "fl"); //FLASH_VERSION | |
S("campaignId", "ci"); | |
S("campaignName", "cn"); | |
S("campaignSource", "cs"); | |
S("campaignMedium", "cm"); | |
S("campaignKeyword", "ck"); | |
S("campaignContent", "cc"); | |
// 事件相关字段 | |
var EVENT_CATEGORY = S("eventCategory", "ec") //EVENT_CATEGORY | |
, EVENT_ACTION = S("eventAction", "ea") //EVENT_ACTION | |
, EVENT_LABEL = S("eventLabel", "el") //EVENT_LABEL | |
, EVENT_VALUE = S("eventValue", "ev") //EVENT_VALUE | |
// 社交请求相关字段 | |
, SOCIAL_NETWORK = S("socialNetwork", "sn") //SOCIAL_NETWORK | |
, SOCIAL_ACTION = S("socialAction", "sa") //SOCIAL_ACTION | |
, SOCIAL_TARGET = S("socialTarget", "st") //SOCIAL_TARGET | |
, L1 = S("l1", "plt") | |
, L2 = S("l2", "pdt") | |
, L3 = S("l3", "dns") | |
, L4 = S("l4", "rrt") | |
, L5 = S("l5", "srt") | |
, L6 = S("l6", "tcp") | |
, L7 = S("l7", "dit") | |
, L8 = S("l8", "clt") | |
// 计时器相关字段 | |
, TIMING_CATEGORY = S("timingCategory", "utc") //TIMING_CATEGORY | |
, TIMING_VAR = S("timingVar", "utv") //TIMING_VAR | |
, TIMING_LABEL = S("timingLabel", "utl") //TIMING_LABEL | |
, TIMING_VALUE = S("timingValue", "utt"); //TIMING_VALUE | |
// 应用名称 | |
S("appName", "an"); | |
S("appVersion", "av", "");// 应用版本 | |
S("appId", "aid", "");// 应用名称 | |
S("appInstallerId", "aiid", "");// 应用安装程序 ID | |
S("exDescription", "exd");// 异常说明 | |
S("exFatal", "exf");// 异常是否严重? | |
// 实验 ID | |
var EXP_ID = S("expId", "xid") //EXP_ID | |
// 实验变体 | |
, EXP_VAR = S("expVar", "xvar")//EXP_VAR | |
, EXPm = S("exp", "exp") | |
, _UTMA = S("_utma", "_utma") //_UTMA | |
, _UTMZ = S("_utmz", "_utmz") //_UTMZ | |
, _UTMHT = S("_utmht", "_utmht") //_UTMHT | |
, HIT_COUNT = S("_hc", void 0, 0) //HIT_COUNT | |
, LAST_SEND_TIME = S("_ti", void 0, 0) //LAST_SEND_TIME | |
, AVAILABLE_COUNT = S("_to", void 0, 20); //AVAILABLE_COUNT | |
putHookToQ("dimension([0-9]+)", function (a) { | |
return new Hook(a[0], "cd" + a[1]) | |
}); | |
putHookToQ("metric([0-9]+)", function (a) { | |
return new Hook(a[0], "cm" + a[1]) | |
}); | |
S("linkerParam", void 0, void 0, linkerParamGetter, emptyFunction2); | |
var USAGE = S("usage", "_u") | |
var USAGE_MANAGER = S("_um"); | |
S("forceSSL", void 0, void 0, function () { | |
return forceHTTPS | |
}, function (a, b, c) { | |
reg(34); | |
forceHTTPS = !!c | |
}); | |
var JID = S("_j1", "jid"); | |
putHookToQ("\\&(.*)", function (a) { | |
var hook = new Hook(a[0], a[1]) | |
, c = getHookFromGlobal(a[0].substring(1)); | |
c && ( | |
hook.Z = function (a) { | |
return a.get(c) | |
} | |
, | |
hook.o = function (model, b, g, ca) { | |
model.set(c, g, ca) | |
} | |
, | |
hook.F = void 0); | |
return hook | |
}); | |
var _OOT = T("_oot") | |
, PREVIEW_TASK = S("previewTask") | |
, CHECK_PROTOCOL_TASK = S("checkProtocolTask") | |
, VALIDATION_TASK = S("validationTask") | |
, CHECK_STORAGE_TASK = S("checkStorageTask") | |
, HISTORY_IMPORT_TASK = S("historyImportTask") | |
, SAMPLER_TASK = S("samplerTask") | |
, _RLT = S("_rlt") | |
, BUILD_HIT_TASK = S("buildHitTask") | |
, SEND_HIT_TASK = S("sendHitTask") | |
, CE_TASK = S("ceTask") | |
, DEV_ID_TASK = S("devIdTask") | |
, TIMING_TASK = S("timingTask") | |
, DISPLAY_FEATURES_TASK = S("displayFeaturesTask") | |
, TRACKER_NAME = T("name")// 跟踪器名称 | |
, CLIENT_ID = T("clientId", "cid")// 客户端 ID | |
, CLIENT_ID_TIME = T("clientIdTime") | |
, USER_ID = S("userId", "uid")// 用户 ID | |
, TRACKING_ID = T("trackingId", "tid")// 跟踪 ID/网络媒体资源 ID | |
, COOKIE_NAME = T("cookieName", void 0, "_ga")// Cookie 名称 | |
, COOKIE_DOMAIN = T("cookieDomain")// Cookie 网域 | |
, COOKIE_PATH = T("cookiePath", void 0, "/") | |
, COOKIE_EXPIRES = T("cookieExpires", void 0, 63072E3)// 63072E3 单位为秒,时长两年 | |
, LEGACY_COOKIE_DOMAIN = T("legacyCookieDomain") // 旧版本的 | |
, LEGACY_HISTORY_IMPORT = T("legacyHistoryImport", void 0, !0) | |
, STORAGE = T("storage", void 0, "cookie") | |
, ALLOW_LINKER = T("allowLinker", void 0, !1) | |
, ALLOW_ANCHOR = T("allowAnchor", void 0, !0) | |
// 抽样率,指定应对多大比例的用户进行跟踪。默认值为100(跟踪所有用户),但是大型网站可能需要降低抽样率,以免超出Google Analytics(分析)的处理上限。 | |
, SAMPLE_RATE = T("sampleRate", "sf", 100) | |
// 网站速度抽样率 | |
, SITE_SPEED_SAMPLE_RATE = T("siteSpeedSampleRate", void 0, 1) | |
, ALWAYS_SEND_REFERRER = T("alwaysSendReferrer", void 0, !1) | |
, TRANSPORT_URL = S("transportUrl") // 发送内容的目标URL | |
, _R = S("_r", "_r"); | |
/** | |
* 包裹一下指定的API函数 | |
* 每次执行都会记录一下idx | |
* 如果执行出错则发错误记录 | |
* | |
* function wrapApi(methodName, obj, method, idx) | |
*/ | |
function X(methodName, obj, method, idx) { | |
obj[methodName] = function () { | |
try { | |
return idx && reg(idx), | |
method.apply(this, arguments) | |
} catch (e) { | |
throw errorPing("exc", methodName, e && e.name), | |
e; | |
} | |
} | |
} | |
/** | |
* 这个对象未被引用到,但是是在计算网站速度频率的时候使用到的,感觉像一个锚点 | |
* | |
* | |
*/ | |
var SpeedAnchor = function (int_a) { | |
this.V = int_a; | |
this.fa = void 0; | |
this.$ = !1; | |
this.oa = void 0; | |
this.ea = 1 | |
}; | |
/** | |
* 这个地方感觉有bug fa变量一直没被别的地方用到 | |
* | |
* | |
* | |
* @return {number} | |
*/ | |
var workWithSpeedAnchor = function (sAnchor, model) { | |
var _uu; | |
if (sAnchor.fa && sAnchor.$) | |
return 0; | |
sAnchor.$ = !0; | |
if (model) { | |
if (sAnchor.oa && getAttrToInt(model, sAnchor.oa)) | |
return getAttrToInt(model, sAnchor.oa); | |
if (0 == model.get(SITE_SPEED_SAMPLE_RATE)) | |
return 0 | |
} | |
if (0 == sAnchor.V) | |
return 0; | |
void 0 === _uu && (_uu = uuid()); | |
return 0 == _uu % sAnchor.V ? Math.floor(_uu / sAnchor.V) % sAnchor.ea + 1 : 0 | |
}; | |
/** | |
* flash 版本 | |
*/ | |
function getFlashVersion() { | |
var a, b, c; | |
if ((c = (c = iwin.navigator) ? c.plugins : null ) && c.length) | |
for (var d = 0; d < c.length && !b; d++) { | |
var e = c[d]; | |
-1 < e.name.indexOf("Shockwave Flash") && (b = e.description) | |
} | |
if (!b) | |
try { | |
a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"), | |
b = a.GetVariable("$version") | |
} catch (g) { | |
} | |
if (!b) | |
try { | |
a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"), | |
b = "WIN 6,0,21,0", | |
a.AllowScriptAccess = "always", | |
b = a.GetVariable("$version") | |
} catch (g) { | |
} | |
if (!b) | |
try { | |
a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"), | |
b = a.GetVariable("$version") | |
} catch (g) { | |
} | |
b && (a = b.match(/[\d]+/g)) && 3 <= a.length && (b = a[0] + "." + a[1] + " r" + a[2]); | |
return b || void 0 | |
} | |
/** | |
* | |
* | |
*/ | |
var aa = function (model) { | |
var b = Math.min(getAttrToInt(model, SITE_SPEED_SAMPLE_RATE), 100); | |
return str2Num(getAttrToStr(model, CLIENT_ID)) % 100 >= b ? !1 : !0 | |
}; | |
/** | |
* 计算页面的加载性能 | |
* config 是配置 | |
* callback 是回调函数 | |
* | |
* var calTiming = function(config, callback) { | |
*/ | |
var calTiming = function (callback) { | |
var config = {}; | |
if (calPagePerf(config) || calLoadTime(config)) { | |
var c = config[L1]; | |
void 0 == c || Infinity == c || isNaN(c) || (0 < c ? (removeUselessValue(config, L3), | |
removeUselessValue(config, L6), | |
removeUselessValue(config, L5), | |
removeUselessValue(config, L2), | |
removeUselessValue(config, L4), | |
removeUselessValue(config, L7), | |
removeUselessValue(config, L8), | |
callback(config)) : iAddEventListener(iwin, "load", function () { | |
calTiming(callback) | |
}, !1)) | |
} | |
}; | |
/** | |
* 通过performance API来抓去加载时间等性能参数 | |
* | |
* | |
* | |
* var calPagePerf = function(config) { | |
*/ | |
var calPagePerf = function (config) { | |
var b = iwin.performance || iwin.webkitPerformance | |
, b = b && b.timing; | |
if (!b) | |
return !1; | |
var c = b.navigationStart; | |
if (0 == c) | |
return !1; | |
config[L1] = b.loadEventStart - c; | |
config[L3] = b.domainLookupEnd - b.domainLookupStart; | |
config[L6] = b.connectEnd - b.connectStart; | |
config[L5] = b.responseStart - b.requestStart; | |
config[L2] = b.responseEnd - b.responseStart; | |
config[L4] = b.fetchStart - c; | |
config[L7] = b.domInteractive - c; | |
config[L8] = b.domContentLoadedEventStart - c; | |
return !0 | |
}; | |
/** | |
* | |
* 抓去加载时间等参数 | |
* | |
* var calLoadTime = function(config) { | |
*/ | |
var calLoadTime = function (config) { | |
if (iwin.top != iwin) | |
return !1; | |
var b = iwin.external | |
, c = b && b.onloadT; | |
b && !b.isValidLoadTime && (c = void 0); | |
//// 2147483648 === 10000000000000000000000000000000 (32位) | |
2147483648 < c && (c = void 0); | |
0 < c && b.setPageReadyTime(); | |
if (void 0 == c) | |
return !1; | |
config[L1] = c; | |
return !0 | |
}; | |
/** | |
* 如果配置中没有这个参数的值是NaN或者无限大或者小于0,则设置为undefined | |
* | |
* var removeUselessValue = function(conf, key) | |
*/ | |
var removeUselessValue = function (configObj, key) { | |
var val = configObj[key]; | |
if (isNaN(val) || Infinity == val || 0 > val) | |
configObj[key] = void 0 | |
}; | |
/** | |
* 创建一个timing任务 | |
* | |
* var createTimingTask = function(tracker) | |
*/ | |
var createTimingTask = function (tracker) { | |
return function (b) { | |
if ("pageview" == b.get(HIT_TYPE) && !tracker.I) { | |
tracker.I = !0; | |
var c = aa(b); | |
b = 0 < getUrlParamVal(b.get(LOCATION), "gclid").length; | |
(c || b) && calTiming(function (b) { | |
tracker.send(c ? "timing" : "adtiming", b) | |
}) | |
} | |
} | |
}; | |
//gaCookieSetted | |
var gaCookieSetted = !1 ;// hc | |
/** | |
* 设置GA cookie | |
* | |
* var setGACookie = function(model) | |
*/ | |
var setGACookie = function (model) { | |
if ("cookie" == getAttrToStr(model, STORAGE)) { | |
var b = getAttrToStr(model, COOKIE_NAME) | |
, c = calGACookieValue(model) | |
, d = normalizePath(getAttrToStr(model, COOKIE_PATH)) | |
, e = normalizeDomain(getAttrToStr(model, COOKIE_DOMAIN)) | |
, g = 1E3 * getAttrToInt(model, COOKIE_EXPIRES) | |
, ca = getAttrToStr(model, TRACKING_ID); | |
if ("auto" != e) | |
setCookie(b, c, d, e, ca, g) && (gaCookieSetted = !0); | |
else { | |
reg(32); | |
var l; | |
a: { | |
c = []; | |
// => e.mp.qq.com | |
e = getHostName().split("."); | |
// => ['e', 'mp', 'qq', 'com'] | |
if (4 == e.length && (l = e[e.length - 1], | |
parseInt(l, 10) == l)) { | |
// hostname是ip地址的情况下 | |
// 10.6.8.10 | |
l = ["none"]; | |
break a | |
} | |
for (l = e.length - 2; 0 <= l; l--) | |
c.push(e.slice(l).join(".")); | |
// => ['qq.com', 'mp.qq.com', 'e.mp.qq.com'] | |
c.push("none"); | |
// => ['qq.com', 'mp.qq.com', 'e.mp.qq.com', 'none']; | |
l = c | |
} | |
for (var k = 0; k < l.length; k++) | |
if (e = l[k], | |
model.data.set(COOKIE_DOMAIN, e), | |
c = calGACookieValue(model), | |
setCookie(b, c, d, e, ca, g)) { | |
gaCookieSetted = !0; | |
return | |
} | |
model.data.set(COOKIE_DOMAIN, "auto") | |
} | |
} | |
}; | |
/** | |
* 检查cookie的storage | |
* 如果没设置cookie,则设置一遍 | |
* var checkStorageTaskFunc = function(model) | |
*/ | |
var checkCookieStorageTaskFunc = function (model) { | |
if ("cookie" == getAttrToStr(model, STORAGE) && !gaCookieSetted && (setGACookie(model), | |
!gaCookieSetted)) | |
throw "abort"; | |
}; | |
/** | |
* 前一版本GA的数据的导入,方便迁移 | |
* var historyImportTaskFunc = function(model) | |
*/ | |
var historyImportTaskFunc = function (model) { | |
if (model.get(LEGACY_HISTORY_IMPORT)) { | |
var b = getAttrToStr(model, COOKIE_DOMAIN) | |
, c = getAttrToStr(model, LEGACY_COOKIE_DOMAIN) || getHostName() | |
, d = parseAndGetOldGACookie("__utma", c, b); | |
d && (reg(19), | |
model.set(_UTMHT, (new Date).getTime(), !0), | |
model.set(_UTMA, d.R), | |
(b = parseAndGetOldGACookie("__utmz", c, b)) && d.hash == b.hash && model.set(_UTMZ, b.R)) | |
} | |
}; | |
/** | |
* 计算 _ga 的cookie值 | |
* var calGACookieValue = function(conf) | |
*/ | |
var calGACookieValue = function (model) { | |
var clientId = encodeURIComponentWithBrackets(getAttrToStr(model, CLIENT_ID)) | |
, baseDomain = normalizeDomain(getAttrToStr(model, COOKIE_DOMAIN)).split(".").length; | |
var pathCount = getPathCount(getAttrToStr(model, COOKIE_PATH)); | |
1 < pathCount && (baseDomain += "-" + pathCount); | |
return ["GA1", baseDomain, clientId].join(".") | |
}; | |
/** | |
* 计算cookie值中,层级相同或更小层级的cookie值 | |
* 层级最小的值如果有多个,则同时保留 | |
* | |
* var getSameOrSmallCookieValues = function(parsedGaCookieValues, count, index) | |
*/ | |
var getSameOrSmallCookieValues = function (parsedGaCookieValues, b, index) { | |
for (var sameCountValue = [], smallCountValue = [], g, i = 0; i < parsedGaCookieValues.length; i++) { | |
var cookieValue = parsedGaCookieValues[i]; | |
cookieValue.H[index] == b ? sameCountValue.push(cookieValue) : void 0 == g || cookieValue.H[index] < g ? (smallCountValue = [cookieValue], | |
g = cookieValue.H[index]) : cookieValue.H[index] == g && smallCountValue.push(cookieValue) | |
} | |
return 0 < sameCountValue.length ? sameCountValue : smallCountValue | |
}; | |
/** | |
* 如果第一个字符是“.”,则去掉 | |
* var normalizeDomain = function(domain) | |
*/ | |
var normalizeDomain = function (domain) { | |
return 0 == domain.indexOf(".") ? domain.substr(1) : domain | |
}; | |
/** | |
* 补全path | |
* 没有输入,则返回 '/' | |
* 如果最后一个字符是'/'并且还有别的字符,则去掉path中的最后一个 '/' | |
* 如果path的第一个字符不是 “/”,则补全 | |
* | |
* var normalizePath = function(path) | |
* | |
* path | |
*/ | |
var normalizePath = function (path) { | |
if (!path) | |
return "/"; | |
// 如果最后一个字符是'/'并且还有别的字符,则去掉path中的最后一个 '/' | |
1 < path.length && path.lastIndexOf("/") == path.length - 1 && (path = path.substr(0, path.length - 1)); | |
// 如果path的第一个字符不是 “/”,则补全 | |
0 != path.indexOf("/") && (path = "/" + path); | |
return path | |
}; | |
/** | |
* 获取path的层级 | |
* 首页表示1级 | |
* '/as'表示2级 | |
* '/as/a'表示三级 | |
* | |
* var getPathCount = function(a) | |
*/ | |
var getPathCount = function (path) { | |
var a = normalizePath(path); | |
return "/" == a ? 1 : a.split("/").length | |
}; | |
/** | |
* 解析和获取旧的GA cookie | |
* name为 __utma 或者 __utmz | |
* | |
* name, legacyDomain, curDomain | |
* | |
* function parseAndGetOldGACookie(name, legacyDomain, curDomain) | |
*/ | |
function parseAndGetOldGACookie(name, legacyDomain, curDomain) { | |
"none" == legacyDomain && (legacyDomain = ""); | |
var parsedValues = [] | |
, e = getCookie(name); | |
name = "__utma" == name ? 6 : 2; | |
for (var g = 0; g < e.length; g++) { | |
var ca = ("" + e[g]).split("."); | |
ca.length >= name && parsedValues.push({ | |
hash: ca[0], | |
R: e[g], | |
O: ca | |
}) | |
} | |
// 优先使用旧域名的 | |
if (0 != parsedValues.length) | |
return 1 == parsedValues.length ? parsedValues[0] : getCookieFromSpecifiedDomain(legacyDomain, parsedValues) || getCookieFromSpecifiedDomain(curDomain, parsedValues) || getCookieFromSpecifiedDomain(null, parsedValues) || parsedValues[0] | |
} | |
/** | |
* 找到指定域名的cookie值 domain, parsedValues | |
* | |
* function getCookieFromSpecifiedDomain(domain, parsedValues) | |
*/ | |
function getCookieFromSpecifiedDomain(domain, parsedValues) { | |
// domain == 'qq.com' | |
// hash1|hash2 == 'qq.com' | |
// hash1|hash2 == '.qq.com' | |
var c, d; | |
null == domain ? c = d = 1 : (c = str2Num(domain), | |
d = str2Num(startWith(domain, ".") ? domain.substring(1) : "." + domain)); | |
for (var e = 0; e < parsedValues.length; e++) | |
if (parsedValues[e].hash == c || parsedValues[e].hash == d) | |
return parsedValues[e] | |
} | |
var URL_REGEX = new RegExp(/^https?:\/\/([^\/:]+)/) | |
, ANCHOR_GA_REGEX = /(.*)([?&#])(?:_ga=[^&#]*)(?:&?)(.*)/; | |
/** | |
* linkerParam 参数的getter | |
* 用于增加其校验字符串 | |
* function linkerParamGetter(a) | |
*/ | |
function linkerParamGetter(model) { | |
var a = model.get(CLIENT_ID); | |
var b = calCheckCode(a, 0); | |
return "_ga=1." + iEncodeURIComponent(b + "." + a) | |
} | |
/** | |
* 计算校验字符串,计算依赖于: | |
* 1. 指定的字符串 | |
* 2. userAgent | |
* 3. 时区 | |
* 4. 当前时间的年、月、日、小时、分钟 | |
* | |
* function calCheckCode(str, minuteOffset) | |
*/ | |
function calCheckCode(str, minuteOffset) { | |
for (var date = new Date, | |
nav = iwin.navigator, | |
plugins = nav.plugins || [], | |
c = [str, | |
nav.userAgent, | |
date.getTimezoneOffset(), | |
date.getYear(), | |
date.getDate(), | |
date.getHours(), | |
date.getMinutes() + minuteOffset], | |
i = 0; i < plugins.length; ++i) | |
c.push(plugins[i].description); | |
return str2Num(c.join(".")) | |
} | |
/** | |
* | |
* | |
* Linker | |
* | |
* var Linker = function(a) | |
* | |
* | |
*/ | |
var Linker = function (a) { | |
reg(48); | |
this.target = a; | |
this.T = !1 | |
}; | |
/** | |
* 给连接地址、a标签、form标签加上特定的ga参数 | |
* | |
* Linker.prototype.decorate = function(a, b) | |
*/ | |
Linker.prototype.ca = function (element, b) { | |
if (element.tagName) { | |
if ("a" == element.tagName.toLowerCase()) { | |
element.href && (element.href = getGaHrefFromLinker(this, element.href, b)); | |
return | |
} | |
if ("form" == element.tagName.toLowerCase()) | |
return addGaInputToForm(this, element) | |
} | |
if ("string" == typeof element) | |
return getGaHrefFromLinker(this, element, b) | |
}; | |
/** | |
* | |
* @param linker | |
* @param href | |
* @param params | |
* @returns {XML|string|void} | |
*/ | |
var getGaHrefFromLinker = function (linker, href, params) { | |
var d = ANCHOR_GA_REGEX.exec(href); | |
d && 3 <= d.length && (href = d[1] + (d[3] ? d[2] + d[3] : "")); | |
linker = linker.target.get("linkerParam"); | |
var e = href.indexOf("?") | |
, anchorPosition = href.indexOf("#"); | |
params ? href += (-1 == anchorPosition ? "#" : "&") + linker : (params = -1 == e ? "?" : "&", | |
href = -1 == anchorPosition ? href + (params + linker) : href.substring(0, anchorPosition) + params + linker + href.substring(anchorPosition)); | |
return href = href.replace(/&+_ga=/, "&_ga=") | |
}; | |
/** | |
* | |
* @param linker | |
* @param iForm | |
*/ | |
var addGaInputToForm = function (linker, iForm) { | |
if (iForm && iForm.action) { | |
var val = linker.target.get("linkerParam").split("=")[1]; | |
if ("get" == iForm.method.toLowerCase()) { | |
for (var inputs = iForm.childNodes || [], i = 0; i < inputs.length; i++) | |
if ("_ga" == inputs[i].name) { | |
inputs[i].setAttribute("value", val); | |
return | |
} | |
var gaInput = idoc.createElement("input"); | |
gaInput.setAttribute("type", "hidden"); | |
gaInput.setAttribute("name", "_ga"); | |
gaInput.setAttribute("value", val); | |
iForm.appendChild(gaInput) | |
} else | |
"post" == iForm.method.toLowerCase() && (iForm.action = getGaHrefFromLinker(linker, iForm.action)) | |
} | |
}; | |
/** | |
* 自动给页面绑定mousedown、keyup、submit事情 | |
* 在事件触发的时候,给连接地址加上特定参数 | |
* | |
* Linker.prototype.autoLink = function(a, b, c) | |
*/ | |
Linker.prototype.S = function (a, b, c) { | |
function eventHandler(event) { | |
try { | |
event = event || iwin.event; | |
var d; | |
a: { | |
var g = event.target || event.srcElement; | |
for (var i = 100; g && 0 < i;) { | |
if (g.href && g.nodeName.match(/^a(?:rea)?$/i)) { | |
d = g; | |
break a | |
} | |
g = g.parentNode; | |
i--; | |
} | |
d = {} | |
} | |
("http:" == d.protocol || "https:" == d.protocol) && urlIsNotClientHost(a, d.hostname || "") && d.href && (d.href = getGaHrefFromLinker(that, d.href, b)) | |
} catch (k) { | |
reg(26) | |
} | |
} | |
var that = this; | |
this.T || (this.T = !0, | |
iAddEventListener(idoc, "mousedown", eventHandler, !1), | |
iAddEventListener(idoc, "keyup", eventHandler, !1)); | |
c && iAddEventListener(idoc, "submit", function (b) { | |
b = b || iwin.event; | |
if ((b = b.target || b.srcElement) && b.action) { | |
var c = b.action.match(URL_REGEX); | |
c && urlIsNotClientHost(a, c[1]) && addGaInputToForm(that, b) | |
} | |
}) | |
}; | |
/** | |
* | |
* | |
*/ | |
function urlIsNotClientHost(regs, url) { | |
if (url == idoc.location.hostname) | |
return !1; | |
for (var i = 0; i < regs.length; i++) | |
if (regs[i] instanceof RegExp) { | |
if (regs[i].test(url)) | |
return !0 | |
} else if (0 <= url.indexOf(regs[i])) | |
return !0; | |
return !1 | |
} | |
var gtmIdReg = /^(GTM|OPT)-[A-Z0-9]+$/ | |
, _gaexpReg = /;_gaexp=[^;]*/g | |
, __utmaReg = /;((__utma=)|([^;=]+=GAX?\d+\.))[^;]*/g; | |
/** | |
* 原来是t方法 | |
* @param cmd | |
* @returns {string} | |
*/ | |
var buildGtmUrl = function (cmd) { | |
function appendParamsToUrl(param, val) { | |
val && (url += "&" + param + "=" + iEncodeURIComponent(val)) | |
} | |
//TODO change URL | |
var url = "https://" + iAnalyseBaseURL + "/gtm/js?id=" + iEncodeURIComponent(cmd.id); | |
"dataLayer" != cmd.B && appendParamsToUrl("l", cmd.B); | |
appendParamsToUrl("t", cmd.target); | |
appendParamsToUrl("cid", cmd.ja); | |
appendParamsToUrl("cidt", cmd.ka); | |
appendParamsToUrl("gac", cmd.la); | |
appendParamsToUrl("aip", cmd.ia); | |
cmd.na && appendParamsToUrl("m", "sync"); | |
appendParamsToUrl("cycle", cmd.G); | |
return url | |
}; | |
/** | |
* | |
* | |
* _gat 用于对每个 tracker 设置限制请求率,所以每个 tracker 的cookie名字不一样 | |
* | |
* var DoubleClickModel = function(model, apiUrl, c) | |
* | |
*/ | |
var DoubleClickModel = function (model, apiUrl, c) { | |
this.U = JID; //jidKey | |
this.aa = apiUrl; //apiUrl | |
(apiUrl = c) || | |
(apiUrl = | |
(apiUrl = getAttrToStr(model, TRACKER_NAME)) && "t0" != apiUrl ? | |
gtmReg.test(apiUrl) ? | |
"_gat_" + encodeURIComponentWithBrackets(getAttrToStr(model, TRACKING_ID)) : | |
"_gat_" + encodeURIComponentWithBrackets(apiUrl) : "_gat"); | |
this.Y = apiUrl; | |
workWithSpeedAnchor(new SpeedAnchor(100), model) && | |
( | |
reg(30), | |
this.pa = !0 | |
) | |
}; | |
/** | |
* | |
* 为 buildHitTask 和 sendHitTask 做个包装 | |
* var wrapBuildAndSendTask = function(doubleCModel, model) | |
*/ | |
var wrapBuildAndSendTask = function (doubleCModel, model) { | |
var c = model.get(BUILD_HIT_TASK); | |
model.set(BUILD_HIT_TASK, function (b) { | |
setJid(doubleCModel, b); | |
var d = c(b); | |
setGatCookie(doubleCModel, b); | |
return d | |
}); | |
var d = model.get(SEND_HIT_TASK); | |
model.set(SEND_HIT_TASK, function (b) { | |
var c = d(b); | |
Id(doubleCModel, b); | |
return c | |
}) | |
}; | |
/** | |
* | |
* 设置jid到model上 | |
* | |
* var setJid = function(jd, model) | |
*/ | |
var setJid = function (jd, model) { | |
model.get(jd.U) || ("1" == getCookie(jd.Y)[0] ? model.set(jd.U, "", !0) : model.set(jd.U, "" + _uuid(), !0)) | |
}; | |
/** | |
* | |
* 设置 _gat cookie值为1 | |
* | |
* var setGatCookie = function(doubleClModel, model) | |
*/ | |
var setGatCookie = function (doubleClModel, model) { | |
if (model.get(doubleClModel.U)) { | |
var c = 6E5; //600000 | |
doubleClModel.pa && (c /= 10); | |
setCookie(doubleClModel.Y, "1", model.get(COOKIE_PATH), model.get(COOKIE_DOMAIN), model.get(TRACKING_ID), c) | |
} | |
}; | |
/** | |
* 发送请求 | |
* | |
* | |
*/ | |
var Id = function (doubleClick, model) { | |
if (model.get(doubleClick.U)) { | |
var tmp = new iMAP; | |
// var setData = function(fieldName) | |
var setData = function (fieldName) { | |
getHook(fieldName).F && tmp.set(getHook(fieldName).F, model.get(fieldName)) | |
}; | |
setData(API_VERSION); | |
setData(CLIENT_VERSION); | |
setData(TRACKING_ID); | |
setData(CLIENT_ID); | |
setData(USER_ID); | |
setData(doubleClick.U); | |
tmp.set(getHook(USAGE).F, mergeAndEncodeUM(model)); | |
var apiUrl = doubleClick.aa; | |
tmp.map(function (fieldName, fieldValue) { | |
apiUrl += iEncodeURIComponent(fieldName) + "="; | |
apiUrl += iEncodeURIComponent("" + fieldValue) + "&"; | |
}); | |
apiUrl += "z=" + _uuid(); | |
//change to imgPing | |
createImg(apiUrl); | |
model.set(doubleClick.U, "", !0) | |
} | |
}; | |
var gtmReg = /^gtm\d+$/; | |
/** | |
* 展示广告插件 | |
* 此插件的工作原理是向 stats.g.doubleclick.net 发送一个额外的请求,以便提供 Google Analytics(分析)中的广告功能(例如再营销以及受众特征和兴趣报告)。 | |
* 该插件还会创建一个名为 _gat 的新 Cookie,其有效时间为 10 分钟。 | |
* 该 Cookie 不会存储任何用户信息,而只会用于限制发送到 doubleclick.net 的请求数量。 | |
* https://developers.google.com/analytics/devguides/collection/analyticsjs/display-features?hl=zh-cn#overview | |
* | |
* var displayFeaturesPlugin = function(tracker, opts) | |
*/ | |
var displayFeaturesPlugin = function (tracker, opts) { | |
var doubleClick = tracker.b; | |
// | |
if (!doubleClick.get("dcLoaded")) { | |
setModelUM(doubleClick, 29); | |
opts = opts || {}; | |
var d; | |
opts[COOKIE_NAME] && (d = encodeURIComponentWithBrackets(opts[COOKIE_NAME])); | |
//TODO change URL | |
var dcModel = new DoubleClickModel(doubleClick, "https://"+iAdBaseURL+"/r/collect?t=dc&aip=1&_r=3&", d); | |
wrapBuildAndSendTask(dcModel, doubleClick); | |
doubleClick.set("dcLoaded", !0) | |
} | |
}; | |
/** | |
* 如果没有加载 doubleclick 的展示广告插件,并且用的cookie存储 | |
* 则使用 /r/collect 作为API地址 | |
* | |
* var displayFeaturesTaskFunc = function(model) | |
*/ | |
var displayFeaturesTaskFunc = function (model) { | |
if (!model.get("dcLoaded") && "cookie" == model.get(STORAGE)) { | |
setModelUM(model, 51); | |
var dcModel = new DoubleClickModel(model); | |
setJid(dcModel, model); | |
setGatCookie(dcModel, model); | |
model.get(dcModel.U) && (model.set(_R, 1, !0), | |
//TODO change URL | |
model.set(TRANSPORT_URL, getGAOriginUrl() + "/r/collect", !0)) | |
} | |
}; | |
/** | |
* set AD_SENSE_ID | |
* @returns {*} | |
* @constructor | |
*/ | |
var setAdSenseId = function () { | |
var a = iwin.gaGlobal = iwin.gaGlobal || {}; | |
return a.hid = a.hid || _uuid() | |
}; | |
//加载In-Page分析的功能 | |
/** | |
* | |
* var loadInpageAnalytics = function(a, b, c) | |
*/ | |
var inpageLoaded, loadInpageAnalytics = function (trackerId, iDomain, iPath) { | |
if (!inpageLoaded) { | |
var d; | |
d = idoc.location.hash; | |
var e = iwin.name | |
, g = /^#?gaso=([^&]*)/; | |
if ( | |
e = (d = (d = d && d.match(g) || e && e.match(g)) ? d[1] : getCookie("GASO")[0] || "") && d.match(/^(?:!([-0-9a-z.]{1,40})!)?([-.\w]{10,1200})$/i) | |
) | |
setCookie("GASO", "" + d, iPath, iDomain, trackerId, 0), | |
window._udo || (window._udo = iDomain), | |
window._utcp || (window._utcp = iPath), | |
trackerId = e[1], | |
//TODO change URL | |
iInpageURL | |
loadScript(iInpageURL + (trackerId ? "prefix=" + trackerId + "&" : "") + _uuid(), "_gasojs"); | |
//loadScript("https://www.google.com/analytics/web/inpage/pub/inpage.js?" + (trackerId ? "prefix=" + trackerId + "&" : "") + _uuid(), "_gasojs"); | |
inpageLoaded = !0 | |
} | |
}; | |
// ga 的用户的 id 格式 UA-7076879-3 | |
//TODO change UA to XD | |
var gaClientIdReg = /^(UA|YT|MO|GP)-(\d+)-(\d+)$/; | |
/** | |
* 跟踪器类 | |
* | |
* https://developers.google.com/analytics/devguides/collection/analyticsjs/tracker-object-reference?hl=zh-cn | |
* | |
* var Tracker = function(opts) | |
*/ | |
var Tracker = function (opts) { | |
/** | |
* function setData(fieldName, fieldValue) | |
*/ | |
function setData(fieldName, fieldValue) { | |
that.b.data.set(fieldName, fieldValue) | |
} | |
/** | |
* function addFilter(filterName, filter) | |
*/ | |
function addFilter(filterName, filter) { | |
setData(filterName, filter); | |
that.filters.add(filterName) | |
} | |
var that = this; | |
this.b = new iModel; | |
this.filters = new Queue; | |
setData(TRACKER_NAME, opts[TRACKER_NAME]); | |
setData(TRACKING_ID, trim(opts[TRACKING_ID])); | |
setData(COOKIE_NAME, opts[COOKIE_NAME]); | |
setData(COOKIE_DOMAIN, opts[COOKIE_DOMAIN] || getHostName()); | |
setData(COOKIE_PATH, opts[COOKIE_PATH]); | |
setData(COOKIE_EXPIRES, opts[COOKIE_EXPIRES]); | |
setData(LEGACY_COOKIE_DOMAIN, opts[LEGACY_COOKIE_DOMAIN]); | |
setData(LEGACY_HISTORY_IMPORT, opts[LEGACY_HISTORY_IMPORT]); | |
setData(ALLOW_LINKER, opts[ALLOW_LINKER]); | |
setData(ALLOW_ANCHOR, opts[ALLOW_ANCHOR]); | |
setData(SAMPLE_RATE, opts[SAMPLE_RATE]); | |
setData(SITE_SPEED_SAMPLE_RATE, opts[SITE_SPEED_SAMPLE_RATE]); | |
setData(ALWAYS_SEND_REFERRER, opts[ALWAYS_SEND_REFERRER]); | |
setData(STORAGE, opts[STORAGE]); | |
setData(USER_ID, opts[USER_ID]); | |
setData(CLIENT_ID_TIME, opts[CLIENT_ID_TIME]); | |
setData(API_VERSION, 1); | |
setData(CLIENT_VERSION, "j47"); | |
addFilter(_OOT, isGAPrefsAllowed); | |
addFilter(PREVIEW_TASK, isPreviewLoad); | |
addFilter(CHECK_PROTOCOL_TASK, checkProtocol); | |
addFilter(VALIDATION_TASK, validationTaskFunc); | |
addFilter(CHECK_STORAGE_TASK, checkCookieStorageTaskFunc); | |
addFilter(HISTORY_IMPORT_TASK, historyImportTaskFunc); | |
addFilter(SAMPLER_TASK, samplerTaskFunc); | |
addFilter(_RLT, rtlTaskFunc); | |
addFilter(CE_TASK, ceTaskFunc); | |
addFilter(DEV_ID_TASK, devIdTaskFunc); | |
addFilter(DISPLAY_FEATURES_TASK, displayFeaturesTaskFunc); | |
addFilter(BUILD_HIT_TASK, buildHitTaskFunc); | |
addFilter(SEND_HIT_TASK, sendHitTaskFunc); | |
addFilter(TIMING_TASK, createTimingTask(this)); | |
buildAndSetGACookie(this.b, opts[CLIENT_ID]); | |
setBasicData(this.b); | |
this.b.set(AD_SENSE_ID, setAdSenseId()); | |
loadInpageAnalytics(this.b.get(TRACKING_ID), this.b.get(COOKIE_DOMAIN), this.b.get(COOKIE_PATH)); | |
}; | |
/** | |
* | |
* | |
*/ | |
var buildAndSetGACookie = function (model, cookieOpts) { | |
//存储方式是cookie | |
if ("cookie" == getAttrToStr(model, STORAGE)) { | |
gaCookieSetted = !1; | |
var c; | |
b: { | |
var tmpCookie = getCookie(getAttrToStr(model, COOKIE_NAME)); | |
if (tmpCookie && !(1 > tmpCookie.length)) { | |
c = []; | |
for (var itemp = 0; itemp < tmpCookie.length; itemp++) { | |
// _ga 的 cookie 值有四个区域,以点间隔 | |
// 四个区域的含义参考别人的答案 http://stackoverflow.com/questions/16102436/what-are-the-values-in-ga-cookie | |
// 1.2.286403989.1366364567 | |
// GA1.3.494346849.1446193077 | |
var g; | |
g = tmpCookie[itemp].split("."); | |
// 第一个区域值是版本号 gaVersion | |
var ca = g.shift(); | |
// 第二个区域用于确认是否是指定域名和路径的cookie,因为GA可以在不同的域名和路径上设置多个cookie | |
// 所以需要这个区域值来区分,以获取到正确的cookie值 | |
// 值的格式是 \d[-\d],例如:“2-1” 或者 “2” | |
// 第一个数字是 域名的层级,qq.com 为 “2;b.qq.com” 为 “3” | |
// 第二个数字是 路径的层级, / 为空字符, /data 为 “-2”,/user/xxx 为 “-3” | |
("GA1" == ca || "1" == ca) && 1 < g.length ? (ca = g.shift().split("-"), | |
1 == ca.length && (ca[1] = "1"), // 补全下 路径为 / 时,省略的 “-1” | |
// 字符串转换成数字 | |
ca[0] *= 1, | |
ca[1] *= 1, | |
g = { | |
// 第二区域的值 [1, 2] | |
// domainAndPathCount: ca, | |
H: ca, | |
// 第三和第四区域的组合值,也就是clientId的值 | |
// 第三区域是一个随机数 | |
// 第四区域是cookie第一次设置时候的时间值 | |
// idAndTime: gaCookie.join('.') | |
s: g.join(".") | |
}) : g = void 0; | |
g && c.push(g) | |
} | |
if (1 == c.length) { | |
reg(13); | |
c = c[0].s; | |
break b | |
} | |
if (0 == c.length) | |
reg(12); | |
else { | |
reg(14); | |
tmpCookie = normalizeDomain(getAttrToStr(model, COOKIE_DOMAIN)).split(".").length; | |
c = getSameOrSmallCookieValues(c, tmpCookie, 0); | |
if (1 == c.length) { | |
c = c[0].s; | |
break b | |
} | |
tmpCookie = getPathCount(getAttrToStr(model, COOKIE_PATH)); | |
c = getSameOrSmallCookieValues(c, tmpCookie, 1); | |
c = c[0] && c[0].s; | |
break b | |
} | |
} | |
c = void 0 | |
} | |
c || (c = getAttrToStr(model, COOKIE_DOMAIN), | |
tmpCookie = getAttrToStr(model, LEGACY_COOKIE_DOMAIN) || getHostName(), | |
c = parseAndGetOldGACookie("__utma", tmpCookie, c), | |
void 0 != c ? (reg(10), | |
c = c.O[1] + "." + c.O[2]) : c = void 0); | |
c && (model.data.set(CLIENT_ID, c), | |
gaCookieSetted = !0) | |
} | |
// 是否允许定位点参数 | |
c = model.get(ALLOW_ANCHOR); | |
if (itemp = getUrlParamVal(idoc.location[c ? "href" : "search"], "_ga")) | |
// 有定位点ga参数 | |
// 定位点 ga 参数值的形式为: '1.校验字符串.clientId' | |
// 允许链接器参数 | |
model.get(ALLOW_LINKER) ? (c = itemp.indexOf("."), | |
-1 == c ? reg(22) : (tmpCookie = itemp.substring(c + 1),// 格式不正确 | |
"1" != itemp.substring(0, c) ? reg(22) : (c = tmpCookie.indexOf("."), | |
-1 == c ? reg(22) : (itemp = tmpCookie.substring(0, c), | |
c = tmpCookie.substring(c + 1), | |
itemp != calCheckCode(c, 0) && itemp != calCheckCode(c, -1) && itemp != calCheckCode(c, -2) ? reg(23) : (reg(11),// 2分钟内计算的校验字符串都不对,则是很久以前复制的地址现在才打开// 2分钟内的定位点GA参数,还有效,则记录 | |
model.data.set(CLIENT_ID, c)))))) : reg(21);// 不允许 | |
// 如果在初始化时设置了clientId,则优先使用这个 | |
cookieOpts && (reg(9), | |
model.data.set(CLIENT_ID, iEncodeURIComponent(cookieOpts))); | |
if (!model.get(CLIENT_ID)) | |
if (c = (c = iwin.gaGlobal && iwin.gaGlobal.vid) && -1 != c.search(/^(?:utma\.)?\d+\.\d+$/) ? c : void 0) | |
reg(17), | |
model.data.set(CLIENT_ID, c); | |
else { | |
// 如果没有clientId,则自己生成一个 | |
reg(8); | |
c = iwin.navigator.userAgent + (idoc.cookie ? idoc.cookie : "") + (idoc.referrer ? idoc.referrer : ""); | |
tmpCookie = c.length; | |
for (itemp = iwin.history.length; 0 < itemp;) | |
c += itemp-- ^ tmpCookie++; | |
model.data.set(CLIENT_ID, [_uuid() ^ str2Num(c) & 2147483647, Math.round((new Date).getTime() / 1E3)].join(".")) | |
} | |
setGACookie(model) | |
}; | |
/** | |
* | |
* | |
* var setBasicData = function(model) | |
*/ | |
var setBasicData = function (model) { | |
var b = iwin.navigator | |
, c = iwin.screen | |
, d = idoc.location; | |
model.set(REFERRER, getReferrer(model.get(ALWAYS_SEND_REFERRER))); | |
if (d) { | |
var e = d.pathname || ""; | |
"/" != e.charAt(0) && (reg(31), | |
e = "/" + e); | |
model.set(LOCATION, d.protocol + "//" + d.hostname + e + d.search) | |
} | |
c && model.set(SCREEN_RESOLUTION, c.width + "x" + c.height); | |
c && model.set(SCREEN_COLORS, c.colorDepth + "-bit"); | |
var c = idoc.documentElement | |
, g = (e = idoc.body) && e.clientWidth && e.clientHeight | |
, ca = []; | |
c && c.clientWidth && c.clientHeight && ("CSS1Compat" === idoc.compatMode || !g) ? ca = [c.clientWidth, c.clientHeight] : g && (ca = [e.clientWidth, e.clientHeight]); | |
c = 0 >= ca[0] || 0 >= ca[1] ? "" : ca.join("x"); | |
model.set(VIEWPORT_SIZE, c); | |
model.set(FLASH_VERSION, getFlashVersion()); | |
model.set(ENCODING, idoc.characterSet || idoc.charset); | |
model.set(JAVA_ENABLED, b && "function" === typeof b.javaEnabled && b.javaEnabled() || !1); | |
model.set(LANGUAGE, (b && (b.language || b.browserLanguage) || "").toLowerCase()); | |
if (d && model.get(ALLOW_ANCHOR) && (b = idoc.location.hash)) { | |
b = b.split(/[?&#]+/); | |
d = []; | |
for (c = 0; c < b.length; ++c) | |
(startWith(b[c], "utm_id") || startWith(b[c], "utm_campaign") || startWith(b[c], "utm_source") || startWith(b[c], "utm_medium") || startWith(b[c], "utm_term") || startWith(b[c], "utm_content") || startWith(b[c], "gclid") || startWith(b[c], "dclid") || startWith(b[c], "gclsrc")) && d.push(b[c]); | |
0 < d.length && (b = "#" + d.join("&"), | |
model.set(LOCATION, model.get(LOCATION) + b)) | |
} | |
}; | |
Tracker.prototype.get = function (a) { | |
return this.b.get(a) | |
}; | |
Tracker.prototype.set = function (a, b) { | |
this.b.set(a, b) | |
}; | |
var SEND_PARAMS_NAMES = { | |
pageview: [PAGE], | |
event: [EVENT_CATEGORY, EVENT_ACTION, EVENT_LABEL, EVENT_VALUE], | |
social: [SOCIAL_NETWORK, SOCIAL_ACTION, SOCIAL_TARGET], | |
timing: [TIMING_CATEGORY, TIMING_VAR, TIMING_VALUE, TIMING_LABEL] | |
}; | |
// Tracker的send方法 | |
// ga('send', 'pageview'); | |
// ga('send', 'event', '1', '2', '3', '4'); | |
// 每次send之前都会执行所有获取器,并将当前配置临时存储到model中 | |
// send结束之后,删掉临时数据 | |
Tracker.prototype.send = function (a) { | |
if (!(1 > arguments.length)) { | |
var hitTypeV, opts; | |
( "string" === typeof arguments[0] ) ? | |
( | |
hitTypeV = arguments[0], | |
opts = [].slice.call(arguments, 1) | |
) : ( | |
hitTypeV = arguments[0] && arguments[0][HIT_TYPE], | |
opts = arguments | |
); | |
hitTypeV && | |
( | |
opts = transformInput(SEND_PARAMS_NAMES[hitTypeV] || [], opts), | |
opts[HIT_TYPE] = hitTypeV, | |
// 将配置存为临时数据 | |
this.b.set(opts, void 0, !0), | |
// 执行filters | |
this.filters.D(this.b), | |
// 删掉临时数据 | |
this.b.data.m = {} | |
) | |
} | |
}; | |
/** | |
* | |
* 本脚本中基本未曾调用过 | |
* | |
* @param key | |
* @param b | |
*/ | |
Tracker.prototype.ma = function (key, b) { | |
var tracker = this; | |
setPluginToGA(key, tracker, b) || | |
( | |
setBasePlugin(key, function () { | |
setPluginToGA(key, tracker, b) | |
}), | |
setMorePlugins(String(tracker.get(TRACKER_NAME)), key, void 0, b, !0) | |
) | |
}; | |
/** | |
* 在浏览器预渲染的时候避免执行函数 | |
* 返回:是否预渲染 | |
* | |
* var executeWithoutPrerender = function(func) | |
*/ | |
var isNotPreRender = function (callback) { | |
if ("prerender" == idoc.visibilityState) | |
return !1; | |
callback(); | |
return !0 | |
}; | |
/** | |
* 主要逻辑入口 | |
* | |
* | |
*/ | |
var bootUp = function (func) { | |
if (!isNotPreRender(func)) { | |
// 处于预渲染中,则等待真正的展示开始才进行逻辑 | |
reg(16); | |
var executed = !1, | |
c = function () { | |
if (!executed && isNotPreRender(func)) { | |
executed = !0; | |
var d = c | |
, e = idoc; | |
e.removeEventListener ? e.removeEventListener("visibilitychange", d, !1) : e.detachEvent && e.detachEvent("onvisibilitychange", d) | |
} | |
}; | |
iAddEventListener(idoc, "visibilitychange", c) | |
} | |
}; | |
// command 标识符的正则解析 | |
// [trackerName.][pluginName:]methodName | |
// https://developers.google.com/analytics/devguides/collection/analyticsjs/command-queue-reference?hl=zh-cn#header | |
// 调用方法:ga(command, [...fields], [fieldsObject]) | |
// args = [command, [...fields], [fieldsObject]]; | |
// commandRegex | |
var commandRegex = /^(?:(\w+)\.)?(?:(\w+):)?(\w+)$/; | |
/** | |
* | |
* var Command = function(args) | |
*/ | |
var Command = function (args) { | |
if (isFunction(args[0])) | |
this.u = args[0]; | |
else { | |
var b = commandRegex.exec(args[0]); | |
// Tracker名字默认为t0 | |
null != b && 4 == b.length && (this.c = b[1] || "t0", | |
this.K = b[2] || "",// pluginName | |
this.C = b[3],// methodName | |
this.a = [].slice.call(args, 1), | |
this.K || (this.A = "create" == this.C, | |
this.i = "require" == this.C, | |
this.g = "provide" == this.C, | |
this.ba = "remove" == this.C), | |
this.i && (3 <= this.a.length ? (this.X = this.a[1], | |
this.W = this.a[2]) : this.a[1] && (isString(this.a[1]) ? this.X = this.a[1] : this.W = this.a[1]))); | |
b = args[1]; | |
args = args[2]; | |
if (!this.C) | |
// 必须有一个方法名 | |
throw "abort"; | |
if (this.i && (!isString(b) || "" == b)) | |
// require命令的第二个参数,必须是字符串,且不为空字符串 | |
throw "abort"; | |
if (this.g && (!isString(b) || "" == b || !isFunction(args))) | |
// 必须是这种输入,才算正确的provide命令 | |
// ga('provide', pluginName, pluginConstuctor); | |
throw "abort"; | |
if (hasPointOrColon(this.c) || hasPointOrColon(this.K)) | |
// tracker和plugin的名字不能包含点和冒号 | |
throw "abort"; | |
if (this.g && "t0" != this.c) | |
// 不能单独为某个Tracker来provide插件 | |
throw "abort"; | |
} | |
}; | |
/** | |
* 是否有点或者冒号 | |
* string have . or : | |
* | |
* function hasPointOrColon(str) | |
*/ | |
function hasPointOrColon(str) { | |
return 0 <= str.indexOf(".") || 0 <= str.indexOf(":") | |
} | |
var allPlugins, pluginUsageIdMap, loadedPlugins, basePlugins; | |
// 记录了所有插件的map,插件名作为key | |
allPlugins = new iMAP; | |
// 记录了已经加载的GA内置插件,插件名作为key | |
loadedPlugins = new iMAP; | |
// 记录所有GA内置插件的usageId的map,插件名作为key | |
basePlugins = new iMAP; | |
pluginUsageIdMap = { | |
ec: 45, | |
ecommerce: 46, | |
linkid: 47 | |
}; | |
/** | |
* | |
* | |
*/ | |
var setPluginToGA = function (key, tracker, c) { | |
tracker == GA || tracker.get(TRACKER_NAME); | |
var plugin = allPlugins.get(key); | |
if (!isFunction(plugin)) | |
return !1; | |
tracker.plugins_ = tracker.plugins_ || new iMAP; | |
// 如果没有创建过这个插件的实例,则创建一个 | |
if (tracker.plugins_.get(key)) | |
return !0; | |
tracker.plugins_.set(key, new plugin(tracker, c || {})); | |
return !0 | |
}; | |
/** | |
* gtm 加载相关 | |
* | |
*/ | |
var setMorePlugins = function (trackerName, key, url, cmd, e) { | |
if (!isFunction(allPlugins.get(key)) && !loadedPlugins.get(key)) { | |
pluginUsageIdMap.hasOwnProperty(key) && reg(pluginUsageIdMap[key]); | |
if (gtmIdReg.test(key)) { | |
reg(52); | |
var trackerTmp = GA.j(trackerName); | |
if (!trackerTmp) | |
return !0; | |
url = cmd || {}; | |
// | |
cmd = { | |
id: key, | |
B: url.dataLayer || "dataLayer", | |
ia: !!trackerTmp.get("anonymizeIp"), | |
na: e, | |
G: !1 | |
}; | |
trackerTmp.get(">m") == key && (cmd.G = !0); | |
var g = String(trackerTmp.get("name")); | |
"t0" != g && (cmd.target = g); | |
checkGaUserPrefs(String(trackerTmp.get("trackingId"))) || | |
( | |
cmd.ja = String(trackerTmp.get(CLIENT_ID)), | |
cmd.ka = Number(trackerTmp.get(CLIENT_ID_TIME)), | |
trackerTmp = url.palindrome ? __utmaReg : _gaexpReg, | |
trackerTmp = (trackerTmp = idoc.cookie.replace(/^|(; +)/g, ";").match(trackerTmp)) ? trackerTmp.sort().join("").substring(1) : void 0, | |
cmd.la = trackerTmp | |
); | |
var dataLayer = cmd.B; | |
url = (new Date).getTime(); | |
iwin[dataLayer] = iwin[dataLayer] || []; | |
url = { | |
"gtm.start": url | |
}; | |
e || (url.event = "gtm.js"); | |
iwin[dataLayer].push(url); | |
url = buildGtmUrl(cmd); | |
} | |
!url && pluginUsageIdMap.hasOwnProperty(key) ? | |
(reg(39), url = key + ".js") : reg(43); | |
var pluginUrl,pluginProtocol,clientProtocol; | |
url && | |
//TODO change URL | |
(url && 0 <= url.indexOf("/") || (url = (forceHTTPS || isHTTPS() ? "https:" : "http:") + "//" + iAnalyseBaseURL + "/plugins/ua/" + url), | |
pluginUrl = parseUrl(url), | |
pluginProtocol = pluginUrl.protocol, | |
clientProtocol = idoc.location.protocol, | |
("https:" == pluginProtocol || pluginProtocol == clientProtocol || ("http:" != pluginProtocol ? 0 : "http:" == clientProtocol)) && | |
isOfficialUrl(pluginUrl) && | |
(loadScript(pluginUrl.url, void 0, e), | |
loadedPlugins.set(key, !0) | |
) | |
) | |
} | |
}; | |
/** | |
* | |
* @param key | |
* @param func | |
*/ | |
var setBasePlugin = function (key, func) { | |
var plugin = basePlugins.get(key) || []; | |
plugin.push(func); | |
basePlugins.set(key, plugin) | |
}; | |
/** | |
* | |
*/ | |
var execBasePlugins = function (key, obj) { | |
allPlugins.set(key, obj); | |
for (var plugin = basePlugins.get(key) || [], i = 0; i < plugin.length; i++) | |
plugin[i](); | |
basePlugins.set(key, []) | |
}; | |
/** | |
* 验证是官方插件地址 | |
* plugins url check | |
* @return {boolean} | |
*/ | |
var isOfficialUrl = function (cmd) { | |
// | |
var clientUrl = parseUrl(idoc.location.href); | |
//TODO change URL | |
if (startWith(cmd.url, "https://"+iAnalyseBaseURL+"/gtm/js?id=")) | |
return true; | |
if (cmd.query || 0 <= cmd.url.indexOf("?") || 0 <= cmd.path.indexOf("://")) | |
return false; | |
if (cmd.host == clientUrl.host && cmd.port == clientUrl.port) | |
return true; | |
var cmdPort = "http:" == cmd.protocol ? 80 : 443; | |
//TODO change URL | |
return iAnalyseBaseURL == cmd.host && (cmd.port || cmdPort) == cmdPort && startWith(cmd.path, "/plugins/") ? !0 : !1 | |
}; | |
/** | |
* class | |
* | |
* | |
* // 解析url地址 | |
* // 返回: | |
* // { | |
* // protocol: '', | |
* // host: '', | |
* // port: '', | |
* // path: '', | |
* // query: '', | |
* // url: '' | |
* // } | |
* | |
* | |
* | |
*/ | |
var parseUrl = function (url) { | |
function parseLink(link) { | |
var host = (link.hostname || "").split(":")[0].toLowerCase() | |
, protocol = (link.protocol || "").toLowerCase() | |
, port = 1 * link.port || ("http:" == protocol ? 80 : "https:" == protocol ? 443 : ""); | |
var pathname = link.pathname || ""; | |
startWith(pathname, "/") || (pathname = "/" + pathname); | |
return [host, "" + port, pathname] | |
} | |
var link = idoc.createElement("a"); | |
link.href = idoc.location.href; | |
var protocol = (link.protocol || "").toLowerCase() | |
, parsedLocalLink = parseLink(link) | |
, query = link.search || "" | |
, clientUrl = protocol + "//" + parsedLocalLink[0] + (parsedLocalLink[1] ? ":" + parsedLocalLink[1] : ""); | |
startWith(url, "//") ? | |
url = protocol + url : | |
startWith(url, "/") ? | |
url = clientUrl + url : | |
!url || startWith(url, "?") ? | |
url = clientUrl + parsedLocalLink[2] + (url || query) : | |
0 > url.split("/")[0].indexOf(":") && (url = clientUrl + parsedLocalLink[2].substring(0, parsedLocalLink[2].lastIndexOf("/")) + "/" + url); | |
link.href = url; | |
var parsedLink = parseLink(link); | |
return { | |
protocol: (link.protocol || "").toLowerCase(), | |
host: parsedLink[0], | |
port: parsedLink[1], | |
path: parsedLink[2], | |
query: link.search || "", | |
url: url || "" | |
} | |
}; | |
// Command Queue Query | |
// ga = ga || []; | |
// ga.push('create', 'xxxx', 'auto'); | |
// var MethodQueue = | |
var MethodQueue = { | |
ga: function () {//init: function() | |
//MethodQueue.cmdQueue = [] | |
MethodQueue.f = [] | |
} | |
}; | |
//MethodQueue.init(); | |
MethodQueue.ga(); | |
// 运行命令队列里面的命令 | |
//MethodQueue.run = function(a) | |
MethodQueue.D = function (a) { | |
var commands = MethodQueue.J.apply(MethodQueue, arguments) | |
, b = MethodQueue.f.concat(commands); | |
for (MethodQueue.f = []; 0 < b.length && !MethodQueue.v(b[0]) && !(b.shift(), | |
0 < MethodQueue.f.length);) | |
; | |
MethodQueue.f = MethodQueue.f.concat(b) | |
}; | |
// 将输入的参数转换成Command类的实例对象数组 | |
// 如果是require命令则需要加载js代码 | |
// 如果是provide命令则需要记录提供的插件构造函数 | |
// MethodQueue.toCommands = function() | |
MethodQueue.J = function (a) { | |
for (var b = [], c = 0; c < arguments.length; c++) | |
try { | |
var cmd = new Command(arguments[c]); | |
cmd.g ? execBasePlugins(cmd.a[0], cmd.a[1]) : (cmd.i && (cmd.ha = setMorePlugins(cmd.c, cmd.a[0], cmd.X, cmd.W)), | |
b.push(cmd)) | |
} catch (e) { | |
} | |
return b | |
}; | |
/** | |
* 运行command对象 | |
* 运行终端 | |
* | |
* MethodQueue.runCommand = function(cmd) | |
*/ | |
MethodQueue.v = function (cmd) { | |
try { | |
if (cmd.u) | |
cmd.u.call(iwin, GA.j("t0")); | |
else { | |
var tmpGA = cmd.c == GA_HOOK ? GA : GA.j(cmd.c); | |
if (cmd.A) | |
"t0" != cmd.c || GA.create.apply(GA, cmd.a); | |
else if (cmd.ba) | |
GA.remove(cmd.c); | |
else if (tmpGA) | |
if (cmd.i) { | |
// 如果没有创建过这个插件的实例,则创建一个 | |
if (cmd.ha && (cmd.ha = setMorePlugins(cmd.c, cmd.a[0], cmd.X, cmd.W)), | |
!setPluginToGA(cmd.a[0], tmpGA, cmd.W)) | |
return !0 | |
// 很可能这时候加载的插件还没有下载下来 | |
// 所以需要终端执行 | |
} else if (cmd.K) { //cmd.pluginName | |
var c = cmd.C | |
, d = cmd.a | |
, e = tmpGA.plugins_.get(cmd.K); | |
e[c].apply(e, d) | |
} else | |
tmpGA[cmd.C].apply(tmpGA, cmd.a) | |
} | |
} catch (g) { | |
} | |
} | |
; | |
//N => GA | |
/** | |
* 主要的对象,提供很多静态方法使用 | |
* var GA = function(a) | |
*/ | |
var GA = function (a) { | |
reg(1); | |
MethodQueue.D.apply(MethodQueue, [arguments]) | |
}; | |
// GA.trackerMap = {}; | |
GA.h = {}; | |
//GA.trackers | |
GA.P = []; | |
//GA.startTime | |
GA.L = 0; | |
//GA.answer | |
GA.answer = 42; | |
var neededParams = [TRACKING_ID, COOKIE_DOMAIN, TRACKER_NAME]; | |
/** | |
* 创建一个Tracker | |
* | |
* | |
*/ | |
GA.create = function () { | |
var opts = transformInput(neededParams, [].slice.call(arguments)); | |
opts[TRACKER_NAME] || (opts[TRACKER_NAME] = "t0"); | |
var trackerName = "" + opts[TRACKER_NAME]; | |
if (GA.h[trackerName]) | |
return GA.h[trackerName]; | |
var tracker = new Tracker(opts); | |
GA.h[trackerName] = tracker; | |
GA.P.push(tracker); | |
return tracker | |
}; | |
/** | |
* 移除一个tracker | |
*/ | |
GA.remove = function (trackerName) { | |
for (var i = 0; i < GA.P.length; i++) | |
if (GA.P[i].get(TRACKER_NAME) == trackerName) { | |
GA.P.splice(i, 1); | |
GA.h[trackerName] = null; | |
break | |
} | |
}; | |
/** | |
* 获取tracker的名字 | |
* N.j => GA.getByName | |
*/ | |
GA.j = function (trackerName) { | |
return GA.h[trackerName] | |
}; | |
/** | |
* 获取所有的trackers | |
* | |
*/ | |
GA.getAll = function () { | |
return GA.P.slice(0) | |
}; | |
/** | |
* 主入口方法 | |
* GA.main = function() | |
* | |
* | |
*/ | |
GA.N = function () { | |
"ga" != GA_HOOK && reg(49); | |
var a = iwin[GA_HOOK]; | |
if (!a || 42 != a.answer) { | |
// | |
GA.L = a && a.l; | |
GA.loaded = !0; | |
var b = iwin[GA_HOOK] = GA; | |
X("create", b, b.create); | |
X("remove", b, b.remove); | |
X("getByName", b, b.j, 5); | |
X("getAll", b, b.getAll, 6); | |
var trackerPrototype = Tracker.prototype; | |
X("get", trackerPrototype, trackerPrototype.get, 7); | |
X("set", trackerPrototype, trackerPrototype.set, 4); | |
X("send", trackerPrototype, trackerPrototype.send); | |
X("requireSync", trackerPrototype, trackerPrototype.ma); | |
var modelPrototype = iModel.prototype; | |
X("get", modelPrototype, modelPrototype.get); | |
X("set", modelPrototype, modelPrototype.set); | |
var scriptIsHttps = !1; | |
// | |
if (!isHTTPS() && !forceHTTPS) { | |
// 如果设置使用https,则通过引入的js文件地址来判断是否使用https | |
a: { | |
for (var scripts = idoc.getElementsByTagName("script"), i = 0; i < scripts.length && 100 > i; i++) { | |
var scriptSrc = scripts[i].src; | |
//TODO change URL | |
if (scriptSrc && 0 == scriptSrc.indexOf("https://" + iAnalyseBaseURL + "/analytics")) { | |
reg(33); | |
scriptIsHttps = !0; | |
break a | |
} | |
} | |
} | |
scriptIsHttps && (forceHTTPS = !0) | |
} | |
isHTTPS() || forceHTTPS || !workWithSpeedAnchor(new SpeedAnchor(1E4)) || (reg(36), forceHTTPS = !0); | |
(iwin.gaplugins = iwin.gaplugins || {}).Linker = Linker; | |
var linkerPrototype = Linker.prototype; | |
execBasePlugins("linker", Linker); | |
X("decorate", linkerPrototype, linkerPrototype.ca, 20); | |
X("autoLink", linkerPrototype, linkerPrototype.S, 25); | |
execBasePlugins("displayfeatures", displayFeaturesPlugin); | |
execBasePlugins("adfeatures", displayFeaturesPlugin); | |
//// tmpGa.q ga的js代码执行前,push到ga命令队列里面的命令 | |
//tmpGa = tmpGa && tmpGa.q; | |
a = a && a.q; | |
isArray(a) ? MethodQueue.D.apply(GA, a) : reg(50) | |
} | |
}; | |
/** | |
* | |
* | |
*/ | |
GA.da = function () { | |
for (var trackers = GA.getAll(), i = 0; i < trackers.length; i++) | |
trackers[i].get(TRACKER_NAME) | |
}; | |
var startUp = GA.N; | |
var gaObj = iwin[GA_HOOK]; | |
gaObj && gaObj.r ? startUp() : bootUp(startUp); | |
bootUp(function () { | |
MethodQueue.D(["provide", "render", emptyFunction]) | |
}); | |
/** | |
* str to Number | |
* 将字符串转换成一个数字 | |
* 同一个字符串的输入转换结果是固定的 | |
* 通常用于将随机字符串转换成数字,然后计算概率 | |
* | |
* function str2Num(str) | |
*/ | |
function str2Num(str) { | |
var resInt = 1, charCode, i; | |
if (str) | |
for (resInt = 0, i = str.length - 1; 0 <= i; i--) | |
charCode = str.charCodeAt(i), | |
resInt = (resInt << 6 & 268435455) + charCode + (charCode << 14), | |
charCode = resInt & 266338304, | |
resInt = 0 != charCode ? resInt ^ charCode >> 21 : resInt; | |
return resInt | |
} | |
})(window); | |
/** | |
* Created by zhangmx on 11/1/16. | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
var $c = function (a) { | |
this.w = a || [] | |
}; | |
$c.prototype.set = function (a) { | |
this.w[a] = !0 | |
} | |
; | |
$c.prototype.encode = function () { | |
for (var a = [], b = 0; b < this.w.length; b++) | |
this.w[b] && (a[Math.floor(b / 6)] ^= 1 << b % 6); | |
for (b = 0; b < a.length; b++) | |
a[b] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".charAt(a[b] || 0); | |
return a.join("") + "~" | |
} | |
; | |
var vd = new $c; | |
function J(a) { | |
vd.set(a) | |
} | |
var Nd = function (a, b) { | |
var c = new $c(Dd(a)); | |
c.set(b); | |
a.set(Gd, c.w) | |
} | |
, Td = function (a) { | |
a = Dd(a); | |
a = new $c(a); | |
for (var b = vd.w.slice(), c = 0; c < a.w.length; c++) | |
b[c] = b[c] || a.w[c]; | |
return (new $c(b)).encode() | |
} | |
, Dd = function (a) { | |
a = a.get(Gd); | |
ka(a) || (a = []); | |
return a | |
}; | |
var ea = function (a) { | |
return "function" == typeof a | |
} | |
, ka = function (a) { | |
return "[object Array]" == Object.prototype.toString.call(Object(a)) | |
} | |
, qa = function (a) { | |
return void 0 != a && -1 < (a.constructor + "").indexOf("String") | |
} | |
, D = function (a, b) { | |
return 0 == a.indexOf(b) | |
} | |
, sa = function (a) { | |
return a ? a.replace(/^[\s\xa0]+|[\s\xa0]+$/g, "") : "" | |
} | |
, ta = function (a) { | |
var b = M.createElement("img"); | |
b.width = 1; | |
b.height = 1; | |
b.src = a; | |
return b | |
} | |
, ua = function () { | |
} | |
, K = function (a) { | |
if (encodeURIComponent instanceof Function) | |
return encodeURIComponent(a); | |
J(28); | |
return a | |
} | |
, L = function (a, b, c, d) { | |
try { | |
a.addEventListener ? a.addEventListener(b, c, !!d) : a.attachEvent && a.attachEvent("on" + b, c) | |
} catch (e) { | |
J(27) | |
} | |
} | |
, f = /^[\w\-:/.?=&%!]+$/ | |
, wa = function (a, b, c) { | |
a && (c ? (c = "", | |
b && f.test(b) && (c = ' id="' + b + '"'), | |
f.test(a) && M.write("<script" + c + ' src="' + a + '">\x3c/script>')) : (c = M.createElement("script"), | |
c.type = "text/javascript", | |
c.async = !0, | |
c.src = a, | |
b && (c.id = b), | |
a = M.getElementsByTagName("script")[0], | |
a.parentNode.insertBefore(c, a))) | |
} | |
, Ud = function () { | |
return "https:" == M.location.protocol | |
} | |
, E = function (a, b) { | |
var c = a.match("(?:&|#|\\?)" + K(b).replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1") + "=([^&#]*)"); | |
return c && 2 == c.length ? c[1] : "" | |
} | |
, xa = function () { | |
var a = "" + M.location.hostname; | |
return 0 == a.indexOf("www.") ? a.substring(4) : a | |
} | |
, ya = function (a) { | |
var b = M.referrer; | |
if (/^https?:\/\//i.test(b)) { | |
if (a) | |
return b; | |
a = "//" + M.location.hostname; | |
var c = b.indexOf(a); | |
if (5 == c || 6 == c) | |
if (a = b.charAt(c + a.length), | |
"/" == a || "?" == a || "" == a || ":" == a) | |
return; | |
return b | |
} | |
} | |
, za = function (a, b) { | |
if (1 == b.length && null != b[0] && "object" === typeof b[0]) | |
return b[0]; | |
for (var c = {}, d = Math.min(a.length + 1, b.length), e = 0; e < d; e++) | |
if ("object" === typeof b[e]) { | |
for (var g in b[e]) | |
b[e].hasOwnProperty(g) && (c[g] = b[e][g]); | |
break | |
} else | |
e < a.length && (c[a[e]] = b[e]); | |
return c | |
}; | |
var ee = function () { | |
this.keys = []; | |
this.values = {}; | |
this.m = {} | |
}; | |
ee.prototype.set = function (a, b, c) { | |
this.keys.push(a); | |
c ? this.m[":" + a] = b : this.values[":" + a] = b | |
} | |
; | |
ee.prototype.get = function (a) { | |
return this.m.hasOwnProperty(":" + a) ? this.m[":" + a] : this.values[":" + a] | |
} | |
; | |
ee.prototype.map = function (a) { | |
for (var b = 0; b < this.keys.length; b++) { | |
var c = this.keys[b] | |
, d = this.get(c); | |
d && a(c, d) | |
} | |
} | |
; | |
var O = window | |
, M = document; | |
var F = window | |
, G = function (a) { | |
var b = F._gaUserPrefs; | |
if (b && b.ioo && b.ioo() || a && !0 === F["ga-disable-" + a]) | |
return !0; | |
try { | |
var c = F.external; | |
if (c && c._gaUserPrefs && "oo" == c._gaUserPrefs) | |
return !0 | |
} catch (d) { | |
} | |
return !1 | |
}; | |
var Ca = function (a) { | |
var b = [] | |
, c = M.cookie.split(";"); | |
a = new RegExp("^\\s*" + a + "=\\s*(.*?)\\s*$"); | |
for (var d = 0; d < c.length; d++) { | |
var e = c[d].match(a); | |
e && b.push(e[1]) | |
} | |
return b | |
} | |
, zc = function (a, b, c, d, e, g) { | |
e = G(e) ? !1 : eb.test(M.location.hostname) || "/" == c && vc.test(d) ? !1 : !0; | |
if (!e) | |
return !1; | |
b && 1200 < b.length && (b = b.substring(0, 1200), | |
J(24)); | |
c = a + "=" + b + "; path=" + c + "; "; | |
g && (c += "expires=" + (new Date((new Date).getTime() + g)).toGMTString() + "; "); | |
d && "none" != d && (c += "domain=" + d + ";"); | |
d = M.cookie; | |
M.cookie = c; | |
if (!(d = d != M.cookie)) | |
a: { | |
a = Ca(a); | |
for (d = 0; d < a.length; d++) | |
if (b == a[d]) { | |
d = !0; | |
break a | |
} | |
d = !1 | |
} | |
return d | |
} | |
, Cc = function (a) { | |
return K(a).replace(/\(/g, "%28").replace(/\)/g, "%29") | |
} | |
, vc = /^(www\.)?google(\.com?)?(\.[a-z]{2})?$/ | |
, eb = /(^|\.)doubleclick\.net$/i; | |
var oc = function () { | |
return (Ba || Ud() ? "https:" : "http:") + "//www.google-analytics.com" | |
} | |
, Da = function (a) { | |
this.name = "len"; | |
this.message = a + "-8192" | |
} | |
, ba = function (a, b, c) { | |
c = c || ua; | |
if (2036 >= b.length) | |
wc(a, b, c); | |
else if (8192 >= b.length) | |
x(a, b, c) || wd(a, b, c) || wc(a, b, c); | |
else | |
throw ge("len", b.length), | |
new Da(b.length); | |
} | |
, wc = function (a, b, c) { | |
var d = ta(a + "?" + b); | |
d.onload = d.onerror = function () { | |
d.onload = null; | |
d.onerror = null; | |
c() | |
} | |
} | |
, wd = function (a, b, c) { | |
var d = O.XMLHttpRequest; | |
if (!d) | |
return !1; | |
var e = new d; | |
if (!("withCredentials" in e)) | |
return !1; | |
e.open("POST", a, !0); | |
e.withCredentials = !0; | |
e.setRequestHeader("Content-Type", "text/plain"); | |
e.onreadystatechange = function () { | |
4 == e.readyState && (c(), | |
e = null ) | |
} | |
; | |
e.send(b); | |
return !0 | |
} | |
, x = function (a, b, c) { | |
return O.navigator.sendBeacon ? O.navigator.sendBeacon(a, b) ? (c(), | |
!0) : !1 : !1 | |
} | |
, ge = function (a, b, c) { | |
1 <= 100 * Math.random() || G("?") || (a = ["t=error", "_e=" + a, "_v=j47", "sr=1"], | |
b && a.push("_f=" + b), | |
c && a.push("_m=" + K(c.substring(0, 100))), | |
a.push("aip=1"), | |
a.push("z=" + hd()), | |
wc(oc() + "/collect", a.join("&"), ua)) | |
}; | |
var h = function (a) { | |
var b = O.gaData = O.gaData || {}; | |
return b[a] = b[a] || {} | |
}; | |
var Ha = function () { | |
this.M = [] | |
}; | |
Ha.prototype.add = function (a) { | |
this.M.push(a) | |
} | |
; | |
Ha.prototype.D = function (a) { | |
try { | |
for (var b = 0; b < this.M.length; b++) { | |
var c = a.get(this.M[b]); | |
c && ea(c) && c.call(O, a) | |
} | |
} catch (d) { | |
} | |
b = a.get(Ia); | |
b != ua && ea(b) && (a.set(Ia, ua, !0), | |
setTimeout(b, 10)) | |
} | |
; | |
function Ja(a) { | |
if (100 != a.get(Ka) && La(P(a, Q)) % 1E4 >= 100 * R(a, Ka)) | |
throw "abort"; | |
} | |
function Ma(a) { | |
if (G(P(a, Na))) | |
throw "abort"; | |
} | |
function Oa() { | |
var a = M.location.protocol; | |
if ("http:" != a && "https:" != a) | |
throw "abort"; | |
} | |
function Pa(a) { | |
try { | |
O.navigator.sendBeacon ? J(42) : O.XMLHttpRequest && "withCredentials" in new O.XMLHttpRequest && J(40) | |
} catch (c) { | |
} | |
a.set(ld, Td(a), !0); | |
a.set(Ac, R(a, Ac) + 1); | |
var b = []; | |
Qa.map(function (c, d) { | |
if (d.F) { | |
var e = a.get(c); | |
void 0 != e && e != d.defaultValue && ("boolean" == typeof e && (e *= 1), | |
b.push(d.F + "=" + K("" + e))) | |
} | |
}); | |
b.push("z=" + Bd()); | |
a.set(Ra, b.join("&"), !0) | |
} | |
function Sa(a) { | |
var b = P(a, gd) || oc() + "/collect" | |
, c = P(a, fa); | |
!c && a.get(Vd) && (c = "beacon"); | |
if (c) { | |
var d = P(a, Ra) | |
, e = a.get(Ia) | |
, e = e || ua; | |
"image" == c ? wc(b, d, e) : "xhr" == c && wd(b, d, e) || "beacon" == c && x(b, d, e) || ba(b, d, e) | |
} else | |
ba(b, P(a, Ra), a.get(Ia)); | |
b = a.get(Na); | |
b = h(b); | |
c = b.hitcount; | |
b.hitcount = c ? c + 1 : 1; | |
b = a.get(Na); | |
delete h(b).pending_experiments; | |
a.set(Ia, ua, !0) | |
} | |
function Hc(a) { | |
(O.gaData = O.gaData || {}).expId && a.set(Nc, (O.gaData = O.gaData || {}).expId); | |
(O.gaData = O.gaData || {}).expVar && a.set(Oc, (O.gaData = O.gaData || {}).expVar); | |
var b; | |
var c = a.get(Na); | |
if (c = h(c).pending_experiments) { | |
var d = []; | |
for (b in c) | |
c.hasOwnProperty(b) && c[b] && d.push(encodeURIComponent(b) + "." + encodeURIComponent(c[b])); | |
b = d.join("!") | |
} else | |
b = void 0; | |
b && a.set(m, b, !0) | |
} | |
function cd() { | |
if (O.navigator && "preview" == O.navigator.loadPurpose) | |
throw "abort"; | |
} | |
function yd(a) { | |
var b = O.gaDevIds; | |
ka(b) && 0 != b.length && a.set("&did", b.join(","), !0) | |
} | |
function vb(a) { | |
if (!a.get(Na)) | |
throw "abort"; | |
} | |
; | |
var hd = function () { | |
return Math.round(2147483647 * Math.random()) | |
} | |
, Bd = function () { | |
try { | |
var a = new Uint32Array(1); | |
O.crypto.getRandomValues(a); | |
return a[0] & 2147483647 | |
} catch (b) { | |
return hd() | |
} | |
}; | |
function Ta(a) { | |
var b = R(a, Ua); | |
500 <= b && J(15); | |
var c = P(a, Va); | |
if ("transaction" != c && "item" != c) { | |
var c = R(a, Wa) | |
, d = (new Date).getTime() | |
, e = R(a, Xa); | |
0 == e && a.set(Xa, d); | |
e = Math.round(2 * (d - e) / 1E3); | |
0 < e && (c = Math.min(c + e, 20), | |
a.set(Xa, d)); | |
if (0 >= c) | |
throw "abort"; | |
a.set(Wa, --c) | |
} | |
a.set(Ua, ++b) | |
} | |
; | |
var Ya = function () { | |
this.data = new ee | |
} | |
, Qa = new ee | |
, Za = []; | |
Ya.prototype.get = function (a) { | |
var b = $a(a) | |
, c = this.data.get(a); | |
b && void 0 == c && (c = ea(b.defaultValue) ? b.defaultValue() : b.defaultValue); | |
return b && b.Z ? b.Z(this, a, c) : c | |
} | |
; | |
var P = function (a, b) { | |
var c = a.get(b); | |
return void 0 == c ? "" : "" + c | |
} | |
, R = function (a, b) { | |
var c = a.get(b); | |
return void 0 == c || "" === c ? 0 : 1 * c | |
}; | |
Ya.prototype.set = function (a, b, c) { | |
if (a) | |
if ("object" == typeof a) | |
for (var d in a) | |
a.hasOwnProperty(d) && ab(this, d, a[d], c); | |
else | |
ab(this, a, b, c) | |
} | |
; | |
var ab = function (a, b, c, d) { | |
if (void 0 != c) | |
switch (b) { | |
case Na: | |
wb.test(c) | |
} | |
var e = $a(b); | |
e && e.o ? e.o(a, b, c, d) : a.data.set(b, c, d) | |
} | |
, bb = function (a, b, c, d, e) { | |
this.name = a; | |
this.F = b; | |
this.Z = d; | |
this.o = e; | |
this.defaultValue = c | |
} | |
, $a = function (a) { | |
var b = Qa.get(a); | |
if (!b) | |
for (var c = 0; c < Za.length; c++) { | |
var d = Za[c] | |
, e = d[0].exec(a); | |
if (e) { | |
b = d[1](e); | |
Qa.set(b.name, b); | |
break | |
} | |
} | |
return b | |
} | |
, yc = function (a) { | |
var b; | |
Qa.map(function (c, d) { | |
d.F == a && (b = d) | |
}); | |
return b && b.name | |
} | |
, S = function (a, b, c, d, e) { | |
a = new bb(a, b, c, d, e); | |
Qa.set(a.name, a); | |
return a.name | |
} | |
, cb = function (a, b) { | |
Za.push([new RegExp("^" + a + "$"), b]) | |
} | |
, T = function (a, b, c) { | |
return S(a, b, c, void 0, db) | |
} | |
, db = function () { | |
}; | |
var gb = qa(window.GoogleAnalyticsObject) && sa(window.GoogleAnalyticsObject) || "ga" | |
, Ba = !1 | |
, hb = T("apiVersion", "v") | |
, ib = T("clientVersion", "_v"); | |
S("anonymizeIp", "aip"); | |
var jb = S("adSenseId", "a") | |
, Va = S("hitType", "t") | |
, Ia = S("hitCallback") | |
, Ra = S("hitPayload"); | |
S("nonInteraction", "ni"); | |
S("currencyCode", "cu"); | |
S("dataSource", "ds"); | |
var Vd = S("useBeacon", void 0, !1) | |
, fa = S("transport"); | |
S("sessionControl", "sc", ""); | |
S("sessionGroup", "sg"); | |
S("queueTime", "qt"); | |
var Ac = S("_s", "_s"); | |
S("screenName", "cd"); | |
var kb = S("location", "dl", "") | |
, lb = S("referrer", "dr") | |
, mb = S("page", "dp", ""); | |
S("hostname", "dh"); | |
var nb = S("language", "ul") | |
, ob = S("encoding", "de"); | |
S("title", "dt", function () { | |
return M.title || void 0 | |
}); | |
cb("contentGroup([0-9]+)", function (a) { | |
return new bb(a[0], "cg" + a[1]) | |
}); | |
var pb = S("screenColors", "sd") | |
, qb = S("screenResolution", "sr") | |
, rb = S("viewportSize", "vp") | |
, sb = S("javaEnabled", "je") | |
, tb = S("flashVersion", "fl"); | |
S("campaignId", "ci"); | |
S("campaignName", "cn"); | |
S("campaignSource", "cs"); | |
S("campaignMedium", "cm"); | |
S("campaignKeyword", "ck"); | |
S("campaignContent", "cc"); | |
var ub = S("eventCategory", "ec") | |
, xb = S("eventAction", "ea") | |
, yb = S("eventLabel", "el") | |
, zb = S("eventValue", "ev") | |
, Bb = S("socialNetwork", "sn") | |
, Cb = S("socialAction", "sa") | |
, Db = S("socialTarget", "st") | |
, Eb = S("l1", "plt") | |
, Fb = S("l2", "pdt") | |
, Gb = S("l3", "dns") | |
, Hb = S("l4", "rrt") | |
, Ib = S("l5", "srt") | |
, Jb = S("l6", "tcp") | |
, Kb = S("l7", "dit") | |
, Lb = S("l8", "clt") | |
, Mb = S("timingCategory", "utc") | |
, Nb = S("timingVar", "utv") | |
, Ob = S("timingLabel", "utl") | |
, Pb = S("timingValue", "utt"); | |
S("appName", "an"); | |
S("appVersion", "av", ""); | |
S("appId", "aid", ""); | |
S("appInstallerId", "aiid", ""); | |
S("exDescription", "exd"); | |
S("exFatal", "exf"); | |
var Nc = S("expId", "xid") | |
, Oc = S("expVar", "xvar") | |
, m = S("exp", "exp") | |
, Rc = S("_utma", "_utma") | |
, Sc = S("_utmz", "_utmz") | |
, Tc = S("_utmht", "_utmht") | |
, Ua = S("_hc", void 0, 0) | |
, Xa = S("_ti", void 0, 0) | |
, Wa = S("_to", void 0, 20); | |
cb("dimension([0-9]+)", function (a) { | |
return new bb(a[0], "cd" + a[1]) | |
}); | |
cb("metric([0-9]+)", function (a) { | |
return new bb(a[0], "cm" + a[1]) | |
}); | |
S("linkerParam", void 0, void 0, Bc, db); | |
var ld = S("usage", "_u") | |
, Gd = S("_um"); | |
S("forceSSL", void 0, void 0, function () { | |
return Ba | |
}, function (a, b, c) { | |
J(34); | |
Ba = !!c | |
}); | |
var ed = S("_j1", "jid"); | |
cb("\\&(.*)", function (a) { | |
var b = new bb(a[0], a[1]) | |
, c = yc(a[0].substring(1)); | |
c && (b.Z = function (a) { | |
return a.get(c) | |
} | |
, | |
b.o = function (a, b, g, ca) { | |
a.set(c, g, ca) | |
} | |
, | |
b.F = void 0); | |
return b | |
}); | |
var Qb = T("_oot") | |
, dd = S("previewTask") | |
, Rb = S("checkProtocolTask") | |
, md = S("validationTask") | |
, Sb = S("checkStorageTask") | |
, Uc = S("historyImportTask") | |
, Tb = S("samplerTask") | |
, Vb = S("_rlt") | |
, Wb = S("buildHitTask") | |
, Xb = S("sendHitTask") | |
, Vc = S("ceTask") | |
, zd = S("devIdTask") | |
, Cd = S("timingTask") | |
, Ld = S("displayFeaturesTask") | |
, V = T("name") | |
, Q = T("clientId", "cid") | |
, n = T("clientIdTime") | |
, Ad = S("userId", "uid") | |
, Na = T("trackingId", "tid") | |
, U = T("cookieName", void 0, "_ga") | |
, W = T("cookieDomain") | |
, Yb = T("cookiePath", void 0, "/") | |
, Zb = T("cookieExpires", void 0, 63072E3) | |
, $b = T("legacyCookieDomain") | |
, Wc = T("legacyHistoryImport", void 0, !0) | |
, ac = T("storage", void 0, "cookie") | |
, bc = T("allowLinker", void 0, !1) | |
, cc = T("allowAnchor", void 0, !0) | |
, Ka = T("sampleRate", "sf", 100) | |
, dc = T("siteSpeedSampleRate", void 0, 1) | |
, ec = T("alwaysSendReferrer", void 0, !1) | |
, gd = S("transportUrl") | |
, Md = S("_r", "_r"); | |
function X(a, b, c, d) { | |
b[a] = function () { | |
try { | |
return d && J(d), | |
c.apply(this, arguments) | |
} catch (e) { | |
throw ge("exc", a, e && e.name), | |
e; | |
} | |
} | |
} | |
; | |
var Od = function (a) { | |
this.V = a; | |
this.fa = void 0; | |
this.$ = !1; | |
this.oa = void 0; | |
this.ea = 1 | |
} | |
, Ed = function (a, b) { | |
var c; | |
if (a.fa && a.$) | |
return 0; | |
a.$ = !0; | |
if (b) { | |
if (a.oa && R(b, a.oa)) | |
return R(b, a.oa); | |
if (0 == b.get(dc)) | |
return 0 | |
} | |
if (0 == a.V) | |
return 0; | |
void 0 === c && (c = Bd()); | |
return 0 == c % a.V ? Math.floor(c / a.V) % a.ea + 1 : 0 | |
}; | |
function fc() { | |
var a, b, c; | |
if ((c = (c = O.navigator) ? c.plugins : null ) && c.length) | |
for (var d = 0; d < c.length && !b; d++) { | |
var e = c[d]; | |
-1 < e.name.indexOf("Shockwave Flash") && (b = e.description) | |
} | |
if (!b) | |
try { | |
a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"), | |
b = a.GetVariable("$version") | |
} catch (g) { | |
} | |
if (!b) | |
try { | |
a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"), | |
b = "WIN 6,0,21,0", | |
a.AllowScriptAccess = "always", | |
b = a.GetVariable("$version") | |
} catch (g) { | |
} | |
if (!b) | |
try { | |
a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"), | |
b = a.GetVariable("$version") | |
} catch (g) { | |
} | |
b && (a = b.match(/[\d]+/g)) && 3 <= a.length && (b = a[0] + "." + a[1] + " r" + a[2]); | |
return b || void 0 | |
} | |
; | |
var aa = function (a) { | |
var b = Math.min(R(a, dc), 100); | |
return La(P(a, Q)) % 100 >= b ? !1 : !0 | |
} | |
, gc = function (a) { | |
var b = {}; | |
if (Ec(b) || Fc(b)) { | |
var c = b[Eb]; | |
void 0 == c || Infinity == c || isNaN(c) || (0 < c ? (Y(b, Gb), | |
Y(b, Jb), | |
Y(b, Ib), | |
Y(b, Fb), | |
Y(b, Hb), | |
Y(b, Kb), | |
Y(b, Lb), | |
a(b)) : L(O, "load", function () { | |
gc(a) | |
}, !1)) | |
} | |
} | |
, Ec = function (a) { | |
var b = O.performance || O.webkitPerformance | |
, b = b && b.timing; | |
if (!b) | |
return !1; | |
var c = b.navigationStart; | |
if (0 == c) | |
return !1; | |
a[Eb] = b.loadEventStart - c; | |
a[Gb] = b.domainLookupEnd - b.domainLookupStart; | |
a[Jb] = b.connectEnd - b.connectStart; | |
a[Ib] = b.responseStart - b.requestStart; | |
a[Fb] = b.responseEnd - b.responseStart; | |
a[Hb] = b.fetchStart - c; | |
a[Kb] = b.domInteractive - c; | |
a[Lb] = b.domContentLoadedEventStart - c; | |
return !0 | |
} | |
, Fc = function (a) { | |
if (O.top != O) | |
return !1; | |
var b = O.external | |
, c = b && b.onloadT; | |
b && !b.isValidLoadTime && (c = void 0); | |
2147483648 < c && (c = void 0); | |
0 < c && b.setPageReadyTime(); | |
if (void 0 == c) | |
return !1; | |
a[Eb] = c; | |
return !0 | |
} | |
, Y = function (a, b) { | |
var c = a[b]; | |
if (isNaN(c) || Infinity == c || 0 > c) | |
a[b] = void 0 | |
} | |
, Fd = function (a) { | |
return function (b) { | |
if ("pageview" == b.get(Va) && !a.I) { | |
a.I = !0; | |
var c = aa(b); | |
b = 0 < E(b.get(kb), "gclid").length; | |
(c || b) && gc(function (b) { | |
a.send(c ? "timing" : "adtiming", b) | |
}) | |
} | |
} | |
}; | |
var hc = !1 | |
, mc = function (a) { | |
if ("cookie" == P(a, ac)) { | |
var b = P(a, U) | |
, c = nd(a) | |
, d = kc(P(a, Yb)) | |
, e = lc(P(a, W)) | |
, g = 1E3 * R(a, Zb) | |
, ca = P(a, Na); | |
if ("auto" != e) | |
zc(b, c, d, e, ca, g) && (hc = !0); | |
else { | |
J(32); | |
var l; | |
a: { | |
c = []; | |
e = xa().split("."); | |
if (4 == e.length && (l = e[e.length - 1], | |
parseInt(l, 10) == l)) { | |
l = ["none"]; | |
break a | |
} | |
for (l = e.length - 2; 0 <= l; l--) | |
c.push(e.slice(l).join(".")); | |
c.push("none"); | |
l = c | |
} | |
for (var k = 0; k < l.length; k++) | |
if (e = l[k], | |
a.data.set(W, e), | |
c = nd(a), | |
zc(b, c, d, e, ca, g)) { | |
hc = !0; | |
return | |
} | |
a.data.set(W, "auto") | |
} | |
} | |
} | |
, nc = function (a) { | |
if ("cookie" == P(a, ac) && !hc && (mc(a), | |
!hc)) | |
throw "abort"; | |
} | |
, Yc = function (a) { | |
if (a.get(Wc)) { | |
var b = P(a, W) | |
, c = P(a, $b) || xa() | |
, d = Xc("__utma", c, b); | |
d && (J(19), | |
a.set(Tc, (new Date).getTime(), !0), | |
a.set(Rc, d.R), | |
(b = Xc("__utmz", c, b)) && d.hash == b.hash && a.set(Sc, b.R)) | |
} | |
} | |
, nd = function (a) { | |
var b = Cc(P(a, Q)) | |
, c = lc(P(a, W)).split(".").length; | |
a = jc(P(a, Yb)); | |
1 < a && (c += "-" + a); | |
return ["GA1", c, b].join(".") | |
} | |
, Gc = function (a, b, c) { | |
for (var d = [], e = [], g, ca = 0; ca < a.length; ca++) { | |
var l = a[ca]; | |
l.H[c] == b ? d.push(l) : void 0 == g || l.H[c] < g ? (e = [l], | |
g = l.H[c]) : l.H[c] == g && e.push(l) | |
} | |
return 0 < d.length ? d : e | |
} | |
, lc = function (a) { | |
return 0 == a.indexOf(".") ? a.substr(1) : a | |
} | |
, kc = function (a) { | |
if (!a) | |
return "/"; | |
1 < a.length && a.lastIndexOf("/") == a.length - 1 && (a = a.substr(0, a.length - 1)); | |
0 != a.indexOf("/") && (a = "/" + a); | |
return a | |
} | |
, jc = function (a) { | |
a = kc(a); | |
return "/" == a ? 1 : a.split("/").length | |
}; | |
function Xc(a, b, c) { | |
"none" == b && (b = ""); | |
var d = [] | |
, e = Ca(a); | |
a = "__utma" == a ? 6 : 2; | |
for (var g = 0; g < e.length; g++) { | |
var ca = ("" + e[g]).split("."); | |
ca.length >= a && d.push({ | |
hash: ca[0], | |
R: e[g], | |
O: ca | |
}) | |
} | |
if (0 != d.length) | |
return 1 == d.length ? d[0] : Zc(b, d) || Zc(c, d) || Zc(null, d) || d[0] | |
} | |
function Zc(a, b) { | |
var c, d; | |
null == a ? c = d = 1 : (c = La(a), | |
d = La(D(a, ".") ? a.substring(1) : "." + a)); | |
for (var e = 0; e < b.length; e++) | |
if (b[e].hash == c || b[e].hash == d) | |
return b[e] | |
} | |
; | |
var od = new RegExp(/^https?:\/\/([^\/:]+)/) | |
, pd = /(.*)([?&#])(?:_ga=[^&#]*)(?:&?)(.*)/; | |
function Bc(a) { | |
a = a.get(Q); | |
var b = Ic(a, 0); | |
return "_ga=1." + K(b + "." + a) | |
} | |
function Ic(a, b) { | |
for (var c = new Date, d = O.navigator, e = d.plugins || [], c = [a, d.userAgent, c.getTimezoneOffset(), c.getYear(), c.getDate(), c.getHours(), c.getMinutes() + b], d = 0; d < e.length; ++d) | |
c.push(e[d].description); | |
return La(c.join(".")) | |
} | |
var Dc = function (a) { | |
J(48); | |
this.target = a; | |
this.T = !1 | |
}; | |
Dc.prototype.ca = function (a, b) { | |
if (a.tagName) { | |
if ("a" == a.tagName.toLowerCase()) { | |
a.href && (a.href = qd(this, a.href, b)); | |
return | |
} | |
if ("form" == a.tagName.toLowerCase()) | |
return rd(this, a) | |
} | |
if ("string" == typeof a) | |
return qd(this, a, b) | |
} | |
; | |
var qd = function (a, b, c) { | |
var d = pd.exec(b); | |
d && 3 <= d.length && (b = d[1] + (d[3] ? d[2] + d[3] : "")); | |
a = a.target.get("linkerParam"); | |
var e = b.indexOf("?") | |
, d = b.indexOf("#"); | |
c ? b += (-1 == d ? "#" : "&") + a : (c = -1 == e ? "?" : "&", | |
b = -1 == d ? b + (c + a) : b.substring(0, d) + c + a + b.substring(d)); | |
return b = b.replace(/&+_ga=/, "&_ga=") | |
} | |
, rd = function (a, b) { | |
if (b && b.action) { | |
var c = a.target.get("linkerParam").split("=")[1]; | |
if ("get" == b.method.toLowerCase()) { | |
for (var d = b.childNodes || [], e = 0; e < d.length; e++) | |
if ("_ga" == d[e].name) { | |
d[e].setAttribute("value", c); | |
return | |
} | |
d = M.createElement("input"); | |
d.setAttribute("type", "hidden"); | |
d.setAttribute("name", "_ga"); | |
d.setAttribute("value", c); | |
b.appendChild(d) | |
} else | |
"post" == b.method.toLowerCase() && (b.action = qd(a, b.action)) | |
} | |
}; | |
Dc.prototype.S = function (a, b, c) { | |
function d(c) { | |
try { | |
c = c || O.event; | |
var d; | |
a: { | |
var g = c.target || c.srcElement; | |
for (c = 100; g && 0 < c;) { | |
if (g.href && g.nodeName.match(/^a(?:rea)?$/i)) { | |
d = g; | |
break a | |
} | |
g = g.parentNode; | |
c-- | |
} | |
d = {} | |
} | |
("http:" == d.protocol || "https:" == d.protocol) && sd(a, d.hostname || "") && d.href && (d.href = qd(e, d.href, b)) | |
} catch (k) { | |
J(26) | |
} | |
} | |
var e = this; | |
this.T || (this.T = !0, | |
L(M, "mousedown", d, !1), | |
L(M, "keyup", d, !1)); | |
c && L(M, "submit", function (b) { | |
b = b || O.event; | |
if ((b = b.target || b.srcElement) && b.action) { | |
var c = b.action.match(od); | |
c && sd(a, c[1]) && rd(e, b) | |
} | |
}) | |
} | |
; | |
function sd(a, b) { | |
if (b == M.location.hostname) | |
return !1; | |
for (var c = 0; c < a.length; c++) | |
if (a[c] instanceof RegExp) { | |
if (a[c].test(b)) | |
return !0 | |
} else if (0 <= b.indexOf(a[c])) | |
return !0; | |
return !1 | |
} | |
; | |
var p = /^(GTM|OPT)-[A-Z0-9]+$/ | |
, q = /;_gaexp=[^;]*/g | |
, r = /;((__utma=)|([^;=]+=GAX?\d+\.))[^;]*/g | |
, t = function (a) { | |
function b(a, b) { | |
b && (c += "&" + a + "=" + K(b)) | |
} | |
var c = "https://www.google-analytics.com/gtm/js?id=" + K(a.id); | |
"dataLayer" != a.B && b("l", a.B); | |
b("t", a.target); | |
b("cid", a.ja); | |
b("cidt", a.ka); | |
b("gac", a.la); | |
b("aip", a.ia); | |
a.na && b("m", "sync"); | |
b("cycle", a.G); | |
return c | |
}; | |
var Jd = function (a, b, c) { | |
this.U = ed; | |
this.aa = b; | |
(b = c) || (b = (b = P(a, V)) && "t0" != b ? Wd.test(b) ? "_gat_" + Cc(P(a, Na)) : "_gat_" + Cc(b) : "_gat"); | |
this.Y = b; | |
Ed(new Od(100), a) && (J(30), | |
this.pa = !0) | |
} | |
, Rd = function (a, b) { | |
var c = b.get(Wb); | |
b.set(Wb, function (b) { | |
Pd(a, b); | |
var d = c(b); | |
Qd(a, b); | |
return d | |
}); | |
var d = b.get(Xb); | |
b.set(Xb, function (b) { | |
var c = d(b); | |
Id(a, b); | |
return c | |
}) | |
} | |
, Pd = function (a, b) { | |
b.get(a.U) || ("1" == Ca(a.Y)[0] ? b.set(a.U, "", !0) : b.set(a.U, "" + hd(), !0)) | |
} | |
, Qd = function (a, b) { | |
if (b.get(a.U)) { | |
var c = 6E5; | |
a.pa && (c /= 10); | |
zc(a.Y, "1", b.get(Yb), b.get(W), b.get(Na), c) | |
} | |
} | |
, Id = function (a, b) { | |
if (b.get(a.U)) { | |
var c = new ee | |
, d = function (a) { | |
$a(a).F && c.set($a(a).F, b.get(a)) | |
}; | |
d(hb); | |
d(ib); | |
d(Na); | |
d(Q); | |
d(Ad); | |
d(a.U); | |
c.set($a(ld).F, Td(b)); | |
var e = a.aa; | |
c.map(function (a, b) { | |
e += K(a) + "="; | |
e += K("" + b) + "&" | |
}); | |
e += "z=" + hd(); | |
ta(e); | |
b.set(a.U, "", !0) | |
} | |
} | |
, Wd = /^gtm\d+$/; | |
var fd = function (a, b) { | |
var c = a.b; | |
if (!c.get("dcLoaded")) { | |
Nd(c, 29); | |
b = b || {}; | |
var d; | |
b[U] && (d = Cc(b[U])); | |
d = new Jd(c, "https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&", d); | |
Rd(d, c); | |
c.set("dcLoaded", !0) | |
} | |
}; | |
var Sd = function (a) { | |
if (!a.get("dcLoaded") && "cookie" == a.get(ac)) { | |
Nd(a, 51); | |
var b = new Jd(a); | |
Pd(b, a); | |
Qd(b, a); | |
a.get(b.U) && (a.set(Md, 1, !0), | |
a.set(gd, oc() + "/r/collect", !0)) | |
} | |
}; | |
var Lc = function () { | |
var a = O.gaGlobal = O.gaGlobal || {}; | |
return a.hid = a.hid || hd() | |
}; | |
var ad, bd = function (a, b, c) { | |
if (!ad) { | |
var d; | |
d = M.location.hash; | |
var e = O.name | |
, g = /^#?gaso=([^&]*)/; | |
if (e = (d = (d = d && d.match(g) || e && e.match(g)) ? d[1] : Ca("GASO")[0] || "") && d.match(/^(?:!([-0-9a-z.]{1,40})!)?([-.\w]{10,1200})$/i)) | |
zc("GASO", "" + d, c, b, a, 0), | |
window._udo || (window._udo = b), | |
window._utcp || (window._utcp = c), | |
a = e[1], | |
wa("https://www.google.com/analytics/web/inpage/pub/inpage.js?" + (a ? "prefix=" + a + "&" : "") + hd(), "_gasojs"); | |
ad = !0 | |
} | |
}; | |
var wb = /^(UA|YT|MO|GP)-(\d+)-(\d+)$/ | |
, pc = function (a) { | |
function b(a, b) { | |
d.b.data.set(a, b) | |
} | |
function c(a, c) { | |
b(a, c); | |
d.filters.add(a) | |
} | |
var d = this; | |
this.b = new Ya; | |
this.filters = new Ha; | |
b(V, a[V]); | |
b(Na, sa(a[Na])); | |
b(U, a[U]); | |
b(W, a[W] || xa()); | |
b(Yb, a[Yb]); | |
b(Zb, a[Zb]); | |
b($b, a[$b]); | |
b(Wc, a[Wc]); | |
b(bc, a[bc]); | |
b(cc, a[cc]); | |
b(Ka, a[Ka]); | |
b(dc, a[dc]); | |
b(ec, a[ec]); | |
b(ac, a[ac]); | |
b(Ad, a[Ad]); | |
b(n, a[n]); | |
b(hb, 1); | |
b(ib, "j47"); | |
c(Qb, Ma); | |
c(dd, cd); | |
c(Rb, Oa); | |
c(md, vb); | |
c(Sb, nc); | |
c(Uc, Yc); | |
c(Tb, Ja); | |
c(Vb, Ta); | |
c(Vc, Hc); | |
c(zd, yd); | |
c(Ld, Sd); | |
c(Wb, Pa); | |
c(Xb, Sa); | |
c(Cd, Fd(this)); | |
Jc(this.b, a[Q]); | |
Kc(this.b); | |
this.b.set(jb, Lc()); | |
bd(this.b.get(Na), this.b.get(W), this.b.get(Yb)) | |
} | |
, Jc = function (a, b) { | |
if ("cookie" == P(a, ac)) { | |
hc = !1; | |
var c; | |
b: { | |
var d = Ca(P(a, U)); | |
if (d && !(1 > d.length)) { | |
c = []; | |
for (var e = 0; e < d.length; e++) { | |
var g; | |
g = d[e].split("."); | |
var ca = g.shift(); | |
("GA1" == ca || "1" == ca) && 1 < g.length ? (ca = g.shift().split("-"), | |
1 == ca.length && (ca[1] = "1"), | |
ca[0] *= 1, | |
ca[1] *= 1, | |
g = { | |
H: ca, | |
s: g.join(".") | |
}) : g = void 0; | |
g && c.push(g) | |
} | |
if (1 == c.length) { | |
J(13); | |
c = c[0].s; | |
break b | |
} | |
if (0 == c.length) | |
J(12); | |
else { | |
J(14); | |
d = lc(P(a, W)).split(".").length; | |
c = Gc(c, d, 0); | |
if (1 == c.length) { | |
c = c[0].s; | |
break b | |
} | |
d = jc(P(a, Yb)); | |
c = Gc(c, d, 1); | |
c = c[0] && c[0].s; | |
break b | |
} | |
} | |
c = void 0 | |
} | |
c || (c = P(a, W), | |
d = P(a, $b) || xa(), | |
c = Xc("__utma", d, c), | |
void 0 != c ? (J(10), | |
c = c.O[1] + "." + c.O[2]) : c = void 0); | |
c && (a.data.set(Q, c), | |
hc = !0) | |
} | |
c = a.get(cc); | |
if (e = E(M.location[c ? "href" : "search"], "_ga")) | |
a.get(bc) ? (c = e.indexOf("."), | |
-1 == c ? J(22) : (d = e.substring(c + 1), | |
"1" != e.substring(0, c) ? J(22) : (c = d.indexOf("."), | |
-1 == c ? J(22) : (e = d.substring(0, c), | |
c = d.substring(c + 1), | |
e != Ic(c, 0) && e != Ic(c, -1) && e != Ic(c, -2) ? J(23) : (J(11), | |
a.data.set(Q, c)))))) : J(21); | |
b && (J(9), | |
a.data.set(Q, K(b))); | |
if (!a.get(Q)) | |
if (c = (c = O.gaGlobal && O.gaGlobal.vid) && -1 != c.search(/^(?:utma\.)?\d+\.\d+$/) ? c : void 0) | |
J(17), | |
a.data.set(Q, c); | |
else { | |
J(8); | |
c = O.navigator.userAgent + (M.cookie ? M.cookie : "") + (M.referrer ? M.referrer : ""); | |
d = c.length; | |
for (e = O.history.length; 0 < e;) | |
c += e-- ^ d++; | |
a.data.set(Q, [hd() ^ La(c) & 2147483647, Math.round((new Date).getTime() / 1E3)].join(".")) | |
} | |
mc(a) | |
} | |
, Kc = function (a) { | |
var b = O.navigator | |
, c = O.screen | |
, d = M.location; | |
a.set(lb, ya(a.get(ec))); | |
if (d) { | |
var e = d.pathname || ""; | |
"/" != e.charAt(0) && (J(31), | |
e = "/" + e); | |
a.set(kb, d.protocol + "//" + d.hostname + e + d.search) | |
} | |
c && a.set(qb, c.width + "x" + c.height); | |
c && a.set(pb, c.colorDepth + "-bit"); | |
var c = M.documentElement | |
, g = (e = M.body) && e.clientWidth && e.clientHeight | |
, ca = []; | |
c && c.clientWidth && c.clientHeight && ("CSS1Compat" === M.compatMode || !g) ? ca = [c.clientWidth, c.clientHeight] : g && (ca = [e.clientWidth, e.clientHeight]); | |
c = 0 >= ca[0] || 0 >= ca[1] ? "" : ca.join("x"); | |
a.set(rb, c); | |
a.set(tb, fc()); | |
a.set(ob, M.characterSet || M.charset); | |
a.set(sb, b && "function" === typeof b.javaEnabled && b.javaEnabled() || !1); | |
a.set(nb, (b && (b.language || b.browserLanguage) || "").toLowerCase()); | |
if (d && a.get(cc) && (b = M.location.hash)) { | |
b = b.split(/[?&#]+/); | |
d = []; | |
for (c = 0; c < b.length; ++c) | |
(D(b[c], "utm_id") || D(b[c], "utm_campaign") || D(b[c], "utm_source") || D(b[c], "utm_medium") || D(b[c], "utm_term") || D(b[c], "utm_content") || D(b[c], "gclid") || D(b[c], "dclid") || D(b[c], "gclsrc")) && d.push(b[c]); | |
0 < d.length && (b = "#" + d.join("&"), | |
a.set(kb, a.get(kb) + b)) | |
} | |
}; | |
pc.prototype.get = function (a) { | |
return this.b.get(a) | |
} | |
; | |
pc.prototype.set = function (a, b) { | |
this.b.set(a, b) | |
} | |
; | |
var qc = { | |
pageview: [mb], | |
event: [ub, xb, yb, zb], | |
social: [Bb, Cb, Db], | |
timing: [Mb, Nb, Pb, Ob] | |
}; | |
pc.prototype.send = function (a) { | |
if (!(1 > arguments.length)) { | |
var b, c; | |
"string" === typeof arguments[0] ? (b = arguments[0], | |
c = [].slice.call(arguments, 1)) : (b = arguments[0] && arguments[0][Va], | |
c = arguments); | |
b && (c = za(qc[b] || [], c), | |
c[Va] = b, | |
this.b.set(c, void 0, !0), | |
this.filters.D(this.b), | |
this.b.data.m = {}) | |
} | |
} | |
; | |
pc.prototype.ma = function (a, b) { | |
var c = this; | |
u(a, c, b) || (v(a, function () { | |
u(a, c, b) | |
}), | |
y(String(c.get(V)), a, void 0, b, !0)) | |
} | |
; | |
var rc = function (a) { | |
if ("prerender" == M.visibilityState) | |
return !1; | |
a(); | |
return !0 | |
} | |
, z = function (a) { | |
if (!rc(a)) { | |
J(16); | |
var b = !1 | |
, c = function () { | |
if (!b && rc(a)) { | |
b = !0; | |
var d = c | |
, e = M; | |
e.removeEventListener ? e.removeEventListener("visibilitychange", d, !1) : e.detachEvent && e.detachEvent("onvisibilitychange", d) | |
} | |
}; | |
L(M, "visibilitychange", c) | |
} | |
}; | |
var td = /^(?:(\w+)\.)?(?:(\w+):)?(\w+)$/ | |
, sc = function (a) { | |
if (ea(a[0])) | |
this.u = a[0]; | |
else { | |
var b = td.exec(a[0]); | |
null != b && 4 == b.length && (this.c = b[1] || "t0", | |
this.K = b[2] || "", | |
this.C = b[3], | |
this.a = [].slice.call(a, 1), | |
this.K || (this.A = "create" == this.C, | |
this.i = "require" == this.C, | |
this.g = "provide" == this.C, | |
this.ba = "remove" == this.C), | |
this.i && (3 <= this.a.length ? (this.X = this.a[1], | |
this.W = this.a[2]) : this.a[1] && (qa(this.a[1]) ? this.X = this.a[1] : this.W = this.a[1]))); | |
b = a[1]; | |
a = a[2]; | |
if (!this.C) | |
throw "abort"; | |
if (this.i && (!qa(b) || "" == b)) | |
throw "abort"; | |
if (this.g && (!qa(b) || "" == b || !ea(a))) | |
throw "abort"; | |
if (ud(this.c) || ud(this.K)) | |
throw "abort"; | |
if (this.g && "t0" != this.c) | |
throw "abort"; | |
} | |
}; | |
function ud(a) { | |
return 0 <= a.indexOf(".") || 0 <= a.indexOf(":") | |
} | |
; | |
var Yd, Zd, $d, A; | |
Yd = new ee; | |
$d = new ee; | |
A = new ee; | |
Zd = { | |
ec: 45, | |
ecommerce: 46, | |
linkid: 47 | |
}; | |
var u = function (a, b, c) { | |
b == N || b.get(V); | |
var d = Yd.get(a); | |
if (!ea(d)) | |
return !1; | |
b.plugins_ = b.plugins_ || new ee; | |
if (b.plugins_.get(a)) | |
return !0; | |
b.plugins_.set(a, new d(b, c || {})); | |
return !0 | |
} | |
, y = function (a, b, c, d, e) { | |
if (!ea(Yd.get(b)) && !$d.get(b)) { | |
Zd.hasOwnProperty(b) && J(Zd[b]); | |
if (p.test(b)) { | |
J(52); | |
a = N.j(a); | |
if (!a) | |
return !0; | |
c = d || {}; | |
d = { | |
id: b, | |
B: c.dataLayer || "dataLayer", | |
ia: !!a.get("anonymizeIp"), | |
na: e, | |
G: !1 | |
}; | |
a.get(">m") == b && (d.G = !0); | |
var g = String(a.get("name")); | |
"t0" != g && (d.target = g); | |
G(String(a.get("trackingId"))) || (d.ja = String(a.get(Q)), | |
d.ka = Number(a.get(n)), | |
a = c.palindrome ? r : q, | |
a = (a = M.cookie.replace(/^|(; +)/g, ";").match(a)) ? a.sort().join("").substring(1) : void 0, | |
d.la = a); | |
a = d.B; | |
c = (new Date).getTime(); | |
O[a] = O[a] || []; | |
c = { | |
"gtm.start": c | |
}; | |
e || (c.event = "gtm.js"); | |
O[a].push(c); | |
c = t(d) | |
} | |
!c && Zd.hasOwnProperty(b) ? (J(39), | |
c = b + ".js") : J(43); | |
c && (c && 0 <= c.indexOf("/") || (c = (Ba || Ud() ? "https:" : "http:") + "//www.google-analytics.com/plugins/ua/" + c), | |
d = ae(c), | |
a = d.protocol, | |
c = M.location.protocol, | |
("https:" == a || a == c || ("http:" != a ? 0 : "http:" == c)) && B(d) && (wa(d.url, void 0, e), | |
$d.set(b, !0))) | |
} | |
} | |
, v = function (a, b) { | |
var c = A.get(a) || []; | |
c.push(b); | |
A.set(a, c) | |
} | |
, C = function (a, b) { | |
Yd.set(a, b); | |
for (var c = A.get(a) || [], d = 0; d < c.length; d++) | |
c[d](); | |
A.set(a, []) | |
} | |
, B = function (a) { | |
var b = ae(M.location.href); | |
if (D(a.url, "https://www.google-analytics.com/gtm/js?id=")) | |
return !0; | |
if (a.query || 0 <= a.url.indexOf("?") || 0 <= a.path.indexOf("://")) | |
return !1; | |
if (a.host == b.host && a.port == b.port) | |
return !0; | |
b = "http:" == a.protocol ? 80 : 443; | |
return "www.google-analytics.com" == a.host && (a.port || b) == b && D(a.path, "/plugins/") ? !0 : !1 | |
} | |
, ae = function (a) { | |
function b(a) { | |
var b = (a.hostname || "").split(":")[0].toLowerCase() | |
, c = (a.protocol || "").toLowerCase() | |
, c = 1 * a.port || ("http:" == c ? 80 : "https:" == c ? 443 : ""); | |
a = a.pathname || ""; | |
D(a, "/") || (a = "/" + a); | |
return [b, "" + c, a] | |
} | |
var c = M.createElement("a"); | |
c.href = M.location.href; | |
var d = (c.protocol || "").toLowerCase() | |
, e = b(c) | |
, g = c.search || "" | |
, ca = d + "//" + e[0] + (e[1] ? ":" + e[1] : ""); | |
D(a, "//") ? a = d + a : D(a, "/") ? a = ca + a : !a || D(a, "?") ? a = ca + e[2] + (a || g) : 0 > a.split("/")[0].indexOf(":") && (a = ca + e[2].substring(0, e[2].lastIndexOf("/")) + "/" + a); | |
c.href = a; | |
d = b(c); | |
return { | |
protocol: (c.protocol || "").toLowerCase(), | |
host: d[0], | |
port: d[1], | |
path: d[2], | |
query: c.search || "", | |
url: a || "" | |
} | |
}; | |
var Z = { | |
ga: function () { | |
Z.f = [] | |
} | |
}; | |
Z.ga(); | |
Z.D = function (a) { | |
var b = Z.J.apply(Z, arguments) | |
, b = Z.f.concat(b); | |
for (Z.f = []; 0 < b.length && !Z.v(b[0]) && !(b.shift(), | |
0 < Z.f.length);) | |
; | |
Z.f = Z.f.concat(b) | |
} | |
; | |
Z.J = function (a) { | |
for (var b = [], c = 0; c < arguments.length; c++) | |
try { | |
var d = new sc(arguments[c]); | |
d.g ? C(d.a[0], d.a[1]) : (d.i && (d.ha = y(d.c, d.a[0], d.X, d.W)), | |
b.push(d)) | |
} catch (e) { | |
} | |
return b | |
} | |
; | |
Z.v = function (a) { | |
try { | |
if (a.u) | |
a.u.call(O, N.j("t0")); | |
else { | |
var b = a.c == gb ? N : N.j(a.c); | |
if (a.A) | |
"t0" != a.c || N.create.apply(N, a.a); | |
else if (a.ba) | |
N.remove(a.c); | |
else if (b) | |
if (a.i) { | |
if (a.ha && (a.ha = y(a.c, a.a[0], a.X, a.W)), | |
!u(a.a[0], b, a.W)) | |
return !0 | |
} else if (a.K) { | |
var c = a.C | |
, d = a.a | |
, e = b.plugins_.get(a.K); | |
e[c].apply(e, d) | |
} else | |
b[a.C].apply(b, a.a) | |
} | |
} catch (g) { | |
} | |
} | |
; | |
var N = function (a) { | |
J(1); | |
Z.D.apply(Z, [arguments]) | |
}; | |
N.h = {}; | |
N.P = []; | |
N.L = 0; | |
N.answer = 42; | |
var uc = [Na, W, V]; | |
N.create = function (a) { | |
var b = za(uc, [].slice.call(arguments)); | |
b[V] || (b[V] = "t0"); | |
var c = "" + b[V]; | |
if (N.h[c]) | |
return N.h[c]; | |
b = new pc(b); | |
N.h[c] = b; | |
N.P.push(b); | |
return b | |
} | |
; | |
N.remove = function (a) { | |
for (var b = 0; b < N.P.length; b++) | |
if (N.P[b].get(V) == a) { | |
N.P.splice(b, 1); | |
N.h[a] = null; | |
break | |
} | |
} | |
; | |
N.j = function (a) { | |
return N.h[a] | |
} | |
; | |
N.getAll = function () { | |
return N.P.slice(0) | |
} | |
; | |
N.N = function () { | |
"ga" != gb && J(49); | |
var a = O[gb]; | |
if (!a || 42 != a.answer) { | |
N.L = a && a.l; | |
N.loaded = !0; | |
var b = O[gb] = N; | |
X("create", b, b.create); | |
X("remove", b, b.remove); | |
X("getByName", b, b.j, 5); | |
X("getAll", b, b.getAll, 6); | |
b = pc.prototype; | |
X("get", b, b.get, 7); | |
X("set", b, b.set, 4); | |
X("send", b, b.send); | |
X("requireSync", b, b.ma); | |
b = Ya.prototype; | |
X("get", b, b.get); | |
X("set", b, b.set); | |
if (!Ud() && !Ba) { | |
a: { | |
for (var b = M.getElementsByTagName("script"), c = 0; c < b.length && 100 > c; c++) { | |
var d = b[c].src; | |
if (d && 0 == d.indexOf("https://www.google-analytics.com/analytics")) { | |
J(33); | |
b = !0; | |
break a | |
} | |
} | |
b = !1 | |
} | |
b && (Ba = !0) | |
} | |
Ud() || Ba || !Ed(new Od(1E4)) || (J(36), | |
Ba = !0); | |
(O.gaplugins = O.gaplugins || {}).Linker = Dc; | |
b = Dc.prototype; | |
C("linker", Dc); | |
X("decorate", b, b.ca, 20); | |
X("autoLink", b, b.S, 25); | |
C("displayfeatures", fd); | |
C("adfeatures", fd); | |
a = a && a.q; | |
ka(a) ? Z.D.apply(N, a) : J(50) | |
} | |
} | |
; | |
N.da = function () { | |
for (var a = N.getAll(), b = 0; b < a.length; b++) | |
a[b].get(V) | |
} | |
; | |
var H = N.N | |
, I = O[gb]; | |
I && I.r ? H() : z(H); | |
z(function () { | |
Z.D(["provide", "render", ua]) | |
}); | |
function La(a) { | |
var b = 1, c, d; | |
if (a) | |
for (b = 0, | |
d = a.length - 1; 0 <= d; d--) | |
c = a.charCodeAt(d), | |
b = (b << 6 & 268435455) + c + (c << 14), | |
c = b & 266338304, | |
b = 0 != c ? b ^ c >> 21 : b; | |
return b | |
} | |
; | |
})(window); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment