{"version":3,"sources":["webpack:///./node_modules/@financial-times/ads-legacy-o-ads/dist/index.js"],"names":["perfMark","name","performance","window","LUX","msPerformance","webkitPerformance","mozPerformance","mark","clearMarks","buildPerfmarkSuffix","eventDetailsObj","suffix","pos","size","creativeId","join","broadcast","eventName","data","target","document","body","documentElement","opts","bubbles","cancelable","detail","length","toString","dispatchEvent","CustomEvent","on","callback","addEventListener","off","removeEventListener","once","event","srcElement","getMarksForEvents","events","markNames","map","getEntriesByName","marks","forEach","mName","pMarks","markName","replace","Math","round","startTime","mNameNoSuffix","pMarks2","clearPerfMarks","metricsDefinitions","groupsToClear","getEntriesByType","relevantGroupsMarks","filter","group","includes","spoorAction","eventsToClear","concat","match","getNavigationPerfMarks","desiredMarks","utils","isArray","navMarksArray","navMarks","setupMetrics","definitions","disableSampling","Array","eDef","inSample","sampleSize","triggers","trigger","sendMetricsOnEvent","this","log","warn","eMarkMap","listenOnInitialised","sendMetrics","multiple","eventDetails","navigation","Object","assign","eventPayload","category","action","timings","advert","correlator","oAds","gpt","getCorrelator","creative","isEmpty","markPageChange","breakpoints$1","current","messenger","post","message","source","JSON","stringify","arguments","top","postMessage","parse","e","getNearestBreakpoint","winner","dims","oViewport","getSize","keys","breakpoint","breakpointDims","width","height","fire","setCurrent","getCurrent","init$2","brps","cb","isFunction","listenTo","type","argsIndex","indexOf","args","slice","call","isOn","console","apply","setThrottleInterval","localStorage","getItem","location","search","error","info","start","groupCollapsed","end","groupEnd","table","columns","attributeTable","object","item","key","value","isObject","hop","prototype","hasOwnProperty","is","undefined","obj","isString","isStorage","isWindow","isPlainObject","nodeType","constructor","isNonEmptyString","str","Boolean","isElement","element","tagName","extend","options","src","copy","clone","deep","i","hash","delimiter","pairing","pair","hashObj","split","idx","l","trim","attach","scriptUrl","async","errorcb","autoRemove","tag","createElement","node","getElementsByTagName","hasRun","processCallback","parentElement","removeChild","setAttribute","onreadystatechange","readyState","onload","onerror","parentNode","insertBefore","getReferrer","referrer","dehyphenise","string","hyphen","letter","toUpperCase","parseAttributeName","attribute","getLocation","href","getQueryString","substring","getQueryParamByName","url","results","RegExp","exec","decodeURIComponent","getTimestamp","now","Date","getFullYear","getMonth","getDate","getHours","getMinutes","getSeconds","iframeToSlotName","iframeWindow","slotName","iframes","contentWindow","getAttribute","buildObjectFromArray","targetObject","reduce","prev","cookie","val","pop","getVersion","metricsSampleThreshold","random","responsive","defaults","formats","PartnerContent","sizes","MediumRectangle","Rectangle","WideSkyscraper","Leaderboard","SuperLeaderboard","HalfPage","Billboard","Portrait","AdhesionBanner","MicroBar","Button2","Responsive","extra","large","medium","small","flags","refresh","inview","displayLabelWithBorders","fetchDeclaritiveConfig","from","querySelectorAll","script","innerHTML","fetchCanonicalURL","canonical","canonicalTag","querySelector","Config","store","access","k","v","result","clear","init","config","config$1","bind","init$1","VALID_SIZE_STRINGS","VALID_COLLAPSE_MODES","attributeParsers","regex","test","push","parseInt","mapping","format","responsiveSizes","screenName","toLowerCase","responsiveFormats","lazyLoadThreshold","Number","targeting","base","collapseEmpty","convertLazyLoadBooleanToObject","lazyLoad","onChangeBreakpoint","slot","screensize","hasValidSize","uncollapse","collapse","Slot","container","initLazyLoading","cfg","slotConfig","outer","addContainer","inner","setName","server","defer","center","label","outOfPage","companion","outerEl","allowedLabels","adsLabelPos","modifier","classList","add","parseAttributeConfig","lazyLoadObserver","initLazyLoad","centerContainer","labelContainer","initResponsive","getSlotSizes","getSlotTargeting","params","entries","getSlotGPTSize","attributes","threshold","viewportMargin","getAttributes","observe","render","unobserve","maximise","floor","setFormatLoaded","addClass","className","remove","clearSlot","destroy","destroySlot","submitImpression","submitGptImpression","details","attrs","attr","insertAdjacentHTML","lastChild","isSlot","o","debug$1","slots","row","unitName","lineItemId","Slots","invokeMethodOnSlots","names","method","run","findFormatBySize","prop","s","onBreakpointChange","isCurrentlyResponsive","stillWantsResponsive","initSlot","getElementById","id","removeAttribute","initRefresh","refreshCount","time","setInterval","max","clearInterval","parseFloat","initRendered","breakpoints","initPostMessage","slotClass","flushLazyLoading","lazyLoadingObservers","observer","root","contains","lazyLoadingConfig","lazyLoadingObserver","find","rootMargin","IntersectionObserver","changes","a","intersectionRect","left","sort","b","change","fn","debug","values","parameters","Targeting","get","methods","socialReferrer","getSocialReferrer","timestamp","socialFlow","OADS_VERSION","sf","socialflow","codedValue","lookup","google","socref","searchTerm","qs","keywords","q","query","queryText","searchField","unescape","kw","ts","res","SEARCH_PARAMS","filterNestedParams","nestedParams","keysToStrip","childParams","URLSearchParams","delete","stripUrlParams","filters","URL","param","searchParams","set","DEFAULT_LAZY_LOAD","fetchMarginPercent","renderMarginPercent","mobileScaling","gptConfig","loadGPT","onReady","slotMethods","onRender","onRefresh","onResize","googletag","cmd","setup","err","nonPersonalized","pubads","onRenderEnded","enableCompanions","setRenderingMode","setPageTargeting","setPageCollapseEmpty","enableLazyLoad","enableServices","setTargeting","setRequestNonPersonalizedAds","lazyLoadConf","rendering","enableSyncRendering","enableSingleRequest","enableAsyncRendering","targetingData","String","clearPageTargetingForKey","clearTargeting","mode","collapseEmptyDivs","companions","disableInitialLoad","companionAds","setRefreshUnfilledSlots","defineSlot","addServices","setCollapseEmpty","setURL","display","iframe","gptSlotId","getSlotId","domId","getDomId","iframeId","getId","slotTargeting","getTargetingMap","serviceName","iFrameEl","setUnitName","defineOutOfPageSlot","defineSizeMapping","gptSlot","pubadsReady","updatePageTargeting","sizeMapping","addSize","build","destroySlots","network","site","zone","addService","setCollapseEmptyDiv","impressionURL","trackingUrlElement","dataset","oAdsImpressionUrl","updateCorrelator","clearPageTargeting","override","hasGPTLoaded","apiReady","conf","Ads","addDOMEventListener","configOptions","disableConsentCookie","consents","behavioral","getConsents","programmatic","Promise","resolve","initLibrary","updateTargeting","isInitialised","removeDOMEventListener","setItem","removeItem","version","initAll","ads","then","consentCookie"],"mappings":"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","file":"2.ad2c2e41.js","sourcesContent":["import oViewport from '@financial-times/o-viewport';\n\n/**\n * Utility methods for o-ads events. Methods defined here are added to the utils object not the utils.event object.\n * @author Origami Advertising, origami.advertising@ft.com\n * @module utils/events\n * @see utils\n */\n// Creates a timestamp in the browser's performance entry buffer\n// for later use\nconst perfMark = name => {\n  /* istanbul ignore next */\n  const performance = window.LUX || window.performance || window.msPerformance || window.webkitPerformance || window.mozPerformance;\n\n  if (performance && performance.mark) {\n    performance.clearMarks(name);\n    performance.mark(name);\n  }\n}; // Creates a suffix for an event's performance mark based on some of the attributes on\n// the event payload which help identify unequivocally the slot that originated the event\n\nfunction buildPerfmarkSuffix(eventDetailsObj) {\n  let suffix = '';\n\n  if (eventDetailsObj && typeof eventDetailsObj === 'object' && 'pos' in eventDetailsObj && 'name' in eventDetailsObj) {\n    suffix = '__' + [eventDetailsObj.pos, eventDetailsObj.name, eventDetailsObj.size, eventDetailsObj.creativeId].join('__');\n  }\n\n  return suffix;\n}\n/**\n* Broadscasts an o-ads event\n* @param {string} name The name of the event\n* @param {object} data The data to send as event detail\n* @param {HTMLElement} target The element to attach the event listener to\n*/\n\nfunction broadcast(eventName, data, target) {\n  /* istanbul ignore next: ignore the final fallback as hard trigger */\n  target = target || document.body || document.documentElement;\n  eventName = `oAds.${eventName}`;\n  const opts = {\n    bubbles: true,\n    cancelable: true,\n    detail: data\n  };\n  const isSlotEvent = typeof data === 'object' && 'pos' in data;\n  const evDetails = isSlotEvent ? {\n    pos: data.pos,\n    name: data.name,\n    size: data.size && data.size.length ? data.size.toString() : '',\n    creativeId: data.creativeId\n  } : {};\n  const suffix = buildPerfmarkSuffix(evDetails);\n  const markName = eventName + suffix;\n  perfMark(markName);\n  target.dispatchEvent(new CustomEvent(eventName, opts));\n}\n/**\n* Sets an event listener for an oAds event\n* @param {string} name The name of the event\n* @param {EventListenerOrEventListenerObject} callback The function to execute on the event\n* @param {HTMLElement} [target] The element to attach the event listener to\n*/\n\nfunction on(name, callback, target) {\n  name = `oAds.${name}`;\n  /* istanbul ignore next: ignore the final fallback as hard trigger */\n\n  target = target || document.body || document.documentElement;\n  target.addEventListener(name, callback);\n}\n/**\n* Removes an event listener for an oAds event\n* @param {string} name The name of the event\n* @param {function} callback The function on the event to be removed\n* @param {HTMLElement} target The element the event listener is attached to\n*/\n\nfunction off(name, callback, target) {\n  name = `oAds.${name}`;\n  /* istanbul ignore next: ignore the final fallback as hard trigger */\n\n  target = target || document.body || document.documentElement;\n  target.removeEventListener(name, callback);\n}\n/**\n* Sets a one time event listener for an oAds event\n* @param {string} name The name of the event\n* @param {function} callback The function to execute on the event\n* @param {HTMLElement} [target] The element to attach the event listener to\n*/\n\nfunction once(name, callback, target) {\n  const handler = function (event) {\n    /* istanbul ignore next: ignore the final fallback as hard trigger */\n    const targ = event.target || event.srcElement;\n    targ.removeEventListener(name = `oAds.${name}`, callback);\n\n    if (callback) {\n      callback(event); // we set callback to null so if for some reason the listener isn't removed the callback will still only be called once\n\n      callback = null;\n    }\n  };\n\n  on(name, handler, target);\n}\n\nfunction getMarksForEvents(events, suffix) {\n  const markNames = events.map(eventName => 'oAds.' + eventName + suffix);\n\n  if (!performance || !performance.getEntriesByName) {\n    /* istanbul ignore next  */\n    return {};\n  }\n\n  const marks = {};\n  markNames.forEach(function (mName) {\n    const pMarks = performance.getEntriesByName(mName);\n    const markName = mName.replace('oAds.', '').replace(suffix, '');\n\n    if (pMarks && pMarks.length) {\n      // We don't need sub-millisecond precision\n      marks[markName] = Math.round(pMarks[0].startTime);\n      return;\n    } // If no mark has been found, we might be looking for a page-level\n    // mark name, i.e. one without a suffix\n\n\n    if (suffix) {\n      const mNameNoSuffix = mName.replace(suffix, '');\n      const pMarks2 = performance.getEntriesByName(mNameNoSuffix);\n\n      if (pMarks2 && pMarks2.length) {\n        marks[markName] = Math.round(pMarks2[0].startTime);\n      }\n    }\n  });\n  return marks;\n}\nfunction clearPerfMarks(metricsDefinitions, groupsToClear) {\n  if (!performance || !performance.getEntriesByType) {\n    return;\n  }\n\n  const relevantGroups = metricsDefinitions.filter(group => groupsToClear.includes(group.spoorAction));\n  const relevantGroupsMarks = relevantGroups.map(group => group.marks); // Because relevantGroupsMarks is a 2D array ...\n\n  const eventsToClear = [].concat(...relevantGroupsMarks);\n  const perfMarks = performance.getEntriesByType('mark');\n  perfMarks.forEach(({\n    name\n  }) => {\n    eventsToClear.forEach(eventName => {\n      if (name.match(`oAds.${eventName}`)) {\n        performance.clearMarks(name);\n      }\n    });\n  });\n}\n/* istanbul ignore next */\n\nfunction getNavigationPerfMarks(desiredMarks) {\n  if (!performance || !performance.getEntriesByType || !utils.isArray(desiredMarks)) {\n    /* istanbul ignore next  */\n    return {};\n  }\n\n  const navMarksArray = performance.getEntriesByType('navigation');\n  const navMarks = utils.isArray(navMarksArray) && navMarksArray[0] || {};\n  const marks = {};\n  desiredMarks.forEach(function (markName) {\n    marks[markName] = typeof navMarks[markName] === 'number' ? Math.round(navMarks[markName]) : 0;\n  });\n  return marks;\n}\n\nfunction setupMetrics(definitions, callback, disableSampling) {\n  if (!Array.isArray(definitions)) {\n    this.log.warn('Metrics definitions should be an array. o-Ads will not record any metrics.');\n    return;\n  }\n\n  definitions.forEach(function (eDef) {\n    if (disableSampling || utils.inSample(eDef.sampleSize)) {\n      const triggers = Array.isArray(eDef.triggers) ? eDef.triggers : [];\n      triggers.forEach(function (trigger) {\n        sendMetricsOnEvent('oAds.' + trigger, eDef, callback);\n      });\n    }\n  });\n}\n\nfunction sendMetricsOnEvent(eventName, eMarkMap, callback) {\n  document.addEventListener(eventName, function listenOnInitialised(event) {\n    sendMetrics(eMarkMap, event.detail, callback);\n\n    if (!eMarkMap.multiple) {\n      document.removeEventListener(eventName, listenOnInitialised);\n    }\n  });\n}\n\nfunction sendMetrics(eMarkMap, eventDetails, callback) {\n  const suffix = utils.buildPerfmarkSuffix(eventDetails);\n  const marks = getMarksForEvents(eMarkMap.marks, suffix);\n\n  if (eMarkMap.navigation) {\n    const navMarks = getNavigationPerfMarks(eMarkMap.navigation);\n    Object.assign(marks, navMarks);\n  }\n\n  const eventPayload = {\n    category: 'ads',\n    action: eMarkMap.spoorAction,\n    timings: {\n      marks: marks\n    }\n  };\n  eventPayload.advert = {\n    correlator: window.oAds.gpt.getCorrelator()\n  };\n\n  if (eventDetails && 'pos' in eventDetails) {\n    eventPayload.creative = {\n      name: eventDetails.name,\n      pos: eventDetails.pos,\n      size: eventDetails.size && eventDetails.size.toString(),\n      creativeId: eventDetails.creativeId || 0\n    };\n\n    if (typeof eventDetails.isEmpty === 'boolean') {\n      eventPayload.creative.isEmpty = eventDetails.isEmpty;\n    }\n  }\n\n  callback(eventPayload);\n}\n\nfunction markPageChange(definitions, groupsToClear) {\n  clearPerfMarks(definitions, groupsToClear);\n  utils.broadcast('pageChange');\n}\n\n/**\n * Utility methods for postMessage api.\n * @author Origami Advertising, origami.advertising@ft.com\n * @module utils\n */\nvar messenger = {\n  post: function (message, source) {\n    message = typeof message === 'string' ? message : JSON.stringify(message);\n    source = arguments[1] || window.top;\n    source.postMessage(message, '*');\n  },\n  parse: function (message) {\n    // Check whether the message looks like an object before trying to parse it\n    if (typeof message !== 'string' || message[0] !== '{') {\n      return message;\n    } // try returning the parsed object\n\n\n    try {\n      return JSON.parse(message);\n    } // return the original message\n    catch (e) {\n      return message;\n    }\n  }\n};\n\nlet callback;\nlet breakpoints$1;\nlet current;\n\nfunction getNearestBreakpoint() {\n  let winner;\n  const dims = oViewport.getSize(true);\n\n  function findCurrentBreakpoint(breakpoint) {\n    const breakpointDims = breakpoints$1[breakpoint];\n\n    if (dims.width >= breakpointDims[0] && dims.height >= breakpointDims[1]) {\n      if (!winner || breakpointDims[0] >= breakpoints$1[winner][0]) {\n        winner = breakpoint;\n      }\n    }\n  }\n\n  Object.keys(breakpoints$1).forEach(findCurrentBreakpoint);\n  return winner;\n}\n\nfunction fire() {\n  const winner = getNearestBreakpoint();\n\n  if (current !== winner) {\n    setCurrent(winner);\n    callback(winner);\n  }\n}\n\nfunction setCurrent(name) {\n  current = name;\n}\n\nfunction getCurrent() {\n  return current;\n}\nfunction init$2(brps, cb) {\n  if (!utils.isFunction(cb)) {\n    // must have a call back function\n    return false;\n  }\n\n  breakpoints$1 = brps;\n  callback = cb;\n  setCurrent(getNearestBreakpoint());\n  document.body.addEventListener('oViewport.orientation', fire);\n  document.body.addEventListener('oViewport.resize', fire);\n  oViewport.listenTo('orientation');\n  oViewport.listenTo('resize');\n  return getCurrent();\n}\noViewport.setThrottleInterval;\n\n/* eslint no-console: 0 */\n/**\n * Utility methods for logging.\n * @author Origami Advertising, origami.advertising@ft.com\n * @module utils/log\n * @see utils\n */\n\n/* jshint devel: true */\n\n/**\n * Safe logger for the browser\n * @exports utils/log\n * @param {string} type Sets the type of log message log, warn, error or info, if not set to one of these values log will be used\n * @param {any} args the arguments to be passed to console[type]\n */\n\nfunction log() {\n  let type;\n  let argsIndex;\n\n  if ('log warn error info'.indexOf(arguments[0]) === -1) {\n    type = 'log';\n    argsIndex = 0;\n  } else {\n    type = arguments[0];\n    argsIndex = 1;\n  }\n\n  const args = [].slice.call(arguments, argsIndex);\n\n  if (log.isOn(type)) {\n    window.console[type].apply(window.console, args);\n  }\n}\n/**\n * Determine if debug logging is on and if the type if supported\n * @param {string} type\n */\n\nconst isOn = function (type) {\n  /* istanbul ignore else  */\n  const debug = localStorage && localStorage.getItem('oAds') || location.search.indexOf('DEBUG=OADS') !== -1;\n  return debug && window.console && window.console[type];\n};\n/**\n * Log a warning message\n */\n\nconst warn = function () {\n  const args = ['warn'].concat([].slice.call(arguments, 0));\n  log.apply(null, args);\n};\n/**\n * Log an error message\n */\n\nconst error = function () {\n  const args = ['error'].concat([].slice.call(arguments, 0));\n  log.apply(null, args);\n};\n/**\n * Log an info message\n */\n\nconst info = function () {\n  const args = ['info'].concat([].slice.call(arguments, 0));\n  log.apply(null, args);\n};\n/**\n * Start a collapsed group\n * @param {string} group the name of the group, defaults to o-ads\n */\n\nconst start = function (group) {\n  if (!log.isOn('groupCollapsed')) {\n    return;\n  }\n\n  window.console.groupCollapsed(group || 'o-ads');\n};\n/**\n * End a collapsed group\n */\n\nconst end = function () {\n  if (!log.isOn('groupEnd')) {\n    return;\n  }\n\n  window.console.groupEnd();\n};\nconst table = function (data, columns) {\n  if (log.isOn('log') && window.console) {\n    if (console.table) {\n      console.table(data, columns);\n    } else {\n      console.log(data);\n    }\n  }\n};\nconst attributeTable = function (object, columns) {\n  if (log.isOn('log') && window.console) {\n    if (object && console.table) {\n      const data = Object.keys(object).map(item => {\n        let val;\n\n        if (isArray(object[item]) || isObject(object[item])) {\n          val = JSON.stringify(object[item]);\n        } else {\n          val = object[item];\n        }\n\n        return {\n          key: item,\n          value: val\n        };\n      });\n      console.table(data, columns);\n    } else {\n      console.log(object);\n    }\n  }\n};\n\n// generated by genversion\nvar version = '18.3.3';\n\n/**\n * Utility methods for the advertising library.\n * @author Origami Advertising, origami.advertising@ft.com\n * @module utils\n */\n\nconst hop = Object.prototype.hasOwnProperty;\ninit$2.getCurrent = getCurrent;\nlog.start = start;\nlog.end = end;\nlog.isOn = isOn;\nlog.info = info;\nlog.warn = warn;\nlog.error = error;\nlog.table = table;\nlog.attributeTable = attributeTable;\n/**\n * Uses object prototype toString method to get at the type of object we are dealing,\n * IE returns [object Object] for null and undefined so we need to filter those\n * http://es5.github.com/#x15.2.4.2\n * @private\n * @param {object} Any javascript object\n * @returns The type of the object e.g Array, String, Object\n */\n\nfunction is(object) {\n  const type = Object.prototype.toString.call(object).match(/^\\[object\\s(.*)\\]$/)[1];\n\n  if (object === null) {\n    return 'Null';\n  } else if (object === undefined) {\n    return 'Undefined';\n  } else {\n    return type;\n  }\n}\n/**\n * Test if an object is an Array\n * @param {object} obj The object to be tested\n * @returns {boolean} true if the object is of type Array, otherwise false\n */\n\n\nconst isArray = function (obj) {\n  return is(obj) === 'Array';\n};\n/**\n * Test if an object is a String\n * @param {object} obj The object to be tested\n * @returns {boolean} true if the object is of type String, otherwise false\n */\n\nconst isString = function (obj) {\n  return is(obj) === 'String';\n};\n/**\n * Test if an object is a Function\n * @param {object} obj The object to be tested\n * @returns {boolean} true if the object is of type Function, otherwise false\n */\n\nconst isFunction = function (obj) {\n  return is(obj) === 'Function';\n};\n/**\n * Test if an object is a Storage object\n * @param {object} obj The object to be tested\n * @returns {boolean} true if the object is of type Storage, otherwise false\n */\n\nconst isStorage = function (obj) {\n  return is(obj) === 'Storage';\n};\n/**\n * Test if an object is an Object\n * @param {object} obj The object to be tested\n * @returns {boolean} true if the object is of type Object, otherwise false\n */\n\nconst isObject = function (obj) {\n  return is(obj) === 'Object';\n};\n/**\n * Test if an object is the global window object\n * @param {object} obj The object to be tested\n * @returns {boolean} true if the object is the window obj, otherwise false\n */\n\nconst isWindow = function (obj) {\n  return obj && obj !== null && obj === window;\n};\n/**\n * Test if an object inherits from any other objects, used in extend\n * to protect against deep copies running out of memory and constructors\n * losing there prototypes when cloned\n * @param {object} obj The object to be tested\n * @returns {boolean} true if the object is plain false otherwise\n */\n\nconst isPlainObject = function (obj) {\n  const hop = Object.prototype.hasOwnProperty; // Must be an Object.\n  // Because of IE, we also have to check the presence of the constructor property.\n  // Make sure that DOM nodes and window objects don't pass through, as well\n\n  if (!obj || !isObject(obj) || obj.nodeType || isWindow(obj)) {\n    return false;\n  }\n\n  try {\n    // Not own constructor property must be Object\n    if (obj.constructor && !hop.call(obj, 'constructor') && !hop.call(obj.constructor.prototype, 'isPrototypeOf')) {\n      return false;\n    }\n  } catch (e) {\n    /* istanbul ignore next  */\n    // IE8,9 Will throw exceptions on certain host objects\n    return false;\n  } // Own properties are enumerated firstly, so to speed up,\n  // if last one is own, then all properties are own.\n\n\n  let key;\n\n  for (key in obj) {// empty\n  }\n\n  return key === undefined || hop.call(obj, key);\n};\n/**\n * Test if an object is a string with a length\n * @param {object} str The object to be tested\n * @returns {boolean} true if the object is a string with a length greater than 0\n */\n\nconst isNonEmptyString = function (str) {\n  return isString(str) && Boolean(str.length);\n};\nconst isElement = function (element) {\n  return element && element.nodeType === 1 && element.tagName || false;\n};\nfunction extend() {\n  /* jshint forin: false */\n\n  /* when doing a deep copy we want to copy prototype properties */\n  let options;\n  let src;\n  let copy;\n  let copyIsArray;\n  let clone;\n  let target = arguments[0] || {};\n  const length = arguments.length;\n  let deep = false;\n  let i = 1; // Handle a deep copy situation\n\n  if (typeof target === 'boolean') {\n    deep = target;\n    target = arguments[1] || {}; // skip the boolean and the target\n\n    i = 2;\n  } // Handle case when target is a string or something (possible in deep copy)\n\n  /* istanbul ignore else  */\n\n\n  if (typeof target !== 'object' && !isFunction(target)) {\n    target = {};\n  } // do nothing if only one argument is passed (or 2 for a deep copy)\n\n  /* istanbul ignore else  */\n\n\n  if (length === i) {\n    return target;\n  }\n\n  for (; i < length; i++) {\n    // Only deal with non-null/undefined values\n    if ((options = arguments[i]) !== null) {\n      // Extend the base object\n      for (const name in options) {\n        /* istanbul ignore next */\n        if (options.hasOwnProperty(name)) {\n          src = target[name];\n          copy = options[name]; // Prevent never-ending loop\n\n          if (target === copy) {\n            continue;\n          } // Recurse if we're merging arrays\n\n\n          if (deep && copy && (isPlainObject(copy) || isArray(copy))) {\n            copyIsArray = isArray(copy);\n\n            if (copyIsArray) {\n              copyIsArray = false;\n              clone = src && isArray(src) ? src : [];\n            } else {\n              clone = src && isObject(src) ? src : {};\n            } // Never move original objects, clone them\n\n\n            target[name] = extend(deep, clone, copy); // Don't bring in undefined values\n          } else if (copy !== undefined) {\n            target[name] = copy;\n          }\n        }\n      }\n    }\n  } // Return the modified object\n\n\n  return target;\n}\n/**\n * Create an object hash from a delimited string\n * Beware all properties on the resulting object will have string values.\n * @param {string}        str       The string to transform\n * @param {string|regexp} delimiter The character that delimits each name/value pair\n * @param {string}        pairing   The character that separates the name from the value\n * @return {object}\n *\n */\n\nconst hash = function (str, delimiter, pairing) {\n  let pair;\n  let value;\n  const hashObj = {};\n\n  if (str && str.split) {\n    str = str.split(delimiter);\n\n    for (let idx = 0, l = str.length; idx < l; idx += 1) {\n      value = str[idx];\n      pair = value.split(pairing);\n\n      if (pair.length > 1) {\n        hashObj[pair[0].trim()] = pair.slice(1).join(pairing);\n      }\n    }\n  }\n\n  return hashObj;\n};\n/**\n * Takes a script URL as a string value, creates a new script element, sets the src and attaches to the page\n * The async value of the script can be set by the seccond parameter, which is a boolean\n * Note, we should use protocol-relative URL paths to ensure we don't run into http/https issues\n * @param {string} scriptUrl The url to the script file to be added\n * @param {boolean} async Set the async attribute on the script tag\n * @param {function} callback A function to run when the script loads\n * @param {function} errorcb A function to run if the script fails to load\n * @returns {HTMLElement} the created script tag\n */\n\nconst attach = function (scriptUrl, async, callback, errorcb, autoRemove) {\n  const tag = document.createElement('script');\n  const node = document.getElementsByTagName('script')[0];\n  let hasRun = false;\n\n  function processCallback(callback) {\n    /* istanbul ignore else  */\n    if (!hasRun) {\n      callback.call();\n      hasRun = true;\n      /* istanbul ignore else  */\n\n      if (autoRemove) {\n        tag.parentElement.removeChild(tag);\n      }\n    }\n  }\n\n  tag.setAttribute('src', scriptUrl);\n  tag.setAttribute('o-ads', '');\n  /* istanbul ignore else */\n\n  if (async) {\n    tag.async = 'true';\n  }\n  /* istanbul ignore else  */\n\n\n  if (isFunction(callback)) {\n    /* istanbul ignore if - legacy IE code, won't test */\n    if (hop.call(tag, 'onreadystatechange')) {\n      tag.onreadystatechange = function () {\n        if (tag.readyState === 'loaded') {\n          processCallback(callback);\n        }\n      };\n    } else {\n      tag.onload = function () {\n        processCallback(callback);\n      };\n    }\n  }\n  /* istanbul ignore else  */\n\n\n  if (isFunction(errorcb)) {\n    tag.onerror = function () {\n      processCallback(errorcb);\n    };\n  } // Use insert before, append child has issues with script tags in some browsers.\n\n\n  node.parentNode.insertBefore(tag, node);\n  return tag;\n};\n/**\n * return the current documents referrer or an empty string if non exists\n * This method enables us to mock the referrer in our tests reliably and doesn't really serve any other purpose\n * @returns {string} document.referrer\n */\n\n/* istanbul ignore next - cannot reliably test value of referer */\n\nconst getReferrer = function () {\n  return document.referrer || '';\n};\n/**\n * Remove hyphens from a string and upper case the following letter\n * @param {string} string the string to parse\n * @returns {string}\n */\n\nconst dehyphenise = function (string) {\n  return string.replace(/(-)([a-z])/g, function (match, hyphen, letter) {\n    return letter.toUpperCase();\n  });\n};\n/**\n * remove prefixes from o-ads data attributes and dehyphenise the name\n * @param {string|} name the name of the attribute to parse\n * @returns {string}\n */\n\nconst parseAttributeName = function (attribute) {\n  const name = isString(attribute) ? attribute : attribute.name;\n  return dehyphenise(name.replace(/(data-)?o-ads-/, ''));\n};\n/**\n * return the current documents url or an empty string if non exists\n * This method enables us to mock the document location string in our tests reliably and doesn't really serve any other purpose\n * @returns {string}\n */\n\n/* istanbul ignore next - cannot reliably test value of location */\n\nconst getLocation = function () {\n  return document.location.href || '';\n};\n/**\n * return the current documents search or an empty string if non exists\n * also strips the initial ? from the search string for easier parsing\n * This method enables us to mock the search string in our tests reliably and doesn't really serve any other purpose\n * @returns {string}\n */\n\nconst getQueryString = function () {\n  return document.location.search.substring(1) || '';\n};\n/**\n * Get a query string parameter by name from a url\n * @param name\n * @param url\n * @returns {string | null}\n */\n\nconst getQueryParamByName = function (name, url) {\n  url = url || window.location.href;\n  name = name.replace(/[[\\]]/g, '\\\\$&');\n  const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');\n  const results = regex.exec(url);\n\n  if (!results) {\n    return null;\n  }\n\n  if (!results[2]) {\n    return '';\n  }\n\n  return decodeURIComponent(results[2].replace(/\\+/g, ' '));\n};\n/**\n * returns a timestamp of the current date/time in the format YYYYMMDDHHMMSS\n * @returns {string}\n */\n\nconst getTimestamp = function () {\n  const now = new Date();\n  return [now.getFullYear(), `0${now.getMonth() + 1}`.slice(-2), `0${now.getDate()}`.slice(-2), `0${now.getHours()}`.slice(-2), `0${now.getMinutes()}`.slice(-2), `0${now.getSeconds()}`.slice(-2)].join('');\n};\n/**\n * Given the window object of an iframe this method returns the o-ads slot name\n * that rendered the iframe, if the iframe was not rendered by o-ads this will\n * return false\n * @param {window}  a window object\n * @returns {String|Boolean}\n */\n\nconst iframeToSlotName = function (iframeWindow) {\n  // capture all iframes in the page in a live node list\n  const iframes = document.getElementsByTagName('iframe');\n  let slotName;\n  let node;\n  let i = iframes.length; // Figure out which iframe DOM node we have the window for\n\n  while (i--) {\n    /* istanbul ignore else  */\n    if (iframes[i].contentWindow === iframeWindow) {\n      node = iframes[i];\n      break;\n    }\n  }\n  /* istanbul ignore else  */\n\n\n  if (node) {\n    // find the closest parent with a data-o-ads-name attribute, that's our slot name\n    while (node.parentNode) {\n      slotName = node.getAttribute('data-o-ads-name');\n      /* istanbul ignore else  */\n\n      if (slotName) {\n        return slotName;\n      }\n\n      node = node.parentNode;\n    }\n  }\n\n  return false;\n};\nconst buildObjectFromArray = function buildObjectFromArray(targetObject) {\n  return targetObject.reduce((prev, data) => {\n    prev[data.key] = data.value;\n    return prev;\n  }, {});\n};\nconst cookie = function (name) {\n  const val = document.cookie.match(`(^|;)\\\\s*${name}\\\\s*=\\\\s*([^;]+)`);\n  return val ? val.pop() : null;\n};\nconst getVersion = () => version ;\nconst metricsSampleThreshold = Math.random();\nfunction inSample(sampleSize) {\n  return typeof sampleSize === 'undefined' || sampleSize > metricsSampleThreshold;\n}\nvar utils = {\n  on,\n  off,\n  once,\n  broadcast,\n  messenger,\n  responsive: init$2,\n  log,\n  isArray,\n  isString,\n  isFunction,\n  isStorage,\n  isObject,\n  isWindow,\n  isPlainObject,\n  isNonEmptyString,\n  isElement,\n  extend,\n  hash,\n  attach,\n  getReferrer,\n  dehyphenise,\n  parseAttributeName,\n  getLocation,\n  getQueryString,\n  getQueryParamByName,\n  getTimestamp,\n  iframeToSlotName,\n  buildObjectFromArray,\n  cookie,\n  getVersion,\n  setupMetrics,\n  clearPerfMarks,\n  markPageChange,\n  inSample,\n  perfMark,\n  buildPerfmarkSuffix\n};\n\n//TODO remove all ft.com specific stuff so we can remove this as a global\n/**\n* Default configuration set in the constructor.\n*/\n\nconst defaults = {\n  formats: {\n    PartnerContent: {\n      sizes: ['fluid']\n    },\n    MediumRectangle: {\n      sizes: [300, 250]\n    },\n    Rectangle: {\n      sizes: [180, 50]\n    },\n    WideSkyscraper: {\n      sizes: [160, 600]\n    },\n    Leaderboard: {\n      sizes: [728, 90]\n    },\n    SuperLeaderboard: {\n      sizes: [[970, 90], [970, 66]]\n    },\n    HalfPage: {\n      sizes: [300, 600]\n    },\n    Billboard: {\n      sizes: [970, 250]\n    },\n    Portrait: {\n      sizes: [300, 1050]\n    },\n    AdhesionBanner: {\n      sizes: [320, 50]\n    },\n    MicroBar: {\n      sizes: [88, 31]\n    },\n    Button2: {\n      sizes: [120, 60]\n    },\n    Responsive: {\n      sizes: [2, 2]\n    }\n  },\n  responsive: {\n    extra: [1025, 0],\n    //Reasonable width to show a Billboard (desktop)\n    large: [1000, 0],\n    //reasonable width to show SuperLeaderboard (tablet landscape)\n    medium: [760, 0],\n    //reasonable width to show a leaderboard (tablet portrait)\n    small: [0, 0] //Mobile\n\n  },\n  flags: {\n    refresh: true,\n    inview: true\n  },\n  displayLabelWithBorders: false\n};\n\nfunction fetchDeclaritiveConfig() {\n  let results = {};\n  const scripts = Array.from(document.querySelectorAll('script[data-o-ads-config]'));\n  scripts.forEach(script => {\n    results = window.JSON ? utils.extend(results, JSON.parse(script.innerHTML)) : 'UNSUPPORTED';\n  });\n  return results;\n}\n/**\n* @private\n* @function\n* fetchCanonicalURL Grabs the canonical URL from the page meta if it exists.\n*/\n\n\nfunction fetchCanonicalURL() {\n  let canonical;\n  const canonicalTag = document.querySelector('link[rel=\"canonical\"]');\n\n  if (canonicalTag) {\n    canonical = canonicalTag.href;\n  }\n\n  return {\n    canonical: canonical\n  };\n}\n/**\n* Defines a store for configuration information and returns a getter/setter method for access.\n* @class\n* @constructor\n*/\n\n\nfunction Config() {\n  this.store = {};\n}\n\nConfig.prototype.access = function (k, v) {\n  let result;\n\n  if (utils.isPlainObject(k)) {\n    utils.extend(true, this.store, k);\n    result = this.store;\n  } else if (typeof v === 'undefined') {\n    if (typeof k === 'undefined') {\n      result = this.store;\n    } else {\n      result = this.store[k];\n    }\n  } else {\n    this.store[k] = v;\n    result = v;\n  }\n\n  return result;\n};\n\nConfig.prototype.clear = function (key) {\n  if (key) {\n    delete this.store[key];\n  } else {\n    this.store = {};\n  }\n};\n\nConfig.prototype.init = function () {\n  this.store = utils.extend(true, {}, defaults, fetchCanonicalURL(), fetchDeclaritiveConfig());\n  return this.store;\n};\n\nconst config = new Config();\nvar config$1 = config.access.bind(config);\nconst init$1 = config.init.bind(config);\nconst clear = config.clear.bind(config);\n\nconst VALID_SIZE_STRINGS = ['fluid'];\nconst VALID_COLLAPSE_MODES = ['before', 'after', 'never'];\nconst attributeParsers = {\n  sizes: function (value, sizes) {\n    if (value === false || value === 'false') {\n      return false;\n    }\n    /* istanbul ignore else  */\n    else if (utils.isArray(sizes)) {\n      const regex = /(\\d+)x(\\d+)/;\n      value.split(',').filter(size => size.length).forEach(size => {\n        if (regex.test(size)) {\n          size.replace(regex, function (match, width, height) {\n            sizes.push([parseInt(width, 10), parseInt(height, 10)]);\n          });\n        } else if (VALID_SIZE_STRINGS.indexOf(size) >= 0) {\n          sizes.push(size);\n        }\n      });\n    }\n\n    return sizes;\n  },\n  formats: function (value, sizes) {\n    if (value === false || value === 'false') {\n      sizes = false;\n    } else {\n      const mapping = config$1().formats;\n      const formats = utils.isArray(value) ? value : value.split(',');\n      formats.forEach(format => {\n        if (mapping && mapping[format]) {\n          format = mapping[format];\n\n          if (utils.isArray(format.sizes[0]) || VALID_SIZE_STRINGS.indexOf(format.sizes[0]) >= 0) {\n            format.sizes.forEach(size => {\n              sizes.push(size);\n            });\n          } else {\n            sizes.push(format.sizes);\n          }\n        } else {\n          utils.log.error(`Slot configured with unknown format ${format}`);\n        }\n      });\n    }\n\n    return sizes;\n  },\n  responsiveSizes: function (name, value, sizes) {\n    const screenName = name.replace(/^sizes/, '').toLowerCase();\n    /* istanbul ignore else\t*/\n\n    if (!utils.isPlainObject(sizes)) {\n      sizes = {};\n    }\n\n    sizes[screenName] = attributeParsers.sizes(value, sizes[screenName] || []);\n    return sizes;\n  },\n  responsiveFormats: function (name, value, sizes) {\n    const screenName = name.replace(/^formats/, '').toLowerCase();\n    /* istanbul ignore else\t*/\n\n    if (!utils.isPlainObject(sizes)) {\n      sizes = {};\n    }\n\n    sizes[screenName] = attributeParsers.formats(value, []);\n    return sizes;\n  },\n  lazyLoadThreshold: function (value) {\n    return value.split(',').map(Number);\n  },\n  targeting: function (value, targeting) {\n    value = utils.hash(value, ';', '=');\n    utils.extend(targeting, value);\n    return targeting;\n  },\n  base: function (value) {\n    /* istanbul ignore else\t*/\n    if (value === '' || value === 'true') {\n      value = true;\n    } else if (value === 'false') {\n      value = false;\n    }\n\n    return value;\n  },\n  collapseEmpty: function (value) {\n    const isUnknownAttribute = VALID_COLLAPSE_MODES.indexOf(value) === -1;\n\n    if (isUnknownAttribute) {\n      utils.log.warn(`Invalid attribute ${value} used for collapse-empty attribute, please use 'before', 'after' or 'never'`);\n      return undefined;\n    }\n\n    return value;\n  }\n};\n\nconst convertLazyLoadBooleanToObject = obj => {\n  if (obj.lazyLoad === true) {\n    obj.lazyLoad = {};\n  }\n};\n\nconst onChangeBreakpoint = event => {\n  const slot = event.detail.slot;\n  slot.screensize = event.detail.screensize;\n\n  if (slot.hasValidSize()) {\n    slot.uncollapse();\n  } else {\n    slot.collapse();\n    slot.clear();\n  }\n};\n/**\n * The Slot class.\n * @class\n * @constructor\n */\n\n\nfunction Slot(container, screensize, initLazyLoading) {\n  const renderEvent = 'slotRenderStart';\n  const cfg = config$1();\n  let slotConfig = config$1('slots') || {}; // store the container\n\n  this.container = container; // the current responsive screensize\n\n  /* istanbul ignore else\t*/\n\n  if (screensize) {\n    this.screensize = screensize;\n  } // init slot dom structure\n\n\n  this.outer = this.addContainer(container, {\n    'class': 'o-ads__outer',\n    'aria-hidden': 'true',\n    'tabindex': '-1'\n  });\n  this.inner = this.addContainer(this.outer, {\n    'class': 'o-ads__inner'\n  }); // make sure the slot has a name\n\n  this.setName();\n  slotConfig = slotConfig[this.name] || {}; // default configuration properties\n\n  this.server = 'gpt';\n  this.defer = false; // global slots configuration\n\n  this.targeting = slotConfig.targeting || {};\n  this.sizes = slotConfig.sizes || [];\n  this.center = slotConfig.center || false;\n  this.label = slotConfig.label || false;\n  this.outOfPage = slotConfig.outOfPage || false;\n  this.companion = slotConfig.companion === false ? false : true;\n  this.collapseEmpty = slotConfig.collapseEmpty;\n  /* istanbul ignore else */\n\n  if (utils.isArray(slotConfig.formats)) {\n    attributeParsers.formats(slotConfig.formats, this.sizes);\n  } else if (utils.isPlainObject(slotConfig.formats)) {\n    this.sizes = {};\n    Object.keys(slotConfig.formats).forEach(screenName => {\n      this.sizes[screenName] = attributeParsers.formats(slotConfig.formats[screenName], []);\n    });\n  }\n\n  if (typeof slotConfig.lazyLoad !== 'undefined') {\n    this.lazyLoad = slotConfig.lazyLoad;\n  } else {\n    this.lazyLoad = config$1('lazyLoad') || false;\n  }\n\n  const outerEl = container.querySelector('.o-ads__outer');\n\n  if (outerEl && cfg.displayLabelWithBorders && this.container.getAttribute('data-o-ads-label')) {\n    const allowedLabels = ['left', 'center', 'right'];\n    const adsLabelPos = this.container.getAttribute('data-o-ads-label');\n    utils.once(renderEvent, () => {\n      const modifier = allowedLabels.indexOf(adsLabelPos) ? adsLabelPos : \"left\";\n      outerEl.classList.add('o-ads--label-with-borders', `o-ads--label-with-borders--${modifier}`);\n    });\n  } // extend with imperative configuration options\n\n\n  this.parseAttributeConfig();\n  /* istanbul ignore else\t*/\n\n  if (!this.sizes.length && !utils.isPlainObject(this.sizes)) {\n    utils.log.error('slot %s has no configured sizes!', this.name);\n    return false;\n  } // Either retrieve the existing IntersectionObserver, or tell slots.js to create a new one.\n\n\n  this.lazyLoadObserver = initLazyLoading(this.lazyLoad);\n  this.initLazyLoad();\n  this.centerContainer();\n  this.labelContainer();\n  this.initResponsive();\n}\n/**\n * parse slot attribute config\n */\n\n\nSlot.prototype.parseAttributeConfig = function () {\n  Array.from(this.container.attributes).forEach(attribute => {\n    const name = utils.parseAttributeName(attribute.name);\n    const value = attribute.value;\n\n    if (name === 'formats') {\n      this[name] = attributeParsers[name](value, this.sizes);\n    } else if (name === 'collapseEmpty') {\n      this.collapseEmpty = attributeParsers.collapseEmpty(value);\n    } else if (name === 'lazyLoadThreshold' && this.lazyLoad) {\n      convertLazyLoadBooleanToObject(this);\n      this.lazyLoad.threshold = attributeParsers.lazyLoadThreshold(value);\n    } else if (name === 'lazyLoadViewportMargin' && this.lazyLoad) {\n      convertLazyLoadBooleanToObject(this);\n      this.lazyLoad.viewportMargin = attributeParsers.base(value);\n    } else if (attributeParsers[name]) {\n      this[name] = attributeParsers[name](value, this[name]);\n    } else if (/^formats\\w*/.test(name)) {\n      this.sizes = attributeParsers.responsiveFormats(name, value, this.sizes);\n    } else if (/^sizes\\w*/.test(name)) {\n      this.sizes = attributeParsers.responsiveSizes(name, value, this.sizes);\n    } else if (this.hasOwnProperty(name)) {\n      this[name] = attributeParsers.base(value);\n    }\n  });\n};\n\nSlot.prototype.getAttributes = function () {\n  const attributes = {};\n  Array.from(this.container.attributes).forEach(attribute => {\n    attributes[utils.parseAttributeName(attribute)] = attribute.value;\n  });\n  this.attributes = attributes;\n  return this;\n};\n/**\n *\tLoad a slot when it appears in the viewport\n */\n\n\nSlot.prototype.initLazyLoad = function () {\n  /* istanbul ignore else  */\n  if (this.lazyLoadObserver && this.lazyLoad) {\n    this.defer = true;\n    this.lazyLoadObserver.observe(this.container); //Master/Companion ads don't work with lazy loading, so if a master ad loads trigger\n\n    /* istanbul ignore else */\n\n    if (this.companion) {\n      utils.once('masterLoaded', () => {\n        if (this.hasValidSize()) {\n          this.render();\n        }\n      }, this.container);\n    }\n  }\n\n  return this;\n};\n\nSlot.prototype.render = function () {\n  this.fire('slotCanRender');\n  /* istanbul ignore else  */\n\n  if (this.lazyLoadObserver) {\n    this.lazyLoadObserver.unobserve(this.container);\n  }\n};\n/**\n *\tListen to responsive breakpoints and collapse slots\n * where the configured size is set to false\n */\n\n\nSlot.prototype.initResponsive = function () {\n  /* istanbul ignore else */\n  if (utils.isPlainObject(this.sizes)) {\n    /* istanbul ignore else */\n    if (!this.hasValidSize()) {\n      this.collapse();\n    }\n\n    utils.on('breakpoint', onChangeBreakpoint, this.container);\n  }\n\n  return this;\n};\n/**\n * Maximise the slot when size is 100x100\n */\n\n\nSlot.prototype.maximise = function (size) {\n  if (size && Number(size[0]) === 100 && Number(size[1]) === 100) {\n    this.fire('resize', {\n      size: ['100%', '100%']\n    });\n  }\n};\n/**\n *\tIf the slot doesn't have a name give it one\n */\n\n\nSlot.prototype.setName = function () {\n  this.name = this.container.getAttribute('data-o-ads-name') || this.container.getAttribute('o-ads-name');\n\n  if (!this.name) {\n    this.name = `o-ads-slot-${Math.floor(Math.random() * 10000)}`;\n    this.container.setAttribute('data-o-ads-name', this.name);\n  }\n\n  return this;\n};\n/**\n * add the empty class to the slot\n */\n\n\nSlot.prototype.collapse = function () {\n  this.container.classList.add('o-ads--empty');\n  this.setFormatLoaded(false);\n  document.body.classList.add(`o-ads-no-${this.name}`);\n  utils.broadcast('collapsed', this);\n  return this;\n};\n/**\n * add the additional class to the slot\n */\n\n\nSlot.prototype.addClass = function (className) {\n  this.container.classList.add(`o-ads-${className}`);\n  utils.broadcast('slotClassAdded', this);\n  return this;\n};\n/**\n * sets a classname of the format\n */\n\n\nSlot.prototype.setFormatLoaded = function (format) {\n  this.container.setAttribute('data-o-ads-loaded', format);\n  return this;\n};\n/**\n * remove the empty class from the slot\n */\n\n\nSlot.prototype.uncollapse = function () {\n  this.container.classList.remove('o-ads--empty');\n  document.body.classList.remove(`o-ads-no-${this.name}`);\n  return this;\n};\n/**\n * call the ad server clear method on the slot if one exists\n */\n\n\nSlot.prototype.clear = function () {\n  /* istanbul ignore else  */\n  if (utils.isFunction(this['clearSlot'])) {\n    this.clearSlot();\n  }\n\n  return this;\n};\n/**\n * call the ad server destroySlot method on the slot if one exists\n */\n\n\nSlot.prototype.destroy = function () {\n  /* istanbul ignore else  */\n  if (utils.isFunction(this['destroySlot'])) {\n    utils.off('breakpoint', onChangeBreakpoint, this.container);\n    this.destroySlot();\n\n    if (this.outer.parentElement === this.container) {\n      this.container.removeChild(this.outer);\n    } else {\n      console.error('Error destroying ad slot. The parent node has already been removed.'); // eslint-disable-line no-console\n    }\n  }\n\n  return this;\n};\n/**\n * call the ad server impression URL for an out of page slot if it has been configured correctly for delayed impressions\n */\n\n\nSlot.prototype.submitImpression = function () {\n  /* istanbul ignore else  */\n  if (utils.isFunction(this['submitGptImpression'])) {\n    this.submitGptImpression();\n  }\n\n  return this;\n};\n/**\n *\tfire an event on the slot\n */\n\n\nSlot.prototype.fire = function (name, data) {\n  const gpt = this.gpt || {};\n  const details = {\n    name: this.name || '',\n    pos: this.targeting && this.targeting.pos || '',\n    size: gpt.size || '',\n    creativeId: gpt.creativeId || '',\n    slot: this\n  };\n\n  if (typeof gpt.isEmpty === 'boolean') {\n    details.isEmpty = gpt.isEmpty;\n  }\n\n  if (utils.isPlainObject(data)) {\n    utils.extend(details, data);\n  }\n\n  utils.broadcast(name, details, this.container);\n  return this;\n};\n/**\n *\tadd a div tag into the current slot container\n **/\n\n\nSlot.prototype.addContainer = function (node, attrs) {\n  let container = '<div ';\n  /* istanbul ignore else  */\n\n  if (attrs) {\n    Object.keys(attrs).forEach(function (attr) {\n      const value = attrs[attr];\n      container += `${attr}=${value} `;\n    });\n  }\n\n  container += '></div>';\n  node.insertAdjacentHTML('beforeend', container);\n  return node.lastChild;\n};\n\nSlot.prototype.hasValidSize = function (screensize) {\n  screensize = screensize || this.screensize;\n\n  if (screensize && utils.isPlainObject(this.sizes)) {\n    return this.sizes[screensize] !== false;\n  }\n\n  return true;\n};\n/**\n * Add a center class to the main container\n */\n\n\nSlot.prototype.centerContainer = function () {\n  if (this.center) {\n    this.container.classList.add('o-ads--center');\n  }\n\n  return this;\n};\n/**\n * Add a label class to the main container\n */\n\n\nSlot.prototype.labelContainer = function () {\n  let className;\n\n  if (this.label === true || this.label === 'left') {\n    className = 'label-left';\n  } else if (this.label === 'right') {\n    className = 'label-right';\n  }\n\n  if (className && !config$1('displayLabelWithBorders')) {\n    this.container.classList.add(`o-ads--${className}`);\n  }\n\n  return this;\n};\n\n/** @typedef {import(\"$typings/index\")} Advertising */\n\n/**\n * @param {Advertising.Slot} slot\n * @returns {string}\n */\nfunction getSlotSizes(slot) {\n  if (!Array.isArray(slot.sizes)) return \"responsive slot\";\n  const sizes = [];\n\n  for (const size of slot.sizes) {\n    sizes.push(Array.isArray(size) ? size.join(\"×\") : size);\n  }\n\n  return sizes.join(\", \");\n}\n/**\n * @param {Advertising.Slot} slot\n * @returns {string}\n */\n\n\nfunction getSlotTargeting({\n  targeting\n}) {\n  const params = [];\n\n  for (const [key, val] of Object.entries(targeting)) {\n    params.push(`${key}=${val}`);\n  }\n\n  return params.join(\", \");\n}\n/**\n * @param {Advertising.Slot} slot\n * @returns {string}\n */\n\n\nfunction getSlotGPTSize({\n  gpt\n}) {\n  if (gpt.isEmpty) return \"empty\";\n  if (!Array.isArray(gpt.size)) return \"N/A\";\n  return gpt.size.join(\"×\");\n}\n/**\n * Use a type predicate to distinguish between the `Slots` instance's properties\n * @type {(o: Advertising.Slot | IntersectionObserver) => o is Advertising.Slot }\n */\n\n\nconst isSlot = o => \"name\" in o;\n/**\n * @param {(Advertising.Slot | IntersectionObserver)[]} slots\n */\n\n\nfunction debug$1(slots) {\n  const data = [];\n\n  for (const slot of slots) {\n    if (isSlot(slot)) {\n      const row = {\n        name: slot.name,\n        \"unit name\": slot.gpt.unitName,\n        \"creative id\": slot.gpt.creativeId || \"N/A\",\n        \"line item id\": slot.gpt.lineItemId || \"N/A\",\n        size: getSlotGPTSize(slot),\n        sizes: getSlotSizes(slot),\n        targeting: getSlotTargeting(slot)\n      };\n      data.push(row);\n    }\n  }\n\n  console.group(\"Creatives\");\n  console.table(data);\n  console.groupEnd();\n  return data;\n}\n\n/* eslint no-inner-declarations: 1 */\nlet screensize = null;\n/**\n * The Slots instance tracks all ad slots on the page\n * configures global page events used by a slot and\n * provides utlity methods that act on all slots\n * @constructor\n */\n\nfunction Slots() {//eslint-disable-line no-empty\n}\n\nfunction invokeMethodOnSlots(names, method, callback) {\n  let slots = [];\n  names = names || Object.keys(this);\n  /* istanbul ignore else\t*/\n\n  if (utils.isNonEmptyString(names)) {\n    slots.push(names);\n  } else if (utils.isArray(names)) {\n    slots = names;\n  }\n\n  slots.forEach(run.bind(null, this, method));\n\n  if (utils.isFunction(callback)) {\n    callback.call(this, slots);\n  }\n\n  return this;\n}\n/*\n * Either run a method or fire an event on the named slot.\n * @private\n * @param slots the slots object\n */\n\n\nfunction run(slots, action, name) {\n  const slot = slots[name];\n\n  if (slot) {\n    if (utils.isFunction(slot[action])) {\n      slot[action]();\n    } else {\n      if (utils.isFunction(slot.fire)) {\n        slot.fire(action);\n      } else {\n        utils.log.warn(\"Attempted to %s on a non-slot %s\", action, name);\n      }\n    }\n  } else {\n    utils.log.warn(\"Attempted to %s non-existant slot %s\", action, name);\n  }\n}\n\nfunction findFormatBySize(size) {\n  if (!size) {\n    return false;\n  }\n\n  const formats = config$1(\"formats\");\n\n  for (const prop in formats) {\n    /* istanbul ignore else\t*/\n    if (formats.hasOwnProperty(prop)) {\n      let sizes = formats[prop].sizes;\n      sizes = utils.isArray(sizes[0]) ? sizes : [sizes];\n      const match = sizes.filter(function (s) {\n        return s[0] === parseInt(size[0], 10) && s[1] === parseInt(size[1], 10);\n      });\n\n      if (match.length) {\n        return prop;\n      }\n    }\n  }\n}\n/**\n * Given a slot name or an array of slot names will collapse the slots using the collapse method on the slot\n */\n\n\nSlots.prototype.collapse = function (names) {\n  return invokeMethodOnSlots.call(this, names, \"collapse\");\n};\n/**\n * Given a slot name or an array of slot names will uncollapse the slots using the uncollapse method on the slot\n */\n\n\nSlots.prototype.uncollapse = function (names) {\n  return invokeMethodOnSlots.call(this, names, \"uncollapse\");\n};\n/**\n * Given a slot name or an array of slot names of slotnames will refresh the slots using the refresh method on the slot\n */\n\n\nSlots.prototype.refresh = function (names) {\n  return invokeMethodOnSlots.call(this, names, \"refresh\");\n};\n/**\n * Given a slot name or an array of slot names will clear the slots using the clear method on the slot\n */\n\n\nSlots.prototype.clear = function (names) {\n  return invokeMethodOnSlots.call(this, names, \"clear\");\n};\n/**\n * Given a slot name or an array of slot names will destroy the slots using the destroySlot method on the slot and remove the reference to the slot\n */\n\n\nSlots.prototype.destroy = function (names) {\n  return invokeMethodOnSlots.call(this, names, \"destroy\", function (names) {\n    names.forEach(name => {\n      this[name] = null;\n      delete this[name];\n    });\n  });\n};\n/**\n * Given a slot name will submit a delayed impression for the slot\n */\n\n\nSlots.prototype.submitImpression = function (name) {\n  return invokeMethodOnSlots.call(this, name, \"submitImpression\");\n};\n/**\n * Confirms a container in the page exists and creates a Slot object\n */\n\n\nSlots.prototype.initSlot = function (container) {\n  // if container is a string this is a legacy implementation using ids\n  // find the element and remove the ID in favour of a data attribute\n  if (utils.isString(container)) {\n    container = document.getElementById(container) || document.querySelector(`[data-o-ads-name=\"${container}\"]`);\n\n    if (container && container.id) {\n      container.setAttribute(\"data-o-ads-name\", container.id);\n      container.removeAttribute(\"id\");\n    }\n  } // if not an element or we can't find it in the DOM exit\n\n\n  if (!utils.isElement(container)) {\n    utils.log.error(\"slot container must be an element!\", container);\n    return false;\n  } // add the aria hidden attribute\n\n\n  container.setAttribute(\"aria-hidden\", \"true\"); // pass the method to retrieve or create the single IntersectionObserver instance\n\n  const slot = new Slot(container, screensize, this.initLazyLoading.bind(this));\n  /* istanbul ignore else\t*/\n\n  if (slot && !this[slot.name]) {\n    this[slot.name] = slot;\n    slot.fire(\"slotReady\");\n  } else if (this[slot.name]) {\n    utils.log.error(\"slot %s is already defined!\", slot.name);\n  }\n\n  return slot;\n};\n\nSlots.prototype.initRefresh = function () {\n  if (config$1(\"flags\").refresh && config$1(\"refresh\")) {\n    const data = config$1(\"refresh\");\n    this.refreshCount = 0;\n    /* istanbul ignore else\t*/\n\n    if (data.time && !data.inview) {\n      const refresh = () => {\n        /* istanbul ignore else */\n        if (!data.max || this.refreshCount++ < data.max) {\n          this.refresh();\n        } else if (this.refreshCount >= data.max) {\n          clearInterval(refresh);\n        }\n      };\n\n      setInterval(refresh, (parseFloat(data.time) || 1) * 1000);\n    }\n  }\n\n  return this;\n};\n/*\n *\tlistens for the rendered event from a slot and fires the slotExpand event,\n * after extending the slot with information from the server.\n */\n\n\nSlots.prototype.initRendered = function () {\n  utils.on(\"slotRenderStart\", function (slots, event) {\n    const slot = slots[event.detail.name];\n    /* istanbul ignore else\t*/\n\n    if (slot) {\n      utils.extend(slot[slot.server], event.detail[slot.server]);\n      const size = event.detail.gpt.size;\n      const format = findFormatBySize(size);\n      slot.setFormatLoaded(format);\n      slot.maximise(size);\n      slot.fire(\"slotExpand\", event.detail);\n    }\n  }.bind(null, this));\n  return this;\n};\n/*\n * if responsive configuration exists listen for breakpoint changes\n */\n\n\nSlots.prototype.initResponsive = function () {\n  const breakpoints = config$1(\"responsive\");\n  /* istanbul ignore else\t*/\n\n  if (utils.isObject(breakpoints)) {\n    screensize = utils.responsive(breakpoints, onBreakpointChange.bind(null, this));\n  }\n\n  return this;\n};\n/*\n * called when a responsive breakpoint is crossed though window resizing or orientation change.\n */\n\n\nfunction onBreakpointChange(slots, screensize) {\n  slots.forEach(function (slot) {\n    /* istanbul ignore else\t*/\n    if (slot) {\n      // ADS-766 if format name is Responsive then we have requested a responsive creative and do not want to request new ads at different breakpoints\n\n      /* istanbul ignore else\t*/\n      const isCurrentlyResponsive = slot.container && slot.container.getAttribute(\"data-o-ads-loaded\") === \"Responsive\";\n      const stillWantsResponsive = slot.sizes[screensize] && slot.sizes[screensize].filter(size => findFormatBySize(size) === \"Responsive\").length > 0;\n\n      if (isCurrentlyResponsive && stillWantsResponsive) {\n        return false;\n      }\n\n      slot.screensize = screensize;\n      slot.fire(\"breakpoint\", {\n        screensize: screensize\n      });\n    }\n  });\n}\n/*\n * Initialise the postMessage API\n */\n\n\nSlots.prototype.initPostMessage = function () {\n  // Listen for messages coming from ads\n  window.addEventListener(\"message\", pmHandler.bind(null, this), false);\n\n  function pmHandler(slots, event) {\n    const data = utils.messenger.parse(event.data);\n    /* istanbul ignore else\tdon't process messages with a non oAds type*/\n\n    if (data.type && (/^oAds\\./.test(data.type) || /^touch/.test(data.type))) {\n      const type = data.type.replace(\"oAds.\", \"\"); // Make sure the message is coming from an identified ad slot\n\n      const slotName = utils.iframeToSlotName(event.source.window);\n      const slot = slots[slotName] || false;\n\n      if (!slot) {\n        utils.log.error(\"Message received from unidentified slot\");\n        return;\n      } // TODO: Remove adIframeLoaded once we can tag onto GPTs `slotRenderEnded` event\n\n\n      if (type === \"adIframeLoaded\") {\n        slot.fire(\"slotRenderEnded\");\n      } else if (type === \"slotClass\" && data.slotClass) {\n        slot.addClass(data.slotClass);\n      } // Received message to Collapse ad slot.\n      else if (type === \"collapse\") {\n        slot.fire(\"slotCollapsed\");\n        slot.collapse();\n      } // Received touch events from ad slot iframe\n\n      /* istanbul ignore else*/\n      else if (/^touch/.test(data.type)) {\n        slot.fire(\"touch\", data);\n      } else {\n        utils.log.error(\"Unknown message received from o-ads-embed\");\n      }\n    }\n  }\n}; // remove any observers tied to elements no longer in the DOM\n// e.g. app page has been swiped out from the gallery\n\n\nSlots.prototype.flushLazyLoading = function () {\n  this.lazyLoadingObservers = this.lazyLoadingObservers.filter(observer => {\n    return Boolean(!observer.root || document.contains(observer.root));\n  });\n};\n\nSlots.prototype.initLazyLoading = function (slotConfig) {\n  const lazyLoadingConfig = config$1(\"lazyLoad\") || slotConfig | {};\n  this.lazyLoadingObservers = this.lazyLoadingObservers || [];\n  this.flushLazyLoading(); // find any pre-existing observers\n\n  let lazyLoadingObserver = this.lazyLoadingObservers.find(observer => {\n    // deliberately double-equals to match null and undefined where the viewport is being observed\n    return lazyLoadingConfig.root == observer.root; // eslint-disable-line eqeqeq\n  });\n\n  function onChange(changes) {\n    //Execute the changes in the order they appear on the page. This is because the top slot often determines what the lower slots display.\n\n    /* istanbul ignore next */\n    changes.filter(a => a.intersectionRect.height || a.intersectionRect.width || a.intersectionRect.top || a.intersectionRect.left).sort((a, b) => a.intersectionRect.top - b.intersectionRect.top).forEach(change => {\n      const slotName = change.target.getAttribute(\"data-o-ads-name\");\n      /* istanbul ignore else */\n\n      if (slotName) {\n        invokeMethodOnSlots.call(this, slotName, \"render\");\n      }\n    });\n  } // If we don't already have an instance of the observer, and it is enabled globally or on a slot (force), then create one.\n\n  /* istanbul ignore else\t*/\n\n\n  if (\"IntersectionObserver\" in window && !lazyLoadingObserver && Boolean(lazyLoadingConfig)) {\n    const options = {};\n    /* istanbul ignore else\t*/\n\n    if (typeof lazyLoadingConfig === \"object\") {\n      /* istanbul ignore else\t*/\n      if (lazyLoadingConfig.viewportMargin) {\n        options.rootMargin = lazyLoadingConfig.viewportMargin;\n      }\n      /* istanbul ignore else\t*/\n\n\n      if (lazyLoadingConfig.threshold) {\n        options.threshold = lazyLoadingConfig.threshold;\n      }\n\n      options.root = lazyLoadingConfig.root || null;\n    }\n\n    lazyLoadingObserver = new IntersectionObserver(onChange.bind(this), options);\n    this.lazyLoadingObservers.push(lazyLoadingObserver);\n  }\n\n  return lazyLoadingObserver;\n};\n\nSlots.prototype.forEach = function (fn) {\n  Object.keys(this).forEach(name => {\n    const slot = this[name];\n    /* istanbul ignore else\t*/\n\n    if (slot instanceof Slot) {\n      fn.call(this, slot);\n    }\n  });\n  return this;\n};\n/*\n * Initialise slots\n */\n\n\nSlots.prototype.init = function () {\n  this.initRefresh();\n  this.initRendered();\n  this.initResponsive();\n  this.initPostMessage();\n  this.initLazyLoading();\n};\n\nSlots.prototype.debug = function () {\n  debug$1(Object.values(this));\n};\n\nvar slots = new Slots();\n\nlet parameters = {};\n\nfunction Targeting() {} //eslint-disable-line no-empty-function\n\n\nTargeting.prototype.get = function () {\n  const methods = {\n    socialReferrer: this.getSocialReferrer,\n    timestamp: this.timestamp,\n    responsive: this.responsive\n  };\n  utils.extend(parameters, this.socialFlow(), this.getVersion());\n\n  for (const item in methods) {\n    /* istanbul ignore else  */\n    if (methods.hasOwnProperty(item)) {\n      utils.extend(parameters, methods[item]());\n    }\n  }\n\n  return parameters;\n};\n\nTargeting.prototype.add = function (obj) {\n  /* istanbul ignore else  */\n  if (utils.isPlainObject(obj)) {\n    utils.extend(parameters, obj);\n  }\n};\n\nTargeting.prototype.remove = function (key) {\n  /* istanbul ignore else */\n  if (parameters[key]) {\n    delete parameters[key];\n  }\n};\n\nTargeting.prototype.clear = function () {\n  parameters = {};\n};\n\nTargeting.prototype.getVersion = function () {\n  if (config$1('passOAdsVersion')) {\n    return {\n      OADS_VERSION: utils.getVersion()\n    };\n  }\n};\n/**\n * If there is a query parameter called socialflow=xxx, we need to add it\n * as a tag\n */\n\n\nTargeting.prototype.socialFlow = function () {\n  const sf = utils.getQueryParamByName('socialflow');\n\n  if (sf) {\n    return {\n      socialflow: sf\n    };\n  }\n};\n\nTargeting.prototype.getSocialReferrer = function () {\n  let codedValue;\n  const referrer = utils.getReferrer(); // TODO: add on.ft.com\n\n  const lookup = {\n    't.co': 'twi',\n    'facebook.com': 'fac',\n    'linkedin.com': 'lin',\n    'drudgereport.com': 'dru',\n    'dianomi.com': 'dia',\n    google: 'goo'\n  };\n  Object.keys(lookup).forEach(url => {\n    const refererRegex = new RegExp(`^http(|s)://(www.)*(${url})`);\n    /* istanbul ignore else  */\n\n    if (refererRegex.test(referrer)) {\n      codedValue = lookup[url];\n    }\n  });\n  return codedValue && {\n    socref: codedValue\n  } || {};\n};\n\nTargeting.prototype.searchTerm = function () {\n  const qs = utils.hash(utils.getQueryString(), /&|;/, '=');\n  let keywords = qs.q || qs.s || qs.query || qs.queryText || qs.searchField || undefined;\n  /* istanbul ignore else\t*/\n\n  if (keywords && keywords !== '') {\n    keywords = unescape(keywords).toLowerCase().replace(/[';^+]/g, ' ').replace(/\\s+/g, ' ').trim();\n  }\n\n  return {\n    kw: keywords\n  };\n};\n\nTargeting.prototype.timestamp = function () {\n  return {\n    ts: utils.getTimestamp()\n  };\n};\n\nTargeting.prototype.responsive = function () {\n  return config$1('responsive') ? {\n    res: utils.responsive.getCurrent()\n  } : {};\n};\n\nTargeting.prototype.debug = function () {\n  const log = utils.log;\n  const parameters = this.get();\n  /* istanbul ignore else  */\n\n  if (Object.keys(parameters).length !== 0) {\n    log.start('Targeting');\n    log.attributeTable(this.get());\n    log.end();\n  }\n};\n\nvar targeting = new Targeting();\n\nconst SEARCH_PARAMS = ['q', 'kw'];\n/**\n * @typedef {{ [key: string]: string[] }} FilterDict\n */\n\n/**\n * Remove unwanted params from nested query strings\n *\n * @param   {string}   nestedParams the URIencoded nested params\n * @param   {string[]} keysToStrip  the parameters to remove\n *\n * @return  {string}               [return description]\n */\n\nfunction filterNestedParams(nestedParams, keysToStrip) {\n  if (!keysToStrip || keysToStrip.length < 1) {\n    return nestedParams;\n  }\n\n  const childParams = new URLSearchParams(nestedParams);\n\n  for (const key of keysToStrip) {\n    childParams.delete(key);\n  }\n\n  return childParams.toString();\n}\n/**\n * Purge a URL of sensitive data in query strings\n *\n * Given the URL\n * ```url\n * https://www.ft.com/search?q=goog&cust_params=a%3D1%26b%3D2%26c%3D3%26d%3D4\n * ```\n * Supplying an object in the form\n * ```\n * {\n *   root: ['q', 'kw'],\n *   cust_params: ['a', 'c']\n * }\n * ```\n * will remove `q` from the main query string and `a`, `c` from the nested params\n * under `cust_params`:\n * ```url\n * https://www.ft.com/search?cust_params=b=2%26d%3D4\n * ```\n *\n * @param   {Object}  params\n * @param   {string | Location}  params.href     The base URL or `window.location`\n * @param   {FilterDict}         params.filters  The dictionary of params to be removed\n *\n * @return  {string}              A URL that has been stripped of the supplied params\n */\n\nfunction stripUrlParams({\n  href,\n  filters\n}) {\n  // @ts-ignore: URL absolutely accepts Location!\n  const url = new URL(href);\n\n  for (const [param, filter] of Object.entries(filters)) {\n    if (param === 'root') {\n      // Strip parameters from the main query string\n      for (const key of filter) {\n        url.searchParams.delete(key);\n      }\n    } else {\n      // Handle nested parameters\n      const nestedParams = url.searchParams.get(param);\n\n      if (nestedParams) {\n        url.searchParams.set(param, filterNestedParams(nestedParams, filter));\n      }\n    }\n  }\n\n  return url.href;\n}\n\n/*globals googletag: true */\nconst DEFAULT_LAZY_LOAD = {\n  fetchMarginPercent: 500,\n  renderMarginPercent: 200,\n  mobileScaling: 2.0\n};\nconst DEFAULT_COLLAPSE_MODE = 'never';\nlet breakpoints = false;\n/*\n//###########################\n// Initialisation handlers ##\n//###########################\n*/\n\n/*\n * Initialise Google publisher tags functionality\n */\n\nfunction init() {\n  const gptConfig = config$1('gpt') || {};\n  breakpoints = config$1('responsive');\n  loadGPT();\n  utils.on('slotReady', onReady.bind(null, slotMethods));\n  utils.on('slotCanRender', onRender);\n  utils.on('refresh', onRefresh);\n  utils.on('resize', onResize);\n  googletag.cmd.push(setup.bind(null, gptConfig));\n}\n/*\n * initalise the googletag global namespace and add the google publish tags library to the page\n */\n\n\nfunction loadGPT() {\n  if (!window.googletag) {\n    // set up a place holder for the gpt code downloaded from google\n    window.googletag = {}; // this is a command queue used by GPT any methods added to it will be\n    // executed when GPT code is available, if GPT is already available they\n    // will be executed immediately\n\n    window.googletag.cmd = [];\n  }\n\n  utils.attach('//securepubads.g.doubleclick.net/tag/js/gpt.js', true, () => {\n    utils.broadcast('serverScriptLoaded');\n  }, err => {\n    utils.broadcast('adServerLoadError', err);\n  });\n}\n/*\n//#################################\n// Global configuration handlers ##\n//#################################\n*/\n\n/*\n * Configure the GPT library for the current page\n * this method is pushed onto the googletag command queue and run\n * when the library is available\n */\n\n\nfunction setup(gptConfig) {\n  const nonPersonalized = config$1('nonPersonalized') ? 1 : 0;\n  googletag.pubads().addEventListener('slotRenderEnded', onRenderEnded);\n  enableCompanions(gptConfig);\n  setRenderingMode(gptConfig);\n  setPageTargeting(targeting.get());\n  setPageCollapseEmpty();\n\n  if (gptConfig.hasOwnProperty('enableLazyLoad')) {\n    enableLazyLoad(gptConfig.enableLazyLoad);\n  }\n\n  const url = stripUrlParams({\n    href: window.location.href,\n    filters: {\n      root: SEARCH_PARAMS\n    }\n  });\n  googletag.enableServices();\n  googletag.pubads().setTargeting('url', url);\n  googletag.pubads().setRequestNonPersonalizedAds(nonPersonalized);\n  return true;\n}\n/**\n * Enables GPT's Lazy Loading for serving ads only when it's necessary.\n * \t\tThe lazy load config ooptions are:\n *\n * \t\t\t- fetchMarginPercent,\t\tminimum distance from the current viewport a slot\n * \t\t\t\t\tmust be before we fetch the ad as a percentage of viewport size.\n * \t\t\t\t\t0 means \"when the slot enters the viewport\",\n * \t\t\t\t\t100 means \"when the ad is 1 viewport away\"\n *\n * \t\t\t- renderMarginPercent,\tminimum distance from the current viewport a slot\n * \t\t\t\t\tmust be before we render an ad.\n * \t\t\t\t\tThis allows for prefetching the ad, but waiting to render and\n * \t\t\t\t\tdownload other subresources. The value works just like\n * \t\t\t\t\tfetchMarginPercent as a percentage of viewport.\n *\n * \t\t\t- mobileScaling,\t\t\t\ta multiplier applied to margins on mobile devices.\n * \t\t\t\t\tThis allows varying margins on mobile vs. desktop. For example,\n * \t\t\t\t\ta mobileScaling of 2.0 will multiply all margins by 2 on mobile\n * \t\t\t\t\tdevices, increasing the minimum distance a slot can be before\n * \t\t\t\t\tfetching and rendering.\n *\n * @param {object|boolean} lazyLoadConf The lazy load config object or a boolean.\n * @returns {boolean} true if the object is of type Array, otherwise false\n */\n\n\nfunction enableLazyLoad(lazyLoadConf) {\n  if (lazyLoadConf && (typeof lazyLoadConf === 'object' || typeof lazyLoadConf === 'boolean')) {\n    const opts = Object.assign({}, DEFAULT_LAZY_LOAD, typeof lazyLoadConf === 'object' ? lazyLoadConf : {});\n    window.googletag.pubads().enableLazyLoad(opts);\n  } else {\n    utils.log.warn('lazyLoadConf must be either an object or a boolean', lazyLoadConf);\n  }\n}\n/*\n * set the gpt rendering mode to either sync or async\n * default is async\n */\n\n\nfunction setRenderingMode(gptConfig) {\n  const rendering = gptConfig.rendering;\n\n  if (rendering === 'sync') {\n    googletag.pubads().enableSyncRendering();\n  } else if (rendering === 'sra') {\n    googletag.pubads().enableSingleRequest();\n  } else {\n    googletag.pubads().enableAsyncRendering();\n  }\n}\n/**\n * Adds page targeting to GPT ad calls\n * @name setPageTargeting\n * @memberof GPT\n * @lends GPT\n */\n\n\nfunction setPageTargeting(targetingData) {\n  if (utils.isPlainObject(targetingData)) {\n    googletag.cmd.push(() => {\n      const pubads = googletag.pubads();\n      Object.keys(targetingData).forEach(key => {\n        // Convert to string as boolean values are invalid arguments for GPT setTargeting()\n        pubads.setTargeting(key, String(targetingData[key]));\n      });\n    });\n  } else {\n    /* istanbul ignore next  */\n    utils.log.warn('invalid targeting object passed', targetingData);\n  }\n\n  return targetingData;\n}\n/**\n * Removes page targeting for a specified key from GPT ad calls\n */\n\n\nfunction clearPageTargetingForKey(key) {\n  if (!window.googletag) {\n    utils.log.warn('Attempting to clear page targeting before the GPT library has initialized');\n    return;\n  }\n\n  if (!key) {\n    utils.log.warn('Refusing to unset all keys - a key must be specified');\n    return;\n  }\n\n  googletag.cmd.push(() => {\n    googletag.pubads().clearTargeting(key);\n  });\n}\n/**\n * Sets behaviour of empty slots can be 'after', 'before' or 'never'\n * * 'after' collapse slots that return an empty ad\n * * 'before' collapses all slots and only displays them when an ad is found\n * * 'never' does not collapse any empty slot, the collapseEmptyDivs method is not called in that case\n */\n\n\nfunction setPageCollapseEmpty() {\n  const mode = config$1('collapseEmpty');\n\n  if (mode === 'before') {\n    googletag.pubads().collapseEmptyDivs(true);\n  }\n\n  if (mode === 'after') {\n    googletag.pubads().collapseEmptyDivs(false);\n  }\n}\n/**\n * When companions are enabled we delay the rendering of ad slots until\n * either a master is returned or all slots are returned without a master\n */\n\n\nfunction enableCompanions(gptConfig) {\n  if (gptConfig.companions) {\n    googletag.pubads().disableInitialLoad();\n    googletag.companionAds().setRefreshUnfilledSlots(true);\n  }\n}\n/*\n//##################\n// Event handlers ##\n//##################\n*/\n\n/*\n * Event handler for when a slot is ready for an ad to rendered\n */\n\n\nfunction onReady(slotMethods, event) {\n  const slot = event.detail.slot;\n  /* istanbul ignore else  */\n\n  if (slot.server === 'gpt') {\n    slot.gpt = {}; // extend the slot with gpt methods\n\n    utils.extend(slot, slotMethods); // setup the gpt configuration the ad\n\n    googletag.cmd.push(() => {\n      slot.defineSlot().addServices().setCollapseEmpty().setTargeting().setURL();\n\n      if (!slot.defer && slot.hasValidSize()) {\n        slot.display();\n      }\n    });\n  }\n}\n/*\n * Render is called when a slot is not rendered when the ready event fires\n */\n\n\nfunction onRender(event) {\n  const slot = event.detail.slot;\n  /* istanbul ignore else  */\n\n  if (utils.isFunction(slot.display)) {\n    slot.display();\n  }\n}\n/*\n * refresh is called when a slot requests the ad be flipped\n */\n\n\nfunction onRefresh(event) {\n  window.googletag.cmd.push(() => {\n    const targeting = event.detail.targeting;\n\n    if (utils.isPlainObject(targeting)) {\n      Object.keys(targeting).forEach(name => {\n        event.detail.slot.gpt.slot.setTargeting(name, targeting[name]);\n      });\n    }\n\n    googletag.pubads().refresh([event.detail.slot.gpt.slot]);\n  });\n  return this;\n}\n\nfunction onResize(event) {\n  const iframe = event.detail.slot.gpt.iframe;\n  const size = event.detail.size;\n  iframe.width = size[0];\n  iframe.height = size[1];\n}\n/*\n * function passed to the gpt library that is run when an ad completes rendering\n */\n\n\nfunction onRenderEnded(event) {\n  const data = {\n    gpt: {}\n  };\n  const gptSlotId = event.slot.getSlotId();\n  const domId = gptSlotId.getDomId().split('-');\n  const iframeId = `google_ads_iframe_${gptSlotId.getId()}`;\n  data.type = domId.pop();\n  data.name = domId.join('-');\n  data.size = event.size && event.size.length ? event.size.join() : '';\n  data.creativeId = event.creativeId;\n  const slotTargeting = event.slot.getTargetingMap && event.slot.getTargetingMap();\n\n  if (slotTargeting && slotTargeting.pos) {\n    data.pos = slotTargeting.pos.length ? slotTargeting.pos.join() : '';\n  }\n\n  const detail = data.gpt;\n  detail.isEmpty = event.isEmpty;\n  detail.size = event.size;\n  detail.creativeId = event.creativeId;\n  detail.lineItemId = event.lineItemId;\n  detail.serviceName = event.serviceName;\n  const iFrameEl = document.getElementById(iframeId);\n\n  if (iFrameEl) {\n    iFrameEl.setAttribute('tabindex', '-1');\n    iFrameEl.setAttribute('aria-hidden', 'true');\n    iFrameEl.setAttribute('role', 'presentation');\n    iFrameEl.setAttribute('title', 'Advertisement');\n    detail.iframe = iFrameEl;\n  } else {\n    /* istanbul ignore next */\n    utils.log.warn('No iFrame found matching GPT SlotID');\n  }\n\n  utils.broadcast('slotRenderStart', data);\n}\n/*\n//################\n// Slot methods ##\n//################\n* Set of methods extended on to the slot constructor for GPT served slots\n*/\n\n\nconst slotMethods = {\n  /**\n   * define a GPT slot\n   */\n  defineSlot: function () {\n    window.googletag.cmd.push(() => {\n      this.gpt.id = `${this.name}-gpt`;\n      this.inner.setAttribute('id', this.gpt.id);\n      this.setUnitName();\n\n      if (!this.outOfPage) {\n        if (breakpoints && utils.isObject(this.sizes)) {\n          this.initResponsive();\n          this.gpt.slot = googletag.defineSlot(this.gpt.unitName, [0, 0], this.gpt.id).defineSizeMapping(this.gpt.sizes);\n        } else {\n          this.gpt.slot = googletag.defineSlot(this.gpt.unitName, this.sizes, this.gpt.id);\n        }\n      } else {\n        this.gpt.slot = googletag.defineOutOfPageSlot(this.gpt.unitName, this.gpt.id);\n      }\n    });\n    return this;\n  },\n  clearSlot: function (gptSlot) {\n    if (window.googletag.pubadsReady && window.googletag.pubads) {\n      gptSlot = gptSlot || this.gpt.slot;\n      return googletag.pubads().clear([gptSlot]);\n    } else {\n      return false;\n    }\n  },\n  initResponsive: function () {\n    window.googletag.cmd.push(() => {\n      utils.on('breakpoint', event => {\n        const slot = event.detail.slot;\n        const screensize = event.detail.screensize;\n        updatePageTargeting({\n          res: screensize\n        });\n\n        if (slot.hasValidSize(screensize)) {\n          /* istanbul ignore else  */\n          if (slot.gpt.iframe) {\n            slot.fire('refresh');\n          } else if (!this.defer) {\n            slot.display();\n          }\n        }\n      }, this.container);\n      const mapping = googletag.sizeMapping();\n      Object.keys(breakpoints).forEach(breakpoint => {\n        if (this.sizes[breakpoint]) {\n          mapping.addSize(breakpoints[breakpoint], this.sizes[breakpoint]);\n        }\n      });\n      this.gpt.sizes = mapping.build();\n    });\n    return this;\n  },\n\n  /**\n   * Tell gpt to destroy the slot and its metadata\n   */\n  destroySlot: function (gptSlot) {\n    if (window.googletag.pubadsReady && window.googletag.pubads) {\n      gptSlot = gptSlot || this.gpt.slot;\n      return googletag.destroySlots([gptSlot]);\n    } else {\n      return false;\n    }\n  },\n\n  /*\n   *\tTell gpt to request an ad\n   */\n  display: function () {\n    window.googletag.cmd.push(() => {\n      this.fire('slotGoRender');\n      googletag.display(this.gpt.id);\n    });\n    return this;\n  },\n\n  /**\n   * Set the DFP unit name for the slot.\n   */\n  setUnitName: function () {\n    window.googletag.cmd.push(() => {\n      let unitName;\n      const gpt = config$1('gpt') || {};\n      const attr = this.container.getAttribute('data-o-ads-gpt-unit-name');\n\n      if (utils.isNonEmptyString(attr)) {\n        unitName = attr;\n      } else if (utils.isNonEmptyString(gpt.unitName)) {\n        unitName = gpt.unitName;\n      } else {\n        const network = gpt.network;\n        const site = gpt.site;\n        const zone = gpt.zone;\n        unitName = `/${network}`;\n        unitName += utils.isNonEmptyString(site) ? `/${site}` : '';\n        unitName += utils.isNonEmptyString(zone) ? `/${zone}` : '';\n      }\n\n      this.gpt.unitName = unitName;\n    });\n    return this;\n  },\n\n  /**\n   * Add the slot to the pub ads service and add a companion service if configured\n   */\n  addServices: function (gptSlot) {\n    window.googletag.cmd.push(() => {\n      const gpt = config$1('gpt') || {};\n      gptSlot = gptSlot || this.gpt.slot;\n      gptSlot.addService(googletag.pubads());\n\n      if (gpt.companions && this.companion !== false) {\n        gptSlot.addService(googletag.companionAds());\n      }\n    });\n    return this;\n  },\n\n  /**\n   * Sets the GPT collapse empty mode for a given slot\n   * values can be 'after', 'before', 'never'\n   */\n  setCollapseEmpty: function () {\n    window.googletag.cmd.push(() => {\n      const mode = this.collapseEmpty || config$1('collapseEmpty') || DEFAULT_COLLAPSE_MODE;\n\n      if (mode === 'before') {\n        this.gpt.slot.setCollapseEmptyDiv(true, true);\n      } else if (mode === 'after') {\n        this.gpt.slot.setCollapseEmptyDiv(true);\n      } else if (mode === 'never') {\n        this.gpt.slot.setCollapseEmptyDiv(false);\n      }\n    });\n    return this;\n  },\n  submitGptImpression: function () {\n    /* istanbul ignore next  */\n    function getImpressionURL(iframe) {\n      const trackingUrlElement = iframe.contentWindow.document.querySelector('[data-o-ads-impression-url]');\n\n      if (trackingUrlElement) {\n        return trackingUrlElement.dataset.oAdsImpressionUrl;\n      } else {\n        utils.log.warn('Impression URL not found, this is set via a creative template.');\n        return false;\n      }\n    }\n\n    if (this.outOfPage && this.gpt.iframe) {\n      const impressionURL = getImpressionURL(this.gpt.iframe);\n      /* istanbul ignore next  */\n\n      if (impressionURL) {\n        utils.attach(impressionURL, true, () => {\n          utils.log.info('Impression Url requested');\n        }, () => {\n          utils.log.info('CORS request to submit an impression failed');\n        }, true);\n      }\n    } else {\n      utils.log.warn('Attempting to call submitImpression on a non-oop slot');\n    }\n  },\n\n  /**\n   * Sets page url to be sent to google\n   * prevents later url changes via javascript from breaking the ads\n   */\n  setURL: function (gptSlot) {\n    window.googletag.cmd.push(() => {\n      gptSlot = gptSlot || this.gpt.slot;\n      const canonical = config$1('canonical');\n      gptSlot.set('page_url', canonical ? canonical : utils.getLocation());\n    });\n    return this;\n  },\n\n  /**\n   * Adds key values from a given object to the slot targeting\n   */\n  setTargeting: function (gptSlot) {\n    window.googletag.cmd.push(() => {\n      gptSlot = gptSlot || this.gpt.slot;\n      /* istanbul ignore else  */\n\n      if (utils.isPlainObject(this.targeting)) {\n        Object.keys(this.targeting).forEach(param => {\n          gptSlot.setTargeting(param, this.targeting[param]);\n        });\n      }\n    });\n    return this;\n  }\n};\n/*\n//####################\n// External methods ##\n//####################\n*/\n\n/**\n * The correlator is a random number added to ad calls.\n * It is used by the ad server to determine which impressions where served to the same page\n * Updating is used to tell the ad server to treat subsequent ad calls as being on a new page\n */\n\nfunction updateCorrelator() {\n  utils.log.warn('[DEPRECATED]: Updatecorrelator is being phased out by google and removed from o-ads in future releases.');\n  googletag.cmd.push(() => {\n    googletag.pubads().updateCorrelator();\n  });\n}\n\nfunction getCorrelator() {\n  if (window.googletag && window.googletag.pubads) {\n    return googletag.pubads().getCorrelator();\n  }\n}\n\nfunction clearPageTargeting() {\n  if (window.googletag) {\n    googletag.cmd.push(() => {\n      googletag.pubads().clearTargeting();\n    });\n  } else {\n    utils.log.warn('Attempting to clear page targeting before the GPT library has initialized');\n  }\n}\n\nfunction updatePageTargeting(override) {\n  if (window.googletag) {\n    const params = utils.isPlainObject(override) ? override : targeting.get();\n    setPageTargeting(params);\n  } else {\n    utils.log.warn('Attempting to set page targeting before the GPT library has initialized');\n  }\n} //https://developers.google.com/doubleclick-gpt/common_implementation_mistakes#scenario-2:-checking-the-googletag-object-to-know-whether-gpt-is-ready\n\n\nfunction hasGPTLoaded() {\n  if (window.googletag && window.googletag.apiReady) {\n    return true;\n  } else {\n    return false;\n  }\n}\n\nfunction debug() {\n  const log = utils.log;\n  const conf = config$1('gpt');\n\n  if (!conf) {\n    return;\n  }\n\n  log.start('gpt');\n  log.attributeTable(conf);\n  log.end();\n}\n\nvar gpt = {\n  init,\n  setup,\n  updateCorrelator,\n  getCorrelator,\n  updatePageTargeting,\n  clearPageTargeting,\n  clearPageTargetingForKey,\n  hasGPTLoaded,\n  loadGPT,\n  debug\n};\n\n/* eslint valid-jsdoc: 0 */\n\nfunction Ads() {\n  addDOMEventListener();\n\n  if (window && !window.oAds) {\n    window.oAds = this;\n  }\n}\n\nconfig$1.init = init$1;\nconfig$1.clear = clear; // bung all our modules on the protoype\n\nAds.prototype.config = config$1;\nAds.prototype.slots = slots;\nAds.prototype.gpt = gpt;\nAds.prototype.targeting = targeting;\nAds.prototype.utils = utils;\n/**\n* Initialises the ads library and all sub modules\n* @param options {object} a JSON object containing configuration for the current page\n*/\n\nAds.prototype.init = function (options) {\n  options = options || {};\n  this.config.init();\n  const configOptions = Object.assign(options, {\n    nonPersonalized: !options.disableConsentCookie\n  });\n  this.config(configOptions);\n\n  if (options.disableConsentCookie) {\n    this.consents = {\n      behavioral: true\n    };\n  } else {\n    this.consents = getConsents();\n  }\n\n  if (this.consents.behavioral) {\n    this.utils.broadcast('consentBehavioral');\n  }\n\n  if (this.consents.programmatic) {\n    this.utils.broadcast('consentProgrammatic');\n  }\n\n  this.utils.broadcast('initialising');\n  this.targeting.add(this.config().targeting);\n  return Promise.resolve(this.initLibrary());\n};\n/**\n * Update page level targeting data in o-ads and GPT\n */\n\n\nAds.prototype.updateTargeting = function (data) {\n  this.targeting.add(data);\n  this.gpt.updatePageTargeting(this.targeting.get());\n};\n\nAds.prototype.initLibrary = function () {\n  this.slots.init();\n\n  if (this.consents.programmatic) {\n    this.config({\n      'nonPersonalized': false\n    });\n    this.targeting.add({\n      \"cc\": \"y\"\n    });\n  }\n\n  this.gpt.init();\n  this.utils.on('debug', this.debug.bind(this));\n  this.isInitialised = true;\n  this.utils.broadcast('initialised', this);\n  removeDOMEventListener();\n  return this;\n};\n\nAds.prototype.debug = function () {\n  let remove = true;\n\n  if (localStorage.getItem('oAds')) {\n    remove = false;\n  } else {\n    localStorage.setItem('oAds', true);\n  }\n\n  this.gpt.debug();\n  this.slots.debug();\n  this.targeting.debug();\n\n  if (remove) {\n    localStorage.removeItem('oAds');\n  }\n};\n\nAds.prototype.version = function () {\n  this.utils.log.warn('DEPRECATION NOTICE: Ads.version() will be deprecated in favour of Ads.getVersion()');\n  this.utils.log(`o-ads version: ${this.utils.getVersion()}`);\n};\n\nAds.prototype.getVersion = function () {\n  return this.utils.getVersion();\n};\n\nconst initAll = function () {\n  return ads.init().then(() => {\n    const slots = Array.from(document.querySelectorAll('.o-ads, [data-o-ads-name]'));\n    slots.forEach(ads.slots.initSlot.bind(ads.slots));\n  });\n};\n\nAds.prototype.initAll = initAll;\n\nfunction getConsents() {\n  // derive consent options from ft consent cookie\n  const re = /FTConsent=([^;]+)/;\n  const match = document.cookie.match(re);\n\n  if (!match) {\n    // cookie stasis or no consent cookie found\n    return {\n      behavioral: false,\n      programmatic: false\n    };\n  }\n\n  const consentCookie = decodeURIComponent(match[1]);\n  return {\n    behavioral: consentCookie.indexOf('behaviouraladsOnsite:on') !== -1,\n    programmatic: consentCookie.indexOf('programmaticadsOnsite:on') !== -1\n  };\n}\n\nfunction addDOMEventListener() {\n  document.addEventListener('o.DOMContentLoaded', initAll);\n}\n\nfunction removeDOMEventListener() {\n  document.removeEventListener('o.DOMContentLoaded', initAll);\n}\n\nconst ads = new Ads();\n\nexport { ads as default };\n"],"sourceRoot":""}