{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./node_modules/dom-utils/lib/matches.js","webpack:///./node_modules/dom-utils/lib/delegate.js","webpack:///./node_modules/dom-utils/lib/closest.js","webpack:///./node_modules/dom-utils/lib/parents.js","webpack:///./node_modules/dom-utils/lib/parse-url.js","webpack:///./node_modules/autotrack/lib/constants.js","webpack:///./node_modules/autotrack/lib/method-chain.js","webpack:///./node_modules/autotrack/lib/utilities.js","webpack:///./node_modules/dom-utils/lib/get-attributes.js","webpack:///./node_modules/autotrack/lib/provide.js","webpack:///./node_modules/autotrack/lib/usage.js","webpack:///./node_modules/autotrack/lib/plugins/impression-tracker.js","webpack:///./node_modules/autotrack/lib/plugins/clean-url-tracker.js","webpack:///./node_modules/autotrack/lib/plugins/event-tracker.js","webpack:///./node_modules/autotrack/lib/event-emitter.js","webpack:///./node_modules/autotrack/lib/store.js","webpack:///./node_modules/autotrack/lib/session.js","webpack:///./node_modules/autotrack/lib/plugins/max-scroll-tracker.js","webpack:///./node_modules/autotrack/lib/plugins/media-query-tracker.js","webpack:///./node_modules/autotrack/lib/plugins/outbound-form-tracker.js","webpack:///./node_modules/autotrack/lib/plugins/outbound-link-tracker.js","webpack:///./node_modules/autotrack/lib/plugins/page-visibility-tracker.js","webpack:///./node_modules/autotrack/lib/plugins/url-change-tracker.js","webpack:///./node_modules/autotrack/lib/plugins/social-widget-tracker.js","webpack:///./src/analytics.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","proto","window","Element","nativeMatches","matches","matchesSelector","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector","element","test","nodeType","item","selector","node","nodes","parentNode","querySelectorAll","delegate","ancestor","eventType","callback","opts","arguments","length","undefined","listener","event","delegateTarget","composed","composedPath","shouldCheckSelf","parent","parentElements","concat","list","push","parents","closest","target","addEventListener","useCapture","destroy","removeEventListener","HTTP_PORT","HTTPS_PORT","DEFAULT_PORT","RegExp","a","document","createElement","cache","parseUrl","url","location","href","charAt","port","host","replace","origin","protocol","pathname","hash","hostname","search","VERSION","DEV_ID","VERSION_PARAM","USAGE_PARAM","instances","MethodChain","context","methodName","_this","this","_classCallCheck","isTask","originalMethodReference","methodChain","boundMethodChain","wrappedMethod","apply","set","methodOverride","getOrCreateMethodChain","add","remove","overrideMethod","rebindMethodChain","index","indexOf","splice","method","previousMethod","filter","h","createFieldsObj","defaultFields","userFields","tracker","hitFilter","originalBuildHitTask","buildHitTask","model","assign","getAttributeFields","prefix","attributes","attrs","map","attr","getAttributes","attributeFields","keys","forEach","attribute","field","str","match","p1","toUpperCase","camelCase","slice","debounce","fn","wait","timeout","_len","args","Array","_key","clearTimeout","setTimeout","withTimeout","called","queueMap","len","source","isObject","utilities_typeof","now","Date","uuid","b","Math","random","toString","provide","pluginName","pluginConstructor","gaAlias","GoogleAnalyticsObject","q","gaDevIds","gaplugins","capitalize","plugins","CLEAN_URL_TRACKER","EVENT_TRACKER","IMPRESSION_TRACKER","MEDIA_QUERY_TRACKER","OUTBOUND_FORM_TRACKER","OUTBOUND_LINK_TRACKER","PAGE_VISIBILITY_TRACKER","SOCIAL_WIDGET_TRACKER","URL_CHANGE_TRACKER","MAX_SCROLL_TRACKER","PLUGIN_COUNT","trackUsage","plugin","trackVersion","pluginIndex","usageBin","toAdd","padZeros","hex","parseInt","convertHexToBin","substr","flipBitOn","bin","convertBinToHex","trackPlugin","isTargetVisible","threshold","record","intersectionRect","top","bottom","left","right","intersectionRatio","getItemFromElement","id","trackFirstImpressionOnly","CleanUrlTracker","clean_url_tracker_classCallCheck","queryDimension","stripQuery","queryDimensionIndex","trackerGetOverride","buildHitTaskOverride","originalMethod","fieldsObj","page","cleanUrlFields","_this2","cleanedFieldsObj","indexFilename","parts","split","join","trailingSlash","stripNonWhitelistedQueryParams","urlFieldsFilter","userCleanedFieldsObj","returnValue","searchString","_this3","isArray","queryParamsWhitelist","foundParams","kv","_kv$split2","_slicedToArray","EventTracker","event_tracker_classCallCheck","events","attributePrefix","handleEvents","delegates","getAttribute","type","hitType","send","transport","ImpressionTracker","impression_tracker_classCallCheck","IntersectionObserver","MutationObserver","rootMargin","handleDomMutations","handleIntersectionChanges","handleDomElementAdded","handleDomElementRemoved","mutationObserver","items","elementMap","thresholdMap","readyState","domReady","elements","observeElements","data","deriveDataFromElements","observer","getElementById","observe","body","childList","subtree","requestAnimationFrame","itemsToKeep","itemsToRemove","some","itemToRemove","dataToKeep","dataToRemove","unobserve","disconnect","unobserveAllElements","_this4","mutations","mutation","removedEl","k","removedNodes","walkNodeTree","addedEl","j","addedNodes","child","childNodes","records","handleImpression","unobserveElements","eventCategory","eventAction","eventLabel","nonInteraction","_this5","_this6","EventEmitter","event_emitter_classCallCheck","registry_","getRegistry_","eventRegistry","handlerIndex","eventCount","browserSupportsLocalStorage","AUTOTRACK_PREFIX","isListening","Store","defaults","store_classCallCheck","_possibleConstructorReturn","_getPrototypeOf","key_","defaults_","cache_","trackingId","namespace","storageListener","localStorage","setItem","removeItem","err","getItem","isSupported_","parse","get_","newData","set_","JSON","stringify","clear_","store","oldData","oldValue","newValue","emit","Session","timeZone","session_classCallCheck","DEFAULT_TIMEOUT","sendHitTaskOverride","dateTimeFormatter","Intl","DateTimeFormat","getOrCreate","hitTime","isExpired","getId","sessionData","oldHitTime","currentDate","oldHitDate","datesAreDifferentInTimezone","d1","d2","format","sessionControl","sessionWillStart","sessionWillEnd","MaxScrollTracker","max_scroll_tracker_classCallCheck","defaultOpts","increaseThreshold","sessionTimeout","pagePath","getPagePath","handleScroll","trackerSetOverride","session","listenForMaxScrollChanges","getMaxScrollPercentageForCurrentPage","pageHeight","html","documentElement","max","offsetHeight","scrollHeight","getPageHeight","scrollPos","pageYOffset","windowHeight","innerHeight","scrollPercentage","min","round","sessionId","clear","maxScrollPercentage","stopListeningForMaxScrollChanges","increaseAmount","setMaxScrollPercentageForCurrentPage","sendMaxScrollEvent","_defineProperty","lastPagePath","eventValue","String","maxScrollMetricIndex","_this$store$set","mediaMap","getMediaList","media","matchMedia","MediaQueryTracker","media_query_tracker_classCallCheck","changeTemplate","changeTimeout","definitions","toArray","changeListeners","processMediaQueries","definition","dimensionIndex","mediaName","getMatchName","addChangeListeners","mql","handleChanges","addListener","removeListener","OutboundFormTracker","outbound_form_tracker_classCallCheck","formSelector","shouldTrackOutboundForm","handleFormSubmits","form","action","navigator","sendBeacon","preventDefault","hitCallback","submit","parseUrlFn","OutboundLinkTracker","outbound_link_tracker_classCallCheck","linkSelector","shouldTrackOutboundLink","handleLinkInteractions","link","metaKey","ctrlKey","shiftKey","altKey","which","linkClickWillUnloadCurrentPage","clickHandler","defaultPrevented","oldHitCallback","VISIBLE","PAGE_ID","SECONDS","getPath","PageVisibilityTracker","page_visibility_tracker_classCallCheck","visibilityState","visibleThreshold","sendInitialPageview","lastPageState","visibleThresholdTimeout_","isInitialPageviewSent_","handleChange","handleWindowUnload","handleExternalStoreSet","on","ref","processQueue","queue","deferUntilPluginsLoaded","sendPageview","isPageLoad","time","state","pageId","pageLoadsMetricIndex","sendPageLoad","lastStoredChange","getAndValidateChangeData","change","sendPageVisibilityEvent","delta","getTimeSinceLastStoredChange","deltaInSeconds","queueTime","visibleMetricIndex","_defaultFields","page_visibility_tracker_defineProperty","_ref2","fields","SocialWidgetTracker","social_widget_tracker_classCallCheck","addWidgetListeners","addTwitterEventHandlers","handleTweetEvents","handleFollowEvents","handleLikeEvents","handleUnlikeEvents","FB","addFacebookEventHandlers","twttr","ready","unbind","Event","subscribe","unsubscribe","region","socialNetwork","socialAction","socialTarget","screen_name","removeFacebookEventHandlers","removeTwitterEventHandlers","UrlChangeTracker","url_change_tracker_classCallCheck","history","pushState","shouldTrackUrlChange","trackReplaceState","path","pushStateOverride","replaceStateOverride","handlePopState","handleUrlChange","historyDidUpdate","oldPath","newPath","title","zywave","gaKey","ga"],"mappings":"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","file":"analytics.built.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 283);\n","const proto = window.Element.prototype;\nconst nativeMatches = proto.matches ||\n proto.matchesSelector ||\n proto.webkitMatchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector;\n\n\n/**\n * Tests if a DOM elements matches any of the test DOM elements or selectors.\n * @param {Element} element The DOM element to test.\n * @param {Element|string|Array} test A DOM element, a CSS\n * selector, or an array of DOM elements or CSS selectors to match against.\n * @return {boolean} True of any part of the test matches.\n */\nexport default function matches(element, test) {\n // Validate input.\n if (element && element.nodeType == 1 && test) {\n // if test is a string or DOM element test it.\n if (typeof test == 'string' || test.nodeType == 1) {\n return element == test ||\n matchesSelector(element, /** @type {string} */ (test));\n } else if ('length' in test) {\n // if it has a length property iterate over the items\n // and return true if any match.\n for (let i = 0, item; item = test[i]; i++) {\n if (element == item || matchesSelector(element, item)) return true;\n }\n }\n }\n // Still here? Return false\n return false;\n}\n\n\n/**\n * Tests whether a DOM element matches a selector. This polyfills the native\n * Element.prototype.matches method across browsers.\n * @param {!Element} element The DOM element to test.\n * @param {string} selector The CSS selector to test element against.\n * @return {boolean} True if the selector matches.\n */\nfunction matchesSelector(element, selector) {\n if (typeof selector != 'string') return false;\n if (nativeMatches) return nativeMatches.call(element, selector);\n const nodes = element.parentNode.querySelectorAll(selector);\n for (let i = 0, node; node = nodes[i]; i++) {\n if (node == element) return true;\n }\n return false;\n}\n","import closest from './closest';\nimport matches from './matches';\n\n/**\n * Delegates the handling of events for an element matching a selector to an\n * ancestor of the matching element.\n * @param {!Node} ancestor The ancestor element to add the listener to.\n * @param {string} eventType The event type to listen to.\n * @param {string} selector A CSS selector to match against child elements.\n * @param {!Function} callback A function to run any time the event happens.\n * @param {Object=} opts A configuration options object. The available options:\n * - useCapture: If true, bind to the event capture phase.\n * - deep: If true, delegate into shadow trees.\n * @return {Object} The delegate object. It contains a destroy method.\n */\nexport default function delegate(\n ancestor, eventType, selector, callback, opts = {}) {\n // Defines the event listener.\n const listener = function(event) {\n let delegateTarget;\n\n // If opts.composed is true and the event originated from inside a Shadow\n // tree, check the composed path nodes.\n if (opts.composed && typeof event.composedPath == 'function') {\n const composedPath = event.composedPath();\n for (let i = 0, node; node = composedPath[i]; i++) {\n if (node.nodeType == 1 && matches(node, selector)) {\n delegateTarget = node;\n }\n }\n } else {\n // Otherwise check the parents.\n delegateTarget = closest(event.target, selector, true);\n }\n\n if (delegateTarget) {\n callback.call(delegateTarget, event, delegateTarget);\n }\n };\n\n ancestor.addEventListener(eventType, listener, opts.useCapture);\n\n return {\n destroy: function() {\n ancestor.removeEventListener(eventType, listener, opts.useCapture);\n },\n };\n}\n","import matches from './matches';\nimport parents from './parents';\n\n/**\n * Gets the closest parent element that matches the passed selector.\n * @param {Element} element The element whose parents to check.\n * @param {string} selector The CSS selector to match against.\n * @param {boolean=} shouldCheckSelf True if the selector should test against\n * the passed element itself.\n * @return {Element|undefined} The matching element or undefined.\n */\nexport default function closest(element, selector, shouldCheckSelf = false) {\n if (!(element && element.nodeType == 1 && selector)) return;\n const parentElements =\n (shouldCheckSelf ? [element] : []).concat(parents(element));\n\n for (let i = 0, parent; parent = parentElements[i]; i++) {\n if (matches(parent, selector)) return parent;\n }\n}\n","/**\n * Returns an array of a DOM element's parent elements.\n * @param {!Element} element The DOM element whose parents to get.\n * @return {!Array} An array of all parent elemets, or an empty array if no\n * parent elements are found.\n */\nexport default function parents(element) {\n const list = [];\n while (element && element.parentNode && element.parentNode.nodeType == 1) {\n element = /** @type {!Element} */ (element.parentNode);\n list.push(element);\n }\n return list;\n}\n","const HTTP_PORT = '80';\nconst HTTPS_PORT = '443';\nconst DEFAULT_PORT = RegExp(':(' + HTTP_PORT + '|' + HTTPS_PORT + ')$');\n\n\nconst a = document.createElement('a');\nconst cache = {};\n\n\n/**\n * Parses the given url and returns an object mimicing a `Location` object.\n * @param {string} url The url to parse.\n * @return {!Object} An object with the same properties as a `Location`.\n */\nexport default function parseUrl(url) {\n // All falsy values (as well as \".\") should map to the current URL.\n url = (!url || url == '.') ? location.href : url;\n\n if (cache[url]) return cache[url];\n\n a.href = url;\n\n // When parsing file relative paths (e.g. `../index.html`), IE will correctly\n // resolve the `href` property but will keep the `..` in the `path` property.\n // It will also not include the `host` or `hostname` properties. Furthermore,\n // IE will sometimes return no protocol or just a colon, especially for things\n // like relative protocol URLs (e.g. \"//google.com\").\n // To workaround all of these issues, we reparse with the full URL from the\n // `href` property.\n if (url.charAt(0) == '.' || url.charAt(0) == '/') return parseUrl(a.href);\n\n // Don't include default ports.\n let port = (a.port == HTTP_PORT || a.port == HTTPS_PORT) ? '' : a.port;\n\n // PhantomJS sets the port to \"0\" when using the file: protocol.\n port = port == '0' ? '' : port;\n\n // Sometimes IE incorrectly includes a port for default ports\n // (e.g. `:80` or `:443`) even when no port is specified in the URL.\n // http://bit.ly/1rQNoMg\n const host = a.host.replace(DEFAULT_PORT, '');\n\n // Not all browser support `origin` so we have to build it.\n const origin = a.origin ? a.origin : a.protocol + '//' + host;\n\n // Sometimes IE doesn't include the leading slash for pathname.\n // http://bit.ly/1rQNoMg\n const pathname = a.pathname.charAt(0) == '/' ? a.pathname : '/' + a.pathname;\n\n return cache[url] = {\n hash: a.hash,\n host: host,\n hostname: a.hostname,\n href: a.href,\n origin: origin,\n pathname: pathname,\n port: port,\n protocol: a.protocol,\n search: a.search,\n };\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nexport const VERSION = '2.4.1';\nexport const DEV_ID = 'i5iSjo';\n\nexport const VERSION_PARAM = '_av';\nexport const USAGE_PARAM = '_au';\n\nexport const NULL_DIMENSION = '(not set)';\n","/**\n * Copyright 2017 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/**\n * @fileoverview\n * The functions exported by this module make it easier (and safer) to override\n * foreign object methods (in a modular way) and respond to or modify their\n * invocation. The primary feature is the ability to override a method without\n * worrying if it's already been overridden somewhere else in the codebase. It\n * also allows for safe restoring of an overridden method by only fully\n * restoring a method once all overrides have been removed.\n */\n\n\nconst instances = [];\n\n\n/**\n * A class that wraps a foreign object method and emit events before and\n * after the original method is called.\n */\nexport default class MethodChain {\n /**\n * Adds the passed override method to the list of method chain overrides.\n * @param {!Object} context The object containing the method to chain.\n * @param {string} methodName The name of the method on the object.\n * @param {!Function} methodOverride The override method to add.\n */\n static add(context, methodName, methodOverride) {\n getOrCreateMethodChain(context, methodName).add(methodOverride);\n }\n\n /**\n * Removes a method chain added via `add()`. If the override is the\n * only override added, the original method is restored.\n * @param {!Object} context The object containing the method to unchain.\n * @param {string} methodName The name of the method on the object.\n * @param {!Function} methodOverride The override method to remove.\n */\n static remove(context, methodName, methodOverride) {\n getOrCreateMethodChain(context, methodName).remove(methodOverride);\n }\n\n /**\n * Wraps a foreign object method and overrides it. Also stores a reference\n * to the original method so it can be restored later.\n * @param {!Object} context The object containing the method.\n * @param {string} methodName The name of the method on the object.\n */\n constructor(context, methodName) {\n this.context = context;\n this.methodName = methodName;\n this.isTask = /Task$/.test(methodName);\n\n this.originalMethodReference = this.isTask ?\n context.get(methodName) : context[methodName];\n\n this.methodChain = [];\n this.boundMethodChain = [];\n\n // Wraps the original method.\n this.wrappedMethod = (...args) => {\n const lastBoundMethod =\n this.boundMethodChain[this.boundMethodChain.length - 1];\n\n return lastBoundMethod(...args);\n };\n\n // Override original method with the wrapped one.\n if (this.isTask) {\n context.set(methodName, this.wrappedMethod);\n } else {\n context[methodName] = this.wrappedMethod;\n }\n }\n\n /**\n * Adds a method to the method chain.\n * @param {!Function} overrideMethod The override method to add.\n */\n add(overrideMethod) {\n this.methodChain.push(overrideMethod);\n this.rebindMethodChain();\n }\n\n /**\n * Removes a method from the method chain and restores the prior order.\n * @param {!Function} overrideMethod The override method to remove.\n */\n remove(overrideMethod) {\n const index = this.methodChain.indexOf(overrideMethod);\n if (index > -1) {\n this.methodChain.splice(index, 1);\n if (this.methodChain.length > 0) {\n this.rebindMethodChain();\n } else {\n this.destroy();\n }\n }\n }\n\n /**\n * Loops through the method chain array and recreates the bound method\n * chain array. This is necessary any time a method is added or removed\n * to ensure proper original method context and order.\n */\n rebindMethodChain() {\n this.boundMethodChain = [];\n for (let method, i = 0; method = this.methodChain[i]; i++) {\n const previousMethod = this.boundMethodChain[i - 1] ||\n this.originalMethodReference.bind(this.context);\n this.boundMethodChain.push(method(previousMethod));\n }\n }\n\n /**\n * Calls super and destroys the instance if no registered handlers remain.\n */\n destroy() {\n const index = instances.indexOf(this);\n if (index > -1) {\n instances.splice(index, 1);\n if (this.isTask) {\n this.context.set(this.methodName, this.originalMethodReference);\n } else {\n this.context[this.methodName] = this.originalMethodReference;\n }\n }\n }\n}\n\n\n/**\n * Gets a MethodChain instance for the passed object and method. If the method\n * has already been wrapped via an existing MethodChain instance, that\n * instance is returned.\n * @param {!Object} context The object containing the method.\n * @param {string} methodName The name of the method on the object.\n * @return {!MethodChain}\n */\nfunction getOrCreateMethodChain(context, methodName) {\n let methodChain = instances\n .filter((h) => h.context == context && h.methodName == methodName)[0];\n\n if (!methodChain) {\n methodChain = new MethodChain(context, methodName);\n instances.push(methodChain);\n }\n return methodChain;\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport {getAttributes} from 'dom-utils';\nimport MethodChain from './method-chain';\n\n\n/**\n * Accepts default and user override fields and an optional tracker, hit\n * filter, and target element and returns a single object that can be used in\n * `ga('send', ...)` commands.\n * @param {FieldsObj} defaultFields The default fields to return.\n * @param {FieldsObj} userFields Fields set by the user to override the\n * defaults.\n * @param {Tracker=} tracker The tracker object to apply the hit filter to.\n * @param {Function=} hitFilter A filter function that gets\n * called with the tracker model right before the `buildHitTask`. It can\n * be used to modify the model for the current hit only.\n * @param {Element=} target If the hit originated from an interaction\n * with a DOM element, hitFilter is invoked with that element as the\n * second argument.\n * @param {(Event|TwttrEvent)=} event If the hit originated via a DOM event,\n * hitFilter is invoked with that event as the third argument.\n * @return {!FieldsObj} The final fields object.\n */\nexport function createFieldsObj(\n defaultFields, userFields, tracker = undefined,\n hitFilter = undefined, target = undefined, event = undefined) {\n if (typeof hitFilter == 'function') {\n const originalBuildHitTask = tracker.get('buildHitTask');\n return {\n buildHitTask: (/** @type {!Model} */ model) => {\n model.set(defaultFields, null, true);\n model.set(userFields, null, true);\n hitFilter(model, target, event);\n originalBuildHitTask(model);\n },\n };\n } else {\n return assign({}, defaultFields, userFields);\n }\n}\n\n\n/**\n * Retrieves the attributes from an DOM element and returns a fields object\n * for all attributes matching the passed prefix string.\n * @param {Element} element The DOM element to get attributes from.\n * @param {string} prefix An attribute prefix. Only the attributes matching\n * the prefix will be returned on the fields object.\n * @return {FieldsObj} An object of analytics.js fields and values\n */\nexport function getAttributeFields(element, prefix) {\n const attributes = getAttributes(element);\n const attributeFields = {};\n\n Object.keys(attributes).forEach(function(attribute) {\n // The `on` prefix is used for event handling but isn't a field.\n if (attribute.indexOf(prefix) === 0 && attribute != prefix + 'on') {\n let value = attributes[attribute];\n\n // Detects Boolean value strings.\n if (value == 'true') value = true;\n if (value == 'false') value = false;\n\n const field = camelCase(attribute.slice(prefix.length));\n attributeFields[field] = value;\n }\n });\n\n return attributeFields;\n}\n\n\n/**\n * Accepts a function to be invoked once the DOM is ready. If the DOM is\n * already ready, the callback is invoked immediately.\n * @param {!Function} callback The ready callback.\n */\nexport function domReady(callback) {\n if (document.readyState == 'loading') {\n document.addEventListener('DOMContentLoaded', function fn() {\n document.removeEventListener('DOMContentLoaded', fn);\n callback();\n });\n } else {\n callback();\n }\n}\n\n\n/**\n * Returns a function, that, as long as it continues to be called, will not\n * actually run. The function will only run after it stops being called for\n * `wait` milliseconds.\n * @param {!Function} fn The function to debounce.\n * @param {number} wait The debounce wait timeout in ms.\n * @return {!Function} The debounced function.\n */\nexport function debounce(fn, wait) {\n let timeout;\n return function(...args) {\n clearTimeout(timeout);\n timeout = setTimeout(() => fn(...args), wait);\n };\n}\n\n\n/**\n * Accepts a function and returns a wrapped version of the function that is\n * expected to be called elsewhere in the system. If it's not called\n * elsewhere after the timeout period, it's called regardless. The wrapper\n * function also prevents the callback from being called more than once.\n * @param {!Function} callback The function to call.\n * @param {number=} wait How many milliseconds to wait before invoking\n * the callback.\n * @return {!Function} The wrapped version of the passed function.\n */\nexport function withTimeout(callback, wait = 2000) {\n let called = false;\n const fn = function() {\n if (!called) {\n called = true;\n callback();\n }\n };\n setTimeout(fn, wait);\n return fn;\n}\n\n// Maps trackers to queue by tracking ID.\nconst queueMap = {};\n\n/**\n * Queues a function for execution in the next call stack, or immediately\n * before any send commands are executed on the tracker. This allows\n * autotrack plugins to defer running commands until after all other plugins\n * are required but before any other hits are sent.\n * @param {!Tracker} tracker\n * @param {!Function} fn\n */\nexport function deferUntilPluginsLoaded(tracker, fn) {\n const trackingId = tracker.get('trackingId');\n const ref = queueMap[trackingId] = queueMap[trackingId] || {};\n\n const processQueue = () => {\n clearTimeout(ref.timeout);\n if (ref.send) {\n MethodChain.remove(tracker, 'send', ref.send);\n }\n delete queueMap[trackingId];\n\n ref.queue.forEach((fn) => fn());\n };\n\n clearTimeout(ref.timeout);\n ref.timeout = setTimeout(processQueue, 0);\n ref.queue = ref.queue || [];\n ref.queue.push(fn);\n\n if (!ref.send) {\n ref.send = (originalMethod) => {\n return (...args) => {\n processQueue();\n originalMethod(...args);\n };\n };\n MethodChain.add(tracker, 'send', ref.send);\n }\n}\n\n\n/**\n * A small shim of Object.assign that aims for brevity over spec-compliant\n * handling all the edge cases.\n * @param {!Object} target The target object to assign to.\n * @param {...?Object} sources Additional objects who properties should be\n * assigned to target. Non-objects are converted to objects.\n * @return {!Object} The modified target object.\n */\nexport const assign = Object.assign || function(target, ...sources) {\n for (let i = 0, len = sources.length; i < len; i++) {\n const source = Object(sources[i]);\n for (let key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n return target;\n};\n\n\n/**\n * Accepts a string containing hyphen or underscore word separators and\n * converts it to camelCase.\n * @param {string} str The string to camelCase.\n * @return {string} The camelCased version of the string.\n */\nexport function camelCase(str) {\n return str.replace(/[\\-\\_]+(\\w?)/g, function(match, p1) {\n return p1.toUpperCase();\n });\n}\n\n\n/**\n * Capitalizes the first letter of a string.\n * @param {string} str The input string.\n * @return {string} The capitalized string\n */\nexport function capitalize(str) {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n\n/**\n * Indicates whether the passed variable is a JavaScript object.\n * @param {*} value The input variable to test.\n * @return {boolean} Whether or not the test is an object.\n */\nexport function isObject(value) {\n return typeof value == 'object' && value !== null;\n}\n\n\n/**\n * Accepts a value that may or may not be an array. If it is not an array,\n * it is returned as the first item in a single-item array.\n * @param {*} value The value to convert to an array if it is not.\n * @return {!Array} The array-ified value.\n */\nexport function toArray(value) {\n return Array.isArray(value) ? value : [value];\n}\n\n\n/**\n * @return {number} The current date timestamp\n */\nexport function now() {\n return +new Date();\n}\n\n\n/*eslint-disable */\n// https://gist.github.com/jed/982883\n/** @param {?=} a */\nexport const uuid = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)};\n/*eslint-enable */\n","/**\n * Gets all attributes of an element as a plain JavaScriot object.\n * @param {Element} element The element whose attributes to get.\n * @return {!Object} An object whose keys are the attribute keys and whose\n * values are the attribute values. If no attributes exist, an empty\n * object is returned.\n */\nexport default function getAttributes(element) {\n const attrs = {};\n\n // Validate input.\n if (!(element && element.nodeType == 1)) return attrs;\n\n // Return an empty object if there are no attributes.\n const map = element.attributes;\n if (map.length === 0) return {};\n\n for (let i = 0, attr; attr = map[i]; i++) {\n attrs[attr.name] = attr.value;\n }\n return attrs;\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport {DEV_ID} from './constants';\nimport {capitalize} from './utilities';\n\n\n/**\n * Provides a plugin for use with analytics.js, accounting for the possibility\n * that the global command queue has been renamed or not yet defined.\n * @param {string} pluginName The plugin name identifier.\n * @param {Function} pluginConstructor The plugin constructor function.\n */\nexport default function provide(pluginName, pluginConstructor) {\n const gaAlias = window.GoogleAnalyticsObject || 'ga';\n window[gaAlias] = window[gaAlias] || function(...args) {\n (window[gaAlias].q = window[gaAlias].q || []).push(args);\n };\n\n // Adds the autotrack dev ID if not already included.\n window.gaDevIds = window.gaDevIds || [];\n if (window.gaDevIds.indexOf(DEV_ID) < 0) {\n window.gaDevIds.push(DEV_ID);\n }\n\n // Formally provides the plugin for use with analytics.js.\n window[gaAlias]('provide', pluginName, pluginConstructor);\n\n // Registers the plugin on the global gaplugins object.\n window.gaplugins = window.gaplugins || {};\n window.gaplugins[capitalize(pluginName)] = pluginConstructor;\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport {USAGE_PARAM, VERSION, VERSION_PARAM} from './constants';\n\n\nexport const plugins = {\n CLEAN_URL_TRACKER: 1,\n EVENT_TRACKER: 2,\n IMPRESSION_TRACKER: 3,\n MEDIA_QUERY_TRACKER: 4,\n OUTBOUND_FORM_TRACKER: 5,\n OUTBOUND_LINK_TRACKER: 6,\n PAGE_VISIBILITY_TRACKER: 7,\n SOCIAL_WIDGET_TRACKER: 8,\n URL_CHANGE_TRACKER: 9,\n MAX_SCROLL_TRACKER: 10,\n};\n\n\nconst PLUGIN_COUNT = Object.keys(plugins).length;\n\n\n/**\n * Tracks the usage of the passed plugin by encoding a value into a usage\n * string sent with all hits for the passed tracker.\n * @param {!Tracker} tracker The analytics.js tracker object.\n * @param {number} plugin The plugin enum.\n */\nexport function trackUsage(tracker, plugin) {\n trackVersion(tracker);\n trackPlugin(tracker, plugin);\n}\n\n\n/**\n * Converts a hexadecimal string to a binary string.\n * @param {string} hex A hexadecimal numeric string.\n * @return {string} a binary numeric string.\n */\nfunction convertHexToBin(hex) {\n return parseInt(hex || '0', 16).toString(2);\n}\n\n\n/**\n * Converts a binary string to a hexadecimal string.\n * @param {string} bin A binary numeric string.\n * @return {string} a hexadecimal numeric string.\n */\nfunction convertBinToHex(bin) {\n return parseInt(bin || '0', 2).toString(16);\n}\n\n\n/**\n * Adds leading zeros to a string if it's less than a minimum length.\n * @param {string} str A string to pad.\n * @param {number} len The minimum length of the string\n * @return {string} The padded string.\n */\nfunction padZeros(str, len) {\n if (str.length < len) {\n let toAdd = len - str.length;\n while (toAdd) {\n str = '0' + str;\n toAdd--;\n }\n }\n return str;\n}\n\n\n/**\n * Accepts a binary numeric string and flips the digit from 0 to 1 at the\n * specified index.\n * @param {string} str The binary numeric string.\n * @param {number} index The index to flip the bit.\n * @return {string} The new binary string with the bit flipped on\n */\nfunction flipBitOn(str, index) {\n return str.substr(0, index) + 1 + str.substr(index + 1);\n}\n\n\n/**\n * Accepts a tracker and a plugin index and flips the bit at the specified\n * index on the tracker's usage parameter.\n * @param {Object} tracker An analytics.js tracker.\n * @param {number} pluginIndex The index of the plugin in the global list.\n */\nfunction trackPlugin(tracker, pluginIndex) {\n const usageHex = tracker.get('&' + USAGE_PARAM);\n let usageBin = padZeros(convertHexToBin(usageHex), PLUGIN_COUNT);\n\n // Flip the bit of the plugin being tracked.\n usageBin = flipBitOn(usageBin, PLUGIN_COUNT - pluginIndex);\n\n // Stores the modified usage string back on the tracker.\n tracker.set('&' + USAGE_PARAM, convertBinToHex(usageBin));\n}\n\n\n/**\n * Accepts a tracker and adds the current version to the version param.\n * @param {Object} tracker An analytics.js tracker.\n */\nfunction trackVersion(tracker) {\n tracker.set('&' + VERSION_PARAM, VERSION);\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport provide from '../provide';\nimport {plugins, trackUsage} from '../usage';\nimport {assign, createFieldsObj,\n domReady, getAttributeFields} from '../utilities';\n\n\n/**\n * Class for the `impressionTracker` analytics.js plugin.\n * @implements {ImpressionTrackerPublicInterface}\n */\nclass ImpressionTracker {\n /**\n * Registers impression tracking.\n * @param {!Tracker} tracker Passed internally by analytics.js\n * @param {?ImpressionTrackerOpts} opts Passed by the require command.\n */\n constructor(tracker, opts) {\n trackUsage(tracker, plugins.IMPRESSION_TRACKER);\n\n // Feature detects to prevent errors in unsupporting browsers.\n if (!(window.IntersectionObserver && window.MutationObserver)) return;\n\n /** type {ImpressionTrackerOpts} */\n const defaultOptions = {\n // elements: undefined,\n rootMargin: '0px',\n fieldsObj: {},\n attributePrefix: 'ga-',\n // hitFilter: undefined,\n };\n\n this.opts = /** type {ImpressionTrackerOpts} */ (\n assign(defaultOptions, opts));\n\n this.tracker = tracker;\n\n // Binds methods.\n this.handleDomMutations = this.handleDomMutations.bind(this);\n this.handleIntersectionChanges = this.handleIntersectionChanges.bind(this);\n this.handleDomElementAdded = this.handleDomElementAdded.bind(this);\n this.handleDomElementRemoved = this.handleDomElementRemoved.bind(this);\n\n /** @type {MutationObserver} */\n this.mutationObserver = null;\n\n // The primary list of elements to observe. Each item contains the\n // element ID, threshold, and whether it's currently in-view.\n this.items = [];\n\n // A map of element IDs in the `items` array to DOM elements in the\n // document. The presence of a key indicates that the element ID is in the\n // `items` array, and the presence of an element value indicates that the\n // element is in the DOM.\n this.elementMap = {};\n\n // A map of threshold values. Each threshold is mapped to an\n // IntersectionObserver instance specific to that threshold.\n this.thresholdMap = {};\n\n // Once the DOM is ready, start observing for changes (if present).\n domReady(() => {\n if (this.opts.elements) {\n this.observeElements(this.opts.elements);\n }\n });\n }\n\n /**\n * Starts observing the passed elements for impressions.\n * @param {Array} elements\n */\n observeElements(elements) {\n const data = this.deriveDataFromElements(elements);\n\n // Merge the new data with the data already on the plugin instance.\n this.items = this.items.concat(data.items);\n this.elementMap = assign({}, data.elementMap, this.elementMap);\n this.thresholdMap = assign({}, data.thresholdMap, this.thresholdMap);\n\n // Observe each new item.\n data.items.forEach((item) => {\n const observer = this.thresholdMap[item.threshold] =\n (this.thresholdMap[item.threshold] || new IntersectionObserver(\n this.handleIntersectionChanges, {\n rootMargin: this.opts.rootMargin,\n threshold: [+item.threshold],\n }));\n\n const element = this.elementMap[item.id] ||\n (this.elementMap[item.id] = document.getElementById(item.id));\n\n if (element) {\n observer.observe(element);\n }\n });\n\n if (!this.mutationObserver) {\n this.mutationObserver = new MutationObserver(this.handleDomMutations);\n this.mutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n });\n }\n\n // TODO(philipwalton): Remove temporary hack to force a new frame\n // immediately after adding observers.\n // https://bugs.chromium.org/p/chromium/issues/detail?id=612323\n requestAnimationFrame(() => {});\n }\n\n /**\n * Stops observing the passed elements for impressions.\n * @param {Array} elements\n * @return {undefined}\n */\n unobserveElements(elements) {\n const itemsToKeep = [];\n const itemsToRemove = [];\n\n this.items.forEach((item) => {\n const itemInItems = elements.some((element) => {\n const itemToRemove = getItemFromElement(element);\n return itemToRemove.id === item.id &&\n itemToRemove.threshold === item.threshold &&\n itemToRemove.trackFirstImpressionOnly ===\n item.trackFirstImpressionOnly;\n });\n if (itemInItems) {\n itemsToRemove.push(item);\n } else {\n itemsToKeep.push(item);\n }\n });\n\n // If there are no items to keep, run the `unobserveAllElements` logic.\n if (!itemsToKeep.length) {\n this.unobserveAllElements();\n } else {\n const dataToKeep = this.deriveDataFromElements(itemsToKeep);\n const dataToRemove = this.deriveDataFromElements(itemsToRemove);\n\n this.items = dataToKeep.items;\n this.elementMap = dataToKeep.elementMap;\n this.thresholdMap = dataToKeep.thresholdMap;\n\n // Unobserve removed elements.\n itemsToRemove.forEach((item) => {\n if (!dataToKeep.elementMap[item.id]) {\n const observer = dataToRemove.thresholdMap[item.threshold];\n const element = dataToRemove.elementMap[item.id];\n\n if (element) {\n observer.unobserve(element);\n }\n\n // Disconnect unneeded threshold observers.\n if (!dataToKeep.thresholdMap[item.threshold]) {\n dataToRemove.thresholdMap[item.threshold].disconnect();\n }\n }\n });\n }\n }\n\n /**\n * Stops observing all currently observed elements.\n */\n unobserveAllElements() {\n Object.keys(this.thresholdMap).forEach((key) => {\n this.thresholdMap[key].disconnect();\n });\n\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n\n this.items = [];\n this.elementMap = {};\n this.thresholdMap = {};\n }\n\n /**\n * Loops through each of the passed elements and creates a map of element IDs,\n * threshold values, and a list of \"items\" (which contains each element's\n * `threshold` and `trackFirstImpressionOnly` property).\n * @param {Array} elements A list of elements to derive item data from.\n * @return {Object} An object with the properties `items`, `elementMap`\n * and `threshold`.\n */\n deriveDataFromElements(elements) {\n const items = [];\n const thresholdMap = {};\n const elementMap = {};\n\n if (elements.length) {\n elements.forEach((element) => {\n const item = getItemFromElement(element);\n\n items.push(item);\n elementMap[item.id] = this.elementMap[item.id] || null;\n thresholdMap[item.threshold] =\n this.thresholdMap[item.threshold] || null;\n });\n }\n\n return {items, elementMap, thresholdMap};\n }\n\n /**\n * Handles nodes being added or removed from the DOM. This function is passed\n * as the callback to `this.mutationObserver`.\n * @param {Array} mutations A list of `MutationRecord` instances\n */\n handleDomMutations(mutations) {\n for (let i = 0, mutation; mutation = mutations[i]; i++) {\n // Handles removed elements.\n for (let k = 0, removedEl; removedEl = mutation.removedNodes[k]; k++) {\n this.walkNodeTree(removedEl, this.handleDomElementRemoved);\n }\n // Handles added elements.\n for (let j = 0, addedEl; addedEl = mutation.addedNodes[j]; j++) {\n this.walkNodeTree(addedEl, this.handleDomElementAdded);\n }\n }\n }\n\n /**\n * Iterates through all descendents of a DOM node and invokes the passed\n * callback if any of them match an elememt in `elementMap`.\n * @param {Node} node The DOM node to walk.\n * @param {Function} callback A function to be invoked if a match is found.\n */\n walkNodeTree(node, callback) {\n if (node.nodeType == 1 && node.id in this.elementMap) {\n callback(node.id);\n }\n for (let i = 0, child; child = node.childNodes[i]; i++) {\n this.walkNodeTree(child, callback);\n }\n }\n\n /**\n * Handles intersection changes. This function is passed as the callback to\n * `this.intersectionObserver`\n * @param {Array} records A list of `IntersectionObserverEntry` records.\n */\n handleIntersectionChanges(records) {\n const itemsToRemove = [];\n for (let i = 0, record; record = records[i]; i++) {\n for (let j = 0, item; item = this.items[j]; j++) {\n if (record.target.id !== item.id) continue;\n\n if (isTargetVisible(item.threshold, record)) {\n this.handleImpression(item.id);\n\n if (item.trackFirstImpressionOnly) {\n itemsToRemove.push(item);\n }\n }\n }\n }\n if (itemsToRemove.length) {\n this.unobserveElements(itemsToRemove);\n }\n }\n\n /**\n * Sends a hit to Google Analytics with the impression data.\n * @param {string} id The ID of the element making the impression.\n */\n handleImpression(id) {\n const element = document.getElementById(id);\n\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n eventCategory: 'Viewport',\n eventAction: 'impression',\n eventLabel: id,\n nonInteraction: true,\n };\n\n /** @type {FieldsObj} */\n const userFields = assign({}, this.opts.fieldsObj,\n getAttributeFields(element, this.opts.attributePrefix));\n\n this.tracker.send('event', createFieldsObj(defaultFields,\n userFields, this.tracker, this.opts.hitFilter, element));\n }\n\n /**\n * Handles an element in the items array being added to the DOM.\n * @param {string} id The ID of the element that was added.\n */\n handleDomElementAdded(id) {\n const element = this.elementMap[id] = document.getElementById(id);\n this.items.forEach((item) => {\n if (id == item.id) {\n this.thresholdMap[item.threshold].observe(element);\n }\n });\n }\n\n /**\n * Handles an element currently being observed for intersections being\n * removed from the DOM.\n * @param {string} id The ID of the element that was removed.\n */\n handleDomElementRemoved(id) {\n const element = this.elementMap[id];\n this.items.forEach((item) => {\n if (id == item.id) {\n this.thresholdMap[item.threshold].unobserve(element);\n }\n });\n\n this.elementMap[id] = null;\n }\n\n /**\n * Removes all listeners and observers.\n * @private\n */\n remove() {\n this.unobserveAllElements();\n }\n}\n\n\nprovide('impressionTracker', ImpressionTracker);\n\n\n/**\n * Detects whether or not an intersection record represents a visible target\n * given a particular threshold.\n * @param {number} threshold The threshold the target is visible above.\n * @param {IntersectionObserverEntry} record The most recent record entry.\n * @return {boolean} True if the target is visible.\n */\nfunction isTargetVisible(threshold, record) {\n if (threshold === 0) {\n const i = record.intersectionRect;\n return i.top > 0 || i.bottom > 0 || i.left > 0 || i.right > 0;\n } else {\n return record.intersectionRatio >= threshold;\n }\n}\n\n\n/**\n * Creates an item by merging the passed element with the item defaults.\n * If the passed element is just a string, that string is treated as\n * the item ID.\n * @param {!ImpressionTrackerElementsItem|string} element The element to\n * convert to an item.\n * @return {!ImpressionTrackerElementsItem} The item object.\n */\nfunction getItemFromElement(element) {\n /** @type {ImpressionTrackerElementsItem} */\n const defaultOpts = {\n threshold: 0,\n trackFirstImpressionOnly: true,\n };\n\n if (typeof element == 'string') {\n element = /** @type {!ImpressionTrackerElementsItem} */ ({id: element});\n }\n\n return assign(defaultOpts, element);\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport {parseUrl} from 'dom-utils';\nimport {NULL_DIMENSION} from '../constants';\nimport MethodChain from '../method-chain';\nimport provide from '../provide';\nimport {plugins, trackUsage} from '../usage';\nimport {assign} from '../utilities';\n\n\n/**\n * Class for the `cleanUrlTracker` analytics.js plugin.\n * @implements {CleanUrlTrackerPublicInterface}\n */\nclass CleanUrlTracker {\n /**\n * Registers clean URL tracking on a tracker object. The clean URL tracker\n * removes query parameters from the page value reported to Google Analytics.\n * It also helps to prevent tracking similar URLs, e.g. sometimes ending a\n * URL with a slash and sometimes not.\n * @param {!Tracker} tracker Passed internally by analytics.js\n * @param {?CleanUrlTrackerOpts} opts Passed by the require command.\n */\n constructor(tracker, opts) {\n trackUsage(tracker, plugins.CLEAN_URL_TRACKER);\n\n /** @type {CleanUrlTrackerOpts} */\n const defaultOpts = {\n // stripQuery: undefined,\n // queryParamsWhitelist: undefined,\n // queryDimensionIndex: undefined,\n // indexFilename: undefined,\n // trailingSlash: undefined,\n // urlFilter: undefined,\n };\n this.opts = /** @type {CleanUrlTrackerOpts} */ (assign(defaultOpts, opts));\n\n this.tracker = tracker;\n\n /** @type {string|null} */\n this.queryDimension = this.opts.stripQuery &&\n this.opts.queryDimensionIndex ?\n `dimension${this.opts.queryDimensionIndex}` : null;\n\n // Binds methods to `this`.\n this.trackerGetOverride = this.trackerGetOverride.bind(this);\n this.buildHitTaskOverride = this.buildHitTaskOverride.bind(this);\n\n // Override built-in tracker method to watch for changes.\n MethodChain.add(tracker, 'get', this.trackerGetOverride);\n MethodChain.add(tracker, 'buildHitTask', this.buildHitTaskOverride);\n }\n\n /**\n * Ensures reads of the tracker object by other plugins always see the\n * \"cleaned\" versions of all URL fields.\n * @param {function(string):*} originalMethod A reference to the overridden\n * method.\n * @return {function(string):*}\n */\n trackerGetOverride(originalMethod) {\n return (field) => {\n if (field == 'page' || field == this.queryDimension) {\n const fieldsObj = /** @type {!FieldsObj} */ ({\n location: originalMethod('location'),\n page: originalMethod('page'),\n });\n const cleanedFieldsObj = this.cleanUrlFields(fieldsObj);\n return cleanedFieldsObj[field];\n } else {\n return originalMethod(field);\n }\n };\n }\n\n /**\n * Cleans URL fields passed in a send command.\n * @param {function(!Model)} originalMethod A reference to the\n * overridden method.\n * @return {function(!Model)}\n */\n buildHitTaskOverride(originalMethod) {\n return (model) => {\n const cleanedFieldsObj = this.cleanUrlFields({\n location: model.get('location'),\n page: model.get('page'),\n });\n model.set(cleanedFieldsObj, null, true);\n originalMethod(model);\n };\n }\n\n /**\n * Accepts of fields object containing URL fields and returns a new\n * fields object with the URLs \"cleaned\" according to the tracker options.\n * @param {!FieldsObj} fieldsObj\n * @return {!FieldsObj}\n */\n cleanUrlFields(fieldsObj) {\n const url = parseUrl(\n /** @type {string} */ (fieldsObj.page || fieldsObj.location));\n\n let pathname = url.pathname;\n\n // If an index filename was provided, remove it if it appears at the end\n // of the URL.\n if (this.opts.indexFilename) {\n const parts = pathname.split('/');\n if (this.opts.indexFilename == parts[parts.length - 1]) {\n parts[parts.length - 1] = '';\n pathname = parts.join('/');\n }\n }\n\n // Ensure the URL ends with or doesn't end with slash based on the\n // `trailingSlash` option. Note that filename URLs should never contain\n // a trailing slash.\n if (this.opts.trailingSlash == 'remove') {\n pathname = pathname.replace(/\\/+$/, '');\n } else if (this.opts.trailingSlash == 'add') {\n const isFilename = /\\.\\w+$/.test(pathname);\n if (!isFilename && pathname.substr(-1) != '/') {\n pathname = pathname + '/';\n }\n }\n\n /** @type {!FieldsObj} */\n const cleanedFieldsObj = {\n page: pathname + (this.opts.stripQuery ?\n this.stripNonWhitelistedQueryParams(url.search) : url.search),\n };\n if (fieldsObj.location) {\n cleanedFieldsObj.location = fieldsObj.location;\n }\n if (this.queryDimension) {\n cleanedFieldsObj[this.queryDimension] =\n url.search.slice(1) || NULL_DIMENSION;\n }\n\n // Apply the `urlFieldsFilter()` option if passed.\n if (typeof this.opts.urlFieldsFilter == 'function') {\n /** @type {!FieldsObj} */\n const userCleanedFieldsObj =\n this.opts.urlFieldsFilter(cleanedFieldsObj, parseUrl);\n\n // Ensure only the URL fields are returned.\n const returnValue = {\n page: userCleanedFieldsObj.page,\n location: userCleanedFieldsObj.location,\n };\n if (this.queryDimension) {\n returnValue[this.queryDimension] =\n userCleanedFieldsObj[this.queryDimension];\n }\n return returnValue;\n } else {\n return cleanedFieldsObj;\n }\n }\n\n /**\n * Accpets a raw URL search string and returns a new search string containing\n * only the site search params (if they exist).\n * @param {string} searchString The URL search string (starting with '?').\n * @return {string} The query string\n */\n stripNonWhitelistedQueryParams(searchString) {\n if (Array.isArray(this.opts.queryParamsWhitelist)) {\n const foundParams = [];\n searchString.slice(1).split('&').forEach((kv) => {\n const [key, value] = kv.split('=');\n if (this.opts.queryParamsWhitelist.indexOf(key) > -1 && value) {\n foundParams.push([key, value]);\n }\n });\n\n return foundParams.length ?\n '?' + foundParams.map((kv) => kv.join('=')).join('&') : '';\n } else {\n return '';\n }\n }\n\n /**\n * Restores all overridden tasks and methods.\n */\n remove() {\n MethodChain.remove(this.tracker, 'get', this.trackerGetOverride);\n MethodChain.remove(this.tracker, 'buildHitTask', this.buildHitTaskOverride);\n }\n}\n\n\nprovide('cleanUrlTracker', CleanUrlTracker);\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport {delegate} from 'dom-utils';\nimport provide from '../provide';\nimport {plugins, trackUsage} from '../usage';\nimport {assign, createFieldsObj, getAttributeFields} from '../utilities';\n\n\n/**\n * Class for the `eventTracker` analytics.js plugin.\n * @implements {EventTrackerPublicInterface}\n */\nclass EventTracker {\n /**\n * Registers declarative event tracking.\n * @param {!Tracker} tracker Passed internally by analytics.js\n * @param {?EventTrackerOpts} opts Passed by the require command.\n */\n constructor(tracker, opts) {\n trackUsage(tracker, plugins.EVENT_TRACKER);\n\n // Feature detects to prevent errors in unsupporting browsers.\n if (!window.addEventListener) return;\n\n /** @type {EventTrackerOpts} */\n const defaultOpts = {\n events: ['click'],\n fieldsObj: {},\n attributePrefix: 'ga-',\n // hitFilter: undefined,\n };\n\n this.opts = /** @type {EventTrackerOpts} */ (assign(defaultOpts, opts));\n\n this.tracker = tracker;\n\n // Binds methods.\n this.handleEvents = this.handleEvents.bind(this);\n\n const selector = '[' + this.opts.attributePrefix + 'on]';\n\n // Creates a mapping of events to their delegates\n this.delegates = {};\n this.opts.events.forEach((event) => {\n this.delegates[event] = delegate(document, event, selector,\n this.handleEvents, {composed: true, useCapture: true});\n });\n }\n\n /**\n * Handles all events on elements with event attributes.\n * @param {Event} event The DOM click event.\n * @param {Element} element The delegated DOM element target.\n */\n handleEvents(event, element) {\n const prefix = this.opts.attributePrefix;\n const events = element.getAttribute(prefix + 'on').split(/\\s*,\\s*/);\n\n // Ensures the type matches one of the events specified on the element.\n if (events.indexOf(event.type) < 0) return;\n\n /** @type {FieldsObj} */\n const defaultFields = {transport: 'beacon'};\n const attributeFields = getAttributeFields(element, prefix);\n const userFields = assign({}, this.opts.fieldsObj, attributeFields);\n const hitType = attributeFields.hitType || 'event';\n\n this.tracker.send(hitType, createFieldsObj(defaultFields,\n userFields, this.tracker, this.opts.hitFilter, element, event));\n }\n\n /**\n * Removes all event listeners and instance properties.\n */\n remove() {\n Object.keys(this.delegates).forEach((key) => {\n this.delegates[key].destroy();\n });\n }\n}\n\n\nprovide('eventTracker', EventTracker);\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/**\n * An simple reimplementation of the native Node.js EventEmitter class.\n * The goal of this implementation is to be as small as possible.\n */\nexport default class EventEmitter {\n /**\n * Creates the event registry.\n */\n constructor() {\n this.registry_ = {};\n }\n\n /**\n * Adds a handler function to the registry for the passed event.\n * @param {string} event The event name.\n * @param {!Function} fn The handler to be invoked when the passed\n * event is emitted.\n */\n on(event, fn) {\n this.getRegistry_(event).push(fn);\n }\n\n /**\n * Removes a handler function from the registry for the passed event.\n * @param {string=} event The event name.\n * @param {Function=} fn The handler to be removed.\n */\n off(event = undefined, fn = undefined) {\n if (event && fn) {\n const eventRegistry = this.getRegistry_(event);\n const handlerIndex = eventRegistry.indexOf(fn);\n if (handlerIndex > -1) {\n eventRegistry.splice(handlerIndex, 1);\n }\n } else {\n this.registry_ = {};\n }\n }\n\n /**\n * Runs all registered handlers for the passed event with the optional args.\n * @param {string} event The event name.\n * @param {...*} args The arguments to be passed to the handler.\n */\n emit(event, ...args) {\n this.getRegistry_(event).forEach((fn) => fn(...args));\n }\n\n /**\n * Returns the total number of event handlers currently registered.\n * @return {number}\n */\n getEventCount() {\n let eventCount = 0;\n Object.keys(this.registry_).forEach((event) => {\n eventCount += this.getRegistry_(event).length;\n });\n return eventCount;\n }\n\n /**\n * Returns an array of handlers associated with the passed event name.\n * If no handlers have been registered, an empty array is returned.\n * @private\n * @param {string} event The event name.\n * @return {!Array} An array of handler functions.\n */\n getRegistry_(event) {\n return this.registry_[event] = (this.registry_[event] || []);\n }\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport EventEmitter from './event-emitter';\nimport {assign} from './utilities';\n\n\nconst AUTOTRACK_PREFIX = 'autotrack';\nconst instances = {};\nlet isListening = false;\n\n\n/** @type {boolean|undefined} */\nlet browserSupportsLocalStorage;\n\n\n/**\n * A storage object to simplify interacting with localStorage.\n */\nexport default class Store extends EventEmitter {\n /**\n * Gets an existing instance for the passed arguements or creates a new\n * instance if one doesn't exist.\n * @param {string} trackingId The tracking ID for the GA property.\n * @param {string} namespace A namespace unique to this store.\n * @param {Object=} defaults An optional object of key/value defaults.\n * @return {Store} The Store instance.\n */\n static getOrCreate(trackingId, namespace, defaults) {\n const key = [AUTOTRACK_PREFIX, trackingId, namespace].join(':');\n\n // Don't create multiple instances for the same tracking Id and namespace.\n if (!instances[key]) {\n instances[key] = new Store(key, defaults);\n if (!isListening) initStorageListener();\n }\n return instances[key];\n }\n\n /**\n * Returns true if the browser supports and can successfully write to\n * localStorage. The results is cached so this method can be invoked many\n * times with no extra performance cost.\n * @private\n * @return {boolean}\n */\n static isSupported_() {\n if (browserSupportsLocalStorage != null) {\n return browserSupportsLocalStorage;\n }\n\n try {\n window.localStorage.setItem(AUTOTRACK_PREFIX, AUTOTRACK_PREFIX);\n window.localStorage.removeItem(AUTOTRACK_PREFIX);\n browserSupportsLocalStorage = true;\n } catch (err) {\n browserSupportsLocalStorage = false;\n }\n return browserSupportsLocalStorage;\n }\n\n /**\n * Wraps the native localStorage method for each stubbing in tests.\n * @private\n * @param {string} key The store key.\n * @return {string|null} The stored value.\n */\n static get_(key) {\n return window.localStorage.getItem(key);\n }\n\n /**\n * Wraps the native localStorage method for each stubbing in tests.\n * @private\n * @param {string} key The store key.\n * @param {string} value The value to store.\n */\n static set_(key, value) {\n window.localStorage.setItem(key, value);\n }\n\n /**\n * Wraps the native localStorage method for each stubbing in tests.\n * @private\n * @param {string} key The store key.\n */\n static clear_(key) {\n window.localStorage.removeItem(key);\n }\n\n /**\n * @param {string} key A key unique to this store.\n * @param {Object=} defaults An optional object of key/value defaults.\n */\n constructor(key, defaults = {}) {\n super();\n this.key_ = key;\n this.defaults_ = defaults;\n\n /** @type {?Object} */\n this.cache_ = null; // Will be set after the first get.\n }\n\n /**\n * Gets the data stored in localStorage for this store. If the cache is\n * already populated, return it as is (since it's always kept up-to-date\n * and in sync with activity in other windows via the `storage` event).\n * TODO(philipwalton): Implement schema migrations if/when a new\n * schema version is introduced.\n * @return {!Object} The stored data merged with the defaults.\n */\n get() {\n if (this.cache_) {\n return this.cache_;\n } else {\n if (Store.isSupported_()) {\n try {\n this.cache_ = parse(Store.get_(this.key_));\n } catch(err) {\n // Do nothing.\n }\n }\n return this.cache_ = assign({}, this.defaults_, this.cache_);\n }\n }\n\n /**\n * Saves the passed data object to localStorage,\n * merging it with the existing data.\n * @param {Object} newData The data to save.\n */\n set(newData) {\n this.cache_ = assign({}, this.defaults_, this.cache_, newData);\n\n if (Store.isSupported_()) {\n try {\n Store.set_(this.key_, JSON.stringify(this.cache_));\n } catch(err) {\n // Do nothing.\n }\n }\n }\n\n /**\n * Clears the data in localStorage for the current store.\n */\n clear() {\n this.cache_ = {};\n if (Store.isSupported_()) {\n try {\n Store.clear_(this.key_);\n } catch(err) {\n // Do nothing.\n }\n }\n }\n\n /**\n * Removes the store instance for the global instances map. If this is the\n * last store instance, the storage listener is also removed.\n * Note: this does not erase the stored data. Use `clear()` for that.\n */\n destroy() {\n delete instances[this.key_];\n if (!Object.keys(instances).length) {\n removeStorageListener();\n }\n }\n}\n\n\n/**\n * Adds a single storage event listener and flips the global `isListening`\n * flag so multiple events aren't added.\n */\nfunction initStorageListener() {\n window.addEventListener('storage', storageListener);\n isListening = true;\n}\n\n\n/**\n * Removes the storage event listener and flips the global `isListening`\n * flag so it can be re-added later.\n */\nfunction removeStorageListener() {\n window.removeEventListener('storage', storageListener);\n isListening = false;\n}\n\n\n/**\n * The global storage event listener.\n * @param {!Event} event The DOM event.\n */\nfunction storageListener(event) {\n const store = instances[event.key];\n if (store) {\n const oldData = assign({}, store.defaults_, parse(event.oldValue));\n const newData = assign({}, store.defaults_, parse(event.newValue));\n\n store.cache_ = newData;\n store.emit('externalSet', newData, oldData);\n }\n}\n\n\n/**\n * Parses a source string as JSON\n * @param {string|null} source\n * @return {!Object} The JSON object.\n */\nfunction parse(source) {\n let data = {};\n if (source) {\n try {\n data = /** @type {!Object} */ (JSON.parse(source));\n } catch(err) {\n // Do nothing.\n }\n }\n return data;\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport MethodChain from './method-chain';\nimport Store from './store';\nimport {now, uuid} from './utilities';\n\n\nconst SECONDS = 1000;\nconst MINUTES = 60 * SECONDS;\n\n\nconst instances = {};\n\n\n/**\n * A session management class that helps track session boundaries\n * across multiple open tabs/windows.\n */\nexport default class Session {\n /**\n * Gets an existing instance for the passed arguments or creates a new\n * instance if one doesn't exist.\n * @param {!Tracker} tracker An analytics.js tracker object.\n * @param {number} timeout The session timeout (in minutes). This value\n * should match what's set in the \"Session settings\" section of the\n * Google Analytics admin.\n * @param {string=} timeZone The optional IANA time zone of the view. This\n * value should match what's set in the \"View settings\" section of the\n * Google Analytics admin. (Note: this assumes all views for the property\n * use the same time zone. If that's not true, it's better not to use\n * this feature).\n * @return {Session} The Session instance.\n */\n static getOrCreate(tracker, timeout, timeZone) {\n // Don't create multiple instances for the same property.\n const trackingId = tracker.get('trackingId');\n if (instances[trackingId]) {\n return instances[trackingId];\n } else {\n return instances[trackingId] = new Session(tracker, timeout, timeZone);\n }\n }\n\n /**\n * @param {!Tracker} tracker An analytics.js tracker object.\n * @param {number} timeout The session timeout (in minutes). This value\n * should match what's set in the \"Session settings\" section of the\n * Google Analytics admin.\n * @param {string=} timeZone The optional IANA time zone of the view. This\n * value should match what's set in the \"View settings\" section of the\n * Google Analytics admin. (Note: this assumes all views for the property\n * use the same time zone. If that's not true, it's better not to use\n * this feature).\n */\n constructor(tracker, timeout, timeZone) {\n this.tracker = tracker;\n this.timeout = timeout || Session.DEFAULT_TIMEOUT;\n this.timeZone = timeZone;\n\n // Binds methods.\n this.sendHitTaskOverride = this.sendHitTaskOverride.bind(this);\n\n // Overrides into the trackers sendHitTask method.\n MethodChain.add(tracker, 'sendHitTask', this.sendHitTaskOverride);\n\n // Some browser doesn't support various features of the\n // `Intl.DateTimeFormat` API, so we have to try/catch it. Consequently,\n // this allows us to assume the presence of `this.dateTimeFormatter` means\n // it works in the current browser.\n try {\n this.dateTimeFormatter =\n new Intl.DateTimeFormat('en-US', {timeZone: this.timeZone});\n } catch(err) {\n // Do nothing.\n }\n\n /** @type {SessionStoreData} */\n const defaultProps = {\n hitTime: 0,\n isExpired: false,\n };\n this.store = Store.getOrCreate(\n tracker.get('trackingId'), 'session', defaultProps);\n\n // Ensure the session has an ID.\n if (!this.store.get().id) {\n this.store.set(/** @type {SessionStoreData} */ ({id: uuid()}));\n }\n }\n\n /**\n * Returns the ID of the current session.\n * @return {string}\n */\n getId() {\n return this.store.get().id;\n }\n\n /**\n * Accepts a session ID and returns true if the specified session has\n * evidentially expired. A session can expire for two reasons:\n * - More than 30 minutes has elapsed since the previous hit\n * was sent (The 30 minutes number is the Google Analytics default, but\n * it can be modified in GA admin \"Session settings\").\n * - A new day has started since the previous hit, in the\n * specified time zone (should correspond to the time zone of the\n * property's views).\n *\n * Note: since real session boundaries are determined at processing time,\n * this is just a best guess rather than a source of truth.\n *\n * @param {string} id The ID of a session to check for expiry.\n * @return {boolean} True if the session has not exp\n */\n isExpired(id = this.getId()) {\n // If a session ID is passed and it doesn't match the current ID,\n // assume it's from an expired session. If no ID is passed, assume the ID\n // of the current session.\n if (id != this.getId()) return true;\n\n /** @type {SessionStoreData} */\n const sessionData = this.store.get();\n\n // `isExpired` will be `true` if the sessionControl field was set to\n // 'end' on the previous hit.\n if (sessionData.isExpired) return true;\n\n const oldHitTime = sessionData.hitTime;\n\n // Only consider a session expired if previous hit time data exists, and\n // the previous hit time is greater than that session timeout period or\n // the hits occurred on different days in the session timezone.\n if (oldHitTime) {\n const currentDate = new Date();\n const oldHitDate = new Date(oldHitTime);\n if (currentDate - oldHitDate > (this.timeout * MINUTES) ||\n this.datesAreDifferentInTimezone(currentDate, oldHitDate)) {\n return true;\n }\n }\n\n // For all other cases return false.\n return false;\n }\n\n /**\n * Returns true if (and only if) the timezone date formatting is supported\n * in the current browser and if the two dates are definitively not the\n * same date in the session timezone. Anything short of this returns false.\n * @param {!Date} d1\n * @param {!Date} d2\n * @return {boolean}\n */\n datesAreDifferentInTimezone(d1, d2) {\n if (!this.dateTimeFormatter) {\n return false;\n } else {\n return this.dateTimeFormatter.format(d1)\n != this.dateTimeFormatter.format(d2);\n }\n }\n\n /**\n * Keeps track of when the previous hit was sent to determine if a session\n * has expired. Also inspects the `sessionControl` field to handles\n * expiration accordingly.\n * @param {function(!Model)} originalMethod A reference to the overridden\n * method.\n * @return {function(!Model)}\n */\n sendHitTaskOverride(originalMethod) {\n return (model) => {\n originalMethod(model);\n\n const sessionControl = model.get('sessionControl');\n const sessionWillStart = sessionControl == 'start' || this.isExpired();\n const sessionWillEnd = sessionControl == 'end';\n\n /** @type {SessionStoreData} */\n const sessionData = this.store.get();\n sessionData.hitTime = now();\n if (sessionWillStart) {\n sessionData.isExpired = false;\n sessionData.id = uuid();\n }\n if (sessionWillEnd) {\n sessionData.isExpired = true;\n }\n this.store.set(sessionData);\n };\n }\n\n /**\n * Restores the tracker's original `sendHitTask` to the state before\n * session control was initialized and removes this instance from the global\n * store.\n */\n destroy() {\n MethodChain.remove(this.tracker, 'sendHitTask', this.sendHitTaskOverride);\n this.store.destroy();\n delete instances[this.tracker.get('trackingId')];\n }\n}\n\n\nSession.DEFAULT_TIMEOUT = 30; // minutes\n","/**\n * Copyright 2017 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport {parseUrl} from 'dom-utils';\nimport MethodChain from '../method-chain';\nimport provide from '../provide';\nimport Session from '../session';\nimport Store from '../store';\nimport {plugins, trackUsage} from '../usage';\nimport {assign, createFieldsObj, debounce, isObject} from '../utilities';\n\n\n/**\n * Class for the `maxScrollQueryTracker` analytics.js plugin.\n * @implements {MaxScrollTrackerPublicInterface}\n */\nclass MaxScrollTracker {\n /**\n * Registers outbound link tracking on tracker object.\n * @param {!Tracker} tracker Passed internally by analytics.js\n * @param {?Object} opts Passed by the require command.\n */\n constructor(tracker, opts) {\n trackUsage(tracker, plugins.MAX_SCROLL_TRACKER);\n\n // Feature detects to prevent errors in unsupporting browsers.\n if (!window.addEventListener) return;\n\n /** @type {MaxScrollTrackerOpts} */\n const defaultOpts = {\n increaseThreshold: 20,\n sessionTimeout: Session.DEFAULT_TIMEOUT,\n // timeZone: undefined,\n // maxScrollMetricIndex: undefined,\n fieldsObj: {},\n // hitFilter: undefined\n };\n\n this.opts = /** @type {MaxScrollTrackerOpts} */ (\n assign(defaultOpts, opts));\n\n this.tracker = tracker;\n this.pagePath = this.getPagePath();\n\n // Binds methods to `this`.\n this.handleScroll = debounce(this.handleScroll.bind(this), 500);\n this.trackerSetOverride = this.trackerSetOverride.bind(this);\n\n // Creates the store and binds storage change events.\n this.store = Store.getOrCreate(\n tracker.get('trackingId'), 'plugins/max-scroll-tracker');\n\n // Creates the session and binds session events.\n this.session = Session.getOrCreate(\n tracker, this.opts.sessionTimeout, this.opts.timeZone);\n\n // Override the built-in tracker.set method to watch for changes.\n MethodChain.add(tracker, 'set', this.trackerSetOverride);\n\n this.listenForMaxScrollChanges();\n }\n\n\n /**\n * Adds a scroll event listener if the max scroll percentage for the\n * current page isn't already at 100%.\n */\n listenForMaxScrollChanges() {\n const maxScrollPercentage = this.getMaxScrollPercentageForCurrentPage();\n if (maxScrollPercentage < 100) {\n window.addEventListener('scroll', this.handleScroll);\n }\n }\n\n\n /**\n * Removes an added scroll listener.\n */\n stopListeningForMaxScrollChanges() {\n window.removeEventListener('scroll', this.handleScroll);\n }\n\n\n /**\n * Handles the scroll event. If the current scroll percentage is greater\n * that the stored scroll event by at least the specified increase threshold,\n * send an event with the increase amount.\n */\n handleScroll() {\n const pageHeight = getPageHeight();\n const scrollPos = window.pageYOffset; // scrollY isn't supported in IE.\n const windowHeight = window.innerHeight;\n\n // Ensure scrollPercentage is an integer between 0 and 100.\n const scrollPercentage = Math.min(100, Math.max(0,\n Math.round(100 * (scrollPos / (pageHeight - windowHeight)))));\n\n // If the max scroll data gets out of the sync with the session data\n // (for whatever reason), clear it.\n const sessionId = this.session.getId();\n if (sessionId != this.store.get().sessionId) {\n this.store.clear();\n this.store.set({sessionId});\n }\n\n // If the session has expired, clear the stored data and don't send any\n // events (since they'd start a new session). Note: this check is needed,\n // in addition to the above check, to handle cases where the session IDs\n // got out of sync, but the session didn't expire.\n if (this.session.isExpired(this.store.get().sessionId)) {\n this.store.clear();\n } else {\n const maxScrollPercentage = this.getMaxScrollPercentageForCurrentPage();\n\n if (scrollPercentage > maxScrollPercentage) {\n if (scrollPercentage == 100 || maxScrollPercentage == 100) {\n this.stopListeningForMaxScrollChanges();\n }\n const increaseAmount = scrollPercentage - maxScrollPercentage;\n if (scrollPercentage == 100 ||\n increaseAmount >= this.opts.increaseThreshold) {\n this.setMaxScrollPercentageForCurrentPage(scrollPercentage);\n this.sendMaxScrollEvent(increaseAmount, scrollPercentage);\n }\n }\n }\n }\n\n /**\n * Detects changes to the tracker object and triggers an update if the page\n * field has changed.\n * @param {function((Object|string), (string|undefined))} originalMethod\n * A reference to the overridden method.\n * @return {function((Object|string), (string|undefined))}\n */\n trackerSetOverride(originalMethod) {\n return (field, value) => {\n originalMethod(field, value);\n\n /** @type {!FieldsObj} */\n const fields = isObject(field) ? field : {[field]: value};\n if (fields.page) {\n const lastPagePath = this.pagePath;\n this.pagePath = this.getPagePath();\n\n if (this.pagePath != lastPagePath) {\n // Since event listeners for the same function are never added twice,\n // we don't need to worry about whether we're already listening. We\n // can just add the event listener again.\n this.listenForMaxScrollChanges();\n }\n }\n };\n }\n\n /**\n * Sends an event for the increased max scroll percentage amount.\n * @param {number} increaseAmount\n * @param {number} scrollPercentage\n */\n sendMaxScrollEvent(increaseAmount, scrollPercentage) {\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n eventCategory: 'Max Scroll',\n eventAction: 'increase',\n eventValue: increaseAmount,\n eventLabel: String(scrollPercentage),\n nonInteraction: true,\n };\n\n // If a custom metric was specified, set it equal to the event value.\n if (this.opts.maxScrollMetricIndex) {\n defaultFields['metric' + this.opts.maxScrollMetricIndex] = increaseAmount;\n }\n\n this.tracker.send('event',\n createFieldsObj(defaultFields, this.opts.fieldsObj,\n this.tracker, this.opts.hitFilter));\n }\n\n /**\n * Stores the current max scroll percentage for the current page.\n * @param {number} maxScrollPercentage\n */\n setMaxScrollPercentageForCurrentPage(maxScrollPercentage) {\n this.store.set({\n [this.pagePath]: maxScrollPercentage,\n sessionId: this.session.getId(),\n });\n }\n\n /**\n * Gets the stored max scroll percentage for the current page.\n * @return {number}\n */\n getMaxScrollPercentageForCurrentPage() {\n return this.store.get()[this.pagePath] || 0;\n }\n\n /**\n * Gets the page path from the tracker object.\n * @return {number}\n */\n getPagePath() {\n const url = parseUrl(\n this.tracker.get('page') || this.tracker.get('location'));\n return url.pathname + url.search;\n }\n\n /**\n * Removes all event listeners and restores overridden methods.\n */\n remove() {\n this.session.destroy();\n this.stopListeningForMaxScrollChanges();\n MethodChain.remove(this.tracker, 'set', this.trackerSetOverride);\n }\n}\n\n\nprovide('maxScrollTracker', MaxScrollTracker);\n\n\n/**\n * Gets the maximum height of the page including scrollable area.\n * @return {number}\n */\nfunction getPageHeight() {\n const html = document.documentElement;\n const body = document.body;\n return Math.max(html.offsetHeight, html.scrollHeight,\n body.offsetHeight, body.scrollHeight);\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport {NULL_DIMENSION} from '../constants';\nimport provide from '../provide';\nimport {plugins, trackUsage} from '../usage';\nimport {assign, createFieldsObj,\n debounce, isObject, toArray} from '../utilities';\n\n\n/**\n * Declares the MediaQueryList instance cache.\n */\nconst mediaMap = {};\n\n\n/**\n * Class for the `mediaQueryTracker` analytics.js plugin.\n * @implements {MediaQueryTrackerPublicInterface}\n */\nclass MediaQueryTracker {\n /**\n * Registers media query tracking.\n * @param {!Tracker} tracker Passed internally by analytics.js\n * @param {?Object} opts Passed by the require command.\n */\n constructor(tracker, opts) {\n trackUsage(tracker, plugins.MEDIA_QUERY_TRACKER);\n\n // Feature detects to prevent errors in unsupporting browsers.\n if (!window.matchMedia) return;\n\n /** @type {MediaQueryTrackerOpts} */\n const defaultOpts = {\n // definitions: unefined,\n changeTemplate: this.changeTemplate,\n changeTimeout: 1000,\n fieldsObj: {},\n // hitFilter: undefined,\n };\n\n this.opts = /** @type {MediaQueryTrackerOpts} */ (\n assign(defaultOpts, opts));\n\n // Exits early if media query data doesn't exist.\n if (!isObject(this.opts.definitions)) return;\n\n this.opts.definitions = toArray(this.opts.definitions);\n this.tracker = tracker;\n this.changeListeners = [];\n\n this.processMediaQueries();\n }\n\n /**\n * Loops through each media query definition, sets the custom dimenion data,\n * and adds the change listeners.\n */\n processMediaQueries() {\n this.opts.definitions.forEach((definition) => {\n // Only processes definitions with a name and index.\n if (definition.name && definition.dimensionIndex) {\n const mediaName = this.getMatchName(definition);\n this.tracker.set('dimension' + definition.dimensionIndex, mediaName);\n\n this.addChangeListeners(definition);\n }\n });\n }\n\n /**\n * Takes a definition object and return the name of the matching media item.\n * If no match is found, the NULL_DIMENSION value is returned.\n * @param {Object} definition A set of named media queries associated\n * with a single custom dimension.\n * @return {string} The name of the matched media or NULL_DIMENSION.\n */\n getMatchName(definition) {\n let match;\n\n definition.items.forEach((item) => {\n if (getMediaList(item.media).matches) {\n match = item;\n }\n });\n return match ? match.name : NULL_DIMENSION;\n }\n\n /**\n * Adds change listeners to each media query in the definition list.\n * Debounces the changes to prevent unnecessary hits from being sent.\n * @param {Object} definition A set of named media queries associated\n * with a single custom dimension\n */\n addChangeListeners(definition) {\n definition.items.forEach((item) => {\n const mql = getMediaList(item.media);\n const fn = debounce(() => {\n this.handleChanges(definition);\n }, this.opts.changeTimeout);\n\n mql.addListener(fn);\n this.changeListeners.push({mql, fn});\n });\n }\n\n /**\n * Handles changes to the matched media. When the new value differs from\n * the old value, a change event is sent.\n * @param {Object} definition A set of named media queries associated\n * with a single custom dimension\n */\n handleChanges(definition) {\n const newValue = this.getMatchName(definition);\n const oldValue = this.tracker.get('dimension' + definition.dimensionIndex);\n\n if (newValue !== oldValue) {\n this.tracker.set('dimension' + definition.dimensionIndex, newValue);\n\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n eventCategory: definition.name,\n eventAction: 'change',\n eventLabel: this.opts.changeTemplate(oldValue, newValue),\n nonInteraction: true,\n };\n this.tracker.send('event', createFieldsObj(defaultFields,\n this.opts.fieldsObj, this.tracker, this.opts.hitFilter));\n }\n }\n\n /**\n * Removes all event listeners and instance properties.\n */\n remove() {\n for (let i = 0, listener; listener = this.changeListeners[i]; i++) {\n listener.mql.removeListener(listener.fn);\n }\n }\n\n /**\n * Sets the default formatting of the change event label.\n * This can be overridden by setting the `changeTemplate` option.\n * @param {string} oldValue The value of the media query prior to the change.\n * @param {string} newValue The value of the media query after the change.\n * @return {string} The formatted event label.\n */\n changeTemplate(oldValue, newValue) {\n return oldValue + ' => ' + newValue;\n }\n}\n\n\nprovide('mediaQueryTracker', MediaQueryTracker);\n\n\n/**\n * Accepts a media query and returns a MediaQueryList object.\n * Caches the values to avoid multiple unnecessary instances.\n * @param {string} media A media query value.\n * @return {MediaQueryList} The matched media.\n */\nfunction getMediaList(media) {\n return mediaMap[media] || (mediaMap[media] = window.matchMedia(media));\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport {delegate, parseUrl} from 'dom-utils';\nimport provide from '../provide';\nimport {plugins, trackUsage} from '../usage';\nimport {assign, createFieldsObj,\n getAttributeFields, withTimeout} from '../utilities';\n\n\n/**\n * Class for the `outboundFormTracker` analytics.js plugin.\n * @implements {OutboundFormTrackerPublicInterface}\n */\nclass OutboundFormTracker {\n /**\n * Registers outbound form tracking.\n * @param {!Tracker} tracker Passed internally by analytics.js\n * @param {?Object} opts Passed by the require command.\n */\n constructor(tracker, opts) {\n trackUsage(tracker, plugins.OUTBOUND_FORM_TRACKER);\n\n // Feature detects to prevent errors in unsupporting browsers.\n if (!window.addEventListener) return;\n\n /** @type {OutboundFormTrackerOpts} */\n const defaultOpts = {\n formSelector: 'form',\n shouldTrackOutboundForm: this.shouldTrackOutboundForm,\n fieldsObj: {},\n attributePrefix: 'ga-',\n // hitFilter: undefined\n };\n\n this.opts = /** @type {OutboundFormTrackerOpts} */ (\n assign(defaultOpts, opts));\n\n this.tracker = tracker;\n\n this.delegate = delegate(document, 'submit', this.opts.formSelector,\n this.handleFormSubmits.bind(this), {composed: true, useCapture: true});\n }\n\n /**\n * Handles all submits on form elements. A form submit is considered outbound\n * if its action attribute starts with http and does not contain\n * location.hostname.\n * When the beacon transport method is not available, the event's default\n * action is prevented and re-emitted after the hit is sent.\n * @param {Event} event The DOM submit event.\n * @param {Element} form The delegated event target.\n */\n handleFormSubmits(event, form) {\n const action = parseUrl(form.action).href;\n\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n eventCategory: 'Outbound Form',\n eventAction: 'submit',\n eventLabel: action,\n };\n\n if (this.opts.shouldTrackOutboundForm(form, parseUrl)) {\n if (!navigator.sendBeacon) {\n // Stops the submit and waits until the hit is complete (with timeout)\n // for browsers that don't support beacon.\n event.preventDefault();\n defaultFields.hitCallback = withTimeout(function() {\n form.submit();\n });\n }\n\n const userFields = assign({}, this.opts.fieldsObj,\n getAttributeFields(form, this.opts.attributePrefix));\n\n this.tracker.send('event', createFieldsObj(\n defaultFields, userFields,\n this.tracker, this.opts.hitFilter, form, event));\n }\n }\n\n /**\n * Determines whether or not the tracker should send a hit when a form is\n * submitted. By default, forms with an action attribute that starts with\n * \"http\" and doesn't contain the current hostname are tracked.\n * @param {Element} form The form that was submitted.\n * @param {Function} parseUrlFn A cross-browser utility method for url\n * parsing (note: renamed to disambiguate when compiling).\n * @return {boolean} Whether or not the form should be tracked.\n */\n shouldTrackOutboundForm(form, parseUrlFn) {\n const url = parseUrlFn(form.action);\n return url.hostname != location.hostname &&\n url.protocol.slice(0, 4) == 'http';\n }\n\n /**\n * Removes all event listeners and instance properties.\n */\n remove() {\n this.delegate.destroy();\n }\n}\n\n\nprovide('outboundFormTracker', OutboundFormTracker);\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport {delegate, parseUrl} from 'dom-utils';\nimport provide from '../provide';\nimport {plugins, trackUsage} from '../usage';\nimport {assign, createFieldsObj,\n getAttributeFields, withTimeout} from '../utilities';\n\n\n/**\n * Class for the `outboundLinkTracker` analytics.js plugin.\n * @implements {OutboundLinkTrackerPublicInterface}\n */\nclass OutboundLinkTracker {\n /**\n * Registers outbound link tracking on a tracker object.\n * @param {!Tracker} tracker Passed internally by analytics.js\n * @param {?Object} opts Passed by the require command.\n */\n constructor(tracker, opts) {\n trackUsage(tracker, plugins.OUTBOUND_LINK_TRACKER);\n\n // Feature detects to prevent errors in unsupporting browsers.\n if (!window.addEventListener) return;\n\n /** @type {OutboundLinkTrackerOpts} */\n const defaultOpts = {\n events: ['click'],\n linkSelector: 'a, area',\n shouldTrackOutboundLink: this.shouldTrackOutboundLink,\n fieldsObj: {},\n attributePrefix: 'ga-',\n // hitFilter: undefined,\n };\n\n this.opts = /** @type {OutboundLinkTrackerOpts} */ (\n assign(defaultOpts, opts));\n\n this.tracker = tracker;\n\n // Binds methods.\n this.handleLinkInteractions = this.handleLinkInteractions.bind(this);\n\n // Creates a mapping of events to their delegates\n this.delegates = {};\n this.opts.events.forEach((event) => {\n this.delegates[event] = delegate(document, event, this.opts.linkSelector,\n this.handleLinkInteractions, {composed: true, useCapture: true});\n });\n }\n\n /**\n * Handles all interactions on link elements. A link is considered an outbound\n * link if its hostname property does not match location.hostname. When the\n * beacon transport method is not available, the links target is set to\n * \"_blank\" to ensure the hit can be sent.\n * @param {Event} event The DOM click event.\n * @param {Element} link The delegated event target.\n */\n handleLinkInteractions(event, link) {\n if (this.opts.shouldTrackOutboundLink(link, parseUrl)) {\n const href = link.getAttribute('href') || link.getAttribute('xlink:href');\n const url = parseUrl(href);\n\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n eventCategory: 'Outbound Link',\n eventAction: event.type,\n eventLabel: url.href,\n };\n\n /** @type {FieldsObj} */\n const userFields = assign({}, this.opts.fieldsObj,\n getAttributeFields(link, this.opts.attributePrefix));\n\n const fieldsObj = createFieldsObj(defaultFields, userFields,\n this.tracker, this.opts.hitFilter, link, event);\n\n if (!navigator.sendBeacon &&\n linkClickWillUnloadCurrentPage(event, link)) {\n // Adds a new event handler at the last minute to minimize the chances\n // that another event handler for this click will run after this logic.\n const clickHandler = () => {\n window.removeEventListener('click', clickHandler);\n\n // Checks to make sure another event handler hasn't already prevented\n // the default action. If it has the custom redirect isn't needed.\n if (!event.defaultPrevented) {\n // Stops the click and waits until the hit is complete (with\n // timeout) for browsers that don't support beacon.\n event.preventDefault();\n\n const oldHitCallback = fieldsObj.hitCallback;\n fieldsObj.hitCallback = withTimeout(function() {\n if (typeof oldHitCallback == 'function') oldHitCallback();\n location.href = href;\n });\n }\n this.tracker.send('event', fieldsObj);\n };\n window.addEventListener('click', clickHandler);\n } else {\n this.tracker.send('event', fieldsObj);\n }\n }\n }\n\n /**\n * Determines whether or not the tracker should send a hit when a link is\n * clicked. By default links with a hostname property not equal to the current\n * hostname are tracked.\n * @param {Element} link The link that was clicked on.\n * @param {Function} parseUrlFn A cross-browser utility method for url\n * parsing (note: renamed to disambiguate when compiling).\n * @return {boolean} Whether or not the link should be tracked.\n */\n shouldTrackOutboundLink(link, parseUrlFn) {\n const href = link.getAttribute('href') || link.getAttribute('xlink:href');\n const url = parseUrlFn(href);\n return url.hostname != location.hostname &&\n url.protocol.slice(0, 4) == 'http';\n }\n\n /**\n * Removes all event listeners and instance properties.\n */\n remove() {\n Object.keys(this.delegates).forEach((key) => {\n this.delegates[key].destroy();\n });\n }\n}\n\n\nprovide('outboundLinkTracker', OutboundLinkTracker);\n\n\n/**\n * Determines if a link click event will cause the current page to upload.\n * Note: most link clicks *will* cause the current page to unload because they\n * initiate a page navigation. The most common reason a link click won't cause\n * the page to unload is if the clicked was to open the link in a new tab.\n * @param {Event} event The DOM event.\n * @param {Element} link The link element clicked on.\n * @return {boolean} True if the current page will be unloaded.\n */\nfunction linkClickWillUnloadCurrentPage(event, link) {\n return !(\n // The event type can be customized; we only care about clicks here.\n event.type != 'click' ||\n // Links with target=\"_blank\" set will open in a new window/tab.\n link.target == '_blank' ||\n // On mac, command clicking will open a link in a new tab. Control\n // clicking does this on windows.\n event.metaKey || event.ctrlKey ||\n // Shift clicking in Chrome/Firefox opens the link in a new window\n // In Safari it adds the URL to a favorites list.\n event.shiftKey ||\n // On Mac, clicking with the option key is used to download a resouce.\n event.altKey ||\n // Middle mouse button clicks (which == 2) are used to open a link\n // in a new tab, and right clicks (which == 3) on Firefox trigger\n // a click event.\n event.which > 1);\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport {NULL_DIMENSION} from '../constants';\nimport MethodChain from '../method-chain';\nimport provide from '../provide';\nimport Session from '../session';\nimport Store from '../store';\nimport {plugins, trackUsage} from '../usage';\nimport {assign, createFieldsObj, deferUntilPluginsLoaded,\n isObject, now, uuid} from '../utilities';\n\n\nconst HIDDEN = 'hidden';\nconst VISIBLE = 'visible';\nconst PAGE_ID = uuid();\nconst SECONDS = 1000;\n\n\n/**\n * Class for the `pageVisibilityTracker` analytics.js plugin.\n * @implements {PageVisibilityTrackerPublicInterface}\n */\nclass PageVisibilityTracker {\n /**\n * Registers outbound link tracking on tracker object.\n * @param {!Tracker} tracker Passed internally by analytics.js\n * @param {?Object} opts Passed by the require command.\n */\n constructor(tracker, opts) {\n trackUsage(tracker, plugins.PAGE_VISIBILITY_TRACKER);\n\n // Feature detects to prevent errors in unsupporting browsers.\n if (!document.visibilityState) return;\n\n /** @type {PageVisibilityTrackerOpts} */\n const defaultOpts = {\n sessionTimeout: Session.DEFAULT_TIMEOUT,\n visibleThreshold: 5 * SECONDS,\n // timeZone: undefined,\n sendInitialPageview: false,\n // pageLoadsMetricIndex: undefined,\n // visibleMetricIndex: undefined,\n fieldsObj: {},\n // hitFilter: undefined\n };\n\n this.opts = /** @type {PageVisibilityTrackerOpts} */ (\n assign(defaultOpts, opts));\n\n this.tracker = tracker;\n this.lastPageState = document.visibilityState;\n this.visibleThresholdTimeout_ = null;\n this.isInitialPageviewSent_ = false;\n\n // Binds methods to `this`.\n this.trackerSetOverride = this.trackerSetOverride.bind(this);\n this.handleChange = this.handleChange.bind(this);\n this.handleWindowUnload = this.handleWindowUnload.bind(this);\n this.handleExternalStoreSet = this.handleExternalStoreSet.bind(this);\n\n // Creates the store and binds storage change events.\n this.store = Store.getOrCreate(\n tracker.get('trackingId'), 'plugins/page-visibility-tracker');\n this.store.on('externalSet', this.handleExternalStoreSet);\n\n // Creates the session and binds session events.\n this.session = Session.getOrCreate(\n tracker, this.opts.sessionTimeout, this.opts.timeZone);\n\n // Override the built-in tracker.set method to watch for changes.\n MethodChain.add(tracker, 'set', this.trackerSetOverride);\n\n window.addEventListener('unload', this.handleWindowUnload);\n document.addEventListener('visibilitychange', this.handleChange);\n\n // Postpone sending any hits until the next call stack, which allows all\n // autotrack plugins to be required sync before any hits are sent.\n deferUntilPluginsLoaded(this.tracker, () => {\n if (document.visibilityState == VISIBLE) {\n if (this.opts.sendInitialPageview) {\n this.sendPageview({isPageLoad: true});\n this.isInitialPageviewSent_ = true;\n }\n this.store.set(/** @type {PageVisibilityStoreData} */ ({\n time: now(),\n state: VISIBLE,\n pageId: PAGE_ID,\n sessionId: this.session.getId(),\n }));\n } else {\n if (this.opts.sendInitialPageview && this.opts.pageLoadsMetricIndex) {\n this.sendPageLoad();\n }\n }\n });\n }\n\n /**\n * Inspects the last visibility state change data and determines if a\n * visibility event needs to be tracked based on the current visibility\n * state and whether or not the session has expired. If the session has\n * expired, a change to `visible` will trigger an additional pageview.\n * This method also sends as the event value (and optionally a custom metric)\n * the elapsed time between this event and the previously reported change\n * in the same session, allowing you to more accurately determine when users\n * were actually looking at your page versus when it was in the background.\n */\n handleChange() {\n if (!(document.visibilityState == VISIBLE ||\n document.visibilityState == HIDDEN)) {\n return;\n }\n\n const lastStoredChange = this.getAndValidateChangeData();\n\n /** @type {PageVisibilityStoreData} */\n const change = {\n time: now(),\n state: document.visibilityState,\n pageId: PAGE_ID,\n sessionId: this.session.getId(),\n };\n\n // If the visibilityState has changed to visible and the initial pageview\n // has not been sent (and the `sendInitialPageview` option is `true`).\n // Send the initial pageview now.\n if (document.visibilityState == VISIBLE &&\n this.opts.sendInitialPageview && !this.isInitialPageviewSent_) {\n this.sendPageview();\n this.isInitialPageviewSent_ = true;\n }\n\n // If the visibilityState has changed to hidden, clear any scheduled\n // pageviews waiting for the visibleThreshold timeout.\n if (document.visibilityState == HIDDEN && this.visibleThresholdTimeout_) {\n clearTimeout(this.visibleThresholdTimeout_);\n }\n\n if (this.session.isExpired(lastStoredChange.sessionId)) {\n this.store.clear();\n if (this.lastPageState == HIDDEN &&\n document.visibilityState == VISIBLE) {\n // If the session has expired, changes from hidden to visible should\n // be considered a new pageview rather than a visibility event.\n // This behavior ensures all sessions contain a pageview so\n // session-level page dimensions and metrics (e.g. ga:landingPagePath\n // and ga:entrances) are correct.\n // Also, in order to prevent false positives, we add a small timeout\n // that is cleared if the visibilityState changes to hidden shortly\n // after the change to visible. This can happen if a user is quickly\n // switching through their open tabs but not actually interacting with\n // and of them. It can also happen when a user goes to a tab just to\n // immediately close it. Such cases should not be considered pageviews.\n clearTimeout(this.visibleThresholdTimeout_);\n this.visibleThresholdTimeout_ = setTimeout(() => {\n this.store.set(change);\n this.sendPageview({hitTime: change.time});\n }, this.opts.visibleThreshold);\n }\n } else {\n if (lastStoredChange.pageId == PAGE_ID &&\n lastStoredChange.state == VISIBLE) {\n this.sendPageVisibilityEvent(lastStoredChange);\n }\n this.store.set(change);\n }\n\n this.lastPageState = document.visibilityState;\n }\n\n /**\n * Retroactively updates the stored change data in cases where it's known to\n * be out of sync.\n * This plugin keeps track of each visiblity change and stores the last one\n * in localStorage. LocalStorage is used to handle situations where the user\n * has multiple page open at the same time and we don't want to\n * double-report page visibility in those cases.\n * However, a problem can occur if a user closes a page when one or more\n * visible pages are still open. In such cases it's impossible to know\n * which of the remaining pages the user will interact with next.\n * To solve this problem we wait for the next change on any page and then\n * retroactively update the stored data to reflect the current page as being\n * the page on which the last change event occured and measure visibility\n * from that point.\n * @return {!PageVisibilityStoreData}\n */\n getAndValidateChangeData() {\n const lastStoredChange =\n /** @type {PageVisibilityStoreData} */ (this.store.get());\n\n if (this.lastPageState == VISIBLE &&\n lastStoredChange.state == HIDDEN &&\n lastStoredChange.pageId != PAGE_ID) {\n lastStoredChange.state = VISIBLE;\n lastStoredChange.pageId = PAGE_ID;\n this.store.set(lastStoredChange);\n }\n return lastStoredChange;\n }\n\n /**\n * Sends a Page Visibility event to track the time this page was in the\n * visible state (assuming it was in that state long enough to meet the\n * threshold).\n * @param {!PageVisibilityStoreData} lastStoredChange\n * @param {{hitTime: (number|undefined)}=} param1\n * - hitTime: A hit timestap used to help ensure original order in cases\n * where the send is delayed.\n */\n sendPageVisibilityEvent(lastStoredChange, {hitTime} = {}) {\n const delta = this.getTimeSinceLastStoredChange(\n lastStoredChange, {hitTime});\n\n // If the detla is greater than the visibileThreshold, report it.\n if (delta && delta >= this.opts.visibleThreshold) {\n const deltaInSeconds = Math.round(delta / SECONDS);\n\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n nonInteraction: true,\n eventCategory: 'Page Visibility',\n eventAction: 'track',\n eventValue: deltaInSeconds,\n eventLabel: NULL_DIMENSION,\n };\n\n if (hitTime) {\n defaultFields.queueTime = now() - hitTime;\n }\n\n // If a custom metric was specified, set it equal to the event value.\n if (this.opts.visibleMetricIndex) {\n defaultFields['metric' + this.opts.visibleMetricIndex] = deltaInSeconds;\n }\n\n this.tracker.send('event',\n createFieldsObj(defaultFields, this.opts.fieldsObj,\n this.tracker, this.opts.hitFilter));\n }\n }\n\n /**\n * Sends a page load event.\n */\n sendPageLoad() {\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n eventCategory: 'Page Visibility',\n eventAction: 'page load',\n eventLabel: NULL_DIMENSION,\n ['metric' + this.opts.pageLoadsMetricIndex]: 1,\n nonInteraction: true,\n };\n this.tracker.send('event',\n createFieldsObj(defaultFields, this.opts.fieldsObj,\n this.tracker, this.opts.hitFilter));\n }\n\n /**\n * Sends a pageview, optionally calculating an offset if hitTime is passed.\n * @param {{\n * hitTime: (number|undefined),\n * isPageLoad: (boolean|undefined)\n * }=} param1\n * hitTime: The timestamp of the current hit.\n * isPageLoad: True if this pageview was also a page load.\n */\n sendPageview({hitTime, isPageLoad} = {}) {\n /** @type {FieldsObj} */\n const defaultFields = {transport: 'beacon'};\n if (hitTime) {\n defaultFields.queueTime = now() - hitTime;\n }\n if (isPageLoad && this.opts.pageLoadsMetricIndex) {\n defaultFields['metric' + this.opts.pageLoadsMetricIndex] = 1;\n }\n\n this.tracker.send('pageview',\n createFieldsObj(defaultFields, this.opts.fieldsObj,\n this.tracker, this.opts.hitFilter));\n }\n\n /**\n * Detects changes to the tracker object and triggers an update if the page\n * field has changed.\n * @param {function((Object|string), (string|undefined))} originalMethod\n * A reference to the overridden method.\n * @return {function((Object|string), (string|undefined))}\n */\n trackerSetOverride(originalMethod) {\n return (field, value) => {\n /** @type {!FieldsObj} */\n const fields = isObject(field) ? field : {[field]: value};\n if (fields.page && fields.page !== this.tracker.get('page')) {\n if (this.lastPageState == VISIBLE) {\n this.handleChange();\n }\n }\n originalMethod(field, value);\n };\n }\n\n /**\n * Calculates the time since the last visibility change event in the current\n * session. If the session has expired the reported time is zero.\n * @param {PageVisibilityStoreData} lastStoredChange\n * @param {{hitTime: (number|undefined)}=} param1\n * hitTime: The time of the current hit (defaults to now).\n * @return {number} The time (in ms) since the last change.\n */\n getTimeSinceLastStoredChange(lastStoredChange, {hitTime} = {}) {\n return lastStoredChange.time ?\n (hitTime || now()) - lastStoredChange.time : 0;\n }\n\n /**\n * Handles responding to the `storage` event.\n * The code on this page needs to be informed when other tabs or windows are\n * updating the stored page visibility state data. This method checks to see\n * if a hidden state is stored when there are still visible tabs open, which\n * can happen if multiple windows are open at the same time.\n * @param {PageVisibilityStoreData} newData\n * @param {PageVisibilityStoreData} oldData\n */\n handleExternalStoreSet(newData, oldData) {\n // If the change times are the same, then the previous write only\n // updated the active page ID. It didn't enter a new state and thus no\n // hits should be sent.\n if (newData.time == oldData.time) return;\n\n // Page Visibility events must be sent by the tracker on the page\n // where the original event occurred. So if a change happens on another\n // page, but this page is where the previous change event occurred, then\n // this page is the one that needs to send the event (so all dimension\n // data is correct).\n if (oldData.pageId == PAGE_ID &&\n oldData.state == VISIBLE &&\n !this.session.isExpired(oldData.sessionId)) {\n this.sendPageVisibilityEvent(oldData, {hitTime: newData.time});\n }\n }\n\n /**\n * Handles responding to the `unload` event.\n * Since some browsers don't emit a `visibilitychange` event in all cases\n * where a page might be unloaded, it's necessary to hook into the `unload`\n * event to ensure the correct state is always stored.\n */\n handleWindowUnload() {\n // If the stored visibility state isn't hidden when the unload event\n // fires, it means the visibilitychange event didn't fire as the document\n // was being unloaded, so we invoke it manually.\n if (this.lastPageState != HIDDEN) {\n this.handleChange();\n }\n }\n\n /**\n * Removes all event listeners and restores overridden methods.\n */\n remove() {\n this.store.destroy();\n this.session.destroy();\n MethodChain.remove(this.tracker, 'set', this.trackerSetOverride);\n window.removeEventListener('unload', this.handleWindowUnload);\n document.removeEventListener('visibilitychange', this.handleChange);\n }\n}\n\n\nprovide('pageVisibilityTracker', PageVisibilityTracker);\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport MethodChain from '../method-chain';\nimport provide from '../provide';\nimport {plugins, trackUsage} from '../usage';\nimport {assign, createFieldsObj} from '../utilities';\n\n\n/**\n * Class for the `urlChangeTracker` analytics.js plugin.\n * @implements {UrlChangeTrackerPublicInterface}\n */\nclass UrlChangeTracker {\n /**\n * Adds handler for the history API methods\n * @param {!Tracker} tracker Passed internally by analytics.js\n * @param {?Object} opts Passed by the require command.\n */\n constructor(tracker, opts) {\n trackUsage(tracker, plugins.URL_CHANGE_TRACKER);\n\n // Feature detects to prevent errors in unsupporting browsers.\n if (!history.pushState || !window.addEventListener) return;\n\n /** @type {UrlChangeTrackerOpts} */\n const defaultOpts = {\n shouldTrackUrlChange: this.shouldTrackUrlChange,\n trackReplaceState: false,\n fieldsObj: {},\n hitFilter: null,\n };\n\n this.opts = /** @type {UrlChangeTrackerOpts} */ (assign(defaultOpts, opts));\n\n this.tracker = tracker;\n\n // Sets the initial page field.\n // Don't set this on the tracker yet so campaign data can be retreived\n // from the location field.\n this.path = getPath();\n\n // Binds methods.\n this.pushStateOverride = this.pushStateOverride.bind(this);\n this.replaceStateOverride = this.replaceStateOverride.bind(this);\n this.handlePopState = this.handlePopState.bind(this);\n\n // Watches for history changes.\n MethodChain.add(history, 'pushState', this.pushStateOverride);\n MethodChain.add(history, 'replaceState', this.replaceStateOverride);\n window.addEventListener('popstate', this.handlePopState);\n }\n\n /**\n * Handles invocations of the native `history.pushState` and calls\n * `handleUrlChange()` indicating that the history updated.\n * @param {!Function} originalMethod A reference to the overridden method.\n * @return {!Function}\n */\n pushStateOverride(originalMethod) {\n return (...args) => {\n originalMethod(...args);\n this.handleUrlChange(true);\n };\n }\n\n /**\n * Handles invocations of the native `history.replaceState` and calls\n * `handleUrlChange()` indicating that history was replaced.\n * @param {!Function} originalMethod A reference to the overridden method.\n * @return {!Function}\n */\n replaceStateOverride(originalMethod) {\n return (...args) => {\n originalMethod(...args);\n this.handleUrlChange(false);\n };\n }\n\n /**\n * Handles responding to the popstate event and calls\n * `handleUrlChange()` indicating that history was updated.\n */\n handlePopState() {\n this.handleUrlChange(true);\n }\n\n /**\n * Updates the page and title fields on the tracker and sends a pageview\n * if a new history entry was created.\n * @param {boolean} historyDidUpdate True if the history was changed via\n * `pushState()` or the `popstate` event. False if the history was just\n * modified via `replaceState()`.\n */\n handleUrlChange(historyDidUpdate) {\n // Calls the update logic asychronously to help ensure that app logic\n // responding to the URL change happens prior to this.\n setTimeout(() => {\n const oldPath = this.path;\n const newPath = getPath();\n\n if (oldPath != newPath &&\n this.opts.shouldTrackUrlChange.call(this, newPath, oldPath)) {\n this.path = newPath;\n this.tracker.set({\n page: newPath,\n title: document.title,\n });\n\n if (historyDidUpdate || this.opts.trackReplaceState) {\n /** @type {FieldsObj} */\n const defaultFields = {transport: 'beacon'};\n this.tracker.send('pageview', createFieldsObj(defaultFields,\n this.opts.fieldsObj, this.tracker, this.opts.hitFilter));\n }\n }\n }, 0);\n }\n\n /**\n * Determines whether or not the tracker should send a hit with the new page\n * data. This default implementation can be overrided in the config options.\n * @param {string} newPath The path after the URL change.\n * @param {string} oldPath The path prior to the URL change.\n * @return {boolean} Whether or not the URL change should be tracked.\n */\n shouldTrackUrlChange(newPath, oldPath) {\n return !!(newPath && oldPath);\n }\n\n /**\n * Removes all event listeners and restores overridden methods.\n */\n remove() {\n MethodChain.remove(history, 'pushState', this.pushStateOverride);\n MethodChain.remove(history, 'replaceState', this.replaceStateOverride);\n window.removeEventListener('popstate', this.handlePopState);\n }\n}\n\n\nprovide('urlChangeTracker', UrlChangeTracker);\n\n\n/**\n * @return {string} The path value of the current URL.\n */\nfunction getPath() {\n return location.pathname + location.search;\n}\n","/**\n * Copyright 2016 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport provide from '../provide';\nimport {plugins, trackUsage} from '../usage';\nimport {assign, createFieldsObj} from '../utilities';\n\n\n/**\n * Class for the `socialWidgetTracker` analytics.js plugin.\n * @implements {SocialWidgetTrackerPublicInterface}\n */\nclass SocialWidgetTracker {\n /**\n * Registers social tracking on tracker object.\n * Supports both declarative social tracking via HTML attributes as well as\n * tracking for social events when using official Twitter or Facebook widgets.\n * @param {!Tracker} tracker Passed internally by analytics.js\n * @param {?Object} opts Passed by the require command.\n */\n constructor(tracker, opts) {\n trackUsage(tracker, plugins.SOCIAL_WIDGET_TRACKER);\n\n // Feature detects to prevent errors in unsupporting browsers.\n if (!window.addEventListener) return;\n\n /** @type {SocialWidgetTrackerOpts} */\n const defaultOpts = {\n fieldsObj: {},\n hitFilter: null,\n };\n\n this.opts = /** @type {SocialWidgetTrackerOpts} */ (\n assign(defaultOpts, opts));\n\n this.tracker = tracker;\n\n // Binds methods to `this`.\n this.addWidgetListeners = this.addWidgetListeners.bind(this);\n this.addTwitterEventHandlers = this.addTwitterEventHandlers.bind(this);\n this.handleTweetEvents = this.handleTweetEvents.bind(this);\n this.handleFollowEvents = this.handleFollowEvents.bind(this);\n this.handleLikeEvents = this.handleLikeEvents.bind(this);\n this.handleUnlikeEvents = this.handleUnlikeEvents.bind(this);\n\n if (document.readyState != 'complete') {\n // Adds the widget listeners after the window's `load` event fires.\n // If loading widgets using the officially recommended snippets, they\n // will be available at `window.load`. If not users can call the\n // `addWidgetListeners` method manually.\n window.addEventListener('load', this.addWidgetListeners);\n } else {\n this.addWidgetListeners();\n }\n }\n\n\n /**\n * Invokes the methods to add Facebook and Twitter widget event listeners.\n * Ensures the respective global namespaces are present before adding.\n */\n addWidgetListeners() {\n if (window.FB) this.addFacebookEventHandlers();\n if (window.twttr) this.addTwitterEventHandlers();\n }\n\n /**\n * Adds event handlers for the \"tweet\" and \"follow\" events emitted by the\n * official tweet and follow buttons. Note: this does not capture tweet or\n * follow events emitted by other Twitter widgets (tweet, timeline, etc.).\n */\n addTwitterEventHandlers() {\n try {\n window.twttr.ready(() => {\n window.twttr.events.bind('tweet', this.handleTweetEvents);\n window.twttr.events.bind('follow', this.handleFollowEvents);\n });\n } catch(err) {\n // Do nothing.\n }\n }\n\n /**\n * Removes event handlers for the \"tweet\" and \"follow\" events emitted by the\n * official tweet and follow buttons.\n */\n removeTwitterEventHandlers() {\n try {\n window.twttr.ready(() => {\n window.twttr.events.unbind('tweet', this.handleTweetEvents);\n window.twttr.events.unbind('follow', this.handleFollowEvents);\n });\n } catch(err) {\n // Do nothing.\n }\n }\n\n /**\n * Adds event handlers for the \"like\" and \"unlike\" events emitted by the\n * official Facebook like button.\n */\n addFacebookEventHandlers() {\n try {\n window.FB.Event.subscribe('edge.create', this.handleLikeEvents);\n window.FB.Event.subscribe('edge.remove', this.handleUnlikeEvents);\n } catch(err) {\n // Do nothing.\n }\n }\n\n /**\n * Removes event handlers for the \"like\" and \"unlike\" events emitted by the\n * official Facebook like button.\n */\n removeFacebookEventHandlers() {\n try {\n window.FB.Event.unsubscribe('edge.create', this.handleLikeEvents);\n window.FB.Event.unsubscribe('edge.remove', this.handleUnlikeEvents);\n } catch(err) {\n // Do nothing.\n }\n }\n\n /**\n * Handles `tweet` events emitted by the Twitter JS SDK.\n * @param {TwttrEvent} event The Twitter event object passed to the handler.\n */\n handleTweetEvents(event) {\n // Ignores tweets from widgets that aren't the tweet button.\n if (event.region != 'tweet') return;\n\n const url = event.data.url || event.target.getAttribute('data-url') ||\n location.href;\n\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n socialNetwork: 'Twitter',\n socialAction: 'tweet',\n socialTarget: url,\n };\n this.tracker.send('social',\n createFieldsObj(defaultFields, this.opts.fieldsObj,\n this.tracker, this.opts.hitFilter, event.target, event));\n }\n\n /**\n * Handles `follow` events emitted by the Twitter JS SDK.\n * @param {TwttrEvent} event The Twitter event object passed to the handler.\n */\n handleFollowEvents(event) {\n // Ignore follows from widgets that aren't the follow button.\n if (event.region != 'follow') return;\n\n const screenName = event.data.screen_name ||\n event.target.getAttribute('data-screen-name');\n\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n socialNetwork: 'Twitter',\n socialAction: 'follow',\n socialTarget: screenName,\n };\n this.tracker.send('social',\n createFieldsObj(defaultFields, this.opts.fieldsObj,\n this.tracker, this.opts.hitFilter, event.target, event));\n }\n\n /**\n * Handles `like` events emitted by the Facebook JS SDK.\n * @param {string} url The URL corresponding to the like event.\n */\n handleLikeEvents(url) {\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n socialNetwork: 'Facebook',\n socialAction: 'like',\n socialTarget: url,\n };\n this.tracker.send('social', createFieldsObj(defaultFields,\n this.opts.fieldsObj, this.tracker, this.opts.hitFilter));\n }\n\n /**\n * Handles `unlike` events emitted by the Facebook JS SDK.\n * @param {string} url The URL corresponding to the unlike event.\n */\n handleUnlikeEvents(url) {\n /** @type {FieldsObj} */\n const defaultFields = {\n transport: 'beacon',\n socialNetwork: 'Facebook',\n socialAction: 'unlike',\n socialTarget: url,\n };\n this.tracker.send('social', createFieldsObj(defaultFields,\n this.opts.fieldsObj, this.tracker, this.opts.hitFilter));\n }\n\n /**\n * Removes all event listeners and instance properties.\n */\n remove() {\n window.removeEventListener('load', this.addWidgetListeners);\n this.removeFacebookEventHandlers();\n this.removeTwitterEventHandlers();\n }\n}\n\n\nprovide('socialWidgetTracker', SocialWidgetTracker);\n","import 'autotrack';\r\nimport 'autotrack/lib/plugins/event-tracker';\r\nimport 'autotrack/lib/plugins/outbound-link-tracker';\r\nimport 'autotrack/lib/plugins/url-change-tracker';\r\nimport 'autotrack/lib/plugins/page-visibility-tracker';\r\n\r\nwindow.zywave = window.zywave || {};\r\nconst gaKey = window.zywave.gaKey;\r\n\r\nif (gaKey) {\r\n window.ga = window.ga || function () { (window.ga.q = window.ga.q || []).push(arguments); }; window.ga.l = +new Date;\r\n window.ga('create', gaKey, 'auto');\r\n\r\n window.ga('require', 'eventTracker', { events: ['click', 'play'] });\r\n window.ga('require', 'outboundLinkTracker');\r\n window.ga('require', 'urlChangeTracker');\r\n window.ga('require', 'pageVisibilityTracker', { sendInitialPageview: true });\r\n}\r\n"],"sourceRoot":""}