/** * Before committing this file run prettier on it. * 1. Install prettier globally, follow https://prettier.io/docs/en/install.html * 2. prettier path-to-this-file --write * 3. Make sure that no functionality gets affected by prettifying, if so, use * "// prettier-ignore" to ignore any line. */ function trackViewability(viewabilityConfigs) { var viewabilityData = []; function GetTopLeftFromElement(element) { var rect = { top: 0, left: 0 }; var el = element; var win = window; do { rect.left += el.offsetLeft; rect.top += el.offsetTop; el = el.offsetParent; if (el == null) { el = win.frameElement; rect.left -= win.scrollX; rect.top -= win.scrollY; win = win.parent; } } while (el); return rect; } function elementIsVisible(elementId, visibilityFraction) { var element = document.getElementById(elementId); var rect = GetTopLeftFromElement(element); var boundingRect = element.getBoundingClientRect(); return ( rect.left >= 0 && rect.left + boundingRect.width <= window.top.innerWidth && Math.min(window.top.innerHeight, rect.top + boundingRect.height) - Math.max(0, rect.top) >= visibilityFraction * boundingRect.height ); } function elementViewabilityTracker(viewabilityConfig, index) { if ( elementIsVisible( viewabilityConfig.elementId, viewabilityConfig.visibilityFraction ) ) { viewabilityData[index].count++; // Ad is detected viewable for atleast the visibilityDuration specified if ( viewabilityData[index].count >= viewabilityConfig.visibilityDuration / viewabilityConfig.pollingInterval ) { viewabilityConfig.callback({ duration: viewabilityConfig.pollingInterval * viewabilityData[index].count, index: viewabilityData[index].index++ }); //clearInterval if the event needs to be recorded just once if (viewabilityConfig.once) { clearInterval(viewabilityData[index].intervalId); } viewabilityData[index].viewedOnce = true; viewabilityData[index].count = 0; } } else { // callback with even the incomplete view time ( < visibilityDuration ) for events that are recorded continuously if (viewabilityData[index].count > 0 && !viewabilityConfig.once) { viewabilityConfig.callback({ duration: viewabilityConfig.pollingInterval * viewabilityData[index].count, index: viewabilityData[index].index++ }); } viewabilityData[index].count = 0; } } function setTimeoutsForRecordingStop() { for (var i = 0; i < viewabilityConfigs.length; i++) { if (viewabilityConfigs[i].stopRecording) { setTimeout( (function(i) { return function() { if (viewabilityData[i].observer) { // observer will only be present if we are tracking by IntersectionObserver viewabilityData[i].observer.unobserve( document.getElementById(viewabilityConfigs[i].elementId) ); } clearInterval(viewabilityData[i].intervalId); viewabilityData[i].timeoutElapsed = true; }; })(i), viewabilityConfigs[i].stopRecording ); } } } function handlePageViewabilityAndUnload() { // function which stops observing viewability for all the elements function removeViewabilityListeners() { for (var i = 0; i < viewabilityData.length; i++) { if (viewabilityData[i].observer) { viewabilityData[i].observer.unobserve( document.getElementById(viewabilityConfigs[i].elementId) ); } clearInterval(viewabilityData[i].intervalId); } } attachEventListener("unload", window, removeViewabilityListeners); attachEventListener("visibilitychange", document, function() { // stop observing viewability if page isn't visible if (document.visibilityState === "hidden") { removeViewabilityListeners(); } // resume observing if the page is visible again, only for those events which still need to be observed else if (document.visibilityState === "visible") { for (var i = 0; i < viewabilityConfigs.length; i++) { if ( (!viewabilityConfigs[i].once && !viewabilityData[i].timeoutElapsed) || (viewabilityConfigs[i].once && !viewabilityData[i].viewedOnce) ) { if (viewabilityData[i].observer) { viewabilityData[i].observer.observe( document.getElementById(viewabilityConfigs[i].elementId) ); } else { viewabilityData[i].intervalId = setInterval( (function(i) { return function() { elementViewabilityTracker(viewabilityConfigs[i], i); }; })(i), viewabilityConfigs[i].pollingInterval ); } } } } }); } function trackViewabilityByIntersectionObserver(viewabilityConfigs) { var tracker = function(i) { var observer = new IntersectionObserver( function(entries) { if (entries[0].isIntersecting) { viewabilityData[i].viewableStartTime = new Date().getTime(); viewabilityData[i].intervalId = setInterval(function() { viewabilityConfigs[i].callback({ duration: new Date().getTime() - viewabilityData[i].viewableStartTime, index: viewabilityData[i].index++ }); // stop observing and clear Interval if the event needs to be recorded just once if (viewabilityConfigs[i].once) { observer.unobserve( document.getElementById(viewabilityConfigs[i].elementId) ); clearInterval(viewabilityData[i].intervalId); } viewabilityData[i].viewedOnce = true; viewabilityData[i].viewableStartTime = new Date().getTime(); }, viewabilityConfigs[i].visibilityDuration); } else { clearInterval(viewabilityData[i].intervalId); // callback with even the incomplete view time ( < visibilityDuration ) for events that are recorded continuously if ( viewabilityData[i].viewableStartTime && !viewabilityConfigs[i].once ) { viewabilityConfigs[i].callback({ duration: new Date().getTime() - viewabilityData[i].viewableStartTime, index: viewabilityData[i].index++ }); } viewabilityData[i].viewableStartTime = null; } }, { threshold: viewabilityConfigs[i].visibilityFraction } ); var element = document.getElementById(viewabilityConfigs[i].elementId); observer.observe(element); return observer; }; for (var i = 0; i < viewabilityConfigs.length; i++) { viewabilityData.push({ intervalId: null, index: 0, observer: tracker(i), viewableStartTime: null, viewedOnce: false, timeoutElapsed: false }); } } function trackViewabilityByPolling(viewabilityConfigs) { for (var i = 0; i < viewabilityConfigs.length; i++) { var tracker = function(i) { var intervalId = setInterval(function() { elementViewabilityTracker(viewabilityConfigs[i], i); }, viewabilityConfigs[i].pollingInterval); viewabilityData.push({ count: 0, intervalId: intervalId, index: 0, viewedOnce: false, timeoutElapsed: false }); }; tracker(i); } } var measurable = true; try { if (!window.IntersectionObserver) { var height = window.top.innerHeight; // checks if cross-domain iframe is present } } catch (e) { measurable = false; } if (measurable) { if (window.IntersectionObserver) { trackViewabilityByIntersectionObserver(viewabilityConfigs); } else { trackViewabilityByPolling(viewabilityConfigs); } setTimeoutsForRecordingStop(); handlePageViewabilityAndUnload(); eventTrack("measurable impression"); } else { eventTrack("non-measurable impression"); } } function showMyAd() { var frameEl = document.querySelector("#adContainer"); // position Ad with respect to container // prettier-ignore if (document.body.offsetHeight > 250) { frameEl.style.top = "calc(50% - 250px / 2)"; } // prettier-ignore if (document.body.offsetWidth > 300) { frameEl.style.left = "calc(50% - 300px / 2)"; } frameEl.style.display = 'block'; trackViewability([ { elementId: "adContainer", visibilityFraction: 0.5, visibilityDuration: 1000, pollingInterval: 100, once: true, // only needs to be recorded once callback: function() { eventTrack("viewable impression"); } }, { elementId: "adContainer", visibilityFraction: 0, visibilityDuration: 0, pollingInterval: 100, once: true, callback: function() { eventTrack("rendered impression"); } }, { elementId: "adContainer", visibilityFraction: 0.5, visibilityDuration: 5000, // period pollingInterval: 100, once: false, stopRecording: 3 * 60 * 1000, // stop recording viewability after 3 minutes have elapsed callback: function(data) { eventTrack("viewable time", { duration: String(data.duration), index: String(data.index) }); } } ]); var mouseOverListener = function() { eventTrack("mouse over"); removeEventListener("mouseover", frameEl, mouseOverListener); }; attachEventListener("mouseover", frameEl, mouseOverListener); } var trackingType = { 'GDN': 'serial' }; function paceOpen(url) { var mode = trackingType['GDN'] || 'parallel'; var clickTrackers = {"CLICK":["https://adclick.g.doubleclick.net/aclk?sa\u003dl\u0026ai\u003dCtQuizWkIYd6kKanChwekrImwCriJ8YdkyZ6M7YUO4JDTto8OEAEgoK6rDmDJrpmN7KSAEKABqKD7xQPIAQngAgCoAwGqBK8CT9CvIgPTaU3RNgZ0aJVIFf4hjL7q5xViOLkdYybIjMw6m9Ah5CA5e-tbosP21B-yEOm576b1hnP_1VbMU8WVMw9xAlrzjX2IYgzQmmxYKQ4PChZI08iWaxCWTIky4QFBKbLBoOre44UzLtA_aTHp-ngXmyCSRnLpnRy9dTejV7jJtGX1N_oIwUfwIorY-yBNs0Br78PtCk6zicpNyANe9HzwQhSw6mXCO4leZ70fP8v1IiywJ--6Q-sh3NXcjSPv22S96OuSfOZ2VsZ7caa38RgwklgfuwsldwkqEciXgfS11M5VqAB9N8tidvLE3wMCGUbyloctnHlescm5k3B_KKly0-pXgtdKjsJwdqEwDJfk-QBAucCPtGSdETSucviksxO2UIAE97NDmRxUqpcxwATMmpaByAPgBAGgBhGAB76Fvc0BqAfVyRuoB_DZG6gH8tkbqAeOzhuoB5PYG6gHugaoB-6WsQKoB6a-G6gH7NUbqAfz0RuoB-zVG6gHltgbqAeqm7EC2AcA0ggHCIBhEAEYH4AKA5gLAcgLAYAMAbgMAdgTDdAVAYAXAQ\u0026num\u003d1\u0026sig\u003dAOD64_0PgXlK8bz51C9bnxJu1fkX1_dxIw\u0026client\u003dca-pub-0521848186422428\u0026adurl\u003d"],"AD_LOAD":[]}['CLICK'] || []; var openURL = function(clickUrl) { window.open(clickUrl, "_blank"); eventTrack("click", { click_url: clickUrl }); }; try { if (mode === 'serial' && clickTrackers.length) { var targetUrl = clickTrackers[0] + url; openURL(targetUrl); } else { openURL(url); triggerExternalTrackers('CLICK'); } } catch (e) { eventTrack('error', getExceptionParams(e, 'Click')); } } function getTimeStamp() { var currDate = new Date(); return String(currDate.getTime()); } function dropPixel(url) { var event = document.createElement("img"); event.src = url; } function eventTrack(event_type, data) { // This actually makes a GET call not load an image, this is preferred since we don't want a response back from the server. var params = { event_timestamp_utc: getTimeStamp(), additional_attributes: data && JSON.stringify(data), request_id: "0bb6f6b4-bca7-4e0e-89b8-8fce32f3e552", request_signature: "954ad2ee753e467dfa7f9dc7201eabab" }; var queryString = "event_type=" + event_type; for (var key in params) { if (params.hasOwnProperty(key) && params[key]) { queryString += "&" + key + "=" + encodeURIComponent(params[key]); } } dropPixel("https://meh.uber.com/event/trk?" + queryString); } function setupViewport(width) { var element = document.querySelector("meta[name=viewport]"); if (!element) { element = document.createElement("meta"); element.name = "viewport"; element.content = "width=" + width + ", user-scalable=no"; document.getElementsByTagName("head")[0].appendChild(element); } else { element.content = "width=" + width + ", user-scalable=no"; } } // prettier-ignore setupViewport(300); function attachEventListener(evt, el, fn) { if (el.addEventListener) { el.addEventListener(evt, fn, false); } else if (el.attachEvent) { el.attachEvent("on" + evt, fn); } else { el[evt] = fn; } } function removeEventListener(evt, el, fn) { if (el.removeEventListener) { el.removeEventListener(evt, fn, false); } else if (el.detachEvent) { el.detachEvent("on" + evt, fn); } else { el[evt] = null; } } function getExceptionParams (e, action) { var params = {}; if (e) { params = { message: e.message, lineno: String(e.lineno), filename: e.filename, colno: String(e.colno), error: e.error && e.error.toString && e.error.toString() || '', name: e.name }; } params.action = action; return params; } function trackAd() { // prettier-ignore var viewabilityTrackers = []; var trackerScript; for (var i = 0, ii = viewabilityTrackers.length; i < ii; i++) { trackerScript = document.createElement("script"); trackerScript.type = "text/javascript"; trackerScript.src = viewabilityTrackers[i]; document.body.appendChild(trackerScript); } } function triggerExternalTrackers(type) { // prettier-ignore var trackers = {"CLICK":["https://adclick.g.doubleclick.net/aclk?sa\u003dl\u0026ai\u003dCtQuizWkIYd6kKanChwekrImwCriJ8YdkyZ6M7YUO4JDTto8OEAEgoK6rDmDJrpmN7KSAEKABqKD7xQPIAQngAgCoAwGqBK8CT9CvIgPTaU3RNgZ0aJVIFf4hjL7q5xViOLkdYybIjMw6m9Ah5CA5e-tbosP21B-yEOm576b1hnP_1VbMU8WVMw9xAlrzjX2IYgzQmmxYKQ4PChZI08iWaxCWTIky4QFBKbLBoOre44UzLtA_aTHp-ngXmyCSRnLpnRy9dTejV7jJtGX1N_oIwUfwIorY-yBNs0Br78PtCk6zicpNyANe9HzwQhSw6mXCO4leZ70fP8v1IiywJ--6Q-sh3NXcjSPv22S96OuSfOZ2VsZ7caa38RgwklgfuwsldwkqEciXgfS11M5VqAB9N8tidvLE3wMCGUbyloctnHlescm5k3B_KKly0-pXgtdKjsJwdqEwDJfk-QBAucCPtGSdETSucviksxO2UIAE97NDmRxUqpcxwATMmpaByAPgBAGgBhGAB76Fvc0BqAfVyRuoB_DZG6gH8tkbqAeOzhuoB5PYG6gHugaoB-6WsQKoB6a-G6gH7NUbqAfz0RuoB-zVG6gHltgbqAeqm7EC2AcA0ggHCIBhEAEYH4AKA5gLAcgLAYAMAbgMAdgTDdAVAYAXAQ\u0026num\u003d1\u0026sig\u003dAOD64_0PgXlK8bz51C9bnxJu1fkX1_dxIw\u0026client\u003dca-pub-0521848186422428\u0026adurl\u003d"],"AD_LOAD":[]}[type]; for (var i = 0, ii = trackers.length; i < ii; i++) { dropPixel(trackers[i]); } } function trackLoad() { eventTrack("impression", { downloadTime: String( new Date().getTime() - Number("1627941326281") ) }); triggerExternalTrackers("AD_LOAD"); } function postRender() { listenMessages(); } function listenMessages() { window.addEventListener('message', function(event) { var data = event.data; if (data && data.type) { switch(data.type) { case 'paceOpen': paceOpen(data.url); break; case 'image_load': eventTrack('image_load', data.metrics); break; case 'click interaction': eventTrack('click interaction', data.metrics); break; case 'error': eventTrack('error', data.metrics); break; default: break; } } }); } function loadAd() { trackLoad(); if (document.readyState === "complete") { renderAd(); } else { attachEventListener("load", window, renderAd); } trackAd(); } function renderAd() { try { var elemFrame = document.createElement('iframe'); document.body.appendChild(elemFrame); elemFrame.outerHTML = ''; eventTrack("render"); postRender(); } catch (e) { eventTrack('error', getExceptionParams(e, 'Render Ad')); } try { showMyAd(); } catch (e) { eventTrack('error', getExceptionParams(e, 'Show Ad')); } } loadAd();