1/** 2 * JS helpers for image handling 3 */ 4/* eslint-disable no-unused-vars */ 5document.addEventListener('DOMContentLoaded', event => { 6 // Add class to loaded images to apply opacity animation 7 var lazyImages = document.querySelectorAll('.image-attachment .image'); 8 9 lazyImages.forEach((lazyImage) => { 10 if (lazyImage.complete) { 11 imageLoaded(lazyImage); 12 } else { 13 lazyImage.addEventListener('load', imageLoaded.bind(null, lazyImage)); 14 } 15 16 function imageLoaded(lazyImage) { 17 if( '' === lazyImage || !lazyImage ) return; 18 19 lazyImage.classList.add('lazy-image-loaded'); 20 lazyImage.parentElement.classList.add('no-background-color'); 21 } 22 23 }); 24}, false); 25/* eslint-enable no-unused-vars */ 26; 27!function () { 28 29 //=NS 30 FP.Utils = FP.Utils || {}; 31 32 FP.Utils.trapFocus = { 33 34 /** 35 * @summary Trap keyboard focus in DOM elements 36 * 37 * @description Traps focus in expanded nav, modals, etc. 38 * 39 * @param {array} containerElements Array of DOM elements from document.querySelectorAll() 40 * @param {obj} DOM element from document.querySelector() to return focus to after closing trap element 41 * 42 * @return {void} 43 */ 44 init: function(containerElements, returnFocusToElement = false) { 45 // do not continue if there are no container DOM elements passed 46 if (containerElements.length < 1) return; 47 48 // key codes for keyboard nav 49 const KEYCODE_TAB = 9; 50 const KEYCODE_ESC = 27; 51 52 // iterate throgh container DOM elements 53 containerElements.forEach((containerElement) => { 54 // get all focusable elements 55 var focusableEls = this.getfocusableEls(containerElement); 56 // get first focusable element 57 var firstFocusableEl = focusableEls[0]; 58 // get last focusable element 59 var lastFocusableEl = focusableEls[focusableEls.length - 1]; 60 61 // add listener to container DOM elements 62 containerElement.addEventListener('keydown', function(e) { 63 // determine whether user pressed the escape key 64 var isEscapePressed = (e.key === 'Esc' || e.keyCode === KEYCODE_ESC); 65 // determine whether user pressed the tab key 66 var isTabPressed = (e.key === 'Tab' || e.keyCode === KEYCODE_TAB); 67 68 // only evaluate escape and tab keydown 69 if (!isEscapePressed && !isTabPressed) return; 70 71 // escape key pressed 72 if ( isEscapePressed ) { 73 // assuming the close button is the first item 74 // 75 // TO-DO - make this more dynamic to accommodate other elements by class, id, etc.? 76 // 77 firstFocusableEl.click(); 78 if( returnFocusToElement ) { 79 returnFocusToElement.focus(); 80 } 81 // shift + tab keys pressed 82 } else if ( e.shiftKey ) { 83 // if user is on the first focusable element... 84 if (document.activeElement === firstFocusableEl) { 85 // ...move focus to last focusable element
86 lastFocusableEl.focus(); 87 e.preventDefault(); 88 } 89 // tab key pressed 90 } else { 91 // if user is on the last focusable element... 92 if (document.activeElement === lastFocusableEl) { 93 firstFocusableEl.focus(); 94 // ...move focus to first focusable element 95 e.preventDefault(); 96 } 97 } 98 }); 99 }); 100 }, 101 102 /** 103 * @summary Get array of focusable elements in container 104 * 105 * @description Get all focusable elements using the query selector options defined in the function 106 * 107 * @param {array} containerElement DOM element that (may) contains focusable elements 108 * 109 * @return {array} focusable DOM elements 110 */ 111 getfocusableEls: function(containerElement) { 112 return containerElement.querySelectorAll('iframe:not([disabled]), a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="search"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])'); 113 }, 114 115 /** 116 * @summary Toggle inert attribute on elements that should be hidden when a modal is displayed 117 * 118 * @description Get all elements with data-inert-when-modal="true" and toggle "inert" and "aria-hidden" attributes 119 * 120 * @param {bool} enable Whether to enable or disable the "inert" and "aria-hidden" attributes 121 * 122 * @return {void} 123 */ 124 toggleInertAttribute: function(enable = true) { 125 document.querySelectorAll('[data-inert-when-modal="true"]').forEach(element => { 126 if(enable) { 127 element.setAttribute('inert', ''); 128 element.setAttribute('aria-hidden', 'true'); 129 } else { 130 element.removeAttribute('inert'); 131 element.removeAttribute('aria-hidden'); 132 } 133 }); 134 }, 135 136 }; 137 138}(); 139; 140(()=>{"use strict";var __webpack_modules__={"../assets/src/scripts/components/navigation/navigation.js"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/classCallCheck */ \"./node_modules/@babel/runtime/helpers/esm/classCallCheck.js\");\n/* harmony import */ var _babel_runtime_helpers_createClass__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @babel/runtime/helpers/createClass */ \"./node_modules/@babel/runtime/helpers/esm/createClass.js\");\n\n\nvar FPNav = /*#__PURE__*/function () {\n function FPNav() {\n (0,_babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(this, FPNav);\n // define constants\n // key codes for keyboard nav\n this.KEYCODE_TAB = 9;\n this.KEYCODE_ESC = 27;\n\n // get DOM elements needed throughout the code\n this.siteHeader = document.querySelector('.site-header');\n this.headerElement = document.querySelector('header');\n\n // define config for header components and CSS classes for display toggling\n this.nav = document.querySelector('#navigation');\n this.headerNavWrapper = document.querySelector('.header-nav-wrapper');\n this.headerNavDrawerOpen = 'drawer--open';\n this.headerNavParentScrolled = 'nav-menu-scrolled-true--parent';\n this.headerNavParentNotScrolled = 'nav-menu-scrolled-false--parent';\n this.headerNavScrolled = 'nav-menu-scrolled-true';\n this.headerNavNotScrolled = 'nav-menu-scrolled-false';\n\n // define config for user menu elements\n this.userIcon = document.querySelector('.js-site-nav-user-icon-navbar');\n this.userMenu = document.querySelector('.site-nav-usermenu-nav-navbar');\n this.userIconFullMenu = document.querySelector('.js-site-nav-user-icon-full-menu');\n this.userMenuFullMenu = document.querySelector('.site-nav-usermenu-nav-full-menu');\n\n // define config for search menu elements\n this.searchDrawerCloseButton = document.querySelector('#searchform-site-nav-drawer-close-btn');\n this.searchDrawerInputField = document.querySelector('#searchform-site-nav-drawer .searchfield-site-nav');\n\n // define config for mobile drawer buttons\n this.mobileDrawerButtons = document.querySelectorAll('.js-drawer-mobile-button');\n this.mobileDrawerClosed = 'drawer-mobile-button--closed';\n this.mobileDrawerOpen = 'drawer-mobile-button--open';\n\n // define config for full nav menu\n this.hamburgerButtons = document.querySelectorAll('.nav-modal-open');\n this.closeButtons = document.querySelectorAll('.nav-full-menu__close');\n this.desktopMenu = document.querySelector('.nav-full-menu');\n this.desktopMenuClosed = 'nav-full-menu--closed';\n this.desktopMenuOpen = 'nav-full-menu--open';\n\n // track height of open drawers in desktop nav\n // use as padding below\n this.openDrawerHe
140ight = 0;\n\n // define config for drawers and supporting interactive elements \n // and CSS classes for display toggling\n this.drawers = {\n regions: {\n button: document.querySelector('.js-drawer-regions-button'),\n buttonClosed: 'drawer-regions-button--closed',\n buttonOpen: 'drawer-regions-button--open',\n drawer: document.querySelector('.nav-drawer__regions'),\n drawerClosed: 'drawer-regions--closed',\n drawerOpen: 'drawer-regions--open'\n },\n newsletters: {\n button: document.querySelector('.js-drawer-newsletters-button'),\n buttonClosed: 'drawer-newsletters-button--closed',\n buttonOpen: 'drawer-newsletters-button--open',\n drawer: document.querySelector('.nav-drawer__newsletters'),\n drawerClosed: 'drawer-newsletters--closed',\n drawerOpen: 'drawer-newsletters--open'\n },\n search: {\n button: document.querySelector('.js-drawer-search-button'),\n buttonClosed: 'drawer-search-button--closed',\n buttonOpen: 'drawer-search-button--open',\n drawer: document.querySelector('.nav-drawer__search'),\n drawerClosed: 'drawer-search--closed',\n drawerOpen: 'drawer-search--open'\n }\n };\n }\n return (0,_babel_runtime_helpers_createClass__WEBPACK_IMPORTED_MODULE_1__[\"default\"])(FPNav, [{\n key: \"init\",\n value: function init() {\n var self = this;\n\n // Sticky main nav, content toggle on scroll\n self.navAppearanceOnScroll();\n document.addEventListener('DOMContentLoaded', function () {\n // user menus\n self.userMenuInteractivity(self.userIcon, self.userMenu);\n self.userMenuInteractivity(self.userIconFullMenu, self.userMenuFullMenu);\n self.keyboardCloseExpandedDrawerContent(document.querySelectorAll('.site-nav-usermenu-nav'));\n\n // drawers\n self.drawerInteractivity();\n self.keyboardCloseExpandedDrawerContent(document.querySelectorAll('.nav-drawer-wrapper'));\n self.mobileDrawerInteractivity();\n\n // full menu\n self.fullMenuInteractivity();\n\n // focus trap\n self.trapFocusInteractivity();\n });\n\n // Piano iframes\n self.observePianoIframes();\n }\n\n /**\n * @summary Add scroll listener for navigation appearance based on scroll depth\n * \n * @return {void}\n */\n }, {\n key: \"navAppearanceOnScroll\",\n value: function navAppearanceOnScroll() {\n var self = this;\n\n // scroll listener to toggle classes between: \n // - main nav static\n // - main nav scrolled\n window.addEventListener('scroll', function () {\n var mainElement = document.querySelector('main');\n\n // main nav static\n // user has not scrolled to a depth less than the siteHeader height\n // or has scolled back to the top of the page\n if (window.scrollY > self.siteHeader.offsetHeight) {\n self.toggleElementClasses(self.siteHeader,\n // target DOM element\n self.headerNavParentScrolled,\n // class to add\n self.headerNavParentNotScrolled // class to remove\n );\n self.toggleElementClasses(self.headerNavWrapper, self.headerNavScrolled, self.headerNavNotScrolled);\n self.toggleElementClasses(self.nav, self.headerNavScrolled, self.headerNavNotScrolled);
140\n if (self.openDrawerHeight > 0) {\n // add 80 below to account for .header-nav-wrapper height and bottom margin\n mainElement.style.paddingTop = self.openDrawerHeight + 80 + 'px';\n }\n // main nav scrolled\n // user has scrolled to a depth equal to or greater than the siteHeader height\n } else {\n self.toggleElementClasses(self.siteHeader,\n // target DOM element\n self.headerNavParentNotScrolled,\n // class to add\n self.headerNavParentScrolled // class to remove\n );\n self.toggleElementClasses(self.headerNavWrapper, self.headerNavNotScrolled, self.headerNavScrolled);\n self.toggleElementClasses(self.nav, self.headerNavNotScrolled, self.headerNavScrolled);\n mainElement.style.paddingTop = '';\n }\n });\n }\n\n /**\n * @summary Add listeners for drawer interactivity\n * \n * @return {void}\n */\n }, {\n key: \"drawerInteractivity\",\n value: function drawerInteractivity() {\n var self = this;\n\n // Handling for drawer display toggle buttons\n var _loop = function _loop(drawerName) {\n if (!self.drawers[drawerName].button) return 1; // continue\n\n // Handles click and enter keydown\n self.drawers[drawerName].button.addEventListener('click', function (event) {\n event.preventDefault();\n self.toggleDrawer(drawerName, event);\n });\n };\n for (var drawerName in self.drawers) {\n if (_loop(drawerName)) continue;\n }\n\n // Handling for search close button\n if (self.searchDrawerCloseButton) {\n self.searchDrawerCloseButton.addEventListener('click', function () {\n var searchDrawerConfig = self.drawers.search;\n if (searchDrawerConfig.drawer.classList.contains(searchDrawerConfig.drawerOpen)) {\n self.toggleElementClasses(searchDrawerConfig.drawer,\n // target DOM element\n searchDrawerConfig.drawerClosed,\n // class to add\n searchDrawerConfig.drawerOpen // class to remove\n );\n self.toggleElementClasses(searchDrawerConfig.button, searchDrawerConfig.buttonClosed, searchDrawerConfig.buttonOpen);\n if (!self.drawers.regions.drawer.classList.contains(self.drawers.regions.drawerOpen) && !self.drawers.newsletters.drawer.classList.contains(self.drawers.newsletters.drawerOpen)) {\n self.headerNavWrapper.classList.remove(self.headerNavDrawerOpen);\n document.querySelector('.site-nav-search #search').setAttribute('aria-expanded', 'false');\n document.querySelector('.site-nav-search #search').focus();\n\n // Remove padding from <header>\n self.headerElement.style.paddingBottom = '';\n }\n }\n });\n }\n }\n\n /**\n * @summary Drawer display toggling functionality\n * \n * @description Traps focus in expanded nav, modals, etc.\n * \n * @param {string} currentDrawer Name of current drawer\n * @param {object} event DOM event\n *\n * @return {void}\n */\n }, {\n key: \"toggleDrawer\",\n value: function toggleDrawer(currentDrawer, event) {\n var _activeDrawer$drawer$;\n var self = this;\n\n // Check if other drawers are open and close them if they are\n for (var drawerName in self.drawers) {\n if (drawerName !== currentDrawer) {\n var drawerObj = self.drawers[drawerName];\n if (drawerObj.drawer && drawerObj.drawer.classList && drawerObj.drawer.classList.contains(drawerObj.drawerOpen)) {\n self.toggleElementClasses(drawerObj.drawer,\n // target DOM element\n drawerObj.drawerClosed,\n // class to add\n drawerObj.drawerOpen // class to remove\n );\n self.toggleElementClasses(drawerObj.button, drawerObj.buttonClosed, drawerObj.buttonOpen);\n }\n }\n }\n var activeDrawer = self.drawers[currentDrawer];\n if (activeDrawer.drawer.classList.contains(activeDrawer.drawerOpen)) {\n self.toggleElementClasses(activeDrawer.button,\n // target DOM element\n activeDrawer.buttonClosed,\n // class to add\n activeDrawer.buttonOpen // class to remove\n );\n self.toggleElementClasses(activeDrawer.drawer, activeDrawer.drawerClosed, activeDrawer.drawerOpen);\n self.headerNavWrapper.classList.remove(self.headerNavDrawerOpen);\n } else {\n self.toggleElementClasses(activeDrawer.button, activeDrawer.buttonOpen, activeDrawer.buttonClosed);\n self.toggleElementClasses(activeDrawer.drawer, activeDrawer.drawerOpen, activeDrawer.drawerClosed);\n self.headerNavWrapper.classList.add(self.headerNavDrawerOpen);\n }\n var isExpanded = false;\n if (activeDrawer.drawer.classList.contains(activeDrawer.drawerOpen)) isExpanded = true;\n if (isExpanded) {\n // set aria-expanded attribute to true for parent <a> tag\n activeDrawer.button.setAttribute('aria-expanded', 'true');\n } else {\n // set aria-expanded attribute to false for parent <a> tag\n activeDrawer.button.setAttribute('aria-expanded', 'false');\n }\n\n // set padding to <header> to push content down when drawer is open\n self.openDrawerHe
140ight = (_activeDrawer$drawer$ = activeDrawer.drawer.offsetHeight) !== null && _activeDrawer$drawer$ !== void 0 ? _activeDrawer$drawer$ : 0;\n self.headerElement.style.paddingBottom = self.openDrawerHeight + 'px';\n\n // set focus and CSS classes for drawers\n switch (currentDrawer) {\n case 'search':\n activeDrawer.drawer.setAttribute('aria-hidden', 'false');\n self.searchDrawerInputField.focus();\n // only apply focus outline style if user navigated via keyboard\n if ('Enter' !== event.key) {\n self.searchDrawerInputField.classList.add('no-focus-outline');\n } else {\n self.searchDrawerInputField.classList.remove('no-focus-outline');\n }\n break;\n default:\n if (isExpanded) {\n // set aria-hidden attribute to false\n activeDrawer.drawer.setAttribute('aria-hidden', 'false');\n } else {\n // set aria-hidden attribute to false\n activeDrawer.drawer.setAttribute('aria-hidden', 'true');\n }\n break;\n }\n }\n\n /**\n * @summary Mobile drawer display toggling functionality\n * \n * @return {void}\n */\n }, {\n key: \"mobileDrawerInteractivity\",\n value: function mobileDrawerInteractivity() {\n var self = this;\n\n // Handling for mobileDrawerButton\n self.mobileDrawerButtons.forEach(function (mobileDrawerButton) {\n mobileDrawerButton.addEventListener('click', function (e) {\n if (window.innerWidth > 979) return;\n e.preventDefault();\n mobileDrawerButton.classList.toggle(self.mobileDrawerOpen);\n mobileDrawerButton.classList.toggle(self.mobileDrawerClosed);\n if (!mobileDrawerButton.classList.contains(self.mobileDrawerOpen)) {\n self.headerNavWrapper.classList.remove(self.headerNavDrawerOpen);\n }\n });\n });\n }\n\n /**\n * @summary Full menu display toggling functionality\n * \n * @return {void}\n */\n }, {\n key: \"fullMenuInteractivity\",\n value: function fullMenuInteractivity() {\n var self = this;\n self.hamburgerButtons.forEach(function (hamburgerButton) {\n hamburgerButton.addEventListener('click', function () {\n hamburgerButton.setAttribute('aria-expanded', 'true');\n self.toggleElementClasses(self.desktopMenu, self.desktopMenuOpen, self.desktopMenuClosed);\n self.desktopMenu.setAttribute('aria-expanded', 'true');\n self.desktopMenu.setAttribute('aria-hidden', 'false');\n setTimeout(function () {\n self.closeButtons[0].focus();\n }, 100);\n document.querySelector('.nav-full-menu').scrollTop = 0;\n document.body.classList.add('overlay-no-scroll');\n });\n });\n self.closeButtons.forEach(function (closeButton) {\n closeButton.addEventListener('click', function () {\n self.toggleElementClasses(self.desktopMenu, self.desktopMenuClosed, self.desktopMenuOpen);\n self.desktopMenu.setAttribute('aria-expanded', 'false');\n self.desktopMenu.setAttribute('aria-hidden', 'true');\n self.hamburgerButtons.forEach(function (hamburgerButton) {\n hamburgerButton.setAttribute('aria-expanded', 'false');\n });\n self.hamburgerButtons[0].focus();\n document.body.classList.remove('overlay-no-scroll');\n });\n });\n }\n\n /**\n * @summary Add listeners for user menu interactivity\n *\n * @param {object} userIcon user icon DOM element object\n * @param {object} userMenu user menuu DOM element object\n * \n * @return {void}\n */\n }, {\n key: \"userMenuInteractivity\",\n value: function userMenuInteractivity(userIcon, userMenu) {\n if (!userIcon) return;\n userIcon.addEventListener('click', function (event) {\n event.preventDefault();\n if (userMenu.style.display !== 'block') {\n userIcon.setAttribute('aria-expanded', 'true');\n userMenu.style.display = 'block';\n } else {\n userIcon.setAttribute('aria-expanded', 'false');\n userMenu.style.display = 'none';\n }\n });\n userIcon.addEventListener('mouseenter', function () {\n userIcon.setAttribute('aria-expanded', 'true');\n userMenu.style.display = 'block';\n });\n userMenu.addEventListener('mouseleave', function () {\n userIcon.setAttribute('aria-expanded', 'false');\n userMenu.style.display = 'none';\n });\n }\n\n /**\n * @summary Trap focus functionality in expanded menu items and expanded nav\n * \n * @return {void}\n */\n }, {\n key: \"trapFocusInteractivity\",\n value: function trapFocusInteractivity() {\n FP.Utils.trapFocus.init(document.querySelectorAll('#expanded-navigation'));\n }\n\n /**\n * @summary Helper to close all drawers on desktop\n * \n * @return {void}\n */\n }, {\n key: \"closeAllDrawers\",\n value: function closeAllDrawers() {\n var self = this;
140\n for (var drawerName in self.drawers) {\n var drawerObj = self.drawers[drawerName];\n self.toggleElementClasses(drawerObj.drawer, drawerObj.drawerClosed, drawerObj.drawerOpen);\n self.toggleElementClasses(drawerObj.button, drawerObj.buttonClosed, drawerObj.buttonOpen);\n drawerObj.button.setAttribute('aria-expanded', 'false');\n }\n\n // update header elements\n self.headerNavWrapper.classList.remove(self.headerNavDrawerOpen);\n self.headerElement.style.paddingBottom = '';\n\n // reset open drawer height to 0\n self.openDrawerHeight = 0;\n\n // update main element\n var mainElement = document.querySelector('main');\n mainElement.style.paddingTop = '';\n\n // close user menus\n self.userMenu.style.display = 'none';\n self.userMenuFullMenu.style.display = 'none';\n self.userIcon.setAttribute('aria-expanded', 'false');\n self.userIconFullMenu.setAttribute('aria-expanded', 'false');\n }\n\n /**\n * @summary Helper to focus on parent element after closing drawers\n *\n * @param {object} containerElement DOM element object\n * \n * @return {void}\n */\n }, {\n key: \"focusOnParent\",\n value: function focusOnParent(containerElement) {\n // TO-DO - make this more flexible, not only searching for an <a> tag\n var focusEl = containerElement.parentNode.querySelector('a');\n if (focusEl) {\n focusEl.setAttribute('aria-expanded', 'false');\n focusEl.focus();\n }\n }\n\n /**\n * @summary Helper to handle full nav closure with keyboard input\n *\n * @description Allow expanded nav to be closed when:\n * - the user presses the Escape key\n * - the user shift + tabs back past the first item in the drawer\n * - the user tabs past the last item in the drawer\n *\n * @param {array} containerElements Array of DOM elements from document.querySelectorAll()\n * \n * @return {void}\n */\n }, {\n key: \"keyboardCloseExpandedDrawerContent\",\n value: function keyboardCloseExpandedDrawerContent(containerElements) {\n var self = this;\n containerElements.forEach(function (containerElement) {\n var focusableEls = FP.Utils.trapFocus.getfocusableEls(containerElement);\n var firstFocusableEl = focusableEls[0];\n var lastFocusableEl = focusableEls[focusableEls.length - 1];\n containerElement.addEventListener('keydown', function (e) {\n var isEscapePressed = e.key === 'Esc' || e.keyCode === self.KEYCODE_ESC;\n var isTabPressed = e.key === 'Tab' || e.keyCode === self.KEYCODE_TAB;\n if (!isEscapePressed && !isTabPressed) {\n return;\n }\n var processAction = false;\n var changeFocus = false;\n\n // esc pressed\n if (isEscapePressed) {\n processAction = true;\n changeFocus = true;\n // shift + tab pressed\n } else if (e.shiftKey) {\n // if user is on the first focusable element in the drawer\n if (document.activeElement === firstFocusableEl) {\n processAction = true;\n }\n // tab pressed\n } else {\n // if user is on the last focusable element in the drawer\n if (document.activeElement === lastFocusableEl) {\n processAction = true;\n changeFocus = true;\n }\n }\n\n // run additional code to close drawers or focus on parent element\n if (processAction) {\n // close all drawers\n self.closeAllDrawers();\n }\n if (changeFocus) {\n // focus on parent element\n self.focusOnParent(containerElement);\n }\n });\n });\n }\n\n /**\n * @summary Helper to remove and add a class\n *\n * @param {object} element DOM element\n * @param {string} addClass Class name to add to element\n * @param {string}
140 removeClass Class name to remove from element\n * \n * @return {void}\n */\n }, {\n key: \"toggleElementClasses\",\n value: function toggleElementClasses(element, addClass, removeClass) {\n var _element$classList, _element$classList2;\n element === null || element === void 0 || (_element$classList = element.classList) === null || _element$classList === void 0 || _element$classList.remove(removeClass);\n element === null || element === void 0 || (_element$classList2 = element.classList) === null || _element$classList2 === void 0 || _element$classList2.add(addClass);\n }\n\n /**\n * @summary Helper to adjust focus with Piano iframes\n *\n * @description This is needed as a workaround for the iframe focus issue\n * \n * @return {void}\n */\n }, {\n key: \"observePianoIframes\",\n value: function observePianoIframes() {\n // Options for the observer (which mutations to observe)\n var config = {\n attributes: false,\n childList: true,\n subtree: true\n };\n\n // Callback function to execute when mutations are observed\n // eslint-disable-next-line no-unused-vars\n var observer = new MutationObserver(function (mutations) {\n mutations.forEach(function (mutation) {\n // Looping through all added no
140des\n mutation.addedNodes.forEach(function (node) {\n if (node instanceof Element && node.matches('iframe')) {\n // If the added node matches the selector, execute the callback and disconnect the observer\n if (document.querySelector('.tp-close')) {\n document.querySelector('.tp-close').addEventListener('click', function () {\n setTimeout(function () {\n var loginElement = document.querySelector('.FP-paywall--login');\n if (loginElement) {\n loginElement.focus();\n }\n }, 750);\n });\n }\n //observer.disconnect();\n }\n });\n });\n });\n\n // Start observing the target node for configured mutations\n observer.observe(document, config);\n }\n }]);\n}();\nwindow.FPNav = new FPNav();\nwindow.FPNav.init();//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL2NvbXBvbmVudHMvbmF2aWdhdGlvbi9uYXZpZ2F0aW9uLmpzIiwibWFwcGluZ3MiOiI7Ozs7O0FBQUE7QUFFQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBSUE7O0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUlBO0FBSUE7O0FBSUE7QUFDQTtBQUNBO0FBR0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFKQTtBQUFBO0FBQUE7QUFNQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFLQTtBQU1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFLQTtBQU1BO0FBQ0E7QUFDQTtBQUNBOztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFKQTtBQUFBO0FBQUE7QUFNQTs7QUFFQTtBQUFBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBVEE7QUFBQTtBQUNBOztBQVVBO0FBQ0E7QUFFQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQU1BO0FBSUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBVEE7QUFBQTtBQUFBO0FBVUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBS0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFLQTtBQUNBO0FBQ0E7QUFFQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFNQTtBQUNBO0FBQ0E7QUFLQTtBQU1BO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUpBO0FBQUE7QUFBQTtBQU1BOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFFQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFKQTtBQUFBO0FBQUE7QUFNQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBTUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBTUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQVBBO0FBQUE7QUFBQTtBQVNBO0FBRUE7QUFFQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUpBO0FBQUE7QUFBQTtBQU1BO0FBQ0E7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUpBO0FBQUE7QUFBQTtBQU1BO0FBRUE7QUFDQTtBQUVBO0FBS0E7QUFNQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFOQTtBQUFBO0FBQUE7QUFRQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFYQTtBQUFBO0FBQUE7QUFhQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0F
140BRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQVJBO0FBQUE7QUFBQTtBQVNBO0FBQ0E7QUFDQTtBQUNBOztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBTkE7QUFBQTtBQUFBO0FBUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUlBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4uL2Fzc2V0cy9zcmMvc2NyaXB0cy9jb21wb25lbnRzL25hdmlnYXRpb24vbmF2aWdhdGlvbi5qcz82YjEwIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZQTmF2IHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblx0XHQvLyBkZWZpbmUgY29uc3RhbnRzXG5cdFx0Ly8ga2V5IGNvZGVzIGZvciBrZXlib2FyZCBuYXZcblx0XHR0aGlzLktFWUNPREVfVEFCICAgICAgICAgICAgICAgID0gOTtcblx0XHR0aGlzLktFWUNPREVfRVNDICAgICAgICAgICAgICAgID0gMjc7XG5cblx0XHQvLyBnZXQgRE9NIGVsZW1lbnRzIG5lZWRlZCB0aHJvdWdob3V0IHRoZSBjb2RlXG5cdFx0dGhpcy5zaXRlSGVhZGVyICAgICAgICAgICAgICAgICA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5zaXRlLWhlYWRlcicpO1xuXHRcdHRoaXMuaGVhZGVyRWxlbWVudCAgICAgICAgICAgICAgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdoZWFkZXInKTtcblxuXHRcdC8vIGRlZmluZSBjb25maWcgZm9yIGhlYWRlciBjb21wb25lbnRzIGFuZCBDU1MgY2xhc3NlcyBmb3IgZGlzcGxheSB0b2dnbGluZ1xuXHRcdHRoaXMubmF2ICAgICAgICAgICAgICAgICAgICAgICAgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjbmF2aWdhdGlvbicpO1xuXHRcdHRoaXMuaGVhZGVyTmF2V3JhcHBlciAgICAgICAgICAgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuaGVhZGVyLW5hdi13cmFwcGVyJyk7XG5cdFx0dGhpcy5oZWFkZXJOYXZEcmF3ZXJPcGVuICAgICAgICA9ICdkcmF3ZXItLW9wZW4nO1xuXHRcdHRoaXMuaGVhZGVyTmF2UGFyZW50U2Nyb2xsZWQgICAgPSAnbmF2LW1lbnUtc2Nyb2xsZWQtdHJ1ZS0tcGFyZW50Jztcblx0XHR0aGlzLmhlYWRlck5hdlBhcmVudE5vdFNjcm9sbGVkID0gJ25hdi1tZW51LXNjcm9sbGVkLWZhbHNlLS1wYXJlbnQnO1xuXHRcdHRoaXMuaGVhZGVyTmF2U2Nyb2xsZWQgICAgICAgICAgPSAnbmF2LW1lbnUtc2Nyb2xsZWQtdHJ1ZSc7XG5cdFx0dGhpcy5oZWFkZXJOYXZOb3RTY3JvbGxlZCAgICAgICA9ICduYXYtbWVudS1zY3JvbGxlZC1mYWxzZSc7XG5cblx0XHQvLyBkZWZpbmUgY29uZmlnIGZvciB1c2VyIG1lbnUgZWxlbWVudHNcblx0XHR0aGlzLnVzZXJJY29uICAgICAgICAgICAgICAgICAgID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmpzLXNpdGUtbmF2LXVzZXItaWNvbi1uYXZiYXInKTtcblx0XHR0aGlzLnVzZXJNZW51ICAgICAgICAgICAgICAgICAgID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnNpdGUtbmF2LXVzZXJtZW51LW5hdi1uYXZiYXInKTtcblx0XHRcblx0XHR0aGlzLnVzZXJJY29uRnVsbE1lbnUgICAgICAgICAgID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmpzLXNpdGUtbmF2LXVzZXItaWNvbi1mdWxsLW1lbnUnKTtcblx0XHR0aGlzLnVzZXJNZW51RnVsbE1lbnUgICAgICAgICAgID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnNpdGUtbmF2LXVzZXJtZW51LW5hdi1mdWxsLW1lbnUnKTtcblx0XHRcblx0XHQvLyBkZWZpbmUgY29uZmlnIGZvciBzZWFyY2ggbWVudSBlbGVtZW50c1xuXHRcdHRoaXMuc2VhcmNoRHJhd2VyQ2xvc2VCdXR0b24gICAgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjc2VhcmNoZm9ybS1zaXRlLW5hdi1kcmF3ZXItY2xvc2UtYnRuJyk7XG5cdFx0dGhpcy5zZWFyY2hEcmF3ZXJJbnB1dEZpZWxkICAgICA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNzZWFyY2hmb3JtLXNpdGUtbmF2LWRyYXdlciAuc2VhcmNoZmllbGQtc2l0ZS1uYXYnKTtcblxuXHRcdC8vIGRlZmluZSBjb25maWcgZm9yIG1vYmlsZSBkcmF3ZXIgYnV0dG9uc1xuXHRcdHRoaXMubW9iaWxlRHJhd2VyQnV0dG9ucyAgICAgICAgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuanMtZHJhd2VyLW1vYmlsZS1idXR0b24nKTtcblx0XHR0aGlzLm1vYmlsZURyYXdlckNsb3NlZCAgICAgICAgID0gJ2RyYXdlci1tb2JpbGUtYnV0dG9uLS1jbG9zZWQnO1xuXHRcdHRoaXMubW9iaWxlRHJhd2VyT3BlbiAgICAgICAgICAgPSAnZHJhd2VyLW1vYmlsZS1idXR0b24tLW9wZW4nO1xuXG5cdFx0Ly8gZGVmaW5lIGNvbmZpZyBmb3IgZnVsbCBuYXYgbWVudVxuXHRcdHRoaXMuaGFtYnVyZ2VyQnV0dG9ucyAgICAgICAgICAgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcubmF2LW1vZGFsLW9wZW4nKTtcblx0XHR0aGlzLmNsb3NlQnV0dG9ucyAgICAgICAgICAgICAgID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLm5hdi1mdWxsLW1lbnVfX2Nsb3NlJyk7XG5cdFx0dGhpcy5kZXNrdG9wTWVudSAgICAgICAgICAgICAgICA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5uYXYtZnVsbC1tZW51Jyk7XG5cdFx0dGhpcy5kZXNrdG9wTWVudUNsb3NlZCAgICAgICAgICA9ICduYXYtZnVsbC1tZW51LS1jbG9zZWQnO1xuXHRcdHRoaXMuZGVza3RvcE1lbnVPcGVuICAgICAgICAgICAgPSAnbmF2LWZ1bGwtbWVudS0tb3Blbic7XG5cblx0XHQvLyB0cmFjayBoZWlnaHQgb2Ygb3BlbiBkcmF3ZXJzIGluIGRlc2t0b3AgbmF2XG5cdFx0Ly8gdXNlIGFzIHBhZGRpbmcgYmVsb3dcblx0XHR0aGlzLm9wZW5EcmF3ZXJIZWlnaHQgICAgICAgICAgID0gMDtcblxuXHRcdC8vIGRlZmluZSBjb25maWcgZm9yIGRyYXdlcnMgYW5kIHN1cHBvcnRpbmcgaW50ZXJhY3RpdmUgZWxlbWVudHMgXG5cdFx0Ly8gYW5kIENTUyBjbGFzc2VzIGZvciBkaXNwbGF5IHRvZ2dsaW5nXG5cdFx0dGhpcy5kcmF3ZXJzID0ge1xuXHRcdFx0cmVnaW9uczoge1xuXHRcdFx0XHRidXR0b246ICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5qcy1kcmF3ZXItcmVnaW9ucy1idXR0b24nKSxcblx0XHRcdFx0YnV0dG9uQ2xvc2VkOiAnZHJhd2VyLXJlZ2lvbnMtYnV0dG9uLS1jbG9zZWQnLFxuXHRcdFx0XHRidXR0b25PcGVuOiAgICdkcmF3ZXItcmVnaW9ucy1idXR0b24tLW9wZW4nLFxuXHRcdFx0XHRkcmF3ZXI6ICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5uYXYtZHJhd2VyX19yZWdpb25zJyksXG5cdFx0XHRcdGRyYXdlckNsb3NlZDogJ2RyYXdlci1yZWdpb25zLS1jbG9zZWQnLFxuXHRcdFx0XHRkcmF3ZXJPcGVuOiAgICdkcmF3ZXItcmVnaW9ucy0tb3BlbicsXG5cdFx0XHR9LFxuXHRcdFx0bmV3c2xldHRlcnM6IHtcblx0XHRcdFx0YnV0dG9uOiAgICAgICBkb2
140N1bWVudC5xdWVyeVNlbGVjdG9yKCcuanMtZHJhd2VyLW5ld3NsZXR0ZXJzLWJ1dHRvbicpLFxuXHRcdFx0XHRidXR0b25DbG9zZWQ6ICdkcmF3ZXItbmV3c2xldHRlcnMtYnV0dG9uLS1jbG9zZWQnLFxuXHRcdFx0XHRidXR0b25PcGVuOiAgICdkcmF3ZXItbmV3c2xldHRlcnMtYnV0dG9uLS1vcGVuJyxcblx0XHRcdFx0ZHJhd2VyOiAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcubmF2LWRyYXdlcl9fbmV3c2xldHRlcnMnKSxcblx0XHRcdFx0ZHJhd2VyQ2xvc2VkOiAnZHJhd2VyLW5ld3NsZXR0ZXJzLS1jbG9zZWQnLFxuXHRcdFx0XHRkcmF3ZXJPcGVuOiAgICdkcmF3ZXItbmV3c2xldHRlcnMtLW9wZW4nLFxuXHRcdFx0fSxcblx0XHRcdHNlYXJjaDoge1xuXHRcdFx0XHRidXR0b246ICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5qcy1kcmF3ZXItc2VhcmNoLWJ1dHRvbicpLFxuXHRcdFx0XHRidXR0b25DbG9zZWQ6ICdkcmF3ZXItc2VhcmNoLWJ1dHRvbi0tY2xvc2VkJyxcblx0XHRcdFx0YnV0dG9uT3BlbjogICAnZHJhd2VyLXNlYXJjaC1idXR0b24tLW9wZW4nLFxuXHRcdFx0XHRkcmF3ZXI6ICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5uYXYtZHJhd2VyX19zZWFyY2gnKSxcblx0XHRcdFx0ZHJhd2VyQ2xvc2VkOiAnZHJhd2VyLXNlYXJjaC0tY2xvc2VkJyxcblx0XHRcdFx0ZHJhd2VyT3BlbjogICAnZHJhd2VyLXNlYXJjaC0tb3BlbicsXG5cdFx0XHR9XG5cdFx0fTtcblx0fVxuXG5cblx0aW5pdCgpIHtcblx0XHRjb25zdCBzZWxmID0gdGhpcztcblxuXHRcdC8vIFN0aWNreSBtYWluIG5hdiwgY29udGVudCB0b2dnbGUgb24gc2Nyb2xsXG5cdFx0c2VsZi5uYXZBcHBlYXJhbmNlT25TY3JvbGwoKTtcblxuXHRcdGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ0RPTUNvbnRlbnRMb2FkZWQnLCAoKSA9PiB7XG5cdFx0XHQvLyB1c2VyIG1lbnVzXG5cdFx0XHRzZWxmLnVzZXJNZW51SW50ZXJhY3Rpdml0eShcblx0XHRcdFx0c2VsZi51c2VySWNvbixcblx0XHRcdFx0c2VsZi51c2VyTWVudVxuXHRcdFx0KTtcblx0XHRcdHNlbGYudXNlck1lbnVJbnRlcmFjdGl2aXR5KFxuXHRcdFx0XHRzZWxmLnVzZXJJY29uRnVsbE1lbnUsXG5cdFx0XHRcdHNlbGYudXNlck1lbnVGdWxsTWVudVxuXHRcdFx0KTtcblx0XHRcdHNlbGYua2V5Ym9hcmRDbG9zZUV4cGFuZGVkRHJhd2VyQ29udGVudChcblx0XHRcdFx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnNpdGUtbmF2LXVzZXJtZW51LW5hdicpXG5cdFx0XHQpO1xuXHRcdFx0XG5cdFx0XHQvLyBkcmF3ZXJzXG5cdFx0XHRzZWxmLmRyYXdlckludGVyYWN0aXZpdHkoKTtcblx0XHRcdHNlbGYua2V5Ym9hcmRDbG9zZUV4cGFuZGVkRHJhd2VyQ29udGVudChcblx0XHRcdFx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLm5hdi1kcmF3ZXItd3JhcHBlcicpXG5cdFx0XHQpO1xuXHRcdFx0c2VsZi5tb2JpbGVEcmF3ZXJJbnRlcmFjdGl2aXR5KCk7XG5cdFx0XHRcblx0XHRcdC8vIGZ1bGwgbWVudVxuXHRcdFx0c2VsZi5mdWxsTWVudUludGVyYWN0aXZpdHkoKTtcblxuXHRcdFx0Ly8gZm9jdXMgdHJhcFxuXHRcdFx0c2VsZi50cmFwRm9jdXNJbnRlcmFjdGl2aXR5KCk7XG5cdFx0fSk7XG5cblx0XHQvLyBQaWFubyBpZnJhbWVzXG5cdFx0c2VsZi5vYnNlcnZlUGlhbm9JZnJhbWVzKCk7XG5cdH1cblxuXHQvKipcblx0ICogQHN1bW1hcnkgQWRkIHNjcm9sbCBsaXN0ZW5lciBmb3IgbmF2aWdhdGlvbiBhcHBlYXJhbmNlIGJhc2VkIG9uIHNjcm9sbCBkZXB0aFxuXHQgKiBcblx0ICogQHJldHVybiB7dm9pZH1cblx0ICovXG5cdG5hdkFwcGVhcmFuY2VPblNjcm9sbCgpIHtcblx0XHRjb25zdCBzZWxmID0gdGhpcztcblxuXHRcdC8vIHNjcm9sbCBsaXN0ZW5lciB0byB0b2dnbGUgY2xhc3NlcyBiZXR3ZWVuOiBcblx0XHQvLyAtIG1haW4gbmF2IHN0YXRpY1xuXHRcdC8vIC0gbWFpbiBuYXYgc2Nyb2xsZWRcblx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgZnVuY3Rpb24gKCkge1xuXHRcdFx0Y29uc3QgbWFpbkVsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCdtYWluJyk7XG5cblx0XHRcdC8vIG1haW4gbmF2IHN0YXRpY1xuXHRcdFx0Ly8gdXNlciBoYXMgbm90IHNjcm9sbGVkIHRvIGEgZGVwdGggbGVzcyB0aGFuIHRoZSBzaXRlSGVhZGVyIGhlaWdodFxuXHRcdFx0Ly8gb3IgaGFzIHNjb2xsZWQgYmFjayB0byB0aGUgdG9wIG9mIHRoZSBwYWdlXG5cdFx0XHRpZiAod2luZG93LnNjcm9sbFkgPiBzZWxmLnNpdGVIZWFkZXIub2Zmc2V0SGVpZ2h0KSB7XG5cdFx0XHRcdHNlbGYudG9nZ2xlRWxlbWVudENsYXNzZXMoXG5cdFx0XHRcdFx0c2VsZi5zaXRlSGVhZGVyLCAgICAgICAgICAgICAgICAvLyB0YXJnZXQgRE9NIGVsZW1lbnRcblx0XHRcdFx0XHRzZWxmLmhlYWRlck5hdlBhcmVudFNjcm9sbGVkLCAgIC8vIGNsYXNzIHRvIGFkZFxuXHRcdFx0XHRcdHNlbGYuaGVhZGVyTmF2UGFyZW50Tm90U2Nyb2xsZWQgLy8gY2xhc3MgdG8gcmVtb3ZlXG5cdFx0XHRcdCk7XG5cdFx0XHRcdHNlbGYudG9nZ2xlRWxlbWVudENsYXNzZXMoXG5cdFx0XHRcdFx0c2VsZi5oZWFkZXJOYXZXcmFwcGVyLCBcblx0XHRcdFx0XHRzZWxmLmhlYWRlck5hdlNjcm9sbGVkLCBcblx0XHRcdFx0XHRzZWxmLmhlYWRlck5hdk5vdFNjcm9sbGVkXG5cdFx0XHRcdCk7XG5cdFx0XHRcdHNlbGYudG9nZ2xlRWxlbWVudENsYXNzZXMoXG5cdFx0XHRcdFx0c2VsZi5uYXYsIFxuXHRcdFx0XHRcdHNlbGYuaGVhZGVyTmF2U2Nyb2xsZWQsIFxuXHRcdFx0XHRcdHNlbGYuaGVhZGVyTmF2Tm90U2Nyb2xsZWRcblx0XHRcdFx0KTtcblxuXHRcdFx0XHRpZiggc2VsZi5vcGVuRHJhd2VySGVpZ2h0ID4gMCApIHtcblx0XHRcdFx0XHQvLyBhZGQgODAgYmVsb3cgdG8gYWNjb3VudCBmb3IgLmhlYWRlci1uYXYtd3JhcHBlciBoZWlnaHQgYW5kIGJvdHRvbSBtYXJnaW5cblx0XHRcdFx0XHRtYWluRWxlbWVudC5zdHlsZS5wYWRkaW5nVG9wID0gc2VsZi5vcGVuRHJhd2VySGVpZ2h0ICsgODAgKyAncHgnOyBcblx0XHRcdFx0fVxuXHRcdFx0Ly8gbWFpbiBuYXYgc2Nyb2xsZWRcblx0XHRcdC8vIHVzZXIgaGFzIHNjcm9sbGVkIHRvIGEgZGVwdGggZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIHRoZSBzaXRlSGVhZG
140VyIGhlaWdodFxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0c2VsZi50b2dnbGVFbGVtZW50Q2xhc3Nlcyhcblx0XHRcdFx0XHRzZWxmLnNpdGVIZWFkZXIsICAgICAgICAgICAgICAgICAvLyB0YXJnZXQgRE9NIGVsZW1lbnRcblx0XHRcdFx0XHRzZWxmLmhlYWRlck5hdlBhcmVudE5vdFNjcm9sbGVkLCAvLyBjbGFzcyB0byBhZGRcblx0XHRcdFx0XHRzZWxmLmhlYWRlck5hdlBhcmVudFNjcm9sbGVkICAgICAvLyBjbGFzcyB0byByZW1vdmVcblx0XHRcdFx0KTtcblx0XHRcdFx0c2VsZi50b2dnbGVFbGVtZW50Q2xhc3Nlcyhcblx0XHRcdFx0XHRzZWxmLmhlYWRlck5hdldyYXBwZXIsIFxuXHRcdFx0XHRcdHNlbGYuaGVhZGVyTmF2Tm90U2Nyb2xsZWQsIFxuXHRcdFx0XHRcdHNlbGYuaGVhZGVyTmF2U2Nyb2xsZWRcblx0XHRcdFx0KTtcblx0XHRcdFx0c2VsZi50b2dnbGVFbGVtZW50Q2xhc3Nlcyhcblx0XHRcdFx0XHRzZWxmLm5hdiwgXG5cdFx0XHRcdFx0c2VsZi5oZWFkZXJOYXZOb3RTY3JvbGxlZCwgXG5cdFx0XHRcdFx0c2VsZi5oZWFkZXJOYXZTY3JvbGxlZFxuXHRcdFx0XHQpO1xuXG5cdFx0XHRcdG1haW5FbGVtZW50LnN0eWxlLnBhZGRpbmdUb3AgPSAnJztcblx0XHRcdH1cblx0XHR9KTtcblx0fVxuXG5cblx0LyoqXG5cdCAqIEBzdW1tYXJ5IEFkZCBsaXN0ZW5lcnMgZm9yIGRyYXdlciBpbnRlcmFjdGl2aXR5XG5cdCAqIFxuXHQgKiBAcmV0dXJuIHt2b2lkfVxuXHQgKi9cblx0ZHJhd2VySW50ZXJhY3Rpdml0eSgpIHtcblx0XHRjb25zdCBzZWxmID0gdGhpcztcblxuXHRcdC8vIEhhbmRsaW5nIGZvciBkcmF3ZXIgZGlzcGxheSB0b2dnbGUgYnV0dG9uc1xuXHRcdGZvciAoY29uc3QgZHJhd2VyTmFtZSBpbiBzZWxmLmRyYXdlcnMpIHtcblx0XHRcdGlmKCAhc2VsZi5kcmF3ZXJzW2RyYXdlck5hbWVdLmJ1dHRvbiApIGNvbnRpbnVlO1xuXG5cdFx0XHQvLyBIYW5kbGVzIGNsaWNrIGFuZCBlbnRlciBrZXlkb3duXG5cdFx0XHRzZWxmLmRyYXdlcnNbZHJhd2VyTmFtZV0uYnV0dG9uLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKGV2ZW50KSA9PiB7XG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdHNlbGYudG9nZ2xlRHJhd2VyKGRyYXdlck5hbWUsIGV2ZW50KTtcblx0XHRcdH0pO1xuXG5cdFx0fVxuXG5cdFx0Ly8gSGFuZGxpbmcgZm9yIHNlYXJjaCBjbG9zZSBidXR0b25cblx0XHRpZiggc2VsZi5zZWFyY2hEcmF3ZXJDbG9zZUJ1dHRvbiApIHtcblx0XHRcdFxuXHRcdFx0c2VsZi5zZWFyY2hEcmF3ZXJDbG9zZUJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcblx0XHRcdFx0Y29uc3Qgc2VhcmNoRHJhd2VyQ29uZmlnID0gc2VsZi5kcmF3ZXJzLnNlYXJjaDtcblx0XHRcdFx0aWYgKHNlYXJjaERyYXdlckNvbmZpZy5kcmF3ZXIuY2xhc3NMaXN0LmNvbnRhaW5zKHNlYXJjaERyYXdlckNvbmZpZy5kcmF3ZXJPcGVuKSkge1xuXHRcdFx0XHRcdHNlbGYudG9nZ2xlRWxlbWVudENsYXNzZXMoXG5cdFx0XHRcdFx0XHRzZWFyY2hEcmF3ZXJDb25maWcuZHJhd2VyLCAgICAgICAvLyB0YXJnZXQgRE9NIGVsZW1lbnRcblx0XHRcdFx0XHRcdHNlYXJjaERyYXdlckNvbmZpZy5kcmF3ZXJDbG9zZWQsIC8vIGNsYXNzIHRvIGFkZFxuXHRcdFx0XHRcdFx0c2VhcmNoRHJhd2VyQ29uZmlnLmRyYXdlck9wZW4gICAgLy8gY2xhc3MgdG8gcmVtb3ZlXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRzZWxmLnRvZ2dsZUVsZW1lbnRDbGFzc2VzKFxuXHRcdFx0XHRcdFx0c2VhcmNoRHJhd2VyQ29uZmlnLmJ1dHRvbiwgICAgICAgXG5cdFx0XHRcdFx0XHRzZWFyY2hEcmF3ZXJDb25maWcuYnV0dG9uQ2xvc2VkLCBcblx0XHRcdFx0XHRcdHNlYXJjaERyYXdlckNvbmZpZy5idXR0b25PcGVuICAgIFxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XG5cdFx0XHRcdFx0aWYgKFxuXHRcdFx0XHRcdFx0IXNlbGYuZHJhd2Vycy5yZWdpb25zLmRyYXdlci5jbGFzc0xpc3QuY29udGFpbnMoc2VsZi5kcmF3ZXJzLnJlZ2lvbnMuZHJhd2VyT3BlbikgXG5cdFx0XHRcdFx0XHQmJiAhc2VsZi5kcmF3ZXJzLm5ld3NsZXR0ZXJzLmRyYXdlci5jbGFzc0xpc3QuY29udGFpbnMoc2VsZi5kcmF3ZXJzLm5ld3NsZXR0ZXJzLmRyYXdlck9wZW4pXG5cdFx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0XHRzZWxmLmhlYWRlck5hdldyYXBwZXIuY2xhc3NMaXN0LnJlbW92ZShzZWxmLmhlYWRlck5hdkRyYXdlck9wZW4pO1xuXHRcdFx0XHRcdFx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnNpdGUtbmF2LXNlYXJjaCAjc2VhcmNoJykuc2V0QXR0cmlidXRlKCdhcmlhLWV4cGFuZGVkJywgJ2ZhbHNlJyk7XG5cdFx0XHRcdFx0XHRkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuc2l0ZS1uYXYtc2VhcmNoICNzZWFyY2gnKS5mb2N1cygpO1xuXG5cdFx0XHRcdFx0XHQvLyBSZW1vdmUgcGFkZGluZyBmcm9tIDxoZWFkZXI+XG5cdFx0XHRcdFx0XHRzZWxmLmhlYWRlckVsZW1lbnQuc3R5bGUucGFkZGluZ0JvdHRvbSA9ICcnO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fVxuXHR9XG5cblxuXHQvKipcblx0ICogQHN1bW1hcnkgRHJhd2VyIGRpc3BsYXkgdG9nZ2xpbmcgZnVuY3Rpb25hbGl0eVxuXHQgKiBcblx0ICogQGRlc2NyaXB0aW9uIFRyYXBzIGZvY3VzIGluIGV4cGFuZGVkIG5hdiwgbW9kYWxzLCBldGMuXG5cdCAqIFxuXHQgKiBAcGFyYW0gIHtzdHJpbmd9IGN1cnJlbnREcmF3ZXIgTmFtZSBvZiBjdXJyZW50IGRyYXdlclxuXHQgKiBAcGFyYW0gIHtvYmplY3R9IGV2ZW50IERPTSBldmVudFxuXHQgKlxuXHQgKiBAcmV0dXJuIHt2b2lkfVxuXHQgKi9cblx0dG9nZ2xlRHJhd2VyKGN1cnJlbnREcmF3ZXIsIGV2ZW50KSB7XG5cdFx0Y29uc3Qgc2VsZiA9IHRoaXM7XG5cblx0XHQvLyBDaGVjayBpZiBvdGhlciBkcmF3ZXJzIGFyZSBvcGVuIGFuZCBjbG9zZSB0aGVtIGlmIHRoZXkgYXJlXG5cdFx0Zm9yIChsZXQgZHJhd2VyTmFtZSBpbiBzZWxmLmRyYXdlcnMpIHtcblx0XHRcdGlmIChkcmF3ZXJOYW1lICE9PSBjdXJyZW50RHJhd2VyKSB7XG5cdFx0XHRcdGNvbnN0IGRyYXdlck9iaiA9IHNlbGYuZHJhd2Vyc1tkcmF3ZXJOYW1lXTtcblx0XHRcdFx0aWYgKFxuXHRcdFx0XHRcdGRyYXdlck9iai5kcmF3ZXIgXG5cdFx0XHRcdFx0JiYgZHJhd2VyT2JqLmRyYXdlci5jbGFzc0xpc3QgXG5cdFx0XHRcdFx0JiYgZHJhd2VyT2JqLmRyYXdlci5jbGFzc0xpc3QuY29udGFpbnMoZHJhd2VyT2JqLmRyYXdlck9wZW4pXG5cdFx0XHRcdCkge1xuXHRcdFx0XHRcdHNlbGYudG9nZ2xlRWxlbWVudENsYXNzZXMoXG5cdFx0XHRcdFx0XHRkcmF3ZXJPYmouZHJhd2VyLCAgICAgICAvLyB0YXJnZXQgRE9NIGVsZW1lbnRcblx0XHRcdFx0XHRcdGRyYXdlck9iai5kcmF3ZXJDbG9zZWQsIC8vIGNsYXNzIHRvIGFkZFxuXHRcdFx0XHRcdFx0ZHJhd2VyT2JqLmRyYXdlck9wZW4gICAgLy8gY2xhc3MgdG8gcmVtb3ZlXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRzZWxmLnRvZ2dsZUVsZW1lbnRDbGFzc2VzKFxuXHRcdFx0XHRcdFx0ZHJhd2VyT2JqLmJ1dHRvbixcblx0XHRcdFx0XHRcdGRyYXdlck9iai5idXR0b25DbG9zZWQsXG5cdFx0XHRcdFx0XHRkcmF3ZXJPYmouYnV0dG9uT3BlblxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRjb25zdCBhY3RpdmVEcmF3ZXIgPSBzZWxmLmRyYXdlcnNbY3VycmVudERyYXdlcl07XG5cblx0XHRpZiAoYWN0aXZlRHJhd2VyLmRyYXdlci5jbGFzc0xpc3QuY29udGFpbnMoYWN0aXZlRHJhd2VyLmRyYXdlck9wZW4pKSB7XG5cdFx0XHRzZWxmLnRvZ2dsZUVsZW1lbnRDbGFzc2VzKFxuXHRcdFx0XHRhY3RpdmVEcmF3ZXIuYnV0dG9uLCAgICAgICAvLyB0YXJnZXQgRE9NIGVsZW1lbnRcblx0XHRcdFx0YWN0aXZlRHJhd2VyLmJ1dHRvbkNsb3NlZCwgLy8gY2xhc3MgdG8gYWRkXG5cdFx0XHRcdGFjdGl2ZURyYXdlci5idXR0b25PcGVuICAgIC8vIGNsYXNzIHRvIHJlbW92ZVxuXHRcdFx0KTtcblx0XHRcdHNlbGYudG9nZ2xlRWxlbWVudENsYXNzZXMoXG5cdFx0XHRcdGFjdGl2ZURyYXdlci5kcmF3ZXIsXG5cdFx0XHRcdGFjdGl2ZURyYXdlci5kcmF3ZXJDbG9zZWQsXG5cdFx0XHRcdGFjdGl2ZURyYXdlci5kcmF3ZXJPcGVuXG5cdFx0XHQpO1xuXHRcdFx0XG5cdFx0XHRzZWxmLmhlYWRlck5hdldyYXBwZXIuY2xhc3NMaXN0LnJlbW92ZShzZWxmLmhlYWRlck5hdkRyYXdlck9wZW4pO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRzZWxmLnRvZ2dsZUVsZW1lbnRDbGFzc2VzKFxuXHRcdFx0XHRhY3RpdmVEcmF3ZXIuYnV0dG9uLFxuXHRcdFx0XHRhY3RpdmVEcmF3ZXIuYnV0dG9uT3Blbixcblx0XHRcdFx0YWN0aXZlRHJhd2VyLmJ1dHRvbkNsb3NlZFxuXHRcdFx0KTtcblx0XHRcdHNlbGYudG9nZ2xlRWxlbWVudENsYXNzZXMoXG5cdFx0XHRcdGFjdGl2ZURyYXdlci5kcmF3ZXIsXG5cdFx0XHRcdGFjdGl2ZURyYXdlci5kcmF3ZXJPcGVuLFxuXHRcdFx0XHRhY3RpdmVEcmF3ZXIuZHJhd2VyQ2xvc2VkXG5cdFx0XHQpO1xuXHRcdFx0XG5cdFx0XHRzZWxmLmhlYWRlck5hdldyYXBwZXIuY2xhc3NMaXN0LmFkZChzZWxmLmhlYWRlck5hdkRyYXdlck9wZW4pO1xuXHRcdH1cblxuXHRcdGxldCBpc0V4cGFuZGVkID0gZmFsc2U7XG5cdFx0aWYgKGFjdGl2ZURyYXdlci5kcmF3ZXIuY2xhc3NMaXN0LmNvbnRhaW5zKGFjdGl2ZURyYXdlci5kcmF3ZXJPcGVuKSkgaXNFeHBhbmRlZCA9IHRydWU7XG5cdFx0aWYgKGlzRXhwYW5kZWQpIHtcblx0XHRcdC8vIHNldCBhcmlhLWV4cGFuZGVkIGF0dHJpYnV0ZSB0byB0cnVlIGZvciBwYXJlbnQgPGE+IHRhZ1xuXHRcdFx0YWN0aXZlRHJhd2VyLmJ1dHRvbi5zZXRBdHRyaWJ1dGUoJ2FyaWEtZXhwYW5kZWQnLCAndHJ1ZScpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBzZXQgYXJpYS1leHBhbmRlZCBhdHRyaWJ1dGUgdG8gZmFsc2UgZm9yIHBhcmVudCA8YT4gdGFnXG5cdFx0XHRhY3RpdmVEcmF3ZXIuYnV0dG9uLnNldEF0dHJpYnV0ZSgnYXJpYS1leHBhbmRlZCcsICdmYWxzZScpO1xuXHRcdH1cbiBcblx0XHQvLyBzZXQgcGFkZGluZyB0byA8aGVhZGVyPiB0byBwdXNoIGNvbnRlbnQgZG93biB3aGVuIGRyYXdlciBpcyBvcGVuXG5cdFx0c2VsZi5vcGVuRHJhd2VySGVpZ2h0ID0gYWN0aXZlRHJhd2VyLmRyYXdlci5vZmZzZXRIZWlnaHQgPz8gMDtcblx0XHRzZWxmLmhlYWRlckVsZW1lbnQuc3R5bGUucGFkZGluZ0JvdHRvbSA9IHNlbGYub3BlbkRyYXdlckhlaWdodCArICdweCc7XG5cblx0XHQvLyBzZXQgZm9jdXMgYW5kIENTUyBjbGFzc2VzIGZvciBkcmF3ZXJzXG5cdFx0c3dpdGNoIChjdXJyZW50RHJhd2VyKSB7XG5cdFx0Y2FzZSAnc2VhcmNoJzpcblx0XHRcdGFjdGl2ZURyYXdlci5kcmF3ZXIuc2V0QXR0cmlidXRlKCdhcmlhLWh
140pZGRlbicsICdmYWxzZScpO1xuXHRcdFx0c2VsZi5zZWFyY2hEcmF3ZXJJbnB1dEZpZWxkLmZvY3VzKCk7XG5cdFx0XHQvLyBvbmx5IGFwcGx5IGZvY3VzIG91dGxpbmUgc3R5bGUgaWYgdXNlciBuYXZpZ2F0ZWQgdmlhIGtleWJvYXJkXG5cdFx0XHRpZiAoJ0VudGVyJyAhPT0gZXZlbnQua2V5KSB7XG5cdFx0XHRcdHNlbGYuc2VhcmNoRHJhd2VySW5wdXRGaWVsZC5jbGFzc0xpc3QuYWRkKCduby1mb2N1cy1vdXRsaW5lJyk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRzZWxmLnNlYXJjaERyYXdlcklucHV0RmllbGQuY2xhc3NMaXN0LnJlbW92ZSgnbm8tZm9jdXMtb3V0bGluZScpO1xuXHRcdFx0fVxuXHRcdFx0YnJlYWs7XG5cdFx0ZGVmYXVsdDpcblx0XHRcdGlmIChpc0V4cGFuZGVkKSB7XG5cdFx0XHRcdC8vIHNldCBhcmlhLWhpZGRlbiBhdHRyaWJ1dGUgdG8gZmFsc2Vcblx0XHRcdFx0YWN0aXZlRHJhd2VyLmRyYXdlci5zZXRBdHRyaWJ1dGUoJ2FyaWEtaGlkZGVuJywgJ2ZhbHNlJyk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQvLyBzZXQgYXJpYS1oaWRkZW4gYXR0cmlidXRlIHRvIGZhbHNlXG5cdFx0XHRcdGFjdGl2ZURyYXdlci5kcmF3ZXIuc2V0QXR0cmlidXRlKCdhcmlhLWhpZGRlbicsICd0cnVlJyk7XG5cdFx0XHR9XG5cdFx0XHRicmVhaztcblx0XHR9XG5cdH1cblxuXHRcblx0LyoqXG5cdCAqIEBzdW1tYXJ5IE1vYmlsZSBkcmF3ZXIgZGlzcGxheSB0b2dnbGluZyBmdW5jdGlvbmFsaXR5XG5cdCAqIFxuXHQgKiBAcmV0dXJuIHt2b2lkfVxuXHQgKi9cblx0bW9iaWxlRHJhd2VySW50ZXJhY3Rpdml0eSgpIHtcblx0XHRjb25zdCBzZWxmID0gdGhpcztcblxuXHRcdC8vIEhhbmRsaW5nIGZvciBtb2JpbGVEcmF3ZXJCdXR0b25cblx0XHRzZWxmLm1vYmlsZURyYXdlckJ1dHRvbnMuZm9yRWFjaCgobW9iaWxlRHJhd2VyQnV0dG9uKSA9PiB7XG5cdFx0XHRtb2JpbGVEcmF3ZXJCdXR0b24uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoZSkgPT4ge1xuXHRcdFx0XHRpZiAod2luZG93LmlubmVyV2lkdGggPiA5NzkpIHJldHVybjtcblxuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdFx0bW9iaWxlRHJhd2VyQnV0dG9uLmNsYXNzTGlzdC50b2dnbGUoc2VsZi5tb2JpbGVEcmF3ZXJPcGVuKTtcblx0XHRcdFx0bW9iaWxlRHJhd2VyQnV0dG9uLmNsYXNzTGlzdC50b2dnbGUoc2VsZi5tb2JpbGVEcmF3ZXJDbG9zZWQpO1xuXG5cdFx0XHRcdGlmICghbW9iaWxlRHJhd2VyQnV0dG9uLmNsYXNzTGlzdC5jb250YWlucyhzZWxmLm1vYmlsZURyYXdlck9wZW4pKSB7XG5cdFx0XHRcdFx0c2VsZi5oZWFkZXJOYXZXcmFwcGVyLmNsYXNzTGlzdC5yZW1vdmUoc2VsZi5oZWFkZXJOYXZEcmF3ZXJPcGVuKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fSk7XG5cdH1cblxuXG5cdC8qKlxuXHQgKiBAc3VtbWFyeSBGdWxsIG1lbnUgZGlzcGxheSB0b2dnbGluZyBmdW5jdGlvbmFsaXR5XG5cdCAqIFxuXHQgKiBAcmV0dXJuIHt2b2lkfVxuXHQgKi9cblx0ZnVsbE1lbnVJbnRlcmFjdGl2aXR5KCkge1xuXHRcdGNvbnN0IHNlbGYgPSB0aGlzO1xuXG5cdFx0c2VsZi5oYW1idXJnZXJCdXR0b25zLmZvckVhY2goKGhhbWJ1cmdlckJ1dHRvbikgPT4ge1xuXHRcdFx0aGFtYnVyZ2VyQnV0dG9uLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRoYW1idXJnZXJCdXR0b24uc2V0QXR0cmlidXRlKCdhcmlhLWV4cGFuZGVkJywgJ3RydWUnKTtcblx0XHRcdFx0XG5cdFx0XHRcdHNlbGYudG9nZ2xlRWxlbWVudENsYXNzZXMoXG5cdFx0XHRcdFx0c2VsZi5kZXNrdG9wTWVudSxcblx0XHRcdFx0XHRzZWxmLmRlc2t0b3BNZW51T3Blbixcblx0XHRcdFx0XHRzZWxmLmRlc2t0b3BNZW51Q2xvc2VkXG5cdFx0XHRcdCk7XG5cdFx0XHRcdFxuXHRcdFx0XHRzZWxmLmRlc2t0b3BNZW51LnNldEF0dHJpYnV0ZSgnYXJpYS1leHBhbmRlZCcsICd0cnVlJyk7XG5cdFx0XHRcdHNlbGYuZGVza3RvcE1lbnUuc2V0QXR0cmlidXRlKCdhcmlhLWhpZGRlbicsICdmYWxzZScpO1xuXHRcdFx0XHRcblx0XHRcdFx0c2V0VGltZW91dCgoKSA9PiB7XG5cdFx0XHRcdFx0c2VsZi5jbG9zZUJ1dHRvbnNbMF0uZm9jdXMoKTtcblx0XHRcdFx0fSwgMTAwKTtcblx0XHRcdFx0XG5cdFx0XHRcdGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5uYXYtZnVsbC1tZW51Jykuc2Nyb2xsVG9wID0gMDtcblx0XHRcdFx0XG5cdFx0XHRcdGRvY3VtZW50LmJvZHkuY2xhc3NMaXN0LmFkZCgnb3ZlcmxheS1uby1zY3JvbGwnKTtcblx0XHRcdH0pO1xuXHRcdH0pO1xuXG5cdFx0c2VsZi5jbG9zZUJ1dHRvbnMuZm9yRWFjaCgoY2xvc2VCdXR0b24pID0+IHtcblx0XHRcdGNsb3NlQnV0dG9uLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRzZWxmLnRvZ2dsZUVsZW1lbnRDbGFzc2VzKFxuXHRcdFx0XHRcdHNlbGYuZGVza3RvcE1lbnUsXG5cdFx0XHRcdFx0c2VsZi5kZXNrdG9wTWVudUNsb3NlZCxcblx0XHRcdFx0XHRzZWxmLmRlc2t0b3BNZW51T3BlblxuXHRcdFx0XHQpO1xuXHRcdFx0XHRcblx0XHRcdFx0c2VsZi5kZXNrdG9wTWVudS5zZXRBdHRyaWJ1dGUoJ2FyaWEtZXhwYW5kZWQnLCAnZmFsc2UnKTtcblx0XHRcdFx0c2VsZi5kZXNrdG9wTWVudS5zZXRBdHRyaWJ1dGUoJ2FyaWEtaGlkZGVuJywgJ3RydWUnKTtcblxuXHRcdFx0XHRzZWxmLmhhbWJ1cmdlckJ1dHRvbnMuZm9yRWFjaCgoaGFtYnVyZ2VyQnV0dG9uKSA9PiB7XG5cdFx0XHRcdFx0aGFtYnVyZ2VyQnV0dG9uLnNldEF0dHJpYnV0ZSgnYXJpYS1leHBhbmRlZCcsICdmYWxzZScpO1xuXHRcdFx0XHR9KTtcblxuXHRcdFx0XHRzZWxmLmhhbWJ1cmdlckJ1dHRvbnNbMF0uZm9jdXMoKTtcblxuXHRcdFx0XHRkb2N1bWVudC5ib2R5LmNsYXNzTGlzdC5yZW1vdmUoJ292ZXJsYXktbm8tc2Nyb2xsJyk7XG5cdFx0XHR9KTtcblx0XHR9KTtcblx0fVxuXG5cblx0LyoqXG5cdCAqIEBzdW1tYXJ5IEFkZCBsaXN0ZW5lcnMgZm9yIHVzZXIgbWVudSBpbnRlcmFjdGl2aXR5XG5cdCAqXG5cdCAqIEBwYXJhbSAge29iamVjdH0gdXNlckljb24gdXNlciBpY29uIERPTSBlbGVtZW50IG9iamVjdFxuXHQgKiBAcGFyYW0gIHtvYmplY3R9IHVzZXJNZW51IHVzZXIgbWVudXUgRE9NIGVsZW1lbnQgb2JqZWN0XG5cdCAqIFxuXHQgKiBAcmV0dXJuIHt2b2lkfVxuXHQgKi9cblx0dXNlck1lbnVJbnRlcmFjdGl2aXR5KHVzZXJJY29uLCB1c2VyTWVudSkge1xuXHRcdGlmKCAhdXNlckljb24gKSByZXR1cm47XG5cblx0XHR1c2VySWNvb
140i5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uIChldmVudCkge1xuXHRcdFx0XG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRpZiAodXNlck1lbnUuc3R5bGUuZGlzcGxheSAhPT0gJ2Jsb2NrJykge1xuXHRcdFx0XHR1c2VySWNvbi5zZXRBdHRyaWJ1dGUoJ2FyaWEtZXhwYW5kZWQnLCAndHJ1ZScpO1xuXHRcdFx0XHR1c2VyTWVudS5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHVzZXJJY29uLnNldEF0dHJpYnV0ZSgnYXJpYS1leHBhbmRlZCcsICdmYWxzZScpO1xuXHRcdFx0XHR1c2VyTWVudS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0dXNlckljb24uYWRkRXZlbnRMaXN0ZW5lcignbW91c2VlbnRlcicsIGZ1bmN0aW9uICgpIHtcblx0XHRcdHVzZXJJY29uLnNldEF0dHJpYnV0ZSgnYXJpYS1leHBhbmRlZCcsICd0cnVlJyk7XG5cdFx0XHR1c2VyTWVudS5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblx0XHR9KTtcblxuXHRcdHVzZXJNZW51LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbGVhdmUnLCBmdW5jdGlvbiAoKSB7XG5cdFx0XHR1c2VySWNvbi5zZXRBdHRyaWJ1dGUoJ2FyaWEtZXhwYW5kZWQnLCAnZmFsc2UnKTtcblx0XHRcdHVzZXJNZW51LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cdFx0fSk7XG5cdH1cblxuXG5cdC8qKlxuXHQgKiBAc3VtbWFyeSBUcmFwIGZvY3VzIGZ1bmN0aW9uYWxpdHkgaW4gZXhwYW5kZWQgbWVudSBpdGVtcyBhbmQgZXhwYW5kZWQgbmF2XG5cdCAqIFxuXHQgKiBAcmV0dXJuIHt2b2lkfVxuXHQgKi9cblx0dHJhcEZvY3VzSW50ZXJhY3Rpdml0eSgpIHtcblx0XHRGUC5VdGlscy50cmFwRm9jdXMuaW5pdChkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcjZXhwYW5kZWQtbmF2aWdhdGlvbicpKTtcblx0fVxuXG5cblx0LyoqXG5cdCAqIEBzdW1tYXJ5IEhlbHBlciB0byBjbG9zZSBhbGwgZHJhd2VycyBvbiBkZXNrdG9wXG5cdCAqIFxuXHQgKiBAcmV0dXJuIHt2b2lkfVxuXHQgKi9cblx0Y2xvc2VBbGxEcmF3ZXJzKCkge1xuXHRcdGNvbnN0IHNlbGYgPSB0aGlzO1xuXG5cdFx0Zm9yIChsZXQgZHJhd2VyTmFtZSBpbiBzZWxmLmRyYXdlcnMpIHtcblx0XHRcdGNvbnN0IGRyYXdlck9iaiA9IHNlbGYuZHJhd2Vyc1tkcmF3ZXJOYW1lXTtcblx0XHRcdFxuXHRcdFx0c2VsZi50b2dnbGVFbGVtZW50Q2xhc3Nlcyhcblx0XHRcdFx0ZHJhd2VyT2JqLmRyYXdlcixcblx0XHRcdFx0ZHJhd2VyT2JqLmRyYXdlckNsb3NlZCxcblx0XHRcdFx0ZHJhd2VyT2JqLmRyYXdlck9wZW5cblx0XHRcdCk7XG5cdFx0XHRzZWxmLnRvZ2dsZUVsZW1lbnRDbGFzc2VzKFxuXHRcdFx0XHRkcmF3ZXJPYmouYnV0dG9uLFxuXHRcdFx0XHRkcmF3ZXJPYmouYnV0dG9uQ2xvc2VkLFxuXHRcdFx0XHRkcmF3ZXJPYmouYnV0dG9uT3BlblxuXHRcdFx0KTtcblxuXHRcdFx0ZHJhd2VyT2JqLmJ1dHRvbi5zZXRBdHRyaWJ1dGUoJ2FyaWEtZXhwYW5kZWQnLCAnZmFsc2UnKTtcblx0XHR9XG5cblx0XHQvLyB1cGRhdGUgaGVhZGVyIGVsZW1lbnRzXG5cdFx0c2VsZi5oZWFkZXJOYXZXcmFwcGVyLmNsYXNzTGlzdC5yZW1vdmUoc2VsZi5oZWFkZXJOYXZEcmF3ZXJPcGVuKTtcblx0XHRzZWxmLmhlYWRlckVsZW1lbnQuc3R5bGUucGFkZGluZ0JvdHRvbSA9ICcnO1xuXG5cdFx0Ly8gcmVzZXQgb3BlbiBkcmF3ZXIgaGVpZ2h0IHRvIDBcblx0XHRzZWxmLm9wZW5EcmF3ZXJIZWlnaHQgPSAwO1xuXG5cdFx0Ly8gdXBkYXRlIG1haW4gZWxlbWVudFxuXHRcdGNvbnN0IG1haW5FbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignbWFpbicpO1xuXHRcdG1haW5FbGVtZW50LnN0eWxlLnBhZGRpbmdUb3AgPSAnJztcblxuXHRcdC8vIGNsb3NlIHVzZXIgbWVudXNcblx0XHRzZWxmLnVzZXJNZW51LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cdFx0c2VsZi51c2VyTWVudUZ1bGxNZW51LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cdFx0c2VsZi51c2VySWNvbi5zZXRBdHRyaWJ1dGUoJ2FyaWEtZXhwYW5kZWQnLCAnZmFsc2UnKTtcblx0XHRzZWxmLnVzZXJJY29uRnVsbE1lbnUuc2V0QXR0cmlidXRlKCdhcmlhLWV4cGFuZGVkJywgJ2ZhbHNlJyk7XG5cdH1cblxuXHRcblx0LyoqXG5cdCAqIEBzdW1tYXJ5IEhlbHBlciB0byBmb2N1cyBvbiBwYXJlbnQgZWxlbWVudCBhZnRlciBjbG9zaW5nIGRyYXdlcnNcblx0ICpcblx0ICogQHBhcmFtICB7b2JqZWN0fSBjb250YWluZXJFbGVtZW50IERPTSBlbGVtZW50IG9iamVjdFxuXHQgKiBcblx0ICogQHJldHVybiB7dm9pZH1cblx0ICovXG5cdGZvY3VzT25QYXJlbnQoY29udGFpbmVyRWxlbWVudCkge1xuXHRcdC8vIFRPLURPIC0gbWFrZSB0aGlzIG1vcmUgZmxleGlibGUsIG5vdCBvbmx5IHNlYXJjaGluZyBmb3IgYW4gPGE+IHRhZ1xuXHRcdHZhciBmb2N1c0VsID0gY29udGFpbmVyRWxlbWVudC5wYXJlbnROb2RlLnF1ZXJ5U2VsZWN0b3IoJ2EnKTtcblxuXHRcdGlmKCBmb2N1c0VsICkge1xuXHRcdFx0Zm9jdXNFbC5zZXRBdHRyaWJ1dGUoJ2FyaWEtZXhwYW5kZWQnLCAnZmFsc2UnKTtcblx0XHRcdGZvY3VzRWwuZm9jdXMoKTtcblx0XHR9XG5cdH1cblxuXG5cdC8qKlxuXHQgKiBAc3VtbWFyeSBIZWxwZXIgdG8gaGFuZGxlIGZ1bGwgbmF2IGNsb3N1cmUgd2l0aCBrZXlib2FyZCBpbnB1dFxuXHQgKlxuXHQgKiBAZGVzY3JpcHRpb24gQWxsb3cgZXhwYW5kZWQgbmF2IHRvIGJlIGNsb3NlZCB3aGVuOlxuXHQgKiAgICAgIC0gdGhlIHVzZXIgcHJlc3NlcyB0aGUgRXNjYXBlIGtleVxuXHQgKiAgICAgIC0gdGhlIHVzZXIgc2hpZnQgKyB0YWJzIGJhY2sgcGFzdCB0aGUgZmlyc3QgaXRlbSBpbiB0aGUgZHJhd2VyXG5cdCAqICAgICAgLSB0aGUgdXNlciB0YWJzIHBhc3QgdGhlIGxhc3QgaXRlbSBpbiB0aGUgZHJhd2VyXG5cdCAqXG5cdCAqIEBwYXJhbSAge2FycmF5fSBjb250YWluZXJFbGVtZW50cyBBcnJheSBvZiBET00gZWxlbWVudHMgZnJvbSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKClcblx0ICogXG5cdCAqIEByZXR1cm4ge3ZvaWR9XG5cdCAqL1xuXHRrZXlib2FyZENsb3NlRXhwYW5kZWREcmF3ZXJDb250ZW50KGNvbnRhaW5lckVsZW1lbnRzKSB7XG5cdFx0Y29uc3Qgc2VsZiA9IHRoaXM7XG5cblx0XHRjb250YWluZXJFbGVtZW50cy5mb3JFYWNoKChjb250YWluZXJFbGVtZW50KSA9PiB7XG5cdFx0XHR2YXIgZm9jdXNhYmxlRWxzID0gRlAuVXRpbHMudHJhcEZvY3VzLmdldGZvY3VzYWJsZUVscyhjb250YWluZXJFbGVtZW50KTtcblx0XHRcdHZhciBmaXJzdEZvY3VzYWJsZUVsID0gZm9jdXNhYmxlRWxzWzBdOyAgXG5cdFx0XHR2YXIgbGFzdEZvY3VzYWJsZUVsID0gZm9jdXNhYmxlRWxzW2ZvY3VzYWJsZUVscy5sZW5ndGggLSAxXTtcblxuXHRcdFx0Y29udGFpbmVyRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgZnVuY3Rpb24oZSkge1xuXHRcdFx0XHR2YXIgaXNFc2NhcGVQcmVzc2VkID0gKGUua2V5ID09PSAnRXNjJyB8fCBlLmtleUNvZGUgPT09IHNlbGYuS0VZQ09ERV9FU0MpO1xuXHRcdFx0XHR2YXIgaXNUYWJQcmVzc2VkID0gKGUua2V5ID09PSAnVGFiJyB8fCBlLmtleUNvZGUgPT09IHNlbGYuS0VZQ09ERV9UQUIpO1xuXG5cdFx0XHRcdGlmICghaXNFc2NhcGVQcmVzc2VkICYmICFpc1RhYlByZXNzZWQpIHsgXG5cdFx0XHRcdFx0cmV0dXJuOyBcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHZhciBwcm9jZXNzQWN0aW9uID0gZmFsc2U7XG5cdFx0XHRcdHZhciBjaGFuZ2VGb2N1cyA9IGZhbHNlO1xuXG5cdFx0XHRcdC8vIGVzYyBwcmVzc2VkXG5cdFx0XHRcdGlmICggaXNFc2NhcGVQcmVzc2VkICkge1xuXHRcdFx0XHRcdHByb2Nlc3NBY3Rpb24gPSB0cnVlO1xuXHRcdFx0XHRcdGNoYW5nZUZvY3VzID0gdHJ1ZTtcblx0XHRcdFx0Ly8gc2hpZnQgKyB0YWIgcHJlc3NlZFxuXHRcdFx0XHR9IGVsc2UgaWYgKCBlLnNoaWZ0S2V5ICkge1xuXHRcdFx0XHRcdC8vIGlmIHVzZXIgaXMgb24gdGhlIGZpcnN0IGZvY3VzYWJsZSBlbGVtZW50IGluIHRoZSBkcmF3ZXJcblx0XHRcdFx0XHRpZiAoZG9jdW1lbnQuYWN0aXZlRWxlbWVudCA9PT0gZmlyc3RGb2N1c2FibGVFbCkge1xuXHRcdFx0XHRcdFx0cHJvY2Vzc0FjdGlvbiA9IHRydWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHQvLyB0YWIgcHJlc3NlZFxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdC8vIGlmIHVzZXIgaXMgb24gdGhlIGxhc3QgZm9jdXNhYmxlIGVsZW1lbnQgaW4gdGhlIGRyYXdlclxuXHRcdFx0XHRcdGlmIChkb2N1bWVudC5hY3RpdmVFbGVtZW50ID09PSBsYXN0Rm9jdXNhYmxlRWwpIHtcblx0XHRcdFx0XHRcdHByb2Nlc3NBY3Rpb24gPSB0cnVlO1xuXHRcdFx0XHRcdFx0Y2hhbmdlRm9jdXMgPSB0cnVlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIHJ1biBhZGRpdGlvbmFsIGNvZGUgdG8gY2xvc2UgZHJhd2VycyBvciBmb2N1cyBvbiBwYXJlbnQgZWxlbWVudFxuXHRcdFx0XHRpZiAoIHByb2Nlc3NBY3Rpb24gKSB7XG5cdFx0XHRcdFx0Ly8gY2xvc2UgYWxsIGRyYXdlcnNcblx0XHRcdFx0XHRzZWxmLmNsb3NlQWxsRHJhd2VycygpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggY2hhbmdlRm9jdXMgKSB7XG5cdFx0XHRcdFx0Ly8gZm9jdXMgb24gcGFyZW50IGVsZW1lbnRcblx0XHRcdFx0XHRzZWxmLmZvY3VzT25QYXJlbnQoY29udGFpbmVyRWxlbWVudCk7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdH0pO1xuXHR9XG5cblxuXHQvKipcblx0ICogQHN1bW1hcnkgSGVscGVyIHRvIHJlbW92ZSBhbmQgYWRkIGEgY2xhc3Ncblx0ICpcblx0ICogQHBhcmFtICB7b2JqZWN0fSBlbGVtZW50ICAgICBET00gZWxlbWVudFxuXHQgKiBAcGFyYW0gIHtzdHJpbmd9IGFkZENsYXNzICAgIENsYXNzIG5hbWUgdG8gYWRkIHRvIGVsZW1lbnRcblx0ICogQHBhcmFtICB7c3RyaW5nfSByZW1vdmVDbGFzcyBDbGFzcyBuYW1lIHRvIHJlbW92ZSBmcm9tIGVsZW1lbnRcblx0ICogXG5cdCAqIEByZXR1cm4ge3ZvaWR9XG5cdCAqL1xuXHR0b2dnbGVFbGVtZW50Q2xhc3NlcyhlbGVtZW50LCBhZGRDbGFzcywgcmVtb3ZlQ2xhc3MpIHtcblx0XHRlbGVtZW50Py5jbGFzc0xpc3Q/LnJlbW92ZShyZW1vdmVDbGFzcyk7XG5cdFx0ZWxlbWVudD8uY2xhc3NMaXN0Py5hZGQoYWRkQ2xhc3MpO1xuXHR9XG5cblxuXHQvKipcblx0ICogQHN1bW1hcnkgSGVscGVyIHRvIGFkanVzdCBmb2N1cyB3aXRoIFBpYW5vIGlmcmFtZXNcblx0ICpcblx0ICogQGRlc2NyaXB0aW9uIFRoaXMgaXMgbmVlZGVkIGFzIGEgd29ya2Fyb3VuZCBmb3IgdGhlIGlmcmFtZSBmb2N1cyBpc3N1ZVxuXHQgKiBcblx0ICogQHJldHVybi
140B7dm9pZH1cblx0ICovXG5cdG9ic2VydmVQaWFub0lmcmFtZXMoKSB7XG5cdFx0Ly8gT3B0aW9ucyBmb3IgdGhlIG9ic2VydmVyICh3aGljaCBtdXRhdGlvbnMgdG8gb2JzZXJ2ZSlcblx0XHRjb25zdCBjb25maWcgPSB7XG5cdFx0XHRhdHRyaWJ1dGVzOiBmYWxzZSxcblx0XHRcdGNoaWxkTGlzdDogdHJ1ZSxcblx0XHRcdHN1YnRyZWU6IHRydWVcblx0XHR9O1xuXG5cdFx0Ly8gQ2FsbGJhY2sgZnVuY3Rpb24gdG8gZXhlY3V0ZSB3aGVuIG11dGF0aW9ucyBhcmUgb2JzZXJ2ZWRcblx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW51c2VkLXZhcnNcblx0XHRjb25zdCBvYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKG11dGF0aW9ucyA9PiB7XG5cdFx0XHRtdXRhdGlvbnMuZm9yRWFjaChtdXRhdGlvbiA9PiB7XG5cdFx0XHRcdC8vIExvb3BpbmcgdGhyb3VnaCBhbGwgYWRkZWQgbm9kZXNcblx0XHRcdFx0bXV0YXRpb24uYWRkZWROb2Rlcy5mb3JFYWNoKG5vZGUgPT4ge1xuXHRcdFx0XHRcdGlmIChub2RlIGluc3RhbmNlb2YgRWxlbWVudCAmJiBub2RlLm1hdGNoZXMoJ2lmcmFtZScpKSB7XG5cdFx0XHRcdFx0XHQvLyBJZiB0aGUgYWRkZWQgbm9kZSBtYXRjaGVzIHRoZSBzZWxlY3RvciwgZXhlY3V0ZSB0aGUgY2FsbGJhY2sgYW5kIGRpc2Nvbm5lY3QgdGhlIG9ic2VydmVyXG5cdFx0XHRcdFx0XHRpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnRwLWNsb3NlJykpIHtcblx0XHRcdFx0XHRcdFx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLnRwLWNsb3NlJykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0c2V0VGltZW91dCgoKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0XHRsZXQgbG9naW5FbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLkZQLXBheXdhbGwtLWxvZ2luJyk7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAobG9naW5FbGVtZW50KSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGxvZ2luRWxlbWVudC5mb2N1cygpO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH0sIDc1MCk7XG5cdFx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0Ly9vYnNlcnZlci5kaXNjb25uZWN0KCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9KTtcblx0XHRcdH0pO1xuXHRcdH0pO1xuXG5cdFx0Ly8gU3RhcnQgb2JzZXJ2aW5nIHRoZSB0YXJnZXQgbm9kZSBmb3IgY29uZmlndXJlZCBtdXRhdGlvbnNcblx0XHRvYnNlcnZlci5vYnNlcnZlKGRvY3VtZW50LCBjb25maWcpO1xuXHR9XG5cbn1cblxud2luZG93LkZQTmF2ID0gbmV3IEZQTmF2KCk7XG53aW5kb3cuRlBOYXYuaW5pdCgpO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../assets/src/scripts/components/navigation/navigation.js\n\n}")},"./node_modules/@babel/runtime/helpers/esm/classCallCheck.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _classCallCheck)\n/* harmony export */ });\nfunction _classCallCheck(a, n) {\n if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vY2xhc3NDYWxsQ2hlY2suanMiLCJtYXBwaW5ncyI6Ijs7OztBQUFBO0FBQ0E7QUFDQSIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vY2xhc3NDYWxsQ2hlY2suanM/Njk1MiJdLCJzb3VyY2VzQ29udGVudCI6WyJmdW5jdGlvbiBfY2xhc3NDYWxsQ2hlY2soYSwgbikge1xuICBpZiAoIShhIGluc3RhbmNlb2YgbikpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb25cIik7XG59XG5leHBvcnQgeyBfY2xhc3NDYWxsQ2hlY2sgYXMgZGVmYXVsdCB9OyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/classCallCheck.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/createClass.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _createClass)\n/* harmony export */ });\n/* harmony import */ var _toPropertyKey_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./toPropertyKey.js */ "./node_modules/@babel/runtime/helpers/esm/toPropertyKey.js");\n\nfunction _defineProperties(e, r) {\n for (var t = 0; t < r.length; t++) {\n var o = r[t];\n o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, (0,_toPropertyKey_js__WEBPACK_IMPORTED_MODULE_0__["default"])(o.key), o);\n }\n}\nfunction _createClass(e, r, t) {\n return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {\n writable: !1\n }), e;\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vY3JlYXRlQ2xhc3MuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4vbm9kZV9tb2R1bGVzL0BiYWJlbC9ydW50aW1lL2hlbHBlcnMvZXNtL2NyZWF0ZUNsYXNzLmpzPzlhMzYiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHRvUHJv
140cGVydHlLZXkgZnJvbSBcIi4vdG9Qcm9wZXJ0eUtleS5qc1wiO1xuZnVuY3Rpb24gX2RlZmluZVByb3BlcnRpZXMoZSwgcikge1xuICBmb3IgKHZhciB0ID0gMDsgdCA8IHIubGVuZ3RoOyB0KyspIHtcbiAgICB2YXIgbyA9IHJbdF07XG4gICAgby5lbnVtZXJhYmxlID0gby5lbnVtZXJhYmxlIHx8ICExLCBvLmNvbmZpZ3VyYWJsZSA9ICEwLCBcInZhbHVlXCIgaW4gbyAmJiAoby53cml0YWJsZSA9ICEwKSwgT2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIHRvUHJvcGVydHlLZXkoby5rZXkpLCBvKTtcbiAgfVxufVxuZnVuY3Rpb24gX2NyZWF0ZUNsYXNzKGUsIHIsIHQpIHtcbiAgcmV0dXJuIHIgJiYgX2RlZmluZVByb3BlcnRpZXMoZS5wcm90b3R5cGUsIHIpLCB0ICYmIF9kZWZpbmVQcm9wZXJ0aWVzKGUsIHQpLCBPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwgXCJwcm90b3R5cGVcIiwge1xuICAgIHdyaXRhYmxlOiAhMVxuICB9KSwgZTtcbn1cbmV4cG9ydCB7IF9jcmVhdGVDbGFzcyBhcyBkZWZhdWx0IH07Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/createClass.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/toPrimitive.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ toPrimitive)\n/* harmony export */ });\n/* harmony import */ var _typeof_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./typeof.js */ "./node_modules/@babel/runtime/helpers/esm/typeof.js");\n\nfunction toPrimitive(t, r) {\n if ("object" != (0,_typeof_js__WEBPACK_IMPORTED_MODULE_0__["default"])(t) || !t) return t;\n var e = t[Symbol.toPrimitive];\n if (void 0 !== e) {\n var i = e.call(t, r || "default");\n if ("object" != (0,_typeof_js__WEBPACK_IMPORTED_MODULE_0__["default"])(i)) return i;\n throw new TypeError("@@toPrimitive must return a primitive value.");\n }\n return ("string" === r ? String : Number)(t);\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vdG9QcmltaXRpdmUuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZm9yZWlnbnBvbGljeS1idWlsZC8uL25vZGVfbW9kdWxlcy9AYmFiZWwvcnVudGltZS9oZWxwZXJzL2VzbS90b1ByaW1pdGl2ZS5qcz9lNWEzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBfdHlwZW9mIGZyb20gXCIuL3R5cGVvZi5qc1wiO1xuZnVuY3Rpb24gdG9QcmltaXRpdmUodCwgcikge1xuICBpZiAoXCJvYmplY3RcIiAhPSBfdHlwZW9mKHQpIHx8ICF0KSByZXR1cm4gdDtcbiAgdmFyIGUgPSB0W1N5bWJvbC50b1ByaW1pdGl2ZV07XG4gIGlmICh2b2lkIDAgIT09IGUpIHtcbiAgICB2YXIgaSA9IGUuY2FsbCh0LCByIHx8IFwiZGVmYXVsdFwiKTtcbiAgICBpZiAoXCJvYmplY3RcIiAhPSBfdHlwZW9mKGkpKSByZXR1cm4gaTtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQEB0b1ByaW1pdGl2ZSBtdXN0IHJldHVybiBhIHByaW1pdGl2ZSB2YWx1ZS5cIik7XG4gIH1cbiAgcmV0dXJuIChcInN0cmluZ1wiID09PSByID8gU3RyaW5nIDogTnVtYmVyKSh0KTtcbn1cbmV4cG9ydCB7IHRvUHJpbWl0aXZlIGFzIGRlZmF1bHQgfTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/toPrimitive.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/toPropertyKey.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ toPropertyKey)\n/* harmony export */ });\n/* harmony import */ var _typeof_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./typeof.js */ "./node_modules/@babel/runtime/helpers/esm/typeof.js");\n/* harmony import */ var _toPrimitive_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./toPrimitive.js */ "./node_modules/@babel/runtime/helpers/esm/toPrimitive.js");\n\n\nfunction toPropertyKey(t) {\n var i = (0,_toPrimitive_js__WEBPACK_IMPORTED_MODULE_1__["default"])(t, "string");\n return "symbol" == (0,_typeof_js__WEBPACK_IMPORTED_MODULE_0__["default"])(i) ? i : i + "";\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vdG9Qcm9wZXJ0eUtleS5qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4vbm9kZV9tb2R1bGVzL0BiYWJlbC9ydW50aW1lL2hlbHBlcnMvZXNtL3RvUHJvcGVydHlLZXkuanM/NGEyZCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgX3R5cGVvZiBmcm9tIFwiLi90eXBlb2YuanNcIjtcbmltcG9ydCB0b1ByaW1pdGl2ZSBmcm9tIFwiLi90b1ByaW1pdGl2ZS5qc1wiO1xuZnVuY3Rpb24gdG9Qcm9wZXJ0eUtleSh0KSB7XG4gIHZhciBpID0gdG9QcmltaXRpdmUodCwgXCJzdHJpbmdcIik7XG4gIHJldHVybi
140BcInN5bWJvbFwiID09IF90eXBlb2YoaSkgPyBpIDogaSArIFwiXCI7XG59XG5leHBvcnQgeyB0b1Byb3BlcnR5S2V5IGFzIGRlZmF1bHQgfTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/toPropertyKey.js\n\n}')},"./node_modules/@babel/runtime/helpers/esm/typeof.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _typeof)\n/* harmony export */ });\nfunction _typeof(o) {\n "@babel/helpers - typeof";\n\n return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {\n return typeof o;\n } : function (o) {\n return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;\n }, _typeof(o);\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vdHlwZW9mLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4vbm9kZV9tb2R1bGVzL0BiYWJlbC9ydW50aW1lL2hlbHBlcnMvZXNtL3R5cGVvZi5qcz80YmY1Il0sInNvdXJjZXNDb250ZW50IjpbImZ1bmN0aW9uIF90eXBlb2Yobykge1xuICBcIkBiYWJlbC9oZWxwZXJzIC0gdHlwZW9mXCI7XG5cbiAgcmV0dXJuIF90eXBlb2YgPSBcImZ1bmN0aW9uXCIgPT0gdHlwZW9mIFN5bWJvbCAmJiBcInN5bWJvbFwiID09IHR5cGVvZiBTeW1ib2wuaXRlcmF0b3IgPyBmdW5jdGlvbiAobykge1xuICAgIHJldHVybiB0eXBlb2YgbztcbiAgfSA6IGZ1bmN0aW9uIChvKSB7XG4gICAgcmV0dXJuIG8gJiYgXCJmdW5jdGlvblwiID09IHR5cGVvZiBTeW1ib2wgJiYgby5jb25zdHJ1Y3RvciA9PT0gU3ltYm9sICYmIG8gIT09IFN5bWJvbC5wcm90b3R5cGUgPyBcInN5bWJvbFwiIDogdHlwZW9mIG87XG4gIH0sIF90eXBlb2Yobyk7XG59XG5leHBvcnQgeyBfdHlwZW9mIGFzIGRlZmF1bHQgfTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/typeof.js\n\n}')}};const __webpack_module_cache__={};function __webpack_require__(e){const c=__webpack_module_cache__[e];if(void 0!==c)return c.exports;const n=__webpack_module_cache__[e]={exports:{}};if(!(e in __webpack_modules__)){delete __webpack_module_cache__[e];const c=new Error("Cannot find module '"+e+"'");throw c.code="MODULE_NOT_FOUND",c}return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,c)=>{if(Array.isArray(c))for(var n=0;n<c.length;){var l=c[n++],d=c[n++];__webpack_require__.o(e,l)?0===d&&n++:0===d?Object.defineProperty(e,l,{enumerable:!0,value:c[n++]}):Object.defineProperty(e,l,{enumerable:!0,get:d})}else for(var l in c)__webpack_require__.o(c,l)&&!__webpack_require__.o(e,l)&&Object.defineProperty(e,l,{enumerable:!0,get:c[l]})},__webpack_require__.o=(e,c)=>Object.prototype.hasOwnProperty.call(e,c),__webpack_require__.r=e=>{Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};let __webpack_exports__=__webpack_require__("../assets/src/scripts/components/navigation/navigation.js")})();; 141(()=>{var __webpack_modules__={"../assets/src/scripts/components/navigation/navigation-skip-links.js"(){eval("{/**\n * Helper function to check if a given element is focusable.\n * @param {Element} el - The element to check for focusability.\n * @returns {boolean} - Returns true if the element is focusable, false otherwise.\n */\nvar isFocusable = function isFocusable(el) {\n // Get the tag name of the element and convert it to lowercase\n var tagName = el.tagName.toLowerCase();\n // Check if the tag name is one of the focusable elements\n return /^(a|input|select|textarea|button|object)$/.test(tagName) || el.hasAttribute('tabindex');\n};\n\n// Scroll to an element on the page and focus on it if it's focusable\n/**\n * Smoothly scroll to a target element on the page and set focus to it if it's focusable.\n * @param {string} element - The selector of the target element to scroll to.\n * @param {number} [duration=200] - The duration of the scroll animation in milliseconds.\n */\nfunction scrollToFocus(element) {\n var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 200;\n // Find the target element using the given selector\n var target = document.querySelector(element);\n\n // Check if the target element is focusable\n var focusableElement = isFocusable(target);\n\n // Handle search input as a target differently for mobile and desktop\n if (element === '#search') {\n target = window.innerWidth < 980 ? document.querySelector('#searchform-site-nav-menu-search-input') : document.querySelector('a.site-nav-search-button.icon.js-drawer-search-button');\n }\n if (element === '#navigation' && window.innerWidth < 980) {\n target = document.querySelector('.nav-full-menu__content');\n }\n var startPosition = window.pageYOffset;\n var targetPosition = target.getBoundingClientRect().top - 100;\n var startTime = performance.now();\n\n // Scroll the window smoothly to the target position\n var _scroll = function scroll(currentTime) {\n var elapsedTime = currentTime - startTime;\n var easing = easeInOutQuad(elapsedTime, startPosition, targetPosition, duration);\n window.scrollTo(0, easing);\n if (elapsedTime < duration) {\n requestAnimationFrame(_scroll);\n }\n };\n\n // Easing function for smooth scrolling\n function easeInOutQuad(t, b, c, d) {\n t /= d / 2;\n if (t < 1) return c / 2 * t * t + b;\n t--;\n return -c / 2 * (t * (t - 2) - 1) + b;\n }\n requestAnimationFrame(_scroll);\n\n // Make the target element focusable and set focus to it\n if (!focusableElement) {\n target.setAttribute('tabindex', '-1');\n target.addEventListener('onfocusout', function () {\n target.removeAttribute('tabindex');\n });\n }
141\n setTimeout(function () {\n target.focus();\n // if (!focusableElement) {\n // \ttarget.removeAttribute('tabindex');\n // \ttarget.blur();\n // }\n }, duration);\n}\n\n// Handle skip link events\nvar skipLinkEvent = function skipLinkEvent(event) {\n event.preventDefault();\n var targetId = event.currentTarget.getAttribute('href');\n\n // If the target is the search or navigation element, trigger the hamburger button click for mobile\n if (targetId === '#search' && window.innerWidth < 980 || targetId === '#navigation' && window.innerWidth < 980) {\n document.querySelector('.navbar-hamburger-button').click();\n }\n\n // Show the close menu button and add an event listener to it\n var closeMenuButton = document.querySelector('.close-menu-button');\n if (closeMenuButton) {\n closeMenuButton.style.display = 'block';\n closeMenuButton.style.zIndex = '999999';\n closeMenuButton.addEventListener('click', function () {\n closeMenuButton.style.display = 'none';\n closeMenuButton.style.zIndex = '-1';\n closeMenu();\n });\n }\n\n // Smooth scroll to the target element\n scrollToFocus(targetId);\n};\n\n// Close the menu and reset its elements\nvar closeMenu = function closeMenu() {\n var headerNavWrapper = document.querySelector('.header-nav-wrapper');\n if (headerNavWrapper.style.display === 'none' || headerNavWrapper.style.visibility === 'hidden') return;\n var hamburgerButton = document.querySelector('.hamburger-button');\n var elsNoScroll = document.querySelectorAll('.post-content, .grid--container');\n var headerNav = document.querySelector('.header-nav');\n //const headerNavNestedMenu = document.querySelector('.header-nav-nested-menu');\n var closeNav = document.querySelector('.close-menu-button');\n headerNavWrapper.style.display = 'none';\n hamburgerButton.classList.remove('mobile-nav-open');\n document.querySelectorAll('.header-subnav-wrapper').forEach(function (el) {\n return el.style.display = 'block';\n });\n document.querySelectorAll('.nav-menu__item').forEach(function (el) {\n return el.classList.remove('open');\n });\n //headerNavNestedMenu.style.display = 'none';\n headerNav.style.display = '';\n closeNav.style.display = 'none';\n document.body.classList.remove('overlay-no-scroll');\n elsNoScroll.forEach(function (el) {\n el.classList.remove('overlay-no-scroll');\n el.removeAttribute('style');\n });\n};\n// Add event listeners to skip links\ndocument.addEventListener('DOMContentLoaded', function () {\n var skipLinks = document.querySelectorAll('.skip-link');
141\n skipLinks.forEach(function (skipLink) {\n skipLink.addEventListener('focus', function () {\n this.style.opacity = '1';\n this.style.zIndex = '999999999';\n });\n skipLink.addEventListener('blur', function () {\n this.style.opacity = '0';\n this.style.zIndex = '-1';\n });\n skipLink.addEventListener('click', function (event) {\n return skipLinkEvent(event);\n });\n skipLink.addEventListener('keydown', function (event) {\n // Check if the key pressed is the Enter key.\n if (event.key === 'Enter') {\n skipLinkEvent(event);\n }\n });\n });\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL2NvbXBvbmVudHMvbmF2aWdhdGlvbi9uYXZpZ2F0aW9uLXNraXAtbGlua3MuanMiLCJuYW1lcyI6WyJpc0ZvY3VzYWJsZSIsImVsIiwidGFnTmFtZSIsInRvTG93ZXJDYXNlIiwidGVzdCIsImhhc0F0dHJpYnV0ZSIsInNjcm9sbFRvRm9jdXMiLCJlbGVtZW50IiwiZHVyYXRpb24iLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJ1bmRlZmluZWQiLCJ0YXJnZXQiLCJkb2N1bWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJmb2N1c2FibGVFbGVtZW50Iiwid2luZG93IiwiaW5uZXJXaWR0aCIsInN0YXJ0UG9zaXRpb24iLCJwYWdlWU9mZnNldCIsInRhcmdldFBvc2l0aW9uIiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidG9wIiwic3RhcnRUaW1lIiwicGVyZm9ybWFuY2UiLCJub3ciLCJzY3JvbGwiLCJjdXJyZW50VGltZSIsImVsYXBzZWRUaW1lIiwiZWFzaW5nIiwiZWFzZUluT3V0UXVhZCIsInNjcm9sbFRvIiwicmVxdWVzdEFuaW1hdGlvbkZyYW1lIiwidCIsImIiLCJjIiwiZCIsInNldEF0dHJpYnV0ZSIsImFkZEV2ZW50TGlzdGVuZXIiLCJyZW1vdmVBdHRyaWJ1dGUiLCJzZXRUaW1lb3V0IiwiZm9jdXMiLCJza2lwTGlua0V2ZW50IiwiZXZlbnQiLCJwcmV2ZW50RGVmYXVsdCIsInRhcmdldElkIiwiY3VycmVudFRhcmdldCIsImdldEF0dHJpYnV0ZSIsImNsaWNrIiwiY2xvc2VNZW51QnV0dG9uIiwic3R5bGUiLCJkaXNwbGF5IiwiekluZGV4IiwiY2xvc2VNZW51IiwiaGVhZGVyTmF2V3JhcHBlciIsInZpc2liaWxpdHkiLCJoYW1idXJnZXJCdXR0b24iLCJlbHNOb1Njcm9sbCIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJoZWFkZXJOYXYiLCJjbG9zZU5hdiIsImNsYXNzTGlzdCIsInJlbW92ZSIsImZvckVhY2giLCJib2R5Iiwic2tpcExpbmtzIiwic2tpcExpbmsiLCJvcGFjaXR5Iiwia2V5Il0sInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4uL2Fzc2V0cy9zcmMvc2NyaXB0cy9jb21wb25lbnRzL25hdmlnYXRpb24vbmF2aWdhdGlvbi1za2lwLWxpbmtzLmpzPzAzODYiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdG8gY2hlY2sgaWYgYSBnaXZlbiBlbGVtZW50IGlzIGZvY3VzYWJsZS5cbiAqIEBwYXJhbSB7RWxlbWVudH0gZWwgLSBUaGUgZWxlbWVudCB0byBjaGVjayBmb3IgZm9jdXNhYmlsaXR5LlxuICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSBlbGVtZW50IGlzIGZvY3VzYWJsZSwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5jb25zdCBpc0ZvY3VzYWJsZSA9IChlbCkgPT4ge1xuXHQvLyBHZXQgdGhlIHRhZyBuYW1lIG9mIHRoZSBlbGVtZW50IGFuZCBjb252ZXJ0IGl0IHRvIGxvd2VyY2FzZVxuXHRjb25zdCB0YWdOYW1lID0gZWwudGFnTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHQvLyBDaGVjayBpZiB0aGUgdGFnIG5hbWUgaXMgb25lIG9mIHRoZSBmb2N1c2FibGUgZWxlbWVudHNcblx0cmV0dXJuIC9eKGF8aW5wdXR8c2VsZWN0fHRleHRhcmVhfGJ1dHRvbnxvYmplY3QpJC8udGVzdCh0YWdOYW1lKSB8fCBlbC5oYXNBdHRyaWJ1dGUoJ3RhYmluZGV4Jyk7XG59O1xuXG4vLyBTY3JvbGwgdG8gYW4gZWxlbWVudCBvbiB0aGUgcGFnZSBhbmQgZm9jdXMgb24gaXQgaWYgaXQncyBmb2N1c2FibGVcbi8qKlxuICogU21vb3RobHkgc2Nyb2xsIHRvIGEgdGFyZ2V0IGVsZW1lbnQgb24gdGhlIHBhZ2UgYW5kIHNldCBmb2N1cyB0byBpdCBpZiBpdCdzIGZvY3VzYWJsZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBlbGVtZW50IC0gVGhlIHNlbGVjdG9yIG9mIHRoZSB0YXJnZXQgZWxlbWVudCB0byBzY3JvbGwgdG8uXG4gKiBAcGFyYW0ge251bWJlcn0gW2R1cmF0aW9uPTIwMF0gLSBUaGUgZHVyYXRpb24gb2YgdGhlIHNjcm9sbCBhbmltYXRpb24gaW4gbWlsbGlzZWNvbmRzLlxuICovXG5mdW5jdGlvbiBzY3JvbGxUb0ZvY3VzKGVsZW1lbnQsIGR1cmF0aW9uID0gMjAwKSB7XG5cdC8vIEZpbmQgdGhlIHRhcmdldCBlbGVtZW50IHVzaW5nIHRoZSBnaXZlbiBzZWxlY3RvclxuXHRsZXQgdGFyZ2V0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihlbGVtZW50KTtcblxuXHQvLyBDaGVjayBpZiB0aGUgdGFyZ2V0IGVsZW1lbnQgaXMgZm9jdXNhYmxlXG5cdGNvbnN0IGZvY3VzYWJsZUVsZW1lbnQgPSBpc0ZvY3VzYWJsZSh0YXJnZXQpO1xuXG5cdC8vIEhhbmRsZSBzZWFyY2ggaW5wdXQgYXMgYSB0YXJnZXQgZGlmZmVyZW50bHkgZm9yIG1vYmlsZSBhbmQgZGVza3RvcFxuXHRpZiAoZWxlbWVudCA9PT0gJyNzZWFyY2gnKSB7XG5cdFx0dGFyZ2V0ID0gd2luZG93LmlubmVyV2lkdGggPCA5ODAgPyBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjc2VhcmNoZm9ybS1zaXRlLW5hdi1tZW51LXNlYXJjaC1pbnB1dCcpIDogZG9jdW1lbnQucXVlcnlTZWxlY3RvcignYS5zaXRlLW5hdi1zZWFyY2gtYnV0dG9uLmljb24uanMtZHJhd2VyLXNlYXJjaC1idXR0b24nKTtcblx0fVxuXG5cdGlmIChlbGVtZW50ID09PSAnI25hdmlnYXRpb24nICYmIHdpbmRvdy5pbm5lcldpZHRoIDwgOTgwKSB7XG5cdFx0dGFyZ2V0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLm5hdi1mdWxsLW1lbnVfX2NvbnRlbnQnKTtcblx0fVxuXG5cdGNvbnN0IHN0YXJ0UG9zaXRpb24gPSB3aW5kb3cucGFnZVlPZmZzZXQ7XG5cdGNvbnN0IHRhcmdldFBvc2l0aW9uID0gdGFyZ2V0LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtIDEwMDtcblx0Y29uc3Qgc3RhcnRUaW1lID0gcGVyZm9ybWFuY2Uubm93KCk7XG5cblx0Ly8gU2Nyb2xsIHRoZSB3aW5kb3cgc21vb3RobHkgdG8gdGhlIHRhcmdldCBwb3NpdGlvblxuXHRjb25zdCBzY3JvbGwgP
141SBjdXJyZW50VGltZSA9PiB7XG5cdFx0Y29uc3QgZWxhcHNlZFRpbWUgPSBjdXJyZW50VGltZSAtIHN0YXJ0VGltZTtcblx0XHRjb25zdCBlYXNpbmcgPSBlYXNlSW5PdXRRdWFkKGVsYXBzZWRUaW1lLCBzdGFydFBvc2l0aW9uLCB0YXJnZXRQb3NpdGlvbiwgZHVyYXRpb24pO1xuXG5cdFx0d2luZG93LnNjcm9sbFRvKDAsIGVhc2luZyk7XG5cblx0XHRpZiAoZWxhcHNlZFRpbWUgPCBkdXJhdGlvbikge1xuXHRcdFx0cmVxdWVzdEFuaW1hdGlvbkZyYW1lKHNjcm9sbCk7XG5cdFx0fVxuXHR9O1xuXG5cdC8vIEVhc2luZyBmdW5jdGlvbiBmb3Igc21vb3RoIHNjcm9sbGluZ1xuXHRmdW5jdGlvbiBlYXNlSW5PdXRRdWFkKHQsIGIsIGMsIGQpIHtcblx0XHR0IC89IGQgLyAyO1xuXHRcdGlmICh0IDwgMSkgcmV0dXJuIChjIC8gMikgKiB0ICogdCArIGI7XG5cdFx0dC0tO1xuXHRcdHJldHVybiAoLWMgLyAyKSAqICh0ICogKHQgLSAyKSAtIDEpICsgYjtcblx0fVxuXHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoc2Nyb2xsKTtcblxuXHQvLyBNYWtlIHRoZSB0YXJnZXQgZWxlbWVudCBmb2N1c2FibGUgYW5kIHNldCBmb2N1cyB0byBpdFxuXHRpZiAoIWZvY3VzYWJsZUVsZW1lbnQpIHtcblx0XHR0YXJnZXQuc2V0QXR0cmlidXRlKCd0YWJpbmRleCcsICctMScpO1xuXHRcdHRhcmdldC5hZGRFdmVudExpc3RlbmVyKCdvbmZvY3Vzb3V0JywgKCkgPT4ge1xuXHRcdFx0dGFyZ2V0LnJlbW92ZUF0dHJpYnV0ZSgndGFiaW5kZXgnKTtcblx0XHR9KTtcblx0fVxuXG5cdHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuXHRcdHRhcmdldC5mb2N1cygpO1xuXHRcdC8vIGlmICghZm9jdXNhYmxlRWxlbWVudCkge1xuXHRcdC8vIFx0dGFyZ2V0LnJlbW92ZUF0dHJpYnV0ZSgndGFiaW5kZXgnKTtcblx0XHQvLyBcdHRhcmdldC5ibHVyKCk7XG5cdFx0Ly8gfVxuXHR9LCBkdXJhdGlvbik7XG59XG5cbi8vIEhhbmRsZSBza2lwIGxpbmsgZXZlbnRzXG5jb25zdCBza2lwTGlua0V2ZW50ID0gKGV2ZW50KSA9PiB7XG5cdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdGNvbnN0IHRhcmdldElkID0gZXZlbnQuY3VycmVudFRhcmdldC5nZXRBdHRyaWJ1dGUoJ2hyZWYnKTtcblxuXHQvLyBJZiB0aGUgdGFyZ2V0IGlzIHRoZSBzZWFyY2ggb3IgbmF2aWdhdGlvbiBlbGVtZW50LCB0cmlnZ2VyIHRoZSBoYW1idXJnZXIgYnV0dG9uIGNsaWNrIGZvciBtb2JpbGVcblx0aWYgKCh0YXJnZXRJZCA9PT0gJyNzZWFyY2gnICYmIHdpbmRvdy5pbm5lcldpZHRoIDwgOTgwKSB8fCAodGFyZ2V0SWQgPT09ICcjbmF2aWdhdGlvbicgJiYgd2luZG93LmlubmVyV2lkdGggPCA5ODApKSB7XG5cdFx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLm5hdmJhci1oYW1idXJnZXItYnV0dG9uJykuY2xpY2soKTtcblx0fVxuXG5cdC8vIFNob3cgdGhlIGNsb3NlIG1lbnUgYnV0dG9uIGFuZCBhZGQgYW4gZXZlbnQgbGlzdGVuZXIgdG8gaXRcblx0Y29uc3QgY2xvc2VNZW51QnV0dG9uID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmNsb3NlLW1lbnUtYnV0dG9uJyk7XG5cdGlmIChjbG9zZU1lbnVCdXR0b24pIHtcblx0XHRjbG9zZU1lbnVCdXR0b24uc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XG5cdFx0Y2xvc2VNZW51QnV0dG9uLnN0eWxlLnpJbmRleCA9ICc5OTk5OTknO1xuXHRcdGNsb3NlTWVudUJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IHtcblx0XHRcdGNsb3NlTWVudUJ1dHRvbi5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuXHRcdFx0Y2xvc2VNZW51QnV0dG9uLnN0eWxlLnpJbmRleCA9ICctMSc7XG5cdFx0XHRjbG9zZU1lbnUoKTtcblx0XHR9KTtcblx0fVxuXG5cdC8vIFNtb290aCBzY3JvbGwgdG8gdGhlIHRhcmdldCBlbGVtZW50XG5cdHNjcm9sbFRvRm9jdXModGFyZ2V0SWQpO1xufTtcblxuLy8gQ2xvc2UgdGhlIG1lbnUgYW5kIHJlc2V0IGl0cyBlbGVtZW50c1xuY29uc3QgY2xvc2VNZW51ID0gKCkgPT4ge1xuXHRjb25zdCBoZWFkZXJOYXZXcmFwcGVyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmhlYWRlci1uYXYtd3JhcHBlcicpO1xuXHRpZiAoaGVhZGVyTmF2V3JhcHBlci5zdHlsZS5kaXNwbGF5ID09PSAnbm9uZScgfHwgaGVhZGVyTmF2V3JhcHBlci5zdHlsZS52aXNpYmlsaXR5ID09PSAnaGlkZGVuJykgcmV0dXJuO1xuXG5cdGNvbnN0IGhhbWJ1cmdlckJ1dHRvbiA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5oYW1idXJnZXItYnV0dG9uJyk7XG5cdGNvbnN0IGVsc05vU2Nyb2xsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnBvc3QtY29udGVudCwgLmdyaWQtLWNvbnRhaW5lcicpO1xuXHRjb25zdCBoZWFkZXJOYXYgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuaGVhZGVyLW5hdicpO1xuXHQvL2NvbnN0IGhlYWRlck5hdk5lc3RlZE1lbnUgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuaGVhZGVyLW5hdi1uZXN0ZWQtbWVudScpO1xuXHRjb25zdCBjbG9zZU5hdiA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5jbG9zZS1tZW51LWJ1dHRvbicpO1xuXG5cdGhlYWRlck5hdldyYXBwZXIuc3R5bGUuZGlzcGxheSA9ICdub25lJztcblx0aGFtYnVyZ2VyQnV0dG9uLmNsYXNzTGlzdC5yZW1vdmUoJ21vYmlsZS1uYXYtb3BlbicpO1xuXHRkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuaGVhZGVyLXN1Ym5hdi13cmFwcGVyJykuZm9yRWFjaChlbCA9PiBlbC5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJyk7XG5cdGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5uYXYtbWVudV9faXRlbScpLmZvckVhY2goZWwgPT4gZWwuY2xhc3NMaXN0LnJlbW92ZSgnb3BlbicpKTtcblx0Ly9oZWFkZXJOYXZOZXN0ZWRNZW51LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cdGhlYWRlck5hdi5zdHlsZS5kaXNwbGF5ID0gJyc7XG5cdGNsb3NlTmF2LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cdGRvY3VtZW50LmJvZHkuY2xhc3NMaXN0LnJlbW92ZSgnb3ZlcmxheS1uby1zY3JvbGwnKTtcblx0ZWxzTm9TY3JvbGwuZm9yRWFjaChlbCA9PiB7XG5cdFx0ZWwuY2xhc3NMaXN0LnJlbW92ZSgnb3ZlcmxheS1uby1zY3JvbGwnKTtcblx0XHRlbC5yZW1vdmVBdHRyaWJ1dGUoJ3N0eWxlJyk7XG5cdH0pO1xufTtcbi8vIEFkZCBldmVudCBsaXN0ZW5lcnMgdG8gc2tpcCBsaW5rc1xuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsIGZ1bmN0aW9uICgpIHtcblxuXHRjb25zdCBza2lwTGlua3MgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuc2tpcC1saW5rJyk7XG5cblx0c2tpcExpbmtzLmZvckVhY2goc2tpcExpbmsgPT4ge1xuXHRcdHNraXBMaW5rLmFkZEV2ZW50TGlzdGVuZXIoJ2ZvY3VzJywgZnVuY3Rpb24gKCkge1xuXHRcdFx0dGhpcy5zdHlsZS5vcGFjaXR5ID0gJzEnO1xuXHRcdFx0dGhpcy5zdHlsZS56SW5kZXggPSAnOTk5OTk5OTk5Jztcblx0XHR9KTtcblxuXHRcdHNraXBMaW5rLmFkZEV2ZW50TGlzdGVuZXIoJ2JsdXInLCBmdW5jdGlvbiAoKSB7XG5cdFx0XHR0aGlzLnN0eWxlLm9wYWNpdHkgPSAnMCc7XG5cdFx0XHR0aGlzLnN0eWxlLnpJbmRleCA9ICctMSc7XG5cdFx0fSk7XG5cblx0XHRza2lwTGluay5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIChldmVudCkgPT4gc2tpcExpbmtFdmVudChldmVudCkpO1xuXHRcdHNraXBMaW5rLmFkZEV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCAoZXZlbnQpID0+IHtcblx0XHRcdC8vIENoZWNrIGlmIHRoZSBrZXkgcHJlc3NlZCBpcyB0aGUgRW50ZXIga2V5LlxuXHRcdFx0aWYgKGV2ZW50LmtleSA9PT0gJ0VudGVyJykge1xuXHRcdFx0XHRza2lwTGlua0V2ZW50KGV2ZW50KTtcblx0XHRcdH1cblx0XHR9KTtcblx0fSk7XG59
141KTtcbiJdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQU1BLFdBQVcsR0FBRyxTQUFkQSxXQUFXQSxDQUFJQyxFQUFFLEVBQUs7RUFDM0I7RUFDQSxJQUFNQyxPQUFPLEdBQUdELEVBQUUsQ0FBQ0MsT0FBTyxDQUFDQyxXQUFXLENBQUMsQ0FBQztFQUN4QztFQUNBLE9BQU8sMkNBQTJDLENBQUNDLElBQUksQ0FBQ0YsT0FBTyxDQUFDLElBQUlELEVBQUUsQ0FBQ0ksWUFBWSxDQUFDLFVBQVUsQ0FBQztBQUNoRyxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVNDLGFBQWFBLENBQUNDLE9BQU8sRUFBa0I7RUFBQSxJQUFoQkMsUUFBUSxHQUFBQyxTQUFBLENBQUFDLE1BQUEsUUFBQUQsU0FBQSxRQUFBRSxTQUFBLEdBQUFGLFNBQUEsTUFBRyxHQUFHO0VBQzdDO0VBQ0EsSUFBSUcsTUFBTSxHQUFHQyxRQUFRLENBQUNDLGFBQWEsQ0FBQ1AsT0FBTyxDQUFDOztFQUU1QztFQUNBLElBQU1RLGdCQUFnQixHQUFHZixXQUFXLENBQUNZLE1BQU0sQ0FBQzs7RUFFNUM7RUFDQSxJQUFJTCxPQUFPLEtBQUssU0FBUyxFQUFFO0lBQzFCSyxNQUFNLEdBQUdJLE1BQU0sQ0FBQ0MsVUFBVSxHQUFHLEdBQUcsR0FBR0osUUFBUSxDQUFDQyxhQUFhLENBQUMsd0NBQXdDLENBQUMsR0FBR0QsUUFBUSxDQUFDQyxhQUFhLENBQUMsdURBQXVELENBQUM7RUFDdEw7RUFFQSxJQUFJUCxPQUFPLEtBQUssYUFBYSxJQUFJUyxNQUFNLENBQUNDLFVBQVUsR0FBRyxHQUFHLEVBQUU7SUFDekRMLE1BQU0sR0FBR0MsUUFBUSxDQUFDQyxhQUFhLENBQUMseUJBQXlCLENBQUM7RUFDM0Q7RUFFQSxJQUFNSSxhQUFhLEdBQUdGLE1BQU0sQ0FBQ0csV0FBVztFQUN4QyxJQUFNQyxjQUFjLEdBQUdSLE1BQU0sQ0FBQ1MscUJBQXFCLENBQUMsQ0FBQyxDQUFDQyxHQ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\n//# sourceURL=webpack-internal:///../assets/src/scripts/components/navigation/navigation-skip-links.js\n\n}")}};let __webpack_exports__={};__webpack_modules__["../assets/src/scripts/components/navigation/navigation-skip-links.js"]()})();; 142(()=>{var __webpack_modules__={"../assets/src/scripts/components/navigation/navigation-subscribe-takeover.js"(){eval("{var _subscribeButtonClasses = '.site-header .subscribe-prompt, .subscribe-load-takeover, .fp-live__subscribe-trigger-modal';\nvar _subscribeTakeover = document.querySelector('#subscribe-takeover');\nvar _subscribeTakeoverIframe = document.querySelector('#subscribe-takeover-iframe');\nvar _subscribeTakeoverClose = document.querySelectorAll('.subscribe-takeover-close');\n\n/**\n * When clicking the Subscribe button in the top nav, suppress navigation link and\n * show full-screen overlay instead. \n */\nvar handleClick = function handleClick(e) {\n var _e$target$getAttribut;\n e.preventDefault();\n\n // Get iframe src and data-src values\n var iframeSrc = _subscribeTakeoverIframe.getAttribute('src');\n var dataSrc = (_e$target$getAttribut = e.target.getAttribute('data-modal-iframe-url')) !== null && _e$target$getAttribut !== void 0 ? _e$target$getAttribut : _subscribeTakeoverIframe.getAttribute('data-src');\n\n // Set iframe src if not already set or if it has changed \n // since the iframe was last displayed\n if (!iframeSrc || iframeSrc === 'data:text/html;charset=utf-8,' || iframeSrc !== dataSrc) {\n _subscribeTakeoverIframe.setAttribute('src', dataSrc);\n _subscribeTakeoverIframe.contentWindow.location.replace(dataSrc);\n }\n _subscribeTakeover.style.display = 'block';\n _subscribeTakeoverClose.forEach(function (button) {\n // Set close button as contentEditable to allow focus when tabbing\n button.contentEditable = true;\n });\n\n // Set focus to subscribe takeover\n _subscribeTakeover.focus();\n\n // set inert attribute\n FP.Utils.trapFocus.toggleInertAttribute(true);\n\n // close modal when user presses ESC key\n [_subscribeTakeoverIframe, _subscribeTakeover].forEach(function (element) {\n element.addEventListener('keydown', function (event) {\n if (event.key == 'Escape') {\n closeSubscribeModal();\n }\n });\n });\n\n // Take additional action once iframe has loaded\n _subscribeTakeoverIframe.addEventListener('load', function () {\n // Set focus to subscribe takeover\n _subscribeTakeover.focus();\n\n // Ensure subscribe takeover iframe is scrolled to top\n try {\n _subscribeTakeoverIframe.contentWindow.scrollTo({\n top: 0,\n left: 0,\n behavior: 'smooth'\n });\n\n // close modal when user presses ESC key\n _subscribeTakeoverIframe.contentWindow.document.addEventListener('keydown', function (event) {\n if (event.key == 'Escape') {\n closeSubscribeModal();\n }\n });\n } catch (error) {\n console.error(error);\n }\n });\n};\n\n// Hide the takeover on close button click/keydown\nfunction closeSubscribeModal() {\n // remove inert attribute\n FP.Utils.trapFocus.toggleInertAttribute(false);\n // hide takeover and set focus back to subscribe button\n _subscribeTakeover.style.display = 'none';\n\n // delay the following code to give the DOM time to update\n setTimeout(function () {\n // focus on parent window if focus is in iframe\n window.parent.focus();\n // set focus back to clicked button\n var expandedNavigationStyle = window.getComputedStyle(document.querySelector('#expanded-navigation'));\n if (expandedNavigationStyle && 'visible' === expandedNavigationStyle.visibility) {\n // if expanded nav is open, focus on the button in the exp
142anded nav\n document.querySelectorAll('.site-header .subscribe-prompt')[1].focus();\n } else {\n // focus on the button in the sticky nav\n document.querySelectorAll('.site-header .subscribe-prompt')[0].focus();\n }\n }, 250);\n}\nfunction attachListeners() {\n // Attach event listener to each element matching the selector\n document.querySelectorAll(_subscribeButtonClasses).forEach(function (element) {\n // Remove any previously set event listeners\n element.removeEventListener('click', handleClick);\n\n // Add event listeners\n element.addEventListener('click', handleClick);\n element.addEventListener('keydown', function (event) {\n // Check if the key pressed is the Enter key.\n if (event.key === 'Enter') {\n handleClick(event);\n }\n });\n });\n}\nattachListeners();\nwindow.addEventListener('myfp:user-loaded', function () {\n // Listen for MyFP user loaded event\n // Give this an additional second to populate\n // the DOM with any subscribe prompts before\n // attaching new listeners\n setTimeout(function () {\n attachListeners();\n }, '1000');\n});\n\n// Attach event listener to close buttons\n_subscribeTakeoverClose.forEach(function (button) {\n button.addEventListener('click', function () {\n closeSubscribeModal();\n });\n button.addEventListener('keydown', function (event) {\n // Check if the key pressed is the Enter key.\n if (event.key === 'Enter') {\n closeSubscribeModal();\n }\n });\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL2NvbXBvbmVudHMvbmF2aWdhdGlvbi9uYXZpZ2F0aW9uLXN1YnNjcmliZS10YWtlb3Zlci5qcyIsIm5hbWVzIjpbIl9zdWJzY3JpYmVCdXR0b25DbGFzc2VzIiwiX3N1YnNjcmliZVRha2VvdmVyIiwiZG9jdW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiX3N1YnNjcmliZVRha2VvdmVySWZyYW1lIiwiX3N1YnNjcmliZVRha2VvdmVyQ2xvc2UiLCJxdWVyeVNlbGVjdG9yQWxsIiwiaGFuZGxlQ2xpY2siLCJlIiwiX2UkdGFyZ2V0JGdldEF0dHJpYnV0IiwicHJldmVudERlZmF1bHQiLCJpZnJhbWVTcmMiLCJnZXRBdHRyaWJ1dGUiLCJkYXRhU3JjIiwidGFyZ2V0Iiwic2V0QXR0cmlidXRlIiwiY29udGVudFdpbmRvdyIsImxvY2F0aW9uIiwicmVwbGFjZSIsInN0eWxlIiwiZGlzcGxheSIsImZvckVhY2giLCJidXR0b24iLCJjb250ZW50RWRpdGFibGUiLCJmb2N1cyIsIkZQIiwiVXRpbHMiLCJ0cmFwRm9jdXMiLCJ0b2dnbGVJbmVydEF0dHJpYnV0ZSIsImVsZW1lbnQiLCJhZGRFdmVudExpc3RlbmVyIiwiZXZlbnQiLCJrZXkiLCJjbG9zZVN1YnNjcmliZU1vZGFsIiwic2Nyb2xsVG8iLCJ0b3AiLCJsZWZ0IiwiYmVoYXZpb3IiLCJlcnJvciIsImNvbnNvbGUiLCJzZXRUaW1lb3V0Iiwid2luZG93IiwicGFyZW50IiwiZXhwYW5kZWROYXZpZ2F0aW9uU3R5bGUiLCJnZXRDb21wdXRlZFN0eWxlIiwidmlzaWJpbGl0eSIsImF0dGFjaExpc3RlbmVycyIsInJlbW92ZUV2ZW50TGlzdGVuZXIiXSwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi4vYXNzZXRzL3NyYy9zY3JpcHRzL2NvbXBvbmVudHMvbmF2aWdhdGlvbi9uYXZpZ2F0aW9uLXN1YnNjcmliZS10YWtlb3Zlci5qcz8zZDlkIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IF9zdWJzY3JpYmVCdXR0b25DbGFzc2VzID0gJy5zaXRlLWhlYWRlciAuc3Vic2NyaWJlLXByb21wdCwgLnN1YnNjcmliZS1sb2FkLXRha2VvdmVyLCAuZnAtbGl2ZV9fc3Vic2NyaWJlLXRyaWdnZXItbW9kYWwnO1xuY29uc3QgX3N1YnNjcmliZVRha2VvdmVyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3N1YnNjcmliZS10YWtlb3ZlcicpO1xuY29uc3QgX3N1YnNjcmliZVRha2VvdmVySWZyYW1lID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3N1YnNjcmliZS10YWtlb3Zlci1pZnJhbWUnKTtcbmNvbnN0IF9zdWJzY3JpYmVUYWtlb3ZlckNsb3NlID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnN1YnNjcmliZS10YWtlb3Zlci1jbG9zZScpO1xuXG4vKipcbiAqIFdoZW4gY2xpY2tpbmcgdGhlIFN1YnNjcmliZSBidXR0b24gaW4gdGhlIHRvcCBuYXYsIHN1cHByZXNzIG5hdmlnYXRpb24gbGluayBhbmRcbiAqIHNob3cgZnVsbC1zY3JlZW4gb3ZlcmxheSBpbnN0ZWFkLiBcbiAqL1xuY29uc3QgaGFuZGxlQ2xpY2sgPSBlID0+IHtcblx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcblx0Ly8gR2V0IGlmcmFtZSBzcmMgYW5kIGRhdGEtc3JjIHZhbHVlc1xuXHRsZXQgaWZyYW1lU3JjID0gX3
142N1YnNjcmliZVRha2VvdmVySWZyYW1lLmdldEF0dHJpYnV0ZSgnc3JjJyk7XG5cdGxldCBkYXRhU3JjID0gZS50YXJnZXQuZ2V0QXR0cmlidXRlKCdkYXRhLW1vZGFsLWlmcmFtZS11cmwnKSA/PyBfc3Vic2NyaWJlVGFrZW92ZXJJZnJhbWUuZ2V0QXR0cmlidXRlKCdkYXRhLXNyYycpO1xuXG5cdC8vIFNldCBpZnJhbWUgc3JjIGlmIG5vdCBhbHJlYWR5IHNldCBvciBpZiBpdCBoYXMgY2hhbmdlZCBcblx0Ly8gc2luY2UgdGhlIGlmcmFtZSB3YXMgbGFzdCBkaXNwbGF5ZWRcblx0aWYgKFxuXHRcdCFpZnJhbWVTcmMgXG5cdFx0fHwgaWZyYW1lU3JjID09PSAnZGF0YTp0ZXh0L2h0bWw7Y2hhcnNldD11dGYtOCwnIFxuXHRcdHx8IChpZnJhbWVTcmMgIT09IGRhdGFTcmMpXG5cdCkge1xuXHRcdF9zdWJzY3JpYmVUYWtlb3ZlcklmcmFtZS5zZXRBdHRyaWJ1dGUoJ3NyYycsIGRhdGFTcmMpO1xuXHRcdF9zdWJzY3JpYmVUYWtlb3ZlcklmcmFtZS5jb250ZW50V2luZG93LmxvY2F0aW9uLnJlcGxhY2UoZGF0YVNyYyk7XG5cdH1cblxuXHRfc3Vic2NyaWJlVGFrZW92ZXIuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XG5cblx0X3N1YnNjcmliZVRha2VvdmVyQ2xvc2UuZm9yRWFjaChidXR0b24gPT4ge1xuXHRcdC8vIFNldCBjbG9zZSBidXR0b24gYXMgY29udGVudEVkaXRhYmxlIHRvIGFsbG93IGZvY3VzIHdoZW4gdGFiYmluZ1xuXHRcdGJ1dHRvbi5jb250ZW50RWRpdGFibGUgPSB0cnVlO1xuXHR9KTtcblxuXHQvLyBTZXQgZm9jdXMgdG8gc3Vic2NyaWJlIHRha2VvdmVyXG5cdF9zdWJzY3JpYmVUYWtlb3Zlci5mb2N1cygpO1xuXG5cdC8vIHNldCBpbmVydCBhdHRyaWJ1dGVcblx0RlAuVXRpbHMudHJhcEZvY3VzLnRvZ2dsZUluZXJ0QXR0cmlidXRlKHRydWUpO1xuXG5cdC8vIGNsb3NlIG1vZGFsIHdoZW4gdXNlciBwcmVzc2VzIEVTQyBrZXlcblx0W19zdWJzY3JpYmVUYWtlb3ZlcklmcmFtZSxfc3Vic2NyaWJlVGFrZW92ZXJdLmZvckVhY2goZWxlbWVudCA9PiB7XG5cdFx0ZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRcdGlmIChldmVudC5rZXkgPT0gJ0VzY2FwZScpIHtcblx0XHRcdFx0Y2xvc2VTdWJzY3JpYmVNb2RhbCgpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9KTtcblx0XG5cdC8vIFRha2UgYWRkaXRpb25hbCBhY3Rpb24gb25jZSBpZnJhbWUgaGFzIGxvYWRlZFxuXHRfc3Vic2NyaWJlVGFrZW92ZXJJZnJhbWUuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIGZ1bmN0aW9uKCkge1xuXHRcdC8vIFNldCBmb2N1cyB0byBzdWJzY3JpYmUgdGFrZW92ZXJcblx0XHRfc3Vic2NyaWJlVGFrZW92ZXIuZm9jdXMoKTtcblx0XHRcblx0XHQvLyBFbnN1cmUgc3Vic2NyaWJlIHRha2VvdmVyIGlmcmFtZSBpcyBzY3JvbGxlZCB0byB0b3Bcblx0XHR0cnkge1xuXHRcdFx0X3N1YnNjcmliZVRha2VvdmVySWZyYW1lLmNvbnRlbnRXaW5kb3cuc2Nyb2xsVG8oe1xuXHRcdFx0XHR0b3A6IDAsXG5cdFx0XHRcdGxlZnQ6IDAsXG5cdFx0XHRcdGJlaGF2aW9yOiAnc21vb3RoJ1xuXHRcdFx0fSk7XG5cblx0XHRcdC8vIGNsb3NlIG1vZGFsIHdoZW4gdXNlciBwcmVzc2VzIEVTQyBrZXlcblx0XHRcdF9zdWJzY3JpYmVUYWtlb3ZlcklmcmFtZS5jb250ZW50V2luZG93LmRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCBmdW5jdGlvbihldmVudCkge1xuXHRcdFx0XHRpZiAoZXZlbnQua2V5ID09ICdFc2NhcGUnKSB7XG5cdFx0XHRcdFx0Y2xvc2VTdWJzY3JpYmVNb2RhbCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0Y29uc29sZS5lcnJvcihlcnJvcik7XG5cdFx0fVxuXHR9KTtcbn07XG5cbi8vIEhpZGUgdGhlIHRha2VvdmVyIG9uIGNsb3NlIGJ1dHRvbiBjbGljay9rZXlkb3duXG5mdW5jdGlvbiBjbG9zZVN1YnNjcmliZU1vZGFsKCkge1xuXHQvLyByZW1vdmUgaW5lcnQgYXR0cmlidXRlXG5cdEZQLlV0aWxzLnRyYXBGb2N1cy50b2dnbGVJbmVydEF0dHJpYnV0ZShmYWxzZSk7XG5cdC8vIGhpZGUgdGFrZW92ZXIgYW5kIHNldCBmb2N1cyBiYWNrIHRvIHN1YnNjcmliZSBidXR0b25cblx0X3N1YnNjcmliZVRha2VvdmVyLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG5cblx0Ly8gZGVsYXkgdGhlIGZvbGxvd2luZyBjb2RlIHRvIGdpdmUgdGhlIERPTSB0aW1lIHRvIHVwZGF0ZVxuXHRzZXRUaW1lb3V0KCgpID0+IHtcblx0XHQvLyBmb2N1cyBvbiBwYXJlbnQgd2luZG93IGlmIGZvY3VzIGlzIGluIGlmcmFtZVxuXHRcdHdpbmRvdy5wYXJlbnQuZm9jdXMoKTtcblx0XHQvLyBzZXQgZm9jdXMgYmFjayB0byBjbGlja2VkIGJ1dHRvblxuXHRcdHZhciBleHBhbmRlZE5hdmlnYXRpb25TdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNleHBhbmRlZC1uYXZpZ2F0aW9uJykpO1xuXHRcdGlmKCBleHBhbmRlZE5hdmlnYXRpb25TdHlsZSAmJiAndmlzaWJsZScgPT09IGV4cGFuZGVkTmF2aWdhdGlvblN0eWxlLnZpc2liaWxpdHkgKSB7XG5cdFx0XHQvLyBpZiBleHBhbmRlZCBuYXYgaXMgb3BlbiwgZm9jdXMgb24gdGhlIGJ1dHRvbiBpbiB0aGUgZXhwYW5kZWQgbmF2XG5cdFx0XHRkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuc2l0ZS1oZWFkZXIgLnN1YnNjcmliZS1wcm9tcHQnKVsxXS5mb2N1cygpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBmb2N1cyBvbiB0aGUgYnV0dG9uIGluIHRoZSBzdGlja3kgbmF2XG5cdFx0XHRkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuc2l0ZS1oZWFkZXIgLnN1YnNjcmliZS1wcm9tcHQnKVswXS5mb2N1cygpO1xuXHRcdH1cblx0fSwgMjUwKTtcbn1cblxuZnVuY3Rpb24gYXR0YWNoTGlzdGVuZXJzKCkge1xuXHQvLyBBdHRhY2ggZXZlbnQgbGlzdGVuZXIgdG8gZWFjaCBlbGVtZW50IG1hdGNoaW5nIHRoZSBzZWxlY3RvclxuXHRkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKF9zdWJzY3JpYmVCdXR0b25DbGFzc2VzKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuXHRcdC8vIFJlbW92ZSBhbnkgcHJldmlvdXNseSBzZXQgZXZlbnQgbGlzdGVuZXJzXG5cdFx0ZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdjbGljaycsIGhhbmRsZUNsaWNrKTtcblxuXHRcdC8vIEFkZCBldmVudCBsaXN0ZW5lcnNcblx0XHRlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgaGFuZGxlQ2xpY2spO1xuXG5cdFx0ZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgKGV2ZW50KSA9PiB7XG5cdFx0XHQvLyBDaGVjayBpZiB0aGUga2V5IHByZXNzZWQgaXMgdGhlIEVudGVyIGtleS5cblx0XHRcdGlmIChldmVudC5rZXkgPT09ICdFbnRlcicpIHtcblx0XHRcdFx0aGFuZGxlQ2xpY2soZXZlbnQpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9KTtcbn1cbmF0dGFjaExpc3RlbmVycygpO1xuXG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbXlmcDp1c2VyLWxvYWRlZCcsICgpID0+IHtcblx0Ly8gTGlzdGVuIGZvciBNeUZQIHVzZXIgbG9hZGVkIGV2ZW50XG5cdC8vIEdpdmUgdGhpcyBhbiBhZGRpdGlvbmFsIHNlY29uZCB0byBwb3B1bGF0ZVxuXHQvLyB0aGUgRE9NIHdpdGggYW55IHN1YnNjcmliZSBwcm9tcHRzIGJlZm9yZVxuXHQvLyBhdHRhY2hpbmcgbmV3IGxpc3RlbmVyc1xuXHRzZXRUaW
1421lb3V0KCgpID0+IHtcblx0XHRhdHRhY2hMaXN0ZW5lcnMoKTtcblx0fSwgJzEwMDAnKTtcbn0pO1xuXG4vLyBBdHRhY2ggZXZlbnQgbGlzdGVuZXIgdG8gY2xvc2UgYnV0dG9uc1xuX3N1YnNjcmliZVRha2VvdmVyQ2xvc2UuZm9yRWFjaChidXR0b24gPT4ge1xuXHRidXR0b24uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB7XG5cdFx0Y2xvc2VTdWJzY3JpYmVNb2RhbCgpO1xuXHR9KTtcblxuXHRidXR0b24uYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIChldmVudCkgPT4ge1xuXHRcdC8vIENoZWNrIGlmIHRoZSBrZXkgcHJlc3NlZCBpcyB0aGUgRW50ZXIga2V5LlxuXHRcdGlmIChldmVudC5rZXkgPT09ICdFbnRlcicpIHtcblx0XHRcdGNsb3NlU3Vic2NyaWJlTW9kYWwoKTtcblx0XHR9XG5cdH0pO1xufSk7XG4iXSwibWFwcGluZ3MiOiJBQUFBLElBQU1BLHVCQUF1QixHQUFHLDZGQUE2RjtBQUM3SCxJQUFNQyxrQkFBa0IsR0FBR0MsUUFBUSxDQUFDQyxhQUFhLENBQUMscUJBQXFCLENBQUM7QUFDeEUsSUFBTUMsd0JBQXdCLEdBQUdGLFFBQVEsQ0FBQ0MsYUFBYSxDQUFDLDRCQUE0QixDQUFDO0FBQ3JGLElBQU1FLHVCQUF1QixHQUFHSCxRQUFRLENBQUNJLGdCQUFnQixDQUFDLDJCQUEyQixDQUFDOztBQUV0RjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQU1DLFdBQVcsR0FBRyxTQUFkQSxXQUFXQSxDQUFHQyxDQUFDLEVBQUk7RUFBQSxJQUFBQyxxQkFBQTtFQUN4QkQsQ0FBQyxDQUFDRSxjQUFjLENBQUMsQ0FBQzs7RUFFbEI7RUFDQSxJQUFJQyxTQUFTLEdBQUdQLHdCQUF3QixDQUFDUSxZQUFZLENBQUMsS0FBSyxDQUFDO0VBQzVELElBQUlDLE9BQU8sSUFBQUoscUJBQUEsR0FBR0QsQ0FBQyxDQUFDTSxNQUFNLENBQUNGLFlBQVksQ0FBQyx1QkFBdUIsQ0FBQyx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\n//# sourceURL=webpack-internal:///../assets/src/scripts/components/navigation/navigation-subscribe-takeover.js\n\n}")}};let __webpack_exports__={};__webpack_modules__["../assets/src/scripts/components/navigation/navigation-subscribe-takeover.js"]()})();; 143(()=>{"use strict";var __webpack_modules__={"../assets/src/scripts/utils/links.js"(__unused_webpack_module,__webpack_exports__,__webpack_require__){eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _babel_runtime_helpers_typeof__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/typeof */ \"./node_modules/@babel/runtime/helpers/esm/typeof.js\");\n\n/* eslint-disable no-undef */\n(function () {\n // Remove the no-js class from html - testing if js is enabled\n document.documentElement.classList.remove('no-js');\n\n // Stop default behavior on specific links\n document.querySelectorAll('a.no-link').forEach(function (link) {\n link.addEventListener('click', function (e) {\n e.preventDefault();\n });\n });\n\n // Track specific link clicks that have \"track-download\" class\n // e.g. <a href=\"/files/test.pdf\" class=\"track-download\">link text</a>\n document.querySelectorAll('a.track-download').forEach(function (link) {\n link.addEventListener('click', function (e) {\n var url_string = e.target.getAttribute('href');\n if ((0,_babel_runtime_helpers_typeof__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(url_string) !== ( true ? \"undefined\" : 0) && url_string !== false && url_string !== null) {\n var url_array = url_string.split('/');\n var eLabel = url_array[url_array.length - 1];\n if (typeof zaraz !== 'undefined') {\n zaraz.track('dl_event', {\n category: 'download',\n action: 'click',\n label: eLabel\n });\n }\n dataLayer.push({\n 'event': 'dl_event',\n 'event_category': 'download',\n 'event_action': 'click',\n 'event_label': eLabel,\n 'event_value': ''\n });\n }\n });\n });\n})();\n/* eslint-enable no-undef *///# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3V0aWxzL2xpbmtzLmpzIiwibWFwcGluZ3MiOiI7OztBQUFBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4uL2Fzc2V0cy9zcmMvc2NyaXB0cy91dGlscy9saW5rcy5qcz9kMGNmIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXG4oZnVuY3Rpb24gKCkge1xuXHQvLyBSZW1vdmUgdGhlIG5vLWpzIGNsYXNzIGZyb20gaHRtbCAtIHRlc3RpbmcgaWYganMgaXMgZW5hYmxlZFxuXHRkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LnJlbW92ZSgnbm8tanMnKTtcblxuXHQvLyBTdG9wIGRlZmF1bHQgYmVoYXZpb3Igb24gc3BlY2lmaWMgbGlua3Ncblx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnYS5uby1saW5rJykuZm9yRWFjaChmdW5jdGlvbiAobGluaykge1xuXHRcdGxpbmsuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdH0pO1xuXHR9KTtcblxuXHQvLyBUcmFjayBzcGVjaWZpYyBsaW5rIGNsaWNrcyB0aGF0IGhh
143dmUgXCJ0cmFjay1kb3dubG9hZFwiIGNsYXNzXG5cdC8vIGUuZy4gPGEgaHJlZj1cIi9maWxlcy90ZXN0LnBkZlwiIGNsYXNzPVwidHJhY2stZG93bmxvYWRcIj5saW5rIHRleHQ8L2E+XG5cdGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ2EudHJhY2stZG93bmxvYWQnKS5mb3JFYWNoKGZ1bmN0aW9uIChsaW5rKSB7XG5cdFx0bGluay5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uIChlKSB7XG5cdFx0XHR2YXIgdXJsX3N0cmluZyA9IGUudGFyZ2V0LmdldEF0dHJpYnV0ZSgnaHJlZicpO1xuXHRcdFx0aWYgKHR5cGVvZiB1cmxfc3RyaW5nICE9PSB0eXBlb2YgdW5kZWZpbmVkICYmIHVybF9zdHJpbmcgIT09IGZhbHNlICYmIHVybF9zdHJpbmcgIT09IG51bGwpIHtcblx0XHRcdFx0dmFyIHVybF9hcnJheSA9IHVybF9zdHJpbmcuc3BsaXQoJy8nKTtcblx0XHRcdFx0dmFyIGVMYWJlbCA9IHVybF9hcnJheVt1cmxfYXJyYXkubGVuZ3RoIC0gMV07XG5cdFx0XHRcdGlmICh0eXBlb2YgemFyYXogIT09ICd1bmRlZmluZWQnKSB7XG5cdFx0XHRcdFx0emFyYXoudHJhY2soXG5cdFx0XHRcdFx0XHQnZGxfZXZlbnQnLFxuXHRcdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0XHRjYXRlZ29yeTogJ2Rvd25sb2FkJyxcblx0XHRcdFx0XHRcdFx0YWN0aW9uOiAnY2xpY2snLFxuXHRcdFx0XHRcdFx0XHRsYWJlbDogZUxhYmVsLFxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZGF0YUxheWVyLnB1c2goe1xuXHRcdFx0XHRcdCdldmVudCc6ICdkbF9ldmVudCcsXG5cdFx0XHRcdFx0J2V2ZW50X2NhdGVnb3J5JzogJ2Rvd25sb2FkJyxcblx0XHRcdFx0XHQnZXZlbnRfYWN0aW9uJzogJ2NsaWNrJyxcblx0XHRcdFx0XHQnZXZlbnRfbGFiZWwnOiBlTGFiZWwsXG5cdFx0XHRcdFx0J2V2ZW50X3ZhbHVlJzogJydcblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH0pO1xufSkoKTtcbi8qIGVzbGludC1lbmFibGUgbm8tdW5kZWYgKi8iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///../assets/src/scripts/utils/links.js\n\n}")},"./node_modules/@babel/runtime/helpers/esm/typeof.js"(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__){eval('{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (/* binding */ _typeof)\n/* harmony export */ });\nfunction _typeof(o) {\n "@babel/helpers - typeof";\n\n return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {\n return typeof o;\n } : function (o) {\n return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;\n }, _typeof(o);\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvQGJhYmVsL3J1bnRpbWUvaGVscGVycy9lc20vdHlwZW9mLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9mb3JlaWducG9saWN5LWJ1aWxkLy4vbm9kZV9tb2R1bGVzL0BiYWJlbC9ydW50aW1lL2hlbHBlcnMvZXNtL3R5cGVvZi5qcz80YmY1Il0sInNvdXJjZXNDb250ZW50IjpbImZ1bmN0aW9uIF90eXBlb2Yobykge1xuICBcIkBiYWJlbC9oZWxwZXJzIC0gdHlwZW9mXCI7XG5cbiAgcmV0dXJuIF90eXBlb2YgPSBcImZ1bmN0aW9uXCIgPT0gdHlwZW9mIFN5bWJvbCAmJiBcInN5bWJvbFwiID09IHR5cGVvZiBTeW1ib2wuaXRlcmF0b3IgPyBmdW5jdGlvbiAobykge1xuICAgIHJldHVybiB0eXBlb2YgbztcbiAgfSA6IGZ1bmN0aW9uIChvKSB7XG4gICAgcmV0dXJuIG8gJiYgXCJmdW5jdGlvblwiID09IHR5cGVvZiBTeW1ib2wgJiYgby5jb25zdHJ1Y3RvciA9PT0gU3ltYm9sICYmIG8gIT09IFN5bWJvbC5wcm90b3R5cGUgPyBcInN5bWJvbFwiIDogdHlwZW9mIG87XG4gIH0sIF90eXBlb2Yobyk7XG59XG5leHBvcnQgeyBfdHlwZW9mIGFzIGRlZmF1bHQgfTsiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/@babel/runtime/helpers/esm/typeof.js\n\n}')}};const __webpack_module_cache__={};function __webpack_require__(e){const n=__webpack_module_cache__[e];if(void 0!==n)return n.exports;const c=__webpack_module_cache__[e]={exports:{}};if(!(e in __webpack_modules__)){delete __webpack_module_cache__[e];const n=new Error("Cannot find module '"+e+"'");throw n.code="MODULE_NOT_FOUND",n}return __webpack_modules__[e](c,c.exports,__webpack_require__),c.exports}__webpack_require__.d=(e,n)=>{if(Array.isArray(n))for(var c=0;c<n.length;){var l=n[c++],b=n[c++];__webpack_require__.o(e,l)?0===b&&c++:0===b?Object.defineProperty(e,l,{enumerable:!0,value:n[c++]}):Object.defineProperty(e,l,{enumerable:!0,get:b})}else for(var l in n)__webpack_require__.o(n,l)&&!__webpack_require__.o(e,l)&&Object.defineProperty(e,l,{enumerable:!0,get:n[l]})},__webpack_require__.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),__webpack_require__.r=e=>{Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}
143),Object.defineProperty(e,"__esModule",{value:!0})};let __webpack_exports__=__webpack_require__("../assets/src/scripts/utils/links.js")})();; 144/** 145 * Helpers for urls 146 */ 147!function () { 148 //=NS 149 FP.Utils = FP.Utils || {}; 150 151 FP.Utils.url = { 152 /** 153 * Helper to parse URL parameters 154 * @param {string} sParam URL parameter to get 155 * @param {bool} toLower 156 * @returns string. 157 */ 158 getUrlParameter: function(sParam, toLower = true) { 159 var sPageURL = window.location.search.substring(1); 160 if (toLower) sPageURL = sPageURL.toLowerCase(); 161 var sURLVariables = sPageURL.split("&"); 162 var ret = "not found"; 163 for (var i = 0; i < sURLVariables.length; i++) { 164 var sParameterName = sURLVariables[i].split("="); 165 if (sParameterName[0] == sParam) { 166 ret = sParameterName[1]; 167 } 168 } 169 return ret; 170 }, 171 172 /** 173 * Helper to get URL slug. 174 * @returns string. 175 */ 176 getUrlSlug: function() { 177 var urlPath = window.location.pathname; 178 urlPath = urlPath.replace(/^\/+/, ''); // remove leading slash 179 urlPath = urlPath.replace(/\/+$/, ''); // remove trailing slash 180 var urlPathArray = urlPath.split('/'); 181 var urlSlug = urlPathArray[urlPathArray.length-1]; 182 return urlSlug; 183 }, 184 185 /** 186 * Get root domain (necessary for IP access clients with proxy URLs). 187 * @param {string} hostname 188 * @returns string. 189 */ 190 getRootDomain: function(hostname) { 191 let parts = hostname.split("."); 192 if (parts.length <= 2) { 193 return hostname; 194 } 195 196 parts = parts.slice(-3); 197 if (['co','com','edu','ac'].indexOf(parts[1]) > -1) { 198 return parts.join('.'); 199 } 200 201 return parts.slice(-2).join('.'); 202 }, 203 204 /** 205 * Get UTM parameters from URL. All parameters are defined in the function. 206 * @returns object. 207 */ 208 getUtmParameters: function() { 209 let utmParamData = { 210 utm_source: FP.Utils.url.getUrlParameter('utm_source'), 211 utm_medium: FP.Utils.url.getUrlParameter('utm_medium'), 212 utm_campaign: FP.Utils.url.getUrlParameter('utm_campaign'), 213 utm_content: FP.Utils.url.getUrlParameter('utm_content'), 214 utm_term: FP.Utils.url.getUrlParameter('utm_term'), 215 }; 216 217 // FP.Utils.url.getUrlParameter() returns a string "not found" if UTM param is not found 218 // if this is the case, we just need to remove the key from the utmParamData object 219 Object.keys(utmParamData).forEach(key => { 220 if (utmParamData[key] === 'not found') { 221 delete utmParamData[key]; 222 } 223 }); 224 225 return utmParamData; 226 }, 227 228 /** 229 * Check if string is valid base64 230 * (primarily for user email URL param - ?e=[base64-encoded-email]). 231 * @param {string} base64 encoded string to check 232 * @returns bool. 233 */ 234 isValidBase64: function(str) { 235 const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/; 236 return base64Regex.test(str); 237 }, 238 239 } 240}();; 241(()=>{var __webpack_modules__={"../assets/src/scripts/utils/forms.js"(){eval("{(function () {\n //=NS\n FP.Utils = FP.Utils || {};\n FP.Utils.forms = {\n recaptchaSiteKey: '6LdNhYkiAAAAAEo_IrOgwgJPQt4LnKpiSPXhUHxZ',\n recaptchaValidationURL: '/recaptcha-verify/?s=verify_recaptcha&__fp_endpoint_recaptcha_api=1&__fp_endpoint_recaptcha_api_token=',\n /**\n * @summary Helper utility for forms.\n *\n * @description Animated labels, recaptcha form validation, etc.\n *\n * @return {void}\n */\n init: function init() {\n FP.Utils.forms.animateLabels();\n FP.Utils.forms.validateFormsWithRecaptcha();\n FP.Utils.forms.validateHtmxFormsWithRecaptcha();\n },\n /**\n * @summary Animate labels on forms.\n *\n * @de
241scription Animate labels to appear above inputs when input is either in focus or populated.\n *\n * @return {void}\n */\n animateLabels: function animateLabels() {\n var animatedLabels = document.querySelectorAll('.animated-labels');\n if (animatedLabels.length > 0) {\n document.querySelectorAll('.animated-labels input, .animated-labels textarea').forEach(function (animatedLabelInput) {\n animatedLabelInput.addEventListener('focus', function (el) {\n var targetLabel = document.querySelector('label[for=\\'' + el.target.id + '\\']');\n if (targetLabel) {\n targetLabel.classList.add('active');\n }\n });\n animatedLabelInput.addEventListener('blur', function (el) {\n var targetLabel = document.querySelector('label[for=\\'' + el.target.id + '\\']');\n if (targetLabel && el.target.value === '') {\n targetLabel.classList.remove('active');\n }\n });\n });\n }\n },\n /**\n * @summary Handle recaptcha validation on forms.\n *\n * @description Add click events and form validation on forms that have recaptcha.\n *\n * @return {void}\n */\n validateFormsWithRecaptcha: function validateFormsWithRecaptcha() {\n //\n // Pages with form and recaptcha v3\n //\n var formWithRecaptchaV3 = document.querySelectorAll('.salesforce-lead-form--with-recaptcha-v3');\n if (formWithRecaptchaV3.length < 1) {\n return true;\n }\n document.querySelectorAll('.salesforce-lead-form--with-recaptcha-v3 input[type=submit]').forEach(function (submitBtn) {\n submitBtn.addEventListener('click', function (e) {\n var formEl = formWithRecaptchaV3[0];\n // leverage browser native validation primarily for screenreaders\n // browser native functionality will automatically focus on invalid fields\n if (!formEl.checkValidity()) {\n // Prevent form submission\n e.preventDefault();\n // Show browser native validation errors\n formEl.reportValidity();\n return;\n }\n var errorMessage = '';\n var errorFields = '';\n var errorMessageContainer = formEl.querySelector('.form-feedback');\n if (errorMessageContainer) {\n errorMessageContainer.innerHTML = '';\n errorMessageContainer.classList.remove('show-error');\n }\n document.querySelectorAll('.form-feedback-error').forEach(function (el) {\n el.remove();\n });\n\n // verify required fields are populated\n var requiredFieldsFilled = true;\n formEl.querySelectorAll('[required]').forEach(function (field) {\n if ('' === field.value) {\n var _field$getAttribute;\n errorFields = errorFields + '<a href=\"#' + field.getAttribute('id') + '\">' + field.getAttribute('data-field-name') + '</a>, ';\n requiredFieldsFilled = false;\n var formFeedbackText = (_field$getAttribute = field.getAttribute('data-field-error')) !== null && _field$getAttribute !== void 0 ? _field$getAttribute : 'Enter a ' + field.getAttribute('data-field-name');\n var errorEl = document.createElement('div');\n errorEl.className = 'form-feedback-error error';\n errorEl.innerHTML = '<span class=\"sr-only\">Error: </span>' + formFeedbackText;\n field.parentNode.insertBefore(errorEl, field);\n }\n });\n if (!requiredFieldsFilled) {\n errorMessage = '<p>Please complete the following required fields: <b>' + errorFields.substring(0, errorFields.length - 2) + '</b></p>';\n } else {\n // prevent default form submission\n e.preventDefault();\n\n // verify recaptcha\n var grecaptcha = window.grecaptcha;\n grecaptcha.ready(function () {\n grecaptcha.execute(FP.Utils.forms.recaptchaSiteKey, {\n action: 'submit'\n }).then(function (token) {\n fetch(FP.Utils.forms.recaptchaValidationURL + token, {\n method: 'POST',\n cache: 'no-store'\n }).then(function (response) {\n return response.json();\n }).then(function (resp) {\n // recaptcha verification successful\n if (resp.data.success === true && resp.data.score >= 0.7) {\n // continue processing form\n formEl.submit();\n // recaptcha verification failed\n } else {\n // show error below\n errorMessage = '<p>There was an error processing your information. Please contact <a href=\"mailto:[email protected]\">[email protected]</a> for assistance.</p>';\n FP.Utils.forms.showFormErrors(errorMessage, errorMessageContainer);\n console.log('validation score feedback: ' + resp.data.score);\n }\n });\n });\n });\n }\n if ('' !== errorMessage) {\n // prevent default form submission\n e.preventDefault();\n\n // show error\n FP.Utils.forms.showFormErrors(errorMessage, errorMessageContainer);\n return false;\n }\n });\n });\n },\n /**\n * @summary Handle recaptcha validation on HTMx forms.\n *\n * @de
241scription Add form validation on HTMx forms that have recaptcha.\n *\n * @return {void}\n */\n validateHtmxFormsWithRecaptcha: function validateHtmxFormsWithRecaptcha() {\n document.body.addEventListener('htmx:confirm', function (evt) {\n var element = evt.detail.elt;\n\n // Only target .htmx--recaptcha elements\n if (element.classList.contains('htmx--recaptcha') || element.closest('.htmx--recaptcha')) {\n // Pauses the request until validation is complete\n evt.preventDefault();\n\n // Validate recaptcha before processing the request\n FP.Utils.forms.validateRecaptcha().then(function (resp) {\n // Check boolean resp.success return value\n if (typeof resp.success !== 'undefined' && resp.success) {\n // Request met the minimum recaptcha score threshold\n // Allow form processing to continue\n evt.detail.issueRequest();\n }\n });\n }\n });\n },\n /**\n * @summary Returns whether or not the recaptcha has been verified.\n *\n * @description Primarily for SailThru sign up buttons, not tied to an actual form submission.\n *\n * @param {int} scoreThreshold - Recaptcha score threshold.\n *\n * @returns {Promise} Promise resolving with success/data object.\n */\n validateRecaptcha: function validateRecaptcha() {\n var scoreThreshold = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.5;\n return new Promise(function (resolve) {\n var grecaptcha = window.grecaptcha;\n grecaptcha.ready(function () {\n grecaptcha.execute(FP.Utils.forms.recaptchaSiteKey, {\n action: 'submit'\n }).then(function (token) {\n fetch(FP.Utils.forms.recaptchaValidationURL + token, {\n method: 'POST',\n cache: 'no-store'\n }).then(function (response) {\n return response.json();\n }).then(function (resp) {\n // recaptcha verification successful\n if (resp.data.success === true && resp.data.score > scoreThreshold) {\n resolve({\n success: true,\n data: 1\n });\n // recaptcha verification failed\n } else {\n resolve({\n success: false,\n data: 0\n });\n }\n });\n });\n });\n });\n },\n /**\n * @summary Validate email address.\n *\n * @description Validate email address using regex.\n *\n * @param {string} email\n *\n * @returns {boolean} Is valid email string\n */\n validateEmail: function validateEmail(email) {\n var emailReg = /^(([^<>()[\\]\\\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n return emailReg.test(email);\n },\n /**\n * @summary Handles showing error messages.\n *\n * @description Inject form errors into error container and display the container.\n * If a clicked element should revert to a previous state, update the element text.\n *\n * @param {string} errorMessage - HTML string of error message to show.\n * @param {Element} errorMessageContainer - DOM element to show error\n * @param {Element} clickedElement - DOM element that triggered the event.\n *\n * @returns {void}\n */\n showFormErrors: function showFormErrors(errorMessage, errorMessageContainer) {\n var clickedElement = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;\n if (!errorMessageContainer) return;\n\n // show error\n errorMessageContainer.innerHTML = errorMessage;\n errorMessageContainer.classList.add('show-error');\n // TO-DO - the .show-error class needs to be added to the NL HTML?\n\n errorMessageContainer.setAttribute('tabindex', '0');\n\n // update clicked element if present\n if (clickedElement) {\n clickedElement.classList.remove('button-clicked');\n }\n\n // take user to error\n var rect = errorMessageContainer.getBoundingClientRect();\n var siteHeader = document.querySelector('.site-header');\n var headerHeight = siteHeader ? siteHeader.offsetHeight : 0;\n window.scrollTo({\n top: rect.top + window.pageYOffset - headerHeight - 50,\n left: 0,\n behavior: 'smooth'\n });\n errorMessageContainer.focus();\n return;\n },\n /**\n * @summary Error handling for account-related forms.\n *\n * @de
241scription Primarily used for newsletter account signup form error handling.\n *\n * @param {Element} form - DOM form element to validate\n *\n * @returns {bool}\n */\n validateAccountForms: function validateAccountForms(form) {\n // Clear any previous errors\n var errorContainer = form.querySelector('.form-feedback');\n if (errorContainer) {\n errorContainer.querySelectorAll('.error-message').forEach(function (el) {\n el.remove();\n });\n }\n var errors = [];\n\n // TO-DO - make this more dynamic for form fields? Look for a required attribute?\n var emailField = form.querySelector('input[name=\"email\"]');\n var passwordField = form.querySelector('input[name=\"password\"]');\n var firstnameField = form.querySelector('input[name=\"firstname\"]');\n var lastnameField = form.querySelector('input[name=\"lastname\"]');\n var optinField = form.querySelector('input[name=\"optin\"]');\n\n // Every screen has an email field\n if (!emailField || !FP.Utils.forms.validateEmail(emailField.value)) {\n errors.push('Email address is invalid');\n }
241\n if (passwordField) {\n if (passwordField.value.length < 8) {\n errors.push('Password must be at least 8 characters');\n }\n }\n [firstnameField, lastnameField].forEach(function (el) {\n if (el) {\n if (!el.value) {\n errors.push(el.getAttribute('placeholder') + ' is required');\n }\n }\n });\n if (optinField && !optinField.checked) {\n errors.push('Opt-in is required');\n }\n if (errors.length) {\n FP.Utils.forms.showAccountFormErrors(form, errors);\n }\n return !errors.length;\n },\n /**\n * @summary Show errors on account-related forms.\n *\n * @description Primarily used for newsletter account signup form error display.\n *\n * @param {Element} form - DOM element of form\n *\n * @param {array} errors - Array of errors to show\n *\n * @returns {void}\n */\n showAccountFormErrors: function showAccountFormErrors(form, errors) {\n var errorContainer = form.querySelector('.form-feedback');\n var error_list = errors.join('<br>');\n if ('' !== error_list) {\n FP.Utils.forms.showFormErrors('<span class=\"error-message\">' + errors.join('<br>') + '</span>', errorContainer, null, null);\n }\n }\n };\n})();\nFP.Utils.forms.init();//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3V0aWxzL2Zvcm1zLmpzIiwibmFtZXMiOlsiRlAiLCJVdGlscyIsImZvcm1zIiwicmVjYXB0Y2hhU2l0ZUtleSIsInJlY2FwdGNoYVZhbGlkYXRpb25VUkwiLCJpbml0IiwiYW5pbWF0ZUxhYmVscyIsInZhbGlkYXRlRm9ybXNXaXRoUmVjYXB0Y2hhIiwidmFsaWRhdGVIdG14Rm9ybXNXaXRoUmVjYXB0Y2hhIiwiYW5pbWF0ZWRMYWJlbHMiLCJkb2N1bWVudCIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJsZW5ndGgiLCJmb3JFYWNoIiwiYW5pbWF0ZWRMYWJlbElucHV0IiwiYWRkRXZlbnRMaXN0ZW5lciIsImVsIiwidGFyZ2V0TGFiZWwiLCJxdWVyeVNlbGVjdG9yIiwidGFyZ2V0IiwiaWQiLCJjbGFzc0xpc3QiLCJhZGQiLCJ2YWx1ZSIsInJlbW92ZSIsImZvcm1XaXRoUmVjYXB0Y2hhVjMiLCJzdWJtaXRCdG4iLCJlIiwiZm9ybUVsIiwiY2hlY2tWYWxpZGl0eSIsInByZXZlbnREZWZhdWx0IiwicmVwb3J0VmFsaWRpdHkiLCJlcnJvck1lc3NhZ2UiLCJlcnJvckZpZWxkcyIsImVycm9yTWVzc2FnZUNvbnRhaW5lciIsImlubmVySFRNTCIsInJlcXVpcmVkRmllbGRzRmlsbGVkIiwiZmllbGQiLCJfZmllbGQkZ2V0QXR0cmlidXRlIiwiZ2V0QXR0cmlidXRlIiwiZm9ybUZlZWRiYWNrVGV4dCIsImVycm9yRWwiLCJjcmVhdGVFbGVtZW50IiwiY2xhc3NOYW1lIiwicGFyZW50Tm9kZSIsImluc2VydEJlZm9yZSIsInN1YnN0cmluZyIsImdyZWNhcHRjaGEiLCJ3aW5kb3ciLCJyZWFkeSIsImV4ZWN1dGUiLCJhY3Rpb24iLCJ0aGVuIiwidG9rZW4iLCJmZXRjaCIsIm1ldGhvZCIsImNhY2hlIiwicmVzcG9uc2UiLCJqc29uIiwicmVzcCIsImRhdGEiLCJzdWNjZXNzIiwic2NvcmUiLCJzdWJtaXQiLCJzaG93Rm9ybUVycm9ycyIsImNvbnNvbGUiLCJsb2ciLCJib2R5IiwiZXZ0IiwiZWxlbWVudCIsImRldGFpbCIsImVsdCIsImNvbnRhaW5zIiwiY2xvc2VzdCIsInZhbGlkYXRlUmVjYXB0Y2hhIiwiaXNzdWVSZXF1ZXN0Iiwic2NvcmVUaHJlc2hvbGQiLCJhcmd1bWVudHMiLCJ1bmRlZmluZWQiLCJQcm9taXNlIiwicmVzb2x2ZSIsInZhbGlkYXRlRW1haWwiLCJlbWFpbCIsImVtYWlsUmVnIiwidGVzdCIsImNsaWNrZWRFbGVtZW50Iiwic2V0QXR0cmlidXRlIiwicmVjdCIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInNpdGVIZWFkZXIiLCJoZWFkZXJIZWlnaHQiLCJvZmZzZXRIZWlnaHQiLCJzY3JvbGxUbyIsInRvcCIsInBhZ2VZT2Zmc2V0IiwibGVmdCIsImJlaGF2aW9yIiwiZm9jdXMiLCJ2YWxpZGF0ZUFjY291bnRGb3JtcyIsImZvcm0iLCJlcnJvckNvbnRhaW5lciIsImVycm9ycyIsImVtYWlsRmllbGQiLCJwYXNzd29yZEZpZWxkIiwiZmlyc3RuYW1lRmllbGQiLCJsYXN0bmFtZUZpZWxkIiwib3B0aW5GaWVsZCIsInB1c2giLCJjaGVja2VkIiwic2hvd0FjY291bnRGb3JtRXJyb3JzIiwiZXJyb3JfbGlzdCIsImpvaW4iXSwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsid2VicGFjazovL2ZvcmVpZ25wb2xpY3ktYnVpbGQvLi4vYXNzZXRzL3NyYy9zY3JpcHRzL3V0aWxzL2Zvcm1zLmpzPzk3ZDEiXSwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKCkge1xuXG5cdC8vPU5TXG5cdEZQLlV0aWxzID0gRlAuVXRpbHMgfHwge307XG5cblx0RlAuVXRpbHMuZm9ybXMgPSB7XG5cblx0XHRyZWNhcHRjaGFTaXRlS2V5OiAnNkxkTmhZa2lBQUFBQUVvX0lyT2d3Z0pQUXQ0TG5LcGlTUFhoVUh4WicsXG5cdFx0cmVjYXB0Y2hhVmFsaWRhdGlvblVSTDogJy9yZWNhcHRjaGEtdmVyaWZ5Lz9zPXZlcmlmeV9yZWNhcHRjaGEmX19mcF9lbmRwb2ludF9yZWNhcHRjaGFfYXBpPTEmX19mcF9lbmRwb2ludF9yZWNhcHRjaGFfYXBpX3Rva2VuPScsXG5cblx0XHQvKipcblx0XHQgKiBAc3VtbWFyeSBIZWxwZXIgdXRpbGl0eSBmb3IgZm9ybXMuXG5cdFx0ICpcblx0XHQgKiBAZGVzY3JpcHRpb24gQW5pbWF0ZWQgbGFiZWxzLCByZWNhcHRjaGEgZm9ybSB2YWxpZGF0aW9uLCBldGMuXG5cdFx0ICpcblx0XHQgKiBAcmV0dXJuIHt2b2lkfVxuXHRcdCAqL1xuXHRcdGluaXQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0RlAuVXRpbHMuZm9ybXMuYW5pbWF0ZUxhYmVscygpO1xuXHRcdFx0RlAuVXRpbHMuZm9ybXMudmFsaWRhdGVGb3Jtc1dpdGhSZWNhcHRjaGEoKTtcblx0XHRcdEZQLlV0aWxzLmZvcm1zLnZhbGlkYXRlSHRteEZvcm1zV2l0aFJlY2FwdGNoYSgpO1xuXHRcdH0sXG5cblx0XHQvKipcblx0XHQgKiBAc3VtbWFyeSBBbmltYXRlIGxhYmVscyBvbiBmb3Jtcy5cblx0XHQgKlxuXHRcdCAqIEBkZXNjcmlwdGlvbiBBbmltYXRlIGxhYmVscyB0byBhcHBlYXIgYWJvdmUgaW5wdXRzIHdoZW4gaW5wdXQgaXMgZWl0aGVyIGluIGZvY3VzIG9yIHBvcHVsYXRlZC5cblx0XHQgKlxuXHRcdCAqIEByZXR1cm4ge3ZvaWR9XG5cdFx0ICovXG5cdFx0YW5pbWF0ZUxhYmVsczogZnVuY3Rpb24oKSB7XG5cdFx0XHRjb25zdCBhbmltYXRlZExhYmVscyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5hbmltYXRlZC1sYWJlbHMnKTtcblx0XHRcdGlmIChhbmltYXRlZExhYmVscy5sZW5ndGggPiAwKSB7XG5cdFx0XHRcdGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5hbmltYXRlZC1sYWJlbHMgaW5wdXQsIC5hbmltYXRlZC1sYWJlbHMgdGV4dGFyZWEnKS5mb3JFYWNoKChhbmltYXRlZExhYmVsSW5wdXQpID0+IHtcblx0XHRcdFx0XHRhbmltYXRlZExhYmVsSW5wdXQuYWRkRXZlbnRMaXN0ZW5lcignZm9jdXMnLCAoZWwpID0+IHtcblx0XHRcdFx0XHRcdGNvbnN0IHRhcmdldExhYmVsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignbGFiZWxbZm9yPVxcJycgKyBlbC50YXJnZXQuaWQgKyAnXFwnXScpO1xuXHRcdFx0XHRcdFx0aWYgKHRhcmdldExhYmVsKSB7XG5cdFx0XHRcdFx0XHRcdHRhcmdldExhYmVsLmNsYXNzTGlzdC5hZGQoJ2FjdGl2ZScpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0pO1xuXG5cdFx0XHRcdFx0YW5pbWF0ZWRMYWJlbElucHV0LmFkZEV2ZW50TGlzdGVuZXIoJ2JsdXInLCAoZWwpID0+IHtcblx0XHRcdFx0XHRcdGNvbnN0IHRhcmdldExhYmVsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignbGFiZWxbZm9yPVxcJycgKyBlbC50YXJnZXQuaWQgKyAnXFwnXScpO1xuXHRcdFx0XHRcdFx0aWYgKHRhcmdldExhYmVsICYmIGVsLnRhcmdldC52YWx1ZSA9PT0gJycpIHtcblx0XHRcdFx0XHRcdFx0dGFyZ2V0TGFiZWwuY2xhc3NMaXN0LnJlbW92ZSgnYWN0aXZlJyk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHQvKipcblx0XHQgKiBAc3VtbWFyeSBIYW5kbGUgcmVjYXB0Y2hhIHZhbGlkYXRpb24gb24gZm9ybXMuXG5cdFx0ICpcblx0XHQgKiBAZGVzY3JpcHRpb24gQWRkIGNsaWNrIGV2ZW50cyBhbmQgZm9ybSB2YWxpZGF0aW9uIG9uIGZvcm1zIHRoYXQgaGF2ZSByZWNhcHRjaGEuXG5cdFx0ICpcblx0XHQgKiBAcmV0dXJuIHt2b2lkfVxuXHRcdCAqL1xuXHRcdHZhbGlkYXRlRm9ybXNXaXRoUmVjYXB0Y2hhOiBmdW5jdGlvbigpIHtcblx0XHRcdC8vXG5cdFx0XHQvLyBQYWdlcyB3aXRoIGZvcm0gYW5kIHJlY2FwdGNoYSB2M1xuXHRcdFx0Ly9cblx0XHRcdHZhciBmb3JtV2l0aFJlY2FwdGNoYVYzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnNhbGVzZm9yY2UtbGVhZC1mb3JtLS13aXRoLXJlY2FwdGNoYS12MycpO1xuXG5cdFx0XHRpZiAoZm9ybVdpdGhSZWNhcHRjaGFWMy5sZW5ndGggPCAxKSB7XG5cdFx0XHRcdHJldHVybi
241B0cnVlO1xuXHRcdFx0fVxuXG5cdFx0XHRkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuc2FsZXNmb3JjZS1sZWFkLWZvcm0tLXdpdGgtcmVjYXB0Y2hhLXYzIGlucHV0W3R5cGU9c3VibWl0XScpLmZvckVhY2goZnVuY3Rpb24oc3VibWl0QnRuKSB7XG5cdFx0XHRcdHN1Ym1pdEJ0bi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uKGUpIHtcblx0XHRcdFx0XHR2YXIgZm9ybUVsID0gZm9ybVdpdGhSZWNhcHRjaGFWM1swXTtcblx0XHRcdFx0XHQvLyBsZXZlcmFnZSBicm93c2VyIG5hdGl2ZSB2YWxpZGF0aW9uIHByaW1hcmlseSBmb3Igc2NyZWVucmVhZGVyc1xuXHRcdFx0XHRcdC8vIGJyb3dzZXIgbmF0aXZlIGZ1bmN0aW9uYWxpdHkgd2lsbCBhdXRvbWF0aWNhbGx5IGZvY3VzIG9uIGludmFsaWQgZmllbGRzXG5cdFx0XHRcdFx0aWYgKCFmb3JtRWwuY2hlY2tWYWxpZGl0eSgpKSB7XG5cdFx0XHRcdFx0XHQvLyBQcmV2ZW50IGZvcm0gc3VibWlzc2lvblxuXHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0Ly8gU2hvdyBicm93c2VyIG5hdGl2ZSB2YWxpZGF0aW9uIGVycm9yc1xuXHRcdFx0XHRcdFx0Zm9ybUVsLnJlcG9ydFZhbGlkaXR5KCk7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0dmFyIGVycm9yTWVzc2FnZSA9ICcnO1xuXHRcdFx0XHRcdHZhciBlcnJvckZpZWxkcyA9ICcnO1xuXHRcdFx0XHRcdHZhciBlcnJvck1lc3NhZ2VDb250YWluZXIgPSBmb3JtRWwucXVlcnlTZWxlY3RvcignLmZvcm0tZmVlZGJhY2snKTtcblxuXHRcdFx0XHRcdGlmIChlcnJvck1lc3NhZ2VDb250YWluZXIpIHtcblx0XHRcdFx0XHRcdGVycm9yTWVzc2FnZUNvbnRhaW5lci5pbm5lckhUTUwgPSAnJztcblx0XHRcdFx0XHRcdGVycm9yTWVzc2FnZUNvbnRhaW5lci5jbGFzc0xpc3QucmVtb3ZlKCdzaG93LWVycm9yJyk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5mb3JtLWZlZWRiYWNrLWVycm9yJykuZm9yRWFjaChmdW5jdGlvbihlbCkgeyBlbC5yZW1vdmUoKTsgfSk7XG5cblx0XHRcdFx0XHQvLyB2ZXJpZnkgcmVxdWlyZWQgZmllbGRzIGFyZSBwb3B1bGF0ZWRcblx0XHRcdFx0XHRsZXQgcmVxdWlyZWRGaWVsZHNGaWxsZWQgPSB0cnVlO1xuXHRcdFx0XHRcdGZvcm1FbC5xdWVyeVNlbGVjdG9yQWxsKCdbcmVxdWlyZWRdJykuZm9yRWFjaChmdW5jdGlvbihmaWVsZCkge1xuXHRcdFx0XHRcdFx0aWYgKCcnID09PSBmaWVsZC52YWx1ZSkge1xuXHRcdFx0XHRcdFx0XHRlcnJvckZpZWxkcyA9IGVycm9yRmllbGRzICsgJzxhIGhyZWY9XCIjJyArIGZpZWxkLmdldEF0dHJpYnV0ZSgnaWQnKSArICdcIj4nICsgZmllbGQuZ2V0QXR0cmlidXRlKCdkYXRhLWZpZWxkLW5hbWUnKSArICc8L2E+LCAnO1xuXHRcdFx0XHRcdFx0XHRyZXF1aXJlZEZpZWxkc0ZpbGxlZCA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0XHRcdHZhciBmb3JtRmVlZGJhY2tUZXh0ID0gZmllbGQuZ2V0QXR0cmlidXRlKCdkYXRhLWZpZWxkLWVycm9yJykgPz8gJ0VudGVyIGEgJyArIGZpZWxkLmdldEF0dHJpYnV0ZSgnZGF0YS1maWVsZC1uYW1lJyk7XG5cdFx0XHRcdFx0XHRcdHZhciBlcnJvckVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG5cdFx0XHRcdFx0XHRcdGVycm9yRWwuY2xhc3NOYW1lID0gJ2Zvcm0tZmVlZGJhY2stZXJyb3IgZXJyb3InO1xuXHRcdFx0XHRcdFx0XHRlcnJvckVsLmlubmVySFRNTCA9ICc8c3BhbiBjbGFzcz1cInNyLW9ubHlcIj5FcnJvcjogPC9zcGFuPicgKyBmb3JtRmVlZGJhY2tUZXh0O1xuXHRcdFx0XHRcdFx0XHRmaWVsZC5wYXJlbnROb2RlLmluc2VydEJlZm9yZShlcnJvckVsLCBmaWVsZCk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHRpZiAoIXJlcXVpcmVkRmllbGRzRmlsbGVkKSB7XG5cdFx0XHRcdFx0XHRlcnJvck1lc3NhZ2UgPSAnPHA+UGxlYXNlIGNvbXBsZXRlIHRoZSBmb2xsb3dpbmcgcmVxdWlyZWQgZmllbGRzOiA8Yj4nICsgZXJyb3JGaWVsZHMuc3Vic3RyaW5nKDAsIGVycm9yRmllbGRzLmxlbmd0aCAtIDIpICsgJzwvYj48L3A+Jztcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0Ly8gcHJldmVudCBkZWZhdWx0IGZvcm0gc3VibWlzc2lvblxuXHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRcdFx0XHQvLyB2ZXJpZnkgcmVjYXB0Y2hhXG5cdFx0XHRcdFx0XHR2YXIgZ3JlY2FwdGNoYSA9IHdpbmRvdy5ncmVjYXB0Y2hhO1xuXHRcdFx0XHRcdFx0Z3JlY2FwdGNoYS5yZWFkeShmdW5jdGlvbigpIHtcblxuXHRcdFx0XHRcdFx0XHRncmVjYXB0Y2hhLmV4ZWN1dGUoRlAuVXRpbHMuZm9ybXMucmVjYXB0Y2hhU2l0ZUtleSwgeyBhY3Rpb246ICdzdWJtaXQnIH0pLnRoZW4oZnVuY3Rpb24odG9rZW4pIHtcblx0XHRcdFx0XHRcdFx0XHRmZXRjaChGUC5VdGlscy5mb3Jtcy5yZWNhcHRjaGFWYWxpZGF0aW9uVVJMICsgdG9rZW4sIHtcblx0XHRcdFx0XHRcdFx0XHRcdG1ldGhvZDogJ1BPU1QnLFxuXHRcdFx0XHRcdFx0XHRcdFx0Y2FjaGU6ICduby1zdG9yZScsXG5cdFx0XHRcdFx0XHRcdFx0fSkudGhlbihmdW5jdGlvbihyZXNwb25zZSkge1xuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlLmpzb24oKTtcblx0XHRcdFx0XHRcdFx0XHR9KS50aGVuKGZ1bmN0aW9uKHJlc3ApIHtcblx0XHRcdFx0XHRcdFx0XHRcdC8vIHJlY2FwdGNoYSB2ZXJpZmljYXRpb24gc3VjY2Vzc2Z1bFxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKHJlc3AuZGF0YS5zdWNjZXNzID09PSB0cnVlICYmIHJlc3AuZGF0YS5zY29yZSA+PSAwLjcpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gY29udGludWUgcHJvY2Vzc2luZyBmb3JtXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGZvcm1FbC5zdWJtaXQoKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gcmVjYXB0Y2hhIHZlcmlmaWNhdGlvbiBmYWlsZWRcblx0XHRcdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIHNob3cgZXJyb3IgYmVsb3dcblx0XHRcdFx0XHRcdFx0XHRcdFx0ZXJyb3JNZXNzYWdlID0gJzxwPlRoZXJlIHdhcyBhbiBlcnJvciBwcm9jZXNzaW5nIHlvdXIgaW5mb3JtYXRpb24uIFBsZWFzZSBjb250YWN0IDxhIGhyZWY9XCJtYWlsdG86c3VwcG9ydEBmb3JlaWducG9saWN5LmNvbVwiPnN1cHBvcnRAZm9yZWlnbnBvbGljeS5jb208L2E+IGZvciBhc3Npc3RhbmNlLjwvcD4nO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRGUC5VdGlscy5mb3Jtcy5zaG93Rm9ybUVycm9ycyhlcnJvck1lc3NhZ2UsIGVycm9yTWVzc2FnZUNvbnRhaW5lcik7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGNvbnNvbGUubG9nKCd2YWxpZGF0aW9uIHNjb3JlIGZlZWRiYWNrOiAnICsgcmVzcC5kYXRhLnNjb3JlKTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoJycgIT09IGVycm9yTWVzc2FnZSkge1xuXHRcdFx0XHRcdFx0Ly8gcHJldmVudCBkZWZhdWx0IGZvcm0gc3VibWlzc2lvblxuXHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRcdFx0XHQvLyBzaG93IGVycm9yXG5cdFx0XHRcdFx0XHRGUC5VdGlscy5mb3Jtcy5zaG93Rm9ybUVycm9ycyhlcnJvck1lc3NhZ2UsIGVycm9yTWVzc2FnZUNvbnRhaW5lcik7XG5cblx0XHRcdFx0XHRcdHJldHVybi
241BmYWxzZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSk7XG5cdFx0fSxcblxuXHRcdC8qKlxuXHRcdCAqIEBzdW1tYXJ5IEhhbmRsZSByZWNhcHRjaGEgdmFsaWRhdGlvbiBvbiBIVE14IGZvcm1zLlxuXHRcdCAqXG5cdFx0ICogQGRlc2NyaXB0aW9uIEFkZCBmb3JtIHZhbGlkYXRpb24gb24gSFRNeCBmb3JtcyB0aGF0IGhhdmUgcmVjYXB0Y2hhLlxuXHRcdCAqXG5cdFx0ICogQHJldHVybiB7dm9pZH1cblx0XHQgKi9cblx0XHR2YWxpZGF0ZUh0bXhGb3Jtc1dpdGhSZWNhcHRjaGE6IGZ1bmN0aW9uKCkge1xuXHRcdFx0ZG9jdW1lbnQuYm9keS5hZGRFdmVudExpc3RlbmVyKCdodG14OmNvbmZpcm0nLCAoZXZ0KSA9PiB7XG5cdFx0XHRcdGNvbnN0IGVsZW1lbnQgPSBldnQuZGV0YWlsLmVsdDtcblxuXHRcdFx0XHQvLyBPbmx5IHRhcmdldCAuaHRteC0tcmVjYXB0Y2hhIGVsZW1lbnRzXG5cdFx0XHRcdGlmIChlbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygnaHRteC0tcmVjYXB0Y2hhJykgfHwgZWxlbWVudC5jbG9zZXN0KCcuaHRteC0tcmVjYXB0Y2hhJykpIHtcblx0XHRcdFx0XHQvLyBQYXVzZXMgdGhlIHJlcXVlc3QgdW50aWwgdmFsaWRhdGlvbiBpcyBjb21wbGV0ZVxuXHRcdFx0XHRcdGV2dC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRcdFx0Ly8gVmFsaWRhdGUgcmVjYXB0Y2hhIGJlZm9yZSBwcm9jZXNzaW5nIHRoZSByZXF1ZXN0XG5cdFx0XHRcdFx0RlAuVXRpbHMuZm9ybXMudmFsaWRhdGVSZWNhcHRjaGEoKVxuXHRcdFx0XHRcdFx0LnRoZW4oZnVuY3Rpb24ocmVzcCkge1xuXHRcdFx0XHRcdFx0XHQvLyBDaGVjayBib29sZWFuIHJlc3Auc3VjY2VzcyByZXR1cm4gdmFsdWVcblx0XHRcdFx0XHRcdFx0aWYgKHR5cGVvZiByZXNwLnN1Y2Nlc3MgIT09ICd1bmRlZmluZWQnICYmIHJlc3Auc3VjY2Vzcykge1xuXHRcdFx0XHRcdFx0XHRcdC8vIFJlcXVlc3QgbWV0IHRoZSBtaW5pbXVtIHJlY2FwdGNoYSBzY29yZSB0aHJlc2hvbGRcblx0XHRcdFx0XHRcdFx0XHQvLyBBbGxvdyBmb3JtIHByb2Nlc3NpbmcgdG8gY29udGludWVcblx0XHRcdFx0XHRcdFx0XHRldnQuZGV0YWlsLmlzc3VlUmVxdWVzdCgpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fSxcblxuXHRcdC8qKlxuXHRcdCAqIEBzdW1tYXJ5IFJldHVybnMgd2hldGhlciBvciBub3QgdGhlIHJlY2FwdGNoYSBoYXMgYmVlbiB2ZXJpZmllZC5cblx0XHQgKlxuXHRcdCAqIEBkZXNjcmlwdGlvbiBQcmltYXJpbHkgZm9yIFNhaWxUaHJ1IHNpZ24gdXAgYnV0dG9ucywgbm90IHRpZWQgdG8gYW4gYWN0dWFsIGZvcm0gc3VibWlzc2lvbi5cblx0XHQgKlxuXHRcdCAqIEBwYXJhbSB7aW50fSBzY29yZVRocmVzaG9sZCAtIFJlY2FwdGNoYSBzY29yZSB0aHJlc2hvbGQuXG5cdFx0ICpcblx0XHQgKiBAcmV0dXJucyB7UHJvbWlzZX0gUHJvbWlzZSByZXNvbHZpbmcgd2l0aCBzdWNjZXNzL2RhdGEgb2JqZWN0LlxuXHRcdCAqL1xuXHRcdHZhbGlkYXRlUmVjYXB0Y2hhOiBmdW5jdGlvbihzY29yZVRocmVzaG9sZCA9IDAuNSkge1xuXHRcdFx0cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUpIHtcblx0XHRcdFx0dmFyIGdyZWNhcHRjaGEgPSB3aW5kb3cuZ3JlY2FwdGNoYTtcblx0XHRcdFx0Z3JlY2FwdGNoYS5yZWFkeShmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRncmVjYXB0Y2hhLmV4ZWN1dGUoRlAuVXRpbHMuZm9ybXMucmVjYXB0Y2hhU2l0ZUtleSwgeyBhY3Rpb246ICdzdWJtaXQnIH0pLnRoZW4oZnVuY3Rpb24odG9rZW4pIHtcblx0XHRcdFx0XHRcdGZldGNoKEZQLlV0aWxzLmZvcm1zLnJlY2FwdGNoYVZhbGlkYXRpb25VUkwgKyB0b2tlbiwge1xuXHRcdFx0XHRcdFx0XHRtZXRob2Q6ICdQT1NUJyxcblx0XHRcdFx0XHRcdFx0Y2FjaGU6ICduby1zdG9yZScsXG5cdFx0XHRcdFx0XHR9KS50aGVuKGZ1bmN0aW9uKHJlc3BvbnNlKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiByZXNwb25zZS5qc29uKCk7XG5cdFx0XHRcdFx0XHR9KS50aGVuKGZ1bmN0aW9uKHJlc3ApIHtcblx0XHRcdFx0XHRcdFx0Ly8gcmVjYXB0Y2hhIHZlcmlmaWNhdGlvbiBzdWNjZXNzZnVsXG5cdFx0XHRcdFx0XHRcdGlmIChyZXNwLmRhdGEuc3VjY2VzcyA9PT0gdHJ1ZSAmJiByZXNwLmRhdGEuc2NvcmUgPiBzY29yZVRocmVzaG9sZCkge1xuXHRcdFx0XHRcdFx0XHRcdHJlc29sdmUoe1xuXHRcdFx0XHRcdFx0XHRcdFx0c3VjY2VzczogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRcdGRhdGE6IDFcblx0XHRcdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRcdFx0XHQvLyByZWNhcHRjaGEgdmVyaWZpY2F0aW9uIGZhaWxlZFxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdHJlc29sdmUoe1xuXHRcdFx0XHRcdFx0XHRcdFx0c3VjY2VzczogZmFsc2UsXG5cdFx0XHRcdFx0XHRcdFx0XHRkYXRhOiAwXG5cdFx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHR9KTtcblx0XHRcdH0pO1xuXHRcdH0sXG5cblx0XHQvKipcblx0XHQgKiBAc3VtbWFyeSBWYWxpZGF0ZSBlbWFpbCBhZGRyZXNzLlxuXHRcdCAqXG5cdFx0ICogQGRlc2NyaXB0aW9uIFZhbGlkYXRlIGVtYWlsIGFkZHJlc3MgdXNpbmcgcmVnZXguXG5cdFx0ICpcblx0XHQgKiBAcGFyYW0ge3N0cmluZ30gZW1haWxcblx0XHQgKlxuXHRcdCAqIEByZXR1cm5zIHtib29sZWFufSBJcyB2YWxpZCBlbWFpbCBzdHJpbmdcblx0XHQgKi9cblx0XHR2YWxpZGF0ZUVtYWlsOiBmdW5jdGlvbihlbWFpbCkge1xuXHRcdFx0dmFyIGVtYWlsUmVnID0gL14oKFtePD4oKVtcXF1cXFxcLiw7Olxcc0BcXFwiXSsoXFwuW148PigpW1xcXVxcXFwuLDs6XFxzQFxcXCJdKykqKXwoXFxcIi4rXFxcIikpQCgoXFxbWzAtOV17MSwzfVxcLlswLTldezEsM31cXC5bMC05XXsxLDN9XFwuWzAtOV17MSwzfVxcXSl8KChbYS16QS1aXFwtMC05XStcXC4pK1thLXpBLVpdezIsfSkpJC87XG5cblx0XHRcdHJldHVybiBlbWFpbFJlZy50ZXN0KGVtYWlsKTtcblx0XHR9LFxuXG5cdFx0LyoqXG5cdFx0ICogQHN1bW1hcnkgSGFuZGxlcyBzaG93aW5nIGVycm9yIG1lc3NhZ2VzLlxuXHRcdCAqXG5cdFx0ICogQGRlc2NyaXB0aW9uIEluamVjdCBmb3JtIGVycm9ycyBpbnRvIGVycm9yIGNvbnRhaW5lciBhbmQgZGlzcGxheSB0aGUgY29udGFpbmVyLlxuXHRcdCAqIElmIGEgY2xpY2tlZCBlbGVtZW50IHNob3VsZCByZXZlcnQgdG8gYSBwcmV2aW91cyBzdGF0ZSwgdXBkYXRlIHRoZSBlbGVtZW50IHRleHQuXG5cdFx0ICpcblx0XHQgKiBAcGFyYW0ge3N0cmluZ30gZXJyb3JNZXNzYWdlIC0gSFRNTCBzdHJpbmcgb2YgZXJyb3IgbWVzc2FnZSB0byBzaG93LlxuXHRcdCAqIEBwYXJhbSB7RWxlbWVudH0gZXJyb3JNZXNzYWdlQ29udGFpbmVyIC0gRE9NIGVsZW1lbnQgdG8gc2hvdyBlcnJvclxuXHRcdCAqIEBwYXJhbSB7RWxlbWVudH0gY2xpY2tlZEVsZW1lbnQgLSBET00gZWxlbWVudCB0aGF0IHRyaWdnZXJlZCB0aGUgZXZlbnQuXG5cdFx0ICpcblx0XHQgKiBAcmV0dXJucyB7dm9pZH1cblx0XHQgKi9cblx0XHRzaG93Rm9ybUVycm9yczogZnVuY3Rpb24oZXJyb3JNZXNzYWdlLCBlcnJvck1lc3NhZ2VDb250YWluZXIsIGNsaWNrZWRFbGVtZW50ID0gbnVsbCkge1xuXHRcdFx0aWYgKCFlcnJvck1lc3NhZ2VDb250YWluZXIpIHJldHVybjtcblxuXHRcdFx0Ly8gc2hvdyBlcnJvclxuXHRcdFx0ZXJyb3JNZXNzYWdlQ29udGFpbmVyLmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcblx0XHRcdGVycm9yTWVzc2FnZUNvbnRhaW5lci5jbGFzc0xpc3QuYWRkKCdzaG93LWVycm9yJyk7XG5cdFx0XHQvLyBUTy1ETyAtIHRoZSAuc2hvdy1lcnJvciBjbGFzcyBuZWVkcyB0byBiZSBhZGRlZCB0byB0aGUgTkwgSFRNTD9cblxuXHRcdFx0ZXJyb3JNZXNzYWdlQ29udGFpbmVyLnNldEF0dHJpYnV0ZSgndGFiaW5kZXgnLCAnMCcpO1xuXG5cdFx0XHQvLyB1cGRhdGUgY2xpY2tlZCBlbGVtZW50IGlmIHByZXNlbnRcblx0XHRcdGlmIChjbGlja2VkRWxlbWVudCkge1xuXHRcdFx0XHRjbGlja2VkRWxlbWVudC5jbGFzc0xpc3QucmVtb3ZlKCdidXR0b24tY2xpY2tlZCcpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyB0YWtlIHVzZXIgdG8gZXJyb3Jcblx0XHRcdHZhciByZWN0ID0gZXJyb3JNZXNzYWdlQ29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRcdFx0dmFyIHNpdGVIZWFkZXIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuc2l0ZS1oZWFkZXInKTtcblx0XHRcdHZhciBoZWFkZXJIZWlnaHQgPSBzaXRlSGVhZG
241VyID8gc2l0ZUhlYWRlci5vZmZzZXRIZWlnaHQgOiAwO1xuXG5cdFx0XHR3aW5kb3cuc2Nyb2xsVG8oe1xuXHRcdFx0XHR0b3A6IHJlY3QudG9wICsgd2luZG93LnBhZ2VZT2Zmc2V0IC0gaGVhZGVySGVpZ2h0IC0gNTAsXG5cdFx0XHRcdGxlZnQ6IDAsXG5cdFx0XHRcdGJlaGF2aW9yOiAnc21vb3RoJ1xuXHRcdFx0fSk7XG5cdFx0XHRlcnJvck1lc3NhZ2VDb250YWluZXIuZm9jdXMoKTtcblxuXHRcdFx0cmV0dXJuO1xuXHRcdH0sXG5cblx0XHQvKipcblx0XHQgKiBAc3VtbWFyeSBFcnJvciBoYW5kbGluZyBmb3IgYWNjb3VudC1yZWxhdGVkIGZvcm1zLlxuXHRcdCAqXG5cdFx0ICogQGRlc2NyaXB0aW9uIFByaW1hcmlseSB1c2VkIGZvciBuZXdzbGV0dGVyIGFjY291bnQgc2lnbnVwIGZvcm0gZXJyb3IgaGFuZGxpbmcuXG5cdFx0ICpcblx0XHQgKiBAcGFyYW0ge0VsZW1lbnR9IGZvcm0gLSBET00gZm9ybSBlbGVtZW50IHRvIHZhbGlkYXRlXG5cdFx0ICpcblx0XHQgKiBAcmV0dXJucyB7Ym9vbH1cblx0XHQgKi9cblx0XHR2YWxpZGF0ZUFjY291bnRGb3JtczogZnVuY3Rpb24oZm9ybSkge1xuXHRcdFx0Ly8gQ2xlYXIgYW55IHByZXZpb3VzIGVycm9yc1xuXHRcdFx0dmFyIGVycm9yQ29udGFpbmVyID0gZm9ybS5xdWVyeVNlbGVjdG9yKCcuZm9ybS1mZWVkYmFjaycpO1xuXHRcdFx0aWYgKGVycm9yQ29udGFpbmVyKSB7XG5cdFx0XHRcdGVycm9yQ29udGFpbmVyLnF1ZXJ5U2VsZWN0b3JBbGwoJy5lcnJvci1tZXNzYWdlJykuZm9yRWFjaChmdW5jdGlvbihlbCkgeyBlbC5yZW1vdmUoKTsgfSk7XG5cdFx0XHR9XG5cblx0XHRcdHZhciBlcnJvcnMgPSBbXTtcblxuXHRcdFx0Ly8gVE8tRE8gLSBtYWtlIHRoaXMgbW9yZSBkeW5hbWljIGZvciBmb3JtIGZpZWxkcz8gTG9vayBmb3IgYSByZXF1aXJlZCBhdHRyaWJ1dGU/XG5cdFx0XHR2YXIgZW1haWxGaWVsZCA9IGZvcm0ucXVlcnlTZWxlY3RvcignaW5wdXRbbmFtZT1cImVtYWlsXCJdJyk7XG5cdFx0XHR2YXIgcGFzc3dvcmRGaWVsZCA9IGZvcm0ucXVlcnlTZWxlY3RvcignaW5wdXRbbmFtZT1cInBhc3N3b3JkXCJdJyk7XG5cdFx0XHR2YXIgZmlyc3RuYW1lRmllbGQgPSBmb3JtLnF1ZXJ5U2VsZWN0b3IoJ2lucHV0W25hbWU9XCJmaXJzdG5hbWVcIl0nKTtcblx0XHRcdHZhciBsYXN0bmFtZUZpZWxkID0gZm9ybS5xdWVyeVNlbGVjdG9yKCdpbnB1dFtuYW1lPVwibGFzdG5hbWVcIl0nKTtcblx0XHRcdHZhciBvcHRpbkZpZWxkID0gZm9ybS5xdWVyeVNlbGVjdG9yKCdpbnB1dFtuYW1lPVwib3B0aW5cIl0nKTtcblxuXHRcdFx0Ly8gRXZlcnkgc2NyZWVuIGhhcyBhbiBlbWFpbCBmaWVsZFxuXHRcdFx0aWYgKCFlbWFpbEZpZWxkIHx8ICFGUC5VdGlscy5mb3Jtcy52YWxpZGF0ZUVtYWlsKGVtYWlsRmllbGQudmFsdWUpKSB7XG5cdFx0XHRcdGVycm9ycy5wdXNoKCdFbWFpbCBhZGRyZXNzIGlzIGludmFsaWQnKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKHBhc3N3b3JkRmllbGQpIHtcblx0XHRcdFx0aWYgKHBhc3N3b3JkRmllbGQudmFsdWUubGVuZ3RoIDwgOCkge1xuXHRcdFx0XHRcdGVycm9ycy5wdXNoKCdQYXNzd29yZCBtdXN0IGJlIGF0IGxlYXN0IDggY2hhcmFjdGVycycpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdFtmaXJzdG5hbWVGaWVsZCwgbGFzdG5hbWVGaWVsZF0uZm9yRWFjaChmdW5jdGlvbihlbCkge1xuXHRcdFx0XHRpZiAoZWwpIHtcblx0XHRcdFx0XHRpZiAoIWVsLnZhbHVlKSB7XG5cdFx0XHRcdFx0XHRlcnJvcnMucHVzaChlbC5nZXRBdHRyaWJ1dGUoJ3BsYWNlaG9sZG
241VyJykgKyAnIGlzIHJlcXVpcmVkJyk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblxuXHRcdFx0aWYgKG9wdGluRmllbGQgJiYgIW9wdGluRmllbGQuY2hlY2tlZCkge1xuXHRcdFx0XHRlcnJvcnMucHVzaCgnT3B0LWluIGlzIHJlcXVpcmVkJyk7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChlcnJvcnMubGVuZ3RoKSB7XG5cdFx0XHRcdEZQLlV0aWxzLmZvcm1zLnNob3dBY2NvdW50Rm9ybUVycm9ycyhmb3JtLCBlcnJvcnMpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gIWVycm9ycy5sZW5ndGg7XG5cdFx0fSxcblxuXHRcdC8qKlxuXHRcdCAqIEBzdW1tYXJ5IFNob3cgZXJyb3JzIG9uIGFjY291bnQtcmVsYXRlZCBmb3Jtcy5cblx0XHQgKlxuXHRcdCAqIEBkZXNjcmlwdGlvbiBQcmltYXJpbHkgdXNlZCBmb3IgbmV3c2xldHRlciBhY2NvdW50IHNpZ251cCBmb3JtIGVycm9yIGRpc3BsYXkuXG5cdFx0ICpcblx0XHQgKiBAcGFyYW0ge0VsZW1lbnR9IGZvcm0gLSBET00gZWxlbWVudCBvZiBmb3JtXG5cdFx0ICpcblx0XHQgKiBAcGFyYW0ge2FycmF5fSBlcnJvcnMgLSBBcnJheSBvZiBlcnJvcnMgdG8gc2hvd1xuXHRcdCAqXG5cdFx0ICogQHJldHVybnMge3ZvaWR9XG5cdFx0ICovXG5cdFx0c2hvd0FjY291bnRGb3JtRXJyb3JzOiBmdW5jdGlvbihmb3JtLCBlcnJvcnMpIHtcblx0XHRcdHZhciBlcnJvckNvbnRhaW5lciA9IGZvcm0ucXVlcnlTZWxlY3RvcignLmZvcm0tZmVlZGJhY2snKTtcblx0XHRcdHZhciBlcnJvcl9saXN0ID0gZXJyb3JzLmpvaW4oJzxicj4nKTtcblxuXHRcdFx0aWYgKCcnICE9PSBlcnJvcl9saXN0KSB7XG5cdFx0XHRcdEZQLlV0aWxzLmZvcm1zLnNob3dGb3JtRXJyb3JzKCc8c3BhbiBjbGFzcz1cImVycm9yLW1lc3NhZ2VcIj4nICsgZXJyb3JzLmpvaW4oJzxicj4nKSArICc8L3NwYW4+JywgZXJyb3JDb250YWluZXIsIG51bGwsIG51bGwpO1xuXHRcdFx0fVxuXHRcdH0sXG5cblx0fTtcblxufSkoKTtcblxuRlAuVXRpbHMuZm9ybXMuaW5pdCgpOyJdLCJtYXBwaW5ncyI6IkFBQUEsQ0FBQyxZQUFXO0VBRVg7RUFDQUEsRUFBRSxDQUFDQyxLQUFLLEdBQUdELEVBQUUsQ0FBQ0MsS0FBSyxJQUFJLENBQUMsQ0FBQztFQUV6QkQsRUFBRSxDQUFDQyxLQUFLLENBQUNDLEtBQUssR0FBRztJQUVoQkMsZ0JBQWdCLEVBQUUsMENBQTBDO0lBQzVEQyxzQkFBc0IsRUFBRSx3R0FBd0c7SUFFaEk7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7SUFDRUMsSUFBSSxFQUFFLFNBQU5BLElBQUlBLENBQUEsRUFBYTtNQUNoQkwsRUFBRSxDQUFDQyxLQUFLLENBQUNDLEtBQUssQ0FBQ0ksYUFBYSxDQUFDLENBQUM7TUFDOUJOLEVBQUUsQ0FBQ0MsS0FBSyxDQUFDQyxLQUFLLENBQUNLLDBCQUEwQixDQUFDLENBQUM7TUFDM0NQLEVBQUUsQ0FBQ0MsS0FBSyxDQUFDQyxLQUFLLENBQUNNLDhCQUE4QixDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVEO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0lBQ0VGLGFBQWEsRUFBRSxTQUFmQSxhQUFhQSxDQUFBLEVBQWE7TUFDekIsSUFBTUcsY0FBYyxHQUFHQyxRQUFRLENBQUNDLGdCQUFnQixDQUFDLGtCQUFrQixDQUFDO01BQ3BFLElBQUlGLGNBQWMsQ0FBQ0csTUFBTSxHQUFHLENBQUMsRUFBRTtRQUM5QkYsUUFBUSxDQUFDQyxnQkFBZ0IsQ0FBQyxtREFBbUQsQ0FBQyxDQUFDRSxPQUFPLENBQUMsVUFBQ0Msa0JBQWtCLEVBQUs7VUFDOUdBLGtCQUFrQixDQUFDQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsVUFBQ0MsRUFBRSxFQUFLO1lBQ3BELElBQU1DLFdBQVcsR0FBR1AsUUFBUSxDQUF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\n//# sourceURL=webpack-internal:///../assets/src/scripts/utils/forms.js\n\n}")}};let __webpack_exports__={};__webpack_modules__["../assets/src/scripts/utils/forms.js"]()})();; 242//~ Hack for links the proxy does not adjust 243!function($){ 244 $(document).on('pianoAccessCheckComplete', function () { 245 tp = window.tp || []; 246 //~ Data is not ready 247 if(typeof FP.Singletons.UserAltAccess === 'undefined') { 248 return 249 } 250 //~ Does not apply to normal proxy access 251 if (!FP.Singletons.UserAltAccess.isIPAccess || 'proxy_hosts' !== FP.Singletons.UserAltAccess.ipAccessData.access_type) { 252 return; 253 } 254 $(document).on('click', 'a', function(e){ 255 var refLink = null; 256 if (/^trc\.taboola\.com/) { 257 var search = this.search.split('&'); 258 for (var i = 0, len = search.length; i < len; i++) { 259 var query = search[i]; 260 if ('url=' === query.substr(0, 4)) { 261 refLink = decodeURIComponent(query.substr(4)); 262 break; 263 } 264 } 265 } 266 var a; 267 if (null === refLink) { 268 a = this; 269 } else { 270 a = document.createElement('a'); 271 a.href = refLink; 272 } 273 //~ If it's not an internal link, not our problem 274 if (!/^(www\.)?foreignpolicy.com$/.test(a.hostname)) { 275 return; 276 } 277 //~ Stop the internal link 278 e.preventDefault(); 279 document.location = ( 280 document.location.protocol + '//' + 281 document.location.host + 282 a.pathname + 283 a.search + 284 a.hash 285 ); 286 }); 287 }); 288}(jQuery); 289; 290/*! 291 * jQuery Cookie Plugin v1.3.1 292 * https://github.com/carhartl/jquery-cookie 293 * 294 * Copyright 2013 Klaus Hartl 295 * Released under the MIT license 296 */ 297(function (factory) { 298 if (typeof define === 'function' && define.amd) { 299 // AMD. Register as anonymous module. 300 define(['jquery'], factory); 301 } else { 302 // Browser globals. 303 factory(jQuery); 304 } 305}(function ($) { 306 307 var pluses = /\+/g; 308 309 function decode(s) { 310 if (config.raw) { 311 return s; 312 } 313 try { 314 // If we can't decode the cookie, ignore it, it's unusable. 315 return decodeURIComponent(s.replace(pluses, ' ')); 316 } catch(e) {} 317 } 318 319 function decodeAndParse(s) { 320 if (s.indexOf('"') === 0) { 321 // This is a quoted cookie as according to RFC2068, unescape... 322 s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 323 } 324 325 s = decode(s); 326 327 try { 328 // If we can't parse the cookie, ignore it, it's unusable. 329 return config.json ? JSON.parse(s) : s; 330 } catch(e) {} 331 } 332 333 var config = $.cookie = function (key, value, options) { 334 335 // Write 336 if (value !== undefined) { 337 options = $.extend({}, config.defaults, options); 338 339 if (typeof options.expires === 'number') { 340 var days = options.expires, t = options.expires = new Date(); 341 t.setDate(t.getDate() + days); 342 } 343 344 value = config.json ? JSON.stringify(value) : String(value); 345 346 return (document.cookie = [ 347 config.raw ? key : encodeURIComponent(key), 348 '=', 349 config.raw ? value : encodeURIComponent(value), 350 options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 351 options.path ? '; path=' + options.path : '', 352 options.domain ? '; domain=' + options.domain : '', 353 options.secure ? '; secure' : '' 354 ].join('')); 355 } 356 357 // Read 358 359 var result = key ? undefined : {}; 360 361 // To prevent the for loop in the first place assign an empty array 362 // in case there are no cookies at all. Also prevents odd result when 363 // calling $.cookie(). 364 var cookies = document.cookie ? document.cookie.split('; ') : []; 365 366 for (var i = 0, l = cookies.length; i < l; i++) { 367 var parts = cookies[i].split('='); 368 var name = decode(parts.shift()); 369 var cookie = parts.join('='); 370 371 if (key && key === name) { 372 result = decodeAndParse(cookie); 373 break; 374 } 375 376 // Prevent storing a cookie that we couldn't decode. 377 if (!key && (cookie = decodeAndParse(cookie)) !== undefined) { 378 result[name] = cookie; 379 } 380 } 381 382 return result; 383 }; 384 385 config.defaults = {}; 386 387 $.removeCookie = function (key, options) { 388 if ($.cookie(key) !== undefined) {
389 // Must not alter options, thus extending a fresh object... 390 $.cookie(key, '', $.extend({}, options, { expires: -1 })); 391 return true; 392 } 393 return false; 394 }; 395 396})); 397; 398!function ($) { 399 tp = window.tp || []; 400 401 FP.Utils = FP.Utils || {}; 402 403 FP.Utils.Piano = { 404 405 /** 406 * ------------------------------------------------------------------------ 407 * Initialize utility helper 408 * called in /assets/src/scripts/users/user-piano.js 409 * ------------------------------------------------------------------------ 410 */ 411 init: function() { 412 // Piano custom field form handling 413 if ( $('.piano-custom-fields-form').length > 0 ) FP.Utils.Piano.updatePianoUserCustomFieldsFormHandling(); 414 415 // Piano custom button/clickable element custom field handling 416 if ( $('.piano-custom-fields-element').length > 0 ) FP.Utils.Piano.updatePianoUserCustomFieldsElementClickHandling(); 417 418 // Initialize click listeners 419 FP.Utils.Piano.initClickListeners(); 420 421 // Ensure full article content displays in the in-app browser for non-Insider content 422 if( FP.Utils.Piano.isUserFromApp() && !FP.Utils.Piano.isInsiderContent() ) { 423 $( '.content-ungated' ).hide(); 424 $( '.content-gated' ).show(); 425 } 426 427 $(document).on('pianoAccessCheckComplete', function () { 428 if (window.location.pathname === '/' && !FP.Singletons.User.isIPAccess) { 429 const cRegEx = /^(?:.*;)?\s*__utp\s*=\s*([^;]+)(?:.*)?$/ 430 let existingToken = (document.cookie.match(cRegEx)||[,null])[1] 431 432 // We've got an existing cookie use that. 433 if(existingToken !== null) { 434 FP.Utils.Piano.syncUserToST(existingToken); 435 } 436 } 437 // Password reset page logic 438 if ( $('#reset-password-page').length > 0 ) FP.Utils.Piano.initPasswordReset(); 439 440 // Remove Piano auth cookies generated for IP access clients 441 // accessing the PressReader print archive 442 var pressreader_auth = $.cookie( '__utp_ipaccess' ); 443 if ( pressreader_auth && FP.Singletons.User.isIPAccess && '[email protected]' === FP.Singletons.User.userData.email ) { 444 // get root domain (necessary for IP access clients with proxy URLs) 445 var rootDomain = FP.Utils.url.getRootDomain(window.location.hostname); 446 447 // remove cookies by setting expiration date in the past 448 document.cookie = '__utp=0; expires=Thu, 01 Jan 1970 00:00:01 GMT;' + 449 ' path=/; domain=.' + rootDomain + ';'; 450 document.cookie = '__utp_ipaccess=false; expires=Thu, 01 Jan 1970 00:00:01 GMT;' + 451 ' path=/; domain=.' + rootDomain + ';'; 452 453 if( window.location.search !== '?ipaccess_reload=1' ) { 454 // reload to register cookie removal 455 // add URL parameter to avoid an infinite redirect loop 456 window.location.href = window.location.href + '?ipaccess_reload=1'; 457 } 458 } 459 }); 460 }, 461 462 performLogout(event) { 463 // Remove cookies and local storage 464 if(window?.rudderTools?.lib?.reset) { 465 window.rudderTools.lib.reset(); 466 } 467 // Comments 468 $.removeCookie('fp-coral-token', { path: '/' }); 469 470 // VIP cache group 471 $.removeCookie('vip-go-seg', { path: '/' }); 472 473 // Piano user data 474 $.removeCookie('fp-user-data', { path: '/' }); 475 476 // Piano metering 477 $.removeCookie('__utp_mec', { path: '/' }); 478 479 // ST HID 480 $.removeCookie('sailthru_hid', { path: '/' }); 481 482 // Local ST 483 $.removeCookie('__utp_fp_st', { path: '/' }); 484 485 // FP Live 486 window.localStorage.removeItem('fp-live-email-address'); 487 window.localStorage.removeItem('fp-live-registered'); 488 window.localStorage.removeItem('fp-live-attended'); 489 window.localStorage.removeItem('fp-live-ondemand'); 490 window.localStorage.removeItem('fp-live-optout'); 491 window.localStorage.removeItem('fp-live-list-subs'); 492 493 // Logout and refresh the page 494 tp.pianoId.logout(); 495 }, 496 497 498 /** 499 * ------------------------------------------------------------------------ 500 * Initialize click listeners 501 * ------------------------------------------------------------------------ 502 */ 503 initClickListeners: function() { 504 // Trigger Piano login 505 $(document).on('click', 'a.navlink.FP-paywall--login, .FP-paywall--login.FP-paywall--login--login, .FP-paywall--login--ip-access', function (event) { 506 event.preventDefault(); 507 // show login 508 tp.pianoId.show({ 509 displayMode: 'modal', 510 screen: 'login', 511 loggedIn: function(data) { 512 FP.Utils.Piano.toggleHeaderContent(); 513 }, 514 loggedOut: function() { 515 FP.Utils.Piano.toggleHeaderContent(); 516 }, 517 loginDisplayed: function() { 518 $('.tp-modal').attr('role','modal'); 519 $('.tp-modal').attr('title','Sign In to your account'); 520 $('.tp-modal').attr('tabindex','0'); 521 $('.tp-modal').focus(); 522 $('.tp-modal iframe').attr('title','Sign In form'); 523 $('.tp-modal iframe').attr('tabindex','0'); 524 FP.Utils.trapFocus.init(document.querySelectorAll('.tp-modal')); 525 FP.Utils.trapFocus.toggleInertAttribute(true); 526 }, 527 registerDisplayed: function() { 528 $('.tp-modal').attr('role','modal'); 529 $('.tp-modal').attr('title','Sign up for an account'); 530 $('.tp-modal').attr('tabindex','0'); 531 $('.tp-modal').focus(); 532 $('.tp-modal iframe').attr('title','Sign up form'); 533 $('.tp-modal iframe').attr('tabindex','0'); 534 FP.Utils.trapFocus.init(document.querySelectorAll('.tp-modal')); 535 FP.Utils.trapFocus.toggleInertAttribute(true); 536 }, 537 }); 538 }); 539 540 // Trigger Piano signup 541 $(document).on('click', 'a.FP-paywall--login--signup', function (event) { 542 event.preventDefault(); 543 // show signup 544 tp.pianoId.show({ 545 displayMode: 'modal', 546 screen: 'register', 547 loggedIn: function(data) { 548 FP.Utils.Piano.toggleHeaderContent(); 549 }, 550 loggedOut: function() { 551 FP.Utils.Piano.toggleHeaderContent(); 552 }, 553 loginDisplayed: function() { 554 $('.tp-modal iframe').attr('title','Login to your account'); 555 FP.Utils.trapFocus.init(document.querySelectorAll('.tp-modal')); 556 FP.Utils.trapFocus.toggleInertAttribute(true); 557 }, 558 registerDisplayed: function() { 559 $('.tp-modal iframe').attr('title','Sign up for an account'); 560 FP.Utils.trapFocus.init(document.querySelectorAll('.tp-modal')); 561 FP.Utils.trapFocus.toggleInertAttribute(true); 562 }, 563 }); 564 }); 565 566 // Trigger Piano logout 567 $(document).on('click', 'a.FP-paywall--logout', FP.Utils.Piano.performLogout); 568 569 // HTMX Logout 570 document.body.addEventListener('pianoLogout', FP.Utils.Piano.performLogout); 571 572 // Trigger Piano login/sign up modal close 573 $(document).on('click', '.tp-close', function () { 574 FP.Utils.trapFocus.toggleInertAttribute(false); 575 }); 576 577 // Trigger offers on 2022 subscribe page sticky top nav 578 $('.subscribe-link.subscribe-list__item').on('click', function(e) { 579 e.preventDefault(); 580 var termId = ''; 581 if( $('.dropdown__list-item[data-selected="1"]').length > 0 ) { 582 if( typeof $('.dropdown__list-item[data-selected="1"]').attr('data-term-id') !== 'undefined' ) { 583 termId = $('.dropdown__list-item[data-selected="1"]').attr('data-term-id'); 584 } 585 } 586 if( termId !== '' ) { 587 tp.offer.show({ 588 offerId: 'OFC557HUHRK2', 589 templateId: 'OTSW23E1OBRE', 590 termId: termId, 591 }); 592 } 593 }); 594 595 // Trigger offers on Group Subscriptions page 596 const groupSubsButton = document.getElementById('group-subs-subscribe-button'); 597 if (groupSubsButton) { 598 groupSubsButton.addEventListener('click', function(e) { 599 e.preventDefault(); 600 const termId = this.dataset.selectedTermId; 601 if( termId !== '' ) { 602 tp.offer.show({ 603 formNameByTermId: '{"'+termId+'":"group_subs"}',
604 offerId: 'OFTA11MJ1YP0', 605 termId: termId, 606 displayMode: 'modal', 607 }); 608 } 609 }); 610 } 611 }, 612 613 614 /** 615 * ------------------------------------------------------------------------ 616 * Password reset page 617 * ------------------------------------------------------------------------ 618 */ 619 initPasswordReset: function() { 620 if ( tp.user.isUserValid() ) { 621 // Password cannot be reset if user is logged in 622 $('#reset-password-page').css('display','none'); 623 $('#reset-password-page-logged-in-user').css('display','block'); 624 } else { 625 // Password can only be reset if user is anonymous 626 $('#reset-password-page').css('display','block'); 627 $('#reset-password-page-logged-in-user').css('display','none'); 628 // If URL has reset_token parameter 629 var tokenMatch = location.search.match(/reset_token=([A-Za-z0-9]+)/); 630 if (tokenMatch) { 631 // Get value of the token 632 var token = tokenMatch[1]; 633 // Present password reset form with the found token 634 tp.pianoId.show({ 635 'resetPasswordToken': token, 636 displayMode: 'inline', 637 containerSelector: '#reset-password-page', 638 loggedIn: function () { 639 // Once user logs in - refresh the page 640 location.reload(); 641 } 642 }); 643 } 644 } 645 }, 646 647 /** 648 * @summary. Synchronizes user on login with ST 649 * 650 * @description. Validates the user token through our endpoint and 651 * synchronizes the user in ST. We then take the returned cookie from ST and 652 * apply it to a ssailthru_hid cookie. 653 * 654 * @param {string} token - The Piano token 655 * 656 * @return {void} 657 */ 658 syncUserToST: function(token) { 659 const endpoint = '/wp-json/fp/sailthru-hid/'; 660 661 fetch(endpoint, { 662 method: 'GET', 663 headers: { 664 'Authorization': `Bearer ${token}`, 665 'Content-Type' : 'application/json', 666 } 667 }) 668 .then(response => { 669 if (!response.ok) { 670 throw new Error('Network response was not ok ' + response.statusText); 671 } 672 return response.json(); 673 }) 674 .then(data => { 675 if (data.keys && typeof data.keys.cookie === 'string') { 676 const cookieValue = data.keys.cookie; 677 const expires = new Date( 678 Date.now() + 30 * 24 * 60 * 60 * 1000 679 ).toUTCString(); 680 document.cookie = `sailthru_hid=${cookieValue}; ` 681 + `expires=${expires}; ` 682 + `domain=${window.location.hostname}; ` 683 + `path=/;`; 684 } 685 }) 686 .catch(error => { 687 console.error('Could not synchronize ST user', error); 688 }); 689 }, 690 691 /** 692 * ------------------------------------------------------------------------ 693 * Toggle body class based on whether user is logged in/subscribed 694 * ------------------------------------------------------------------------ 695 */ 696 toggleBodyClass: function() { 697 // Check if user is logged in 698 if( FP.Singletons.User.hasAccount || FP.Utils.Piano.isUserFromApp() ) { 699 700 // Check if user is subscribed 701 if( FP.Singletons.User.isSub ) { 702 $( 'body' ).addClass( 'sub_user' ); 703 } else { 704 $( 'body' ).addClass( 'reg_user' ); 705 } 706 707 // Check if user is an insider 708 if ( FP.Singletons.User.isInsider ) { 709 $( 'body' ).addClass( 'insider_user' ); 710 } 711 712 // Check if user is IP access 713 } else if( FP.Singletons.User.isIPAccess ) { 714 $( 'body' ).addClass( 'ip_access_user' ); 715 716 } else { 717 $( 'body' ).addClass( 'anon_user' ); 718 } 719 }, 720 721 722 /** 723 * ------------------------------------------------------------------------ 724 * Toggle header content based on whether user is logged in 725 * ------------------------------------------------------------------------ 726 */ 727 toggleHeaderContent: function() { 728 // If user is logged in 729 if ( 730 // If user is IP access and they are registered 731 // Non-authenticated IP access users are pushed down to the 732 // "If user is IP access client" condition below 733 ( FP.Singletons.User.isIPAccess && FP.Singletons.User.hasAccount ) 734 || 735 // If user is not IP access, but is a sub or registered 736 ( !FP.Singletons.User.isIPAccess && ( FP.Singletons.User.isSub || FP.Singletons.User.hasAccount ) ) 737 ) { 738 // Update header content to match logged in state 739 $('.site-nav-user-button').show(); 740 741 $('.header-nav-wrapper .login-ip-access, .nav-full-menu__header__tools .login-ip-access').hide(); 742 $('.header-nav-wrapper .login-user, .nav-full-menu__header__tools .login-user').hide(); 743 744 if ( FP.Singletons.User.isInsider ) { 745 $('.header-nav-wrapper .subscribe-prompt, .nav-full-menu__header__tools .subscribe-prompt').hide(); 746 $('.header-nav-wrapper .subscribe-link, .nav-full-menu__header__tools .subscribe-link').hide(); 747 $('.header-nav-wrapper .gift-link, .nav-full-menu__header__tools .gift-link').show(); 748 $('.header-nav-wrapper .upgrade-to-insider-prompt, .nav-full-menu__header__tools .upgrade-to-insider-prompt').hide(); 749 } else if( FP.Singletons.User.isSub || FP.Singletons.User.isPrem ) { 750 $('.header-nav-wrapper .subscribe-prompt, .nav-full-menu__header__tools .subscribe-prompt').hide(); 751 $('.header-nav-wrapper .subscribe-link, .nav-full-menu__header__tools .subscribe-link').hide(); 752 $('.header-nav-wrapper .gift-link, .nav-full-menu__header__tools .gift-link').hide(); 753 $('.nav-menu__item.subscribe-link').css('display', 'block'); 754 $('.header-nav-wrapper .upgrade-to-insider-prompt, .nav-full-menu__header__tools .upgrade-to-insider-prompt').show(); 755 } else if( FP.Singletons.User.hasAccount && FP.Singletons.User.isIPAccess ) { 756 $('.header-nav-wrapper .subscribe-prompt, .nav-full-menu__header__tools .subscribe-prompt').hide(); 757 $('.header-nav-wrapper .gift-link, .nav-full-menu__header__tools .gift-link').hide(); 758 $('.header-nav-wrapper .upgrade-to-insider-prompt, .nav-full-menu__header__tools .upgrade-to-insider-prompt').hide(); 759 } else if( FP.Singletons.User.hasAccount ) { 760 $('.nav-menu__item.subscribe-link').css('display', 'block'); 761 $('.header-nav-wrapper .subscribe-prompt, .nav-full-menu__header__tools .subscribe-prompt').show(); 762 $('.header-nav-wrapper .gift-link, .nav-full-menu__header__tools .gift-link').hide(); 763 $('.header-nav-wrapper .upgrade-to-insider-prompt, .nav-full-menu__header__tools .upgrade-to-insider-prompt').hide(); 764 } 765 766 // If user is IP access client 767 } else if( FP.Singletons.UserAltAccess && FP.Singletons.UserAltAccess.isIPAccess ) { 768 // Update header content to match logged in state 769 $('.site-nav-user-button').hide(); 770 771 $('.login-ip-access--welcome > span') 772 .text( FP.Singletons.UserAltAccess.ipAccessData.message ) 773 .attr('href','#') 774 .removeClass('FP-paywall--login'); 775 776 $('.header-nav-wrapper .subscribe-link, .nav-full-menu__header__tools .subscribe-link').hide(); 777 $('.header-nav-wrapper .gift-link, .nav-full-menu__header__tools .gift-link').hide(); 778 $('.header-nav-wrapper .upgrade-to-insider-prompt, .nav-full-menu__header__tools .upgrade-to-insider-prompt').hide(); 779 780 // Prompt IP access users to login 781 $('.header-nav-wrapper .login-user, .nav-full-menu__header__tools .login-user').hide(); 782 $('.header-nav-wrapper .login-ip-access, .nav-full-menu__header__tools .login-ip-access').show(); 783 784 // If user is link access client 785 } else if( FP.Singletons.UserAltAccess && FP.Singletons.UserAltAccess.isLinkAccess ) { 786 // Update header content to match logged in state 787 $('.site-nav-user-button').hide(); 788 789 $('.header-nav-wrapper .login-user.FP-paywall--login') 790 .text( FP.Singletons.UserAltAccess.linkAccessData.message ) 791 .attr('href','#') 792 .removeClass('FP-paywall--login'); 793 794 $('.header-nav-wrapper .login-user').hide(); 795 $('.header-nav-wrapper .subscribe-link').hide(); 796 797 } else { 798 // Update header content to match logged out state 799 $('.site-nav-user-button').hide(); 800 801 $('.nav-menu__item.subscribe-link').css('display', 'block'); 802 $('.header-nav-wrapper .subscribe-prompt, .nav-full-menu__header__tools .subscribe-prompt').show(); 803 $('.header-nav-wrapper .gift-link, .nav-full-menu__header__tools .gift-link').hide(); 804 $('.header-nav-wrapper .upgrade-to-insider-prompt, .nav-full-menu__header__tools .upgrade-to-insider-prompt').hide(); 805 806 $('.header-nav-wrapper .login-user, .nav-full-menu__header__tools .gift-link .login-user').show(); 807 $('.header-nav-wrapper .login-ip-access, .nav-full-menu__header__tools .login-ip-access').hide(); 808 } 809 810 // Hide header for users viewing article in our app 811 if( FP.Utils.Piano.isUserFromApp() ) { 812 $('.site-header, .in-article-dynamic-ad, .ad-container, .ad-container--parent, .sidebar-big-box-ad, .home-ad-region-1, .home-ad-region-2, .channel-sidebar-big-box-ad, #mobile-adhesion-ad').hide(); 813 $('body').css('padding-top','0').addClass('in-app'); 814 } 815 816 // Hide header for users viewing article from Facebook Instant Articles 817 if( FP.Utils.Piano.isUserFromFBIA() ) { 818 $('.header-nav-wrapper').hide(); 819 $('.site-header .logo').removeAttr('href'); 820 $('body').css('padding-top','0'); 821 $('body').addClass('no-piano-modal-margin'); 822 } 823 }, 824 825 826 /** 827 * ------------------------------------------------------------------------ 828 * Add titles to injected Piano iframes for accessibility 829 * ------------------------------------------------------------------------ 830 */ 831 addTitlestoPianoIframes: function() { 832 // FP containers that contain injected Piano content 833 var targetNodes = document.querySelectorAll('.tp-container-inner'); 834 835 for( let targetNode of targetNodes ) { 836 // Add title attributes to iframes 837 let pianoIframe = targetNode.querySelector('iframe');
838 if( pianoIframe ) pianoIframe.setAttribute('title', 'Subscription offer'); 839 } 840 }, 841 842 843 /** 844 * ------------------------------------------------------------------------ 845 * Add the user's Piano id to the gifting link params if user is a sub 846 * ------------------------------------------------------------------------ 847 */ 848 updateGiftingLink: function() { 849 if( !FP.Singletons.User.isSub ) return; 850 var pianoUid = FP.Singletons.User.userData.uid ?? ''; 851 852 if( '' !== pianoUid && $('.gift-article__wrapper').length > 0 ) { 853 $('.gift-article__wrapper .share-dropdown__option[data-url]').each(function() { 854 $(this).attr('data-url', $(this).attr('data-url') + '&pid=' + pianoUid ); 855 }); 856 $('.gift-article__wrapper .share-dropdown__option[href]').each(function() { 857 $(this).attr('href', $(this).attr('href') + '%26pid%3D' + pianoUid ); 858 }); 859 } 860 }, 861 862 863 /** 864 * ------------------------------------------------------------------------ 865 * Determine whether user is coming to the page from our app by 866 * looking for ?app=true in the URL 867 * ------------------------------------------------------------------------ 868 */ 869 isUserFromApp: function() { 870 var isFromApp = ( 871 'true' === FP.Utils.url.getUrlParameter('app') 872 ); 873 return isFromApp; 874 }, 875 876 877 /** 878 * ------------------------------------------------------------------------ 879 * Determine whether user is coming to the page from Facebook 880 * Instant Articles by looking for surface=meter_limit_reached in the URL 881 * ------------------------------------------------------------------------ 882 */ 883 isUserFromFBIA: function() { 884 var isFromFBIA = ( 885 'not found' !== FP.Utils.url.getUrlParameter('account_linking_token') 886 ); 887 888 return isFromFBIA; 889 }, 890 891 892 /** 893 * ------------------------------------------------------------------------ 894 * Track events in Facebook 895 * ------------------------------------------------------------------------ 896 */ 897 sendSignedFbPixel: function( event_name, params ) { 898 jQuery.ajax( { 899 url: '/wp-json/fp/fb-pixel', 900 data: { 901 event_name: event_name, 902 params: params 903 }, 904 type: 'GET', 905 async: false, 906 success: function ( response ) { 907 var image = jQuery( '<img style="display: none;" />' ); 908 image.attr( 'src', response.pixel_url ); 909 jQuery( 'body' ).append( image ); 910 }, 911 error: function( request, error ) { 912 console.error( error ); 913 } 914 } ); 915 }, 916 917 918 /** 919 * ------------------------------------------------------------------------ 920 * Update custom fields in Piano 921 * ------------------------------------------------------------------------ 922 */ 923 updatePianoUserCustomFields: function( piano_form_id, custom_fields, email = '', uid = '' ) { 924 var user_email = ( email ) ? email : FP.Singletons.User.userData.email; 925 var user_uid = ( uid ) ? uid : FP.Singletons.User.userData.uid; 926 927 return $.ajax({ 928 url: '/piano-user-update/results/', 929 data: { 930 '__fp_endpoint_piano_ajax_update_user' : 1, 931 '__fp_endpoint_piano_action_update_user': 'update_user_custom_fields', 932 '__fp_endpoint_piano_user_email' : user_email, 933 '__fp_endpoint_piano_user_uid' : user_uid, 934 '__fp_endpoint_piano_user_form_id' : piano_form_id, 935 '__fp_endpoint_piano_user_custom_fields': custom_fields, 936 '__fp_endpoint_piano_user_nonce' : window.pianoData.cache_group_nonce || '', 937 }, 938 cache: true 939 }); 940 }, 941 942 943 /** 944 * ------------------------------------------------------------------------ 945 * Piano custom field form handling 946 * ------------------------------------------------------------------------ 947 */ 948 updatePianoUserCustomFieldsFormHandling: function() { 949 $('.piano-custom-fields-form').on('submit', function(e) { 950 e.preventDefault(); 951 // Get Piano form id 952 var piano_form_id = $(this).attr('data-piano-form-id') || ''; 953 // Build array of custom fields 954 var custom_fields = {}; 955 $(this).find( '.custom_field' ).each(function() { 956 if( 'checkbox' === $(this).attr('type') ) { 957 if( $(this).is(':checked') ) { 958 custom_fields[$(this).attr('name')] = $(this).val(); 959 } 960 } else { 961 custom_fields[$(this).attr('name')] = $(this).val(); 962 } 963 }); 964 custom_fields = Object.keys(custom_fields).map(function(k){return k+'=='+custom_fields[k];}).join('||'); 965 // Send data to Piano 966 return FP.Utils.Piano.updatePianoUserCustomFields( piano_form_id, custom_fields ); 967 }); 968 }, 969 970 971 /** 972 * ------------------------------------------------------------------------ 973 * Piano custom button/clickable element custom field handling 974 * ------------------------------------------------------------------------ 975 */ 976 updatePianoUserCustomFieldsElementClickHandling: function() { 977 // Remove any existing click events on elements 978 // to avoid running click events twice 979 $('.piano-custom-fields-element').off('click'); 980 981 // Add click events on elements 982 $('.piano-custom-fields-element').on('click', function(e) { 983 // Get Piano form id 984 var piano_form_id = $(this).attr('data-piano-form-id') || ''; 985 // Build array of custom fields 986 var custom_fields = {}; 987 custom_fields[$(this).attr('data-name')] = $(this).attr('data-value'); 988 custom_fields = Object.keys(custom_fields).map(function(k){return k+'=='+custom_fields[k];}).join('||'); 989 // Send data to Piano 990 return FP.Utils.Piano.updatePianoUserCustomFields( piano_form_id, custom_fields ); 991 }); 992 }, 993 994 995 /** 996 * ------------------------------------------------------------------------ 997 * User onboarding trigger 998 * ------------------------------------------------------------------------ 999 */ 1000 triggerUserOnboarding: function( conversionObject ) { 1001 // set custom field values to trigger onboarding flow display 1002 var custom_fields = {}; 1003 // toggle between 'onboarding_shown_regis' and 'onboarding_shown' 1004 // depending on Piano resource id (rid) 1005 if( conversionObject.rid && 'REGISTRATION' === conversionObject.rid ) { 1006 custom_fields['onboarding_shown_regis'] = '1'; 1007 } else { 1008 custom_fields['onboarding_shown'] = '1'; 1009 } 1010 custom_fields = Object.keys(custom_fields).map(function(k){return k+'=='+custom_fields[k];}).join('||'); 1011 // send data to Piano to trigger the display of the onboarding flow for the user 1012 FP.Utils.Piano.updatePianoUserCustomFields( '', custom_fields, conversionObject.email, conversionObject.uid ); 1013 }, 1014 1015 1016 /** 1017 * ------------------------------------------------------------------------ 1018 * Update "Last Purchase Source" custom field 1019 * ------------------------------------------------------------------------ 1020 */ 1021 updateLastPurchaseSource: function( userData ) { 1022 // set custom field value 1023 var custom_fields = {}; 1024 custom_fields['last_purchase_source'] = 'web'; 1025 custom_fields = Object.keys(custom_fields).map(function(k){return k+'=='+custom_fields[k];}).join('||'); 1026 // send data to Piano to update custom field 1027 FP.Utils.Piano.updatePianoUserCustomFields( '', custom_fields, userData.email, userData.uid ); 1028 }, 1029 1030 1031 /** 1032 * ------------------------------------------------------------------------ 1033 * Triggered by custom events from Piano experiences 1034 * ------------------------------------------------------------------------ 1035 */ 1036 onCustomEvent: function(event) { 1037 if (event && event.eventName === 'shared-subscription-redemption') { 1038 parent.location.reload(); 1039 } 1040 }, 1041 1042 1043 /** 1044 * ------------------------------------------------------------------------ 1045 * Triggered by upgrade purchase events from Piano 1046 * ------------------------------------------------------------------------ 1047 */ 1048 onCompleteUpgradePurchase: function(params) { 1049 /* Reset user cache group */ 1050 if( typeof tp.pianoId.getUser().uid !== 'undefined' ) {
1051 /* Update Last Purchase Source custom field */ 1052 if( tp.user.isUserValid() ) { 1053 FP.Utils.Piano.updateLastPurchaseSource( tp.pianoId.getUser() ); 1054 } 1055 /* Ensure we have the user id from Piano before resetting cache group */ 1056 FP.Singletons.User.setUserCacheGroup( tp.pianoId.getUser().uid ); 1057 } 1058 }, 1059 1060 1061 /** 1062 * ------------------------------------------------------------------------ 1063 * Triggered by checkout complete event from Piano 1064 * ------------------------------------------------------------------------ 1065 */ 1066 onCheckoutComplete: function(data) { 1067 FP.Utils.Piano.sendSignedFbPixel( 'Subscribe', { 1068 subscription_id: data.uid, 1069 offer_code: data.rid, 1070 value: data.chargeAmount, 1071 currency: data.chargeCurrency 1072 } ); 1073 1074 /* Trigger onboarding flow */ 1075 FP.Utils.Piano.triggerUserOnboarding( data ); 1076 1077 /* Update Last Purchase Source custom field */ 1078 if( tp.user.isUserValid() ) { 1079 FP.Utils.Piano.updateLastPurchaseSource( tp.pianoId.getUser() ); 1080 } 1081 1082 /* Reset user cache group */ 1083 FP.Singletons.User.setUserCacheGroup( data.uid ); 1084 1085 /* Push zaraz events */ 1086 if(typeof zaraz !== undefined && FP.Config.is_production) { 1087 zaraz.track('checkoutComplete', data); 1088 } 1089 }, 1090 1091 1092 /** 1093 * ------------------------------------------------------------------------ 1094 * Triggered by custom checkout event from Piano 1095 * ------------------------------------------------------------------------ 1096 */ 1097 onCheckoutExternalEvent: function(event) { 1098 switch( event.eventName ) { 1099 case 'show-insider-subscription-page': 1100 FP.Utils.Piano.showInsiderSubscriptionPage(); 1101 break; 1102 case 'hide-insider-subscription-page': 1103 FP.Utils.Piano.hideInsiderSubscriptionPage(); 1104 break; 1105 case 'cta-button': 1106 FP.Utils.Piano.toggleAutoRenew( true ); 1107 break; 1108 case 'ar-offer-cancel': 1109 FP.Utils.Piano.toggleAutoRenew( false ); 1110 break; 1111 case 'expand-offer-in-header': 1112 if( $(window).width() > 599 ) return; 1113 $( 'body' ).addClass( 'tp-modal-open' ); 1114 $( '.in-article-subscribe-expandable-container .tp-container-inner' ).addClass( 'tp-container-expanded' ); 1115 setTimeout(function() { 1116 // Give the DOM a little time to update 1117 $( '.in-article-subscribe-expandable-container .tp-container-inner' ).css({ 1118 'min-height':$('.tp-container-expanded iframe').outerHeight()+200+'px' 1119 }); 1120 }, 500); 1121 break; 1122 case 'expand-benefits-offer-in-header': 1123 case 'close-benefits-offer-in-header': 1124 if( $(window).width() > 599 ) return; 1125 setTimeout(function() { 1126 // Give the DOM a little time to update 1127 $( '.in-article-subscribe-expandable-container .tp-container-inner' ).css({ 1128 'min-height':$('.tp-container-expanded iframe').outerHeight()+200+'px' 1129 }); 1130 }, 500); 1131 break; 1132 case 'close-offer-in-header': 1133 if( $(window).width() > 599 ) return; 1134 $( 'body' ).removeClass( 'tp-modal-open' ); 1135 $( '.in-article-subscribe-expandable-container .tp-container-inner' ).removeClass( 'tp-container-expanded' ); 1136 $( '.in-article-subscribe-expandable-container .tp-container-inner' ).css({ 1137 'min-height':'auto' 1138 }); 1139 break; 1140 } 1141 }, 1142 1143 1144 /** 1145 * ------------------------------------------------------------------------ 1146 * Triggered by checkout close event from Piano 1147 * ------------------------------------------------------------------------ 1148 */ 1149 onCheckoutClose: function(event) { 1150 /* Default behavior is to refresh the page on successful checkout */ 1151 if (event && event.state == 'checkoutCompleted') { 1152 1153 // Redirect user after completed checkout depending on their current page 1154 const path = window.location.pathname.replace(/\/$/, ''); 1155 const search = window.location.search; 1156 1157 switch (path) { 1158 case '/subscribe': 1159 case '/subscribe-offer': 1160 case '/subscribe-academic': 1161 case '/multi-year': 1162 case '/insider': 1163 // Reload parent if user is on embedded subscription iframe 1164 // Primarily for article pages 1165 if ( 1166 window.top !== window.self 1167 && typeof parent.location !== 'undefined' 1168 ) { 1169 parent.location.reload(); 1170 } 1171 1172 // Redirect user to homepage if on a subscription landing page 1173 // Primarily for subscription landing pages that are not an embedded iframe 1174 window.location.href = window.location.origin; 1175 break; 1176 default: 1177 switch (search) { 1178 case '?subscribe-insider': 1179 case '?subscribe': 1180 case '?subscribe&tpcc=navbar': 1181 case '?subscribe-offer&tpcc=navbar': 1182 case '?utm_term=summer_sale_2024': 1183 case '?tpcc=navbar_presidentsday24': 1184 // Reload parent if user is on embedded subscription iframe 1185 if (typeof parent.location !== 'undefined') { 1186 parent.location.reload(); 1187 } 1188 // Reload page as fallback 1189 location.reload(); 1190 break; 1191 default: 1192 // Reload page if on any other post/page 1193 location.reload(); 1194 } 1195 } 1196 } 1197 }, 1198 1199 1200 /** 1201 * ------------------------------------------------------------------------ 1202 * Triggered by checkout cancelled event from Piano 1203 * ------------------------------------------------------------------------ 1204 */ 1205 onCheckoutCancel: function() { 1206 }, 1207 1208 1209 /** 1210 * ------------------------------------------------------------------------ 1211 * Triggered by checkout error event from Piano 1212 * ------------------------------------------------------------------------ 1213 */ 1214 onCheckoutError: function() { 1215 }, 1216 1217 1218 /** 1219 * ------------------------------------------------------------------------ 1220 * Triggered by checkout payment submission event from Piano 1221 * ------------------------------------------------------------------------ 1222 */ 1223 onCheckoutSubmitPayment: function() { 1224 }, 1225 1226 1227 /** 1228 * ------------------------------------------------------------------------ 1229 * Triggered by checkout state change event from Piano 1230 * ------------------------------------------------------------------------ 1231 */ 1232 onCheckoutStateChange: function( stateView ) { 1233 let stateName = stateView.stateName; 1234 let offerId = stateView.offerId; 1235 1236 if ( 'state1' === stateName || 'state2' === stateName ) { 1237 if ( window.fbq ) { 1238 fbq( 'track', 'InitiateCheckout', { 1239 offer_code: offerId 1240 } ); 1241 } 1242 } 1243 }, 1244 1245 /** 1246 * ------------------------------------------------------------------------ 1247 * Triggered by offer displayed event from Piano 1248 * ------------------------------------------------------------------------ 1249 */ 1250 startCheckout: function( params ) { 1251 if('offerShow' === params.logType) { 1252 // Set accessibility attributes for checkout modal 1253 // that is triggered from within an experience 1254 // or from tp.offer.show() in our JS 1255 if('purchase' === params.offerType) { 1256 $('.tp-modal iframe').attr('title','Complete your purchase'); 1257 } else if( !tp.user.isUserValid() ) { 1258 $('.tp-modal iframe').attr('title','Sign up for an account or login to complete your purchase'); 1259 } else { 1260 $('.tp-modal iframe').attr('title','Subscription options'); 1261 } 1262 1263 $('.tp-modal').attr('title','Subscription offer'); 1264 $('.tp-modal').attr('role','modal'); 1265 $('.tp-modal').attr('tabindex','0'); 1266 $('.tp-modal').focus(); 1267 $('.tp-modal iframe').attr('tabindex','0'); 1268 FP.Utils.trapFocus.init(document.querySelectorAll('.tp-modal')); 1269 FP.Utils.trapFocus.toggleInertAttribute(true); 1270 } 1271 }, 1272 1273 1274 /** 1275 * ------------------------------------------------------------------------ 1276 * Meter callback - fired when the meter has expired 1277 * ------------------------------------------------------------------------ 1278 */ 1279 onMeterExpired: function( data ) { 1280 // Only run the code below for one of the following: 1281 // - the default meter used for non-subs 1282 // - the regwall meter used for non-subs 1283 // - the gifting meter used for non-subs viewing gifted articles 1284 if( 1285 (typeof data.meterName !== 'undefined') 1286 && FP.Utils.Piano.getMeterNamesToTarget().includes(data.meterName) 1287 ) { 1288 if ( window.fbq ) { 1289 fbq( 'track', 'ViewPaywall', { 1290 surface: 'mWeb', 1291 meter_count: data.maxViews 1292 } ); 1293 } 1294 // The user's meter has expired. 1295 // Hide the full version of the article and show the truncated version. 1296 $( '.content-ungated' ).show(); 1297 $( '.content-gated' ).hide(); 1298 // Hide the author, tag, and alerts content that appears below the Piano offer 1299 $( '.bio-no-photo' ).hide(); 1300 $( '.the-tags' ).hide(); 1301 $( '.js-myfp-container' ).eq(1).hide().remove(); 1302 // Reduce min-height of sidebar sticky elements 1303 $( '.sidebar .sticky-container--delay' ).removeClass( 'sticky-container--delay' ); 1304 // Restructure sidebar 1305 $( '.hide-on-gated-post' ).remove(); 1306 // Hide read more unit with Insider companion article if present 1307 $( '.related-articles--insider' ).hide(); 1308 // Hide comment related content 1309 $( '.header-social-shares' ).hide(); 1310 // hide sidebar content on mobile 1311 $( '.post-content .sidebar' ).addClass( 'hide-mobile' ); 1312 // hide mobile sticky ad and in-article ads on mobile 1313 $( 'body' ).addClass( 'hide-ads' ); 1314 // hide the fixed/expandable Piano subscribe prompt template 1315 // show the takeover Piano subscribe prompt template 1316 $( '.in-article-subscribe-expandable-container' ).hide(); 1317 $( '.in-article-subscribe-takeover-container' ).show();
1318 $( '.in-article-subscribe-takeover-other-options' ).show(); 1319 // add black background to first recirc unit 1320 $( '.post-content--after .post-content--after--recirc-units .posts-carousel' ).addClass( 'posts-carousel--black-bg' ); 1321 // move the disabled audio embed if present 1322 if ( $( '.fp-audio-embed--disabled' ).length > 0 ) { 1323 $( '.post-content-main' ).prepend( $( '.fp-audio-embed--disabled' ) ); 1324 // audio embed will appear in the same location as 1325 // the FP Live top promo, so it should be hidden 1326 $( '.fp-live-promo-top' ).hide(); 1327 // The My FP prompts should also be hidden 1328 $( '.js-myfp-container' ).hide().remove(); 1329 } 1330 // logging for troubleshooting 1331 console.log( 'PIANO LOG gating - onMeterExpired ' + data.meterName ); 1332 } 1333 }, 1334 1335 1336 /** 1337 * ------------------------------------------------------------------------ 1338 * Meter callback - fired when the meter is active (i.e. user is 1339 * not subscribed), but it has not expired yet 1340 * ------------------------------------------------------------------------ 1341 */ 1342 onMeterActive: function( data ) { 1343 // Only run the code below for one of the following: 1344 // - the default meter used for non-subs 1345 // - the regwall meter used for non-subs 1346 // - the gifting meter used for non-subs viewing gifted articles 1347 if( 1348 (typeof data.meterName !== 'undefined') 1349 && FP.Utils.Piano.getMeterNamesToTarget().includes(data.meterName) 1350 ) { 1351 // This is a free article for the non-subscribed user. 1352 // Hide the truncated version of the article and show the full version. 1353 $( '.content-ungated' ).hide(); 1354 $( '.content-gated' ).show( 1355 1, // Show immediately 1356 FP.Utils.Piano.loadIframes() // Load iframes within gated content after the content is shown 1357 ); 1358 // Add class to adjust spacing on custom feature templates 1359 $( '.piano-gating-offer-container--in-feature' ).addClass( 'piano-gating-offer-container--tighter-space' ); 1360 // Update fixed subscribe prompt on Insider content offer template container for the gifting offer 1361 if( 'true' === FP.Utils.Piano.validateGiftingURL() && $('body.is-fp-insider').length > 0 ) { 1362 $('.insider-in-article-subscribe-container').addClass('insider-in-article-subscribe-container--fixed'); 1363 } 1364 // Add class to first article to toggle content within CSS 1365 $( '.post-content--after' ).addClass( 'hide-duplicate-content-on-mobile' ); 1366 // Do not show soft gating for registrants 1367 if( FP.Singletons.User.isReg ) { 1368 const onboardingContainer = document.querySelector('#new-subs-onboarding-screens'); 1369 if( onboardingContainer ) { 1370 $( '.in-article-subscribe-expandable-container' ).hide(); 1371 $( '.in-article-subscribe-takeover-container' ).hide(); 1372 $( '.in-article-subscribe-takeover-other-options' ).hide(); 1373 return; 1374 } 1375 } 1376 // Move gating for first article to top of the screen on mobile 1377 if( FP.Utils.Piano.getMeterNamesToTargetMobilePositioning().includes(data.meterName) ) {
1378 FP.Utils.Piano.positionArticleGating(); 1379 } 1380 // Show the fixed/expandable Piano subscribe prompt template 1381 // Hide the takeover Piano subscribe prompt template 1382 $( '.in-article-subscribe-expandable-container' ).show(); 1383 $( '.in-article-subscribe-takeover-container' ).hide(); 1384 $( '.in-article-subscribe-takeover-other-options' ).hide(); 1385 1386 // Add class to body for adjusting the placement of the 1387 // JamX popup player on mobile and Piano soft-gating container 1388 $( 'body' ).addClass( 'piano-meter-active' ); 1389 1390 // Logging for troubleshooting 1391 console.log( 'PIANO LOG gating - onMeterActive ' + data.meterName ); 1392 1393 try { 1394 // Do we already have a cookie with articles. 1395 const pathname = window.location.pathname 1396 const cRegEx = /^(?:.*;)?\s*__utp_mec\s*=\s*([^;]+)(?:.*)?$/ 1397 const base64RegEx = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/ 1398 let existingCookie = (document.cookie.match(cRegEx)||[,null])[1] 1399 1400 // Try parsing this cookie. 1401 if(existingCookie !== null && base64RegEx.test(base64RegEx)) { 1402 existingCookie = JSON.parse(atob(existingCookie)); 1403 } 1404 1405 // Create the paths array and add this articles path there. 1406 data.paths = existingCookie?.paths ?? []; 1407 1408 // Push this free article to array if not there. 1409 if(!data.paths.includes(pathname)) { data.paths.push(pathname); } 1410 1411 // Update the metering cookie. 1412 let meterCookie = encodeURIComponent('__utp_mec') 1413 + '=' 1414 + btoa(JSON.stringify(data)) 1415 + '; max-age=2592000' 1416 + '; domain=' + window.location.hostname 1417 + '; path=/;' 1418 + '; secure'; 1419 1420 document.cookie = meterCookie; 1421 1422 } catch(e) { console.error(e) } 1423 } 1424 }, 1425 1426 1427 /** 1428 * ------------------------------------------------------------------------ 1429 * Define which meters to target in gating/paywall 1430 * ------------------------------------------------------------------------ 1431 */ 1432 getMeterNamesToTarget: function() { 1433 return [ 1434 'DefaultMeter', 1435 'Regwallmeter', 1436 'GiftingMeter', 1437 'RedditMeter', 1438 'WhitelistMeter', 1439 ]; 1440 }, 1441 1442 1443 /** 1444 * ------------------------------------------------------------------------ 1445 * Define which meters to target in gating/paywall mobile positioning (first article) 1446 * ------------------------------------------------------------------------ 1447 */ 1448 getMeterNamesToTargetMobilePositioning: function() { 1449 return [ 1450 'DefaultMeter', 1451 'GiftingMeter', 1452 'RedditMeter', 1453 'Regwallmeter', 1454 'WhitelistMeter', 1455 ] 1456 }, 1457 1458 1459 /** 1460 * ------------------------------------------------------------------------ 1461 * Gating logic for Insider content 1462 * ------------------------------------------------------------------------ 1463 */ 1464 gateInsiderContent: function() { 1465 // Return if insider gating container is not present 1466 // Output of the container is determined with PHP cache group check for Insider 1467 if( $( '.insider-in-article-subscribe-container' ).length < 1 ) return; 1468 // Reload the page for IP access Insiders that are being incorrectly gated 1469 // when the 'vip-go-seg' cookie is not available on page load 1470 if( 1471 'Insider' === FP?.Singletons?.UserAltAccess?.ipAccessData?.access_level 1472 && !window.location.search.includes("ipaccess_reload") 1473 ) { 1474 // Reload page, add URL parameter to avoid an infinite redirect loop 1475 window.location.href = window.location.href + '?ipaccess_reload=1'; 1476 } 1477 // Hide the full version of the article and show the truncated version. 1478 $( '.content-ungated' ).show().css( 'display', 'block' ); 1479 $( '.content-gated' ).hide(); 1480 $( '.in-article-placement' ).hide(); 1481 // Hide related content block 1482 $( '.fp-related-wrapper' ).hide().remove(); 1483 $( '.related-articles--insider' ).hide().remove(); 1484 // Hide the author, tag, and alerts content that appears below the Piano offer 1485 $( '.bio-no-photo' ).hide(); 1486 $( '.the-tags' ).hide(); 1487 $( '.js-myfp-container' ).eq(1).hide().remove(); 1488 // if an audio embed is present, hide the My FP prompt as well 1489 if ( $( '.fp-audio-embed--disabled' ).length > 0 ) { 1490 $( '.js-myfp-container' ).hide().remove(); 1491 } 1492 // Reduce min-height of sidebar sticky elements 1493 $( '.sidebar .sticky-container--delay' ).removeClass('sticky-container--delay'); 1494 // Restructure sidebar 1495 $( '.hide-on-gated-post' ).remove(); 1496 // hide sidebar content on mobile 1497 $( '.post-content .sidebar' ).addClass( 'hide-mobile' ); 1498 // hide mobile sticky ad and in-article ads on mobile 1499 $( 'body' ).addClass( 'hide-ads' ); 1500 }, 1501 1502 1503 /** 1504 * ------------------------------------------------------------------------ 1505 * Triggered by login required event from Piano 1506 * ------------------------------------------------------------------------ 1507 */ 1508 onLoginRequired: function( params ) { 1509 if('purchase' === params.offerType && 'modal' === params.displayMode) { 1510 // Set accessibility attributes for sign up/login modal 1511 // that is triggered from within an experience 1512 $('.tp-modal').attr('role','modal'); 1513 $('.tp-modal').attr('title','Sign up for an account'); 1514 $('.tp-modal').attr('tabindex','0'); 1515 $('.tp-modal').focus(); 1516 $('.tp-modal iframe').attr('title','Sign Up form'); 1517 $('.tp-modal iframe').attr('tabindex','0'); 1518 FP.Utils.trapFocus.init(document.querySelectorAll('.tp-modal')); 1519 FP.Utils.trapFocus.toggleInertAttribute(true); 1520 } 1521 1522 // this is a reference implementation only 1523 // your own custom login/registration implementation would 1524 // need to return the tinypass-compatible userRef inside the callback 1525 1526 // mysite.showLoginRegistration(function (tinypassUserRef) 1527 // tp.push(["setUserRef", tinypassUserRef]); // tp.offer.startCheckout(params); // } 1528 1529 // this will prevent the tinypass error screen from displaying 1530 return false;
1531 }, 1532 1533 1534 /** 1535 * ------------------------------------------------------------------------ 1536 * Triggered by login required event from Piano 1537 * The registrationSuccess event fires when a user completes the 1538 * registration process using Piano ID 1539 * ------------------------------------------------------------------------ 1540 */ 1541 onRegistrationSuccess: function(data) { 1542 if(typeof zaraz !== undefined && FP.Config.is_production) { 1543 zaraz.track('registrationSuccess', data); 1544 } 1545 }, 1546 1547 1548 /** 1549 * ------------------------------------------------------------------------ 1550 * Callback executed after an experience executed successfully 1551 * ------------------------------------------------------------------------ 1552 */ 1553 onExperienceExecute: function(event) { 1554 // Add titles to injected Piano iframes 1555 FP.Utils.Piano.addTitlestoPianoIframes(); 1556 1557 // Subscribe page 1558 // Hide secondary subscription content if user is viewing 1559 // the B version of the A/B test 1560 /* 2/11/21 - Remove this toggle until another A/B test is enabled 1561 if( $('.subscribe').length > 0 ) { 1562 var abTestCookie = tp.util.findCookieByName('_pc_variant'); 1563 if( 'b' === abTestCookie ) { 1564 $('.subscribe .secondary-content').hide(); 1565 } 1566 }*/ 1567 }, 1568 1569 1570 /** 1571 * ------------------------------------------------------------------------ 1572 * Callback executed after a response variable is sent from the experience 1573 * ------------------------------------------------------------------------ 1574 */ 1575 onSetResponseVariable: function(eventParams){
1576 var responseVariables = eventParams.responseVariables; 1577 1578 if( typeof responseVariables.show_inline_sub_prompt !== 'undefined' ) { 1579 1580 if( responseVariables.show_inline_sub_prompt ) { 1581 // Add in-article subscribe prompt after the truncated gated content 1582 } 1583 1584 } 1585 1586 if( typeof responseVariables.fire_ar_experience !== 'undefined' ) { 1587 1588 if( responseVariables.fire_ar_experience ) { 1589 // Move gating for first article to top of the screen on mobile 1590 FP.Utils.Piano.positionArticleGating(); 1591 // Hide "Give a Gift" button 1592 $('.gift-prompt').hide(); 1593 // Hide upgrade prompt 1594 $('.upgrade-to-insider-prompt').hide(); 1595 // Show renew button on /manage page 1596 $('.fp-manage-page .renew-button').show(); 1597 1598 $('.renew-button').on('click', function(){ 1599 $('.renew-button > span').text( 'Processing...' ); 1600 FP.Utils.Piano.toggleAutoRenew( true ); 1601 }); 1602 } 1603 } 1604 1605 if( typeof responseVariables.fire_winback_experience !== 'undefined' ) { 1606 // Move gating for first article to top of the screen on mobile
1607 FP.Utils.Piano.positionArticleGating(); 1608 // Hide "Give a Gift" button 1609 $('.gift-prompt').hide(); 1610 } 1611 1612 if( typeof responseVariables.fire_sale_ribbon !== 'undefined' ) { 1613 // Move gating for first article to top of the screen on mobile 1614 FP.Utils.Piano.positionArticleGating(); 1615 } 1616 1617 if( typeof responseVariables.fire_top_ribbon !== 'undefined' ) { 1618 // Move gating for first article to top of the screen on mobile 1619 FP.Utils.Piano.positionArticleGating(); 1620 } 1621 1622 if( 1623 typeof responseVariables.fire_giftpromo_experience !== 'undefined' 1624 || typeof responseVariables.fire_winback_experience !== 'undefined' 1625 || typeof responseVariables.fire_ribbon_experience !== 'undefined' 1626 ) { 1627 // Add new class to body to alter the header button styles? 1628 $('body').addClass('piano_ribbon_shown'); 1629 } 1630 1631 if ( typeof responseVariables.fire_ribbon_experience !== 'undefined' ) { 1632 const rootElement = document.documentElement; 1633 rootElement.style.setProperty('--piano-ribbon-height', $('#piano-sticky-header').outerHeight() + 'px'); 1634 } 1635 1636 if( typeof responseVariables.full_width_page !== 'undefined' ) { 1637 $('#subscribe-page-piano-top .tp-container-inner').addClass('full-width-piano-container'); 1638 } 1639 1640 1641 if( typeof responseVariables.sophi_track_regwall !== 'undefined' ) { 1642 const pianoWallEvent = new CustomEvent('pianoWallEvent', { 1643 detail: { 1644 pianoData: { meterName: 'Regwallmeter' } 1645 } 1646 }); 1647 window.dispatchEvent(pianoWallEvent); 1648 } 1649 1650 if( typeof responseVariables.sophi_track_paywall !== 'undefined' ) { 1651 const pianoWallEvent = new CustomEvent('pianoWallEvent', { 1652 detail: { 1653 pianoData: { meterName: 'DefaultMeter' } 1654 } 1655 }); 1656 window.dispatchEvent(pianoWallEvent); 1657 } 1658 }, 1659 1660 1661 /** 1662 * ------------------------------------------------------------------------ 1663 * Callback executed if experience execution has been failed 1664 * ------------------------------------------------------------------------ 1665 */ 1666 onExperienceExecutionFailed: function(event) { 1667 }, 1668 1669 1670 /** 1671 * ------------------------------------------------------------------------ 1672 * Callback executed if external checkout has been completed successfully 1673 * ------------------------------------------------------------------------ 1674 */ 1675 onExternalCheckoutComplete: function(event) { 1676 /* Default behavior is to refresh the page on successful checkout */ 1677 location.reload(); 1678 }, 1679 1680 1681 /** 1682 * ------------------------------------------------------------------------ 1683 * Determine if content should not be free in the app 1684 * ------------------------------------------------------------------------ 1685 */ 1686 isInsiderContent: function() { 1687 return postDataPiano.includes('insider'); 1688 }, 1689 1690 1691 /** 1692 * ------------------------------------------------------------------------ 1693 * Mobile refinements for article gating position on first article 1694 * ------------------------------------------------------------------------ 1695 */ 1696 positionArticleGating: function() { 1697 if( 1698 $(window).width() < 600 1699 && ( 1700 $('.site-header .in-article-subscribe-expandable-container').length < 1 1701 || $('.site-header .insider-in-article-subscribe-container--fixed').length < 1 1702 ) 1703 ) { 1704 // Standard gating 1705 if( $('.site-header .in-article-subscribe-expandable-container').length < 1 ) { 1706 $('.site-header').append($('.in-article-subscribe-expandable-container')); 1707 } 1708 // Insider gating (mainly for article gifting gating) 1709 if( 1710 $('body.is-fp-insider').length > 0 1711 && $('.site-header .insider-in-article-subscribe-container--fixed').length < 1 1712 ) { 1713 $('.site-header').append($('.insider-in-article-subscribe-container--fixed')); 1714 } 1715 1716 // Listen for Piano content injection via mutation observer 1717 1718 // Node that will be observed for mutations 1719 var targetNode = document.querySelector('.in-article-subscribe-expandable-container'); 1720 if( $('body.is-fp-insider').length > 0 ) { 1721 targetNode = document.querySelector('.insider-in-article-subscribe-container--fixed'); 1722 } 1723 1724 // Options for the observer (which mutations to observe) 1725 const config = { attributes: true, childList: true, subtree: true }; 1726 1727 // Callback function to execute when mutations are observed 1728 const callback = function(mutationsList, observer) { 1729 for(let mutation of mutationsList) { 1730 // CSS injection to account for dynamic height of Piano content injection 1731 if (mutation.attributeName === 'style' && mutation.type === 'attributes' && mutation.target.className === 'tp-container-inner') { 1732 var offsetHeight = $('.in-article-subscribe-expandable-container').outerHeight() + $('.header-nav-wrapper').outerHeight(); 1733 $('html > head').append( 1734 $('<style>.site-header { margin-bottom: -' + offsetHeight + 'px; margin-top: ' + offsetHeight + 'px; transform: translateY(-' + offsetHeight + 'px); }</style>') 1735 ); 1736 $('html > head').append( 1737 $('<style>header.nav-menu-scrolled-true--parent + main { padding-top: ' + offsetHeight + 'px; }</style>') 1738 ); 1739 } 1740 } 1741 }; 1742 1743 // Create an observer instance linked to the callback function 1744 const observer = new MutationObserver(callback); 1745 1746 // Start observing the target node for configured mutations 1747 observer.observe(targetNode, config); 1748 1749 // Stop observing after four seconds 1750 setTimeout(function() { 1751 observer.observe(targetNode, config); 1752 }, 4000); 1753 } 1754 }, 1755 1756 1757 /** 1758 * ------------------------------------------------------------------------ 1759 * Load iframes within gated content 1760 * This is needed for iframes that calculate their width/height dynamically when the iframe loads 1761 * ------------------------------------------------------------------------ 1762 */ 1763 loadIframes: function() { 1764 var iframeDefer = document.querySelectorAll('.content-gated iframe'); 1765 for (var i = 0; i < iframeDefer.length; i++) { 1766 if (iframeDefer[i].getAttribute('data-src')) { 1767 iframeDefer[i].setAttribute('src', iframeDefer[i].getAttribute('data-src')); 1768 } 1769 } 1770 }, 1771 1772 /** 1773 * ------------------------------------------------------------------------ 1774 * Check for user visit to a gifted article link 1775 * get 'gifting_article' URL param value 1776 * return string version of boolean value for use in Piano experience and this file 1777 * ------------------------------------------------------------------------ 1778 */ 1779 validateGiftingURL: function() { 1780 var urlGiftingParamValue = FP.Utils.url.getUrlParameter('gifting_article', false); 1781 var isUrlValid = 'false'; // pass string instead of boolean for use in Piano 1782 1783 // continue if URL param value was found 1784 if( 'not found' !== urlGiftingParamValue ) { 1785 // get URL slug 1786 var urlSlug = FP.Utils.url.getUrlSlug(); 1787 1788 // PostUp occassionally replaces the final '=' 1789 // in a gifting URL with '%3D' 1790 // adding a checkpoint to fix that here 1791 urlGiftingParamValue = urlGiftingParamValue.replaceAll('%3D','='); 1792 1793 try { 1794 // check URL slug against base64 decoded URL param value 1795 if( urlSlug === atob(urlGiftingParamValue) ) { 1796 isUrlValid = 'true'; // pass string instead of boolean for use in Piano 1797 } 1798 } catch (error) { 1799 // console.error(error); 1800 } 1801 1802 } 1803 1804 return isUrlValid; 1805 }, 1806 1807 1808 /** 1809 * Helper to show Insider subscription page content when user chooses to expand benefits 1810 * 1811 * @return {void} 1812 */ 1813 showInsiderSubscriptionPage: function() { 1814 return new Promise( function( resolve, reject ) { 1815 $.ajax({ 1816 type: 'GET', 1817 url: '/wp-json/fp/get-page-by-template/page-insider', 1818 data: { 1819 pageTitle: 'FP Insider', 1820 template: 'layouts/pages/page-insider', 1821 }, 1822 async: true, 1823 cache: true, 1824 }).then(function( response ) { 1825 // add Insider subscription page content to container 1826 $( '#subscribe-takeover--insider' ).html(response); 1827 1828 // hide header offer template 1829 $('.insider-page-header').css('display', 'none');
1830 $( '#insider-page-header-subscribe' ).css( 'display', 'none' ); 1831 1832 // show Insider subscription page content 1833 $( '#subscribe-takeover--insider' ).show(); 1834 1835 // add footer offer template 1836 if( $('#insider-page-footer-subscribe').length > 0 ) { 1837 tp.offer.show({ 1838 offerId: 'OFEYAKCMFC7N', 1839 templateId: 'OTJLYPYEOAKZ', 1840 displayMode: 'inline', 1841 containerSelector: '#insider-page-footer-subscribe', 1842 termIds: [ 'TMN7TTZYTVOH' ], 1843 }); 1844 } 1845 1846 // initialize carousel if present for Insider posts list 1847 if ($( '.posts-carousel' ).length > 0) { 1848 // Initialize Swiper 1849 new Swiper('.posts-carousel__posts-swiper', { 1850 a11y: { 1851 slideRole: 'listitem', 1852 }, 1853 loop: false, 1854 breakpoints: { 1855 200: { 1856 slidesPerView: 1, 1857 slidesPerGroup: 1, 1858 }, 1859 600: { 1860 slidesPerView: 2, 1861 slidesPerGroup: 1, 1862 }, 1863 980: { 1864 slidesPerView: 3, 1865 slidesPerGroup: 1, 1866 } 1867 }, 1868 navigation: { 1869 nextEl: '.swiper-button-next', 1870 prevEl: '.swiper-button-prev', 1871 }, 1872 }); 1873 } 1874 1875 // lazy load images in Insider subscription page content 1876 $(document.body).trigger('post-load'); 1877 $('article img').addClass('lazy-image-loaded'); 1878 $('article .image-attachment').addClass('no-background-color'); 1879 1880 // scroll user to subscribe takeover content 1881 $('html, body').animate({ 1882 scrollTop: $( '#subscribe-takeover--insider' ).offset().top - $('header').outerHeight() - 60 1883 }, 500); 1884 }); 1885 }); 1886 }, 1887 1888 1889 /** 1890 * Helper to hide Insider subscription page content when user chooses to expand benefits 1891 * 1892 * @return {void} 1893 */ 1894 hideInsiderSubscriptionPage: function() { 1895 $( '#subscribe-takeover--insider' ).hide(); 1896 }, 1897 1898 1899 /** 1900 * Helper to toggle auto renew 1901 * 1902 * @return {void} 1903 */ 1904 toggleAutoRenew: function ( enable = true ) { 1905 // Get user's subscription info 1906 FP.Singletons.User.getUserSubscriptionInfo() 1907 .then(function(resp) { 1908 var results = resp.data; 1909 1910 if( 1911 ( !results || typeof results === 'undefined' ) 1912 || ( !results.user_subscription || typeof results.user_subscription === 'undefined' ) 1913 ) { 1914 // return if the necessary data is not available 1915 return; 1916 } 1917 1918 // Iterate through user's subscriptions 1919 Object.keys(results.user_subscription.subscriptions).forEach(subscription => { 1920 var usersubscription = results.user_subscription.subscriptions[subscription]; 1921 1922 if( 1923 ( !usersubscription || typeof usersubscription === 'undefined' ) 1924 || ( typeof usersubscription.auto_renew === 'undefined' ) 1925 || ( typeof usersubscription.status === 'undefined' ) 1926 || ( typeof usersubscription.subscription_id === 'undefined' ) 1927 ) { 1928 // return if the necessary data is not available 1929 return; 1930 } 1931 1932 // handle enable vs disable state change 1933 if( enable ) { 1934 1935 // Continue if auto-renew is disabled and the subscription is active 1936 if( !usersubscription.auto_renew && 'active' === usersubscription.status ) { 1937 var subscriptionId = usersubscription.subscription_id; 1938 1939 if( !subscriptionId || typeof subscriptionId === 'undefined' ) { 1940 // return if the necessary data is not available 1941 return; 1942 } 1943 1944 // update auto-renew value to 'true' 1945 FP.Singletons.User.updateUserAutoRenew( subscriptionId, true ) 1946 .then(function(resp) { 1947 var results = resp.data; 1948 // check results for successful code value of 0 1949 if( 0 === results.code ) { 1950 // update renewal button text 1951 $('.renew-button > span').html( '✓ Confirmed' ); 1952 // Disable click for .renew-button 1953 $('.renew-button').prop('onclick', null).off('click'); 1954 // show success message 1955 $('#piano-sticky-header').html( '<span>✓ Success! Your FP access will continue uninterrupted.</span>' ).css({ 1956 'background':'#5dae0e', 1957 'padding':'10px 14px 11px', 1958 'text-align':'center' 1959 }); 1960 } 1961 }); 1962 } 1963 1964 } else { 1965 1966 // Continue if auto-renew is enabled and the subscription is active 1967 if( usersubscription.auto_renew && 'active' === usersubscription.status ) { 1968 var subscriptionId = usersubscription.subscription_id; 1969 1970 if( !subscriptionId || typeof subscriptionId === 'undefined' ) { 1971 // return if the necessary data is not available 1972 return; 1973 } 1974 1975 // update auto-renew value to 'false' 1976 FP.Singletons.User.updateUserAutoRenew( subscriptionId, false ) 1977 .then(function(resp) { 1978 $('#piano-manage > iframe').attr('src', $('#piano-manage > iframe').attr('src')); 1979 }); 1980 } 1981 1982 } 1983 1984 }); 1985 1986 }); 1987 }, 1988 1989 1990 /** 1991 * ------------------------------------------------------------------------ 1992 * Manage page 1993 * ------------------------------------------------------------------------ 1994 */ 1995 buildManagePage: function() { 1996 // Exit if user is not on Manage page 1997 if ( !$('.fp-manage-page') ) { 1998 return; 1999 } 2000 2001 // Toggle display of FP manage content 2002 if ( FP.Singletons.User.hasAccount || FP.Singletons.User.isSub || FP.Singletons.User.isPrem ) { 2003 $('.fp-manage-anon').hide(); 2004 // $('.fp-manage-menu').show(); 2005 } 2006 if ( FP.Singletons.User.isIPAccess && !FP.Singletons.User.hasAccount ) { 2007 $('.fp-manage-reg').each(function() { 2008 $( this ).hide(); 2009 }); 2010 } 2011 if ( FP.Singletons.User.hasAccount && !FP.Singletons.User.isSub ) { 2012 $('.fp-manage-reg').each(function() { 2013 $( this ).show(); 2014 }); 2015 } 2016 if ( FP.Singletons.User.isSub || FP.Singletons.User.isPrem ) { 2017 $('.fp-manage-sub').each(function() { 2018 $( this ).show(); 2019 }); 2020 } 2021 if ( FP.Singletons.User.isPrem ) { 2022 $('.fp-manage-premium').each(function() { 2023 $( this ).show(); 2024 }); 2025 } 2026 2027 // Show Piano manage content 2028 tp.myaccount.show({ 2029 displayMode: 'inline', 2030 containerSelector: '#piano-manage' 2031 }); 2032 2033 }, 2034 2035 /** 2036 * ------------------------------------------------------------------------ 2037 * Enable commenting 2038 * 2039 * Send a REST request with Piano UID, which will generate a JWT token 2040 * to pass to Coral, which will authenticate the user. 2041 * 2042 * Store the token in a cookie to avoid extra calls subsequent pageloads. 2043 * ------------------------------------------------------------------------ 2044 */ 2045 enableCommenting: function() { 2046 if ( tp.user.isUserValid() && FP.Singletons.User.isSub ) { 2047 if ( FP.Singletons.User.userData.customFields.comments_username ) { 2048 $( '.username-placeholder' ).html( FP.Singletons.User.userData.customFields.comments_username ); 2049 $( '.username-input' ).val( FP.Singletons.User.userData.customFields.comments_username ); 2050 } 2051 2052 var coral_token = $.cookie( 'fp-coral-token' ); 2053 if ( coral_token && window.coral_embed ) { 2054 window.coral_embed.login( coral_token ); 2055 } else { 2056 jQuery.ajax( { 2057 url: '/wp-json/fp/coral-jwt', 2058 data: { 2059 uid: tp.pianoId.getUser().uid, 2060 username: FP.Singletons.User.userData.customFields.comments_username 2061 }, 2062 type: 'POST', 2063 async: true, 2064 success: function ( response ) { 2065 if ( response.token && window.coral_embed ) { 2066 $.cookie( 'fp-coral-token', response.token, { expires: 1, path: '/' } ); 2067 window.coral_embed.login( response.token ); 2068 } 2069 }, 2070 error: function( request, error ) { 2071 console.error( error ); 2072 } 2073 } ); 2074 } 2075 } 2076 }, 2077 2078 /** 2079 * ------------------------------------------------------------------------ 2080 * Show browser compatibility error modal 2081 * 2082 * This primarily targets browsers that are blocking the 2083 * Piano JS from loading (Firefox is the main offender as of July 2024) 2084 * ------------------------------------------------------------------------ 2085 */ 2086 showBrowserCompatibilityErrorModal: function() { 2087 $('body').addClass('sticky_content_takeover_shown'); 2088 $('#browser-compatibility-error').removeAttr('aria-hidden'); 2089 $('#browser-compatibility-error').attr('tabindex','0'); 2090 $('#browser-compatibility-error').attr('aria-labelledby','browser-compatibility-error-message'); 2091 $('#browser-compatibility-error').focus(); 2092 2093 $('.sticky_content_takeover--close, .sticky_content_takeover--close-text').click( function(){ 2094 $('body').removeClass('sticky_content_takeover_shown'); 2095 $('#browser-compatibility-error').attr('aria-hidden', 'true'); 2096 $('#browser-compatibility-error').removeAttr('tabindex'); 2097 }); 2098 }, 2099 2100 }; 2101 2102}(jQuery); 2103; 2104//~Singletons/User 2105// 2106// Helper funcs for interacting with identity provider 2107!function ($) { 2108 var usePianoProduction = window.pianoData.use_piano_environment; 2109 2110 if( 'production' === usePianoProduction ) { 2111 // Production 2112 var pianoAid = 'beVmoi3WRm'; 2113 var pianoAPIFile = '//pianocdn.foreignpolicy.com/api/tinypass.min.js'; 2114 } else { 2115 // Sandbox 2116 var pianoAid = 'Q0Q1FMiXiK'; 2117 var pianoAPIFile = '//pianocdn-sb.foreignpolicy.com/api/tinypass.min.js'; 2118 } 2119 2120 window.dataLayer = window.dataLayer || []; 2121 2122 /* Initialize Piano */ 2123 function initializePiano( postDataPianoFinal ){ 2124 2125 tp = window.tp || []; 2126 2127 /** 2128 * ------------------------------------------------------------------------ 2129 * Pass article tag data to Piano 2130 * ------------------------------------------------------------------------ 2131 */ 2132 function passDataToPiano( postDataPianoFinal ) { 2133 tp.push(["setTags", postDataPianoFinal]); 2134 } 2135 passDataToPiano( postDataPianoFinal ); 2136 2137 /** 2138 * ------------------------------------------------------------------------ 2139 * Initialize Piano 2140 * ------------------------------------------------------------------------ 2141 */ 2142 // Initialize utility helper in /assets/src/scripts/utils/piano.js 2143 FP.Utils = FP.Utils || {}; 2144 FP.Utils.Piano.init(); 2145 2146 // Initialize Piano ID 2147 tp.push(["setAid", pianoAid]); 2148 tp.push(["setCxenseSiteId", "1139724983415417198"]); 2149 2150 /* domain whitelabeling - https://docs.piano.io/full-domain-whitelabeling/ */ 2151 if( "production" === usePianoProduction ) { 2152 tp.push(["setComposerHost","https://pianocomposer.foreignpolicy.com"]); 2153 tp.push(["setPianoIdUrl", "https://pianoauth.foreignpolicy.com"]); 2154 tp.push(["setEndpoint", "https://pianovx.foreignpolicy.com"]); 2155 tp.push(["setStaticDomain", "https://pianocdn.foreignpolicy.com"]); 2156 } else { 2157 tp.push(["setComposerHost","https://pianocomposer-sb.foreignpolicy.com"]); 2158 tp.push(["setPianoIdUrl", "https://pianoauth-sb.foreignpolicy.com"]); 2159 tp.push(["setEndpoint", "https://pianovx-sb.foreignpolicy.com"]); 2160 tp.push(["setStaticDomain", "https://pianocdn-sb.foreignpolicy.com"]); 2161 } 2162
2163 /* do not use Piano Go/Tinypass Accounts legacy user management integration */ 2164 tp.push(["setUseTinypassAccounts", false]); 2165 2166 /* use Piano id */ 2167 tp.push(["setUsePianoIdUserProvider", true]); 2168 2169 /* set content created value from meta data if present */ 2170 if(document.querySelector('meta[name=content_created]')) { 2171 tp.push(["setContentCreated", document.querySelector('meta[name=content_created]').getAttribute('content')]); 2172 } 2173 2174 /* Piano cookie setting - first party */ 2175 tp.push(["setCloudflareWorkerUrl", window.location.origin + "/endpoint/piano-cookies/?__fp_endpoint_piano_cookies=1"]); 2176 2177 /* FB IA tracking (https://docs.piano.io/facebook-experiences/#IAscript) */ 2178 tp.push(["setFbPixelId", "203988873637408"]); 2179 2180 /* checkout related events */ 2181 tp.push(["addHandler", "checkoutComplete", FP.Utils.Piano.onCheckoutComplete]); 2182 tp.push(["addHandler", "checkoutClose", FP.Utils.Piano.onCheckoutClose]); 2183 tp.push(["addHandler", "checkoutCustomEvent", FP.Utils.Piano.onCheckoutExternalEvent]); 2184 tp.push(["addHandler", "checkoutCancel", FP.Utils.Piano.onCheckoutCancel]); 2185 tp.push(["addHandler", "checkoutError", FP.Utils.Piano.onCheckoutError]); 2186 tp.push(["addHandler", "checkoutSubmitPayment", FP.Utils.Piano.onCheckoutSubmitPayment]); 2187 tp.push(["addHandler", "checkoutStateChange", FP.Utils.Piano.onCheckoutStateChange]); 2188 tp.push(["addHandler", "startCheckout", FP.Utils.Piano.startCheckout]); 2189 2190 /* my account related events */ 2191 tp.push(['addHandler', 'customEvent', FP.Utils.Piano.onCustomEvent]); 2192 2193 /* upgrade related events */ 2194 tp.push(["addHandler", "completeUpgradePurchase", FP.Utils.Piano.onCompleteUpgradePurchase]); 2195 2196 /* user login events */ 2197 tp.push(["addHandler", "loginRequired", FP.Utils.Piano.onLoginRequired]); 2198 tp.push(["addHandler", "registrationSuccess", FP.Utils.Piano.onRegistrationSuccess]); 2199 2200 /* content gating */ 2201 if ( postDataPianoFinal.includes('FP Insider') && 'false' === FP.Utils.Piano.validateGiftingURL() ) { 2202 /* handle Insider gating that is not accessed via article gifting URL */ 2203 FP.Utils.Piano.gateInsiderContent(); 2204 } else { 2205 /* meter related to standard content */ 2206 tp.push(["addHandler", "meterExpired", FP.Utils.Piano.onMeterExpired]); 2207 tp.push(["addHandler", "meterActive", FP.Utils.Piano.onMeterActive]); 2208 } 2209 2210 tp.push(["addHandler", "experienceExecute", FP.Utils.Piano.onExperienceExecute]); 2211 tp.push(["addHandler", "experienceExecutionFailed", FP.Utils.Piano.onExperienceExecutionFailed]); 2212 2213 /* get response variable from experience */ 2214 tp.push(["addHandler", "setResponseVariable", FP.Utils.Piano.onSetResponseVariable]); 2215 2216 /* external checkout related events */ 2217 tp.push(["addHandler", "externalCheckoutComplete", FP.Utils.Piano.onExternalCheckoutComplete]); 2218 2219 /* handle user login, signup and logout button clicks - callback executed after a tinypassAccounts login */ 2220 tp.push(["addHandler", "loginSuccess", function(data){ 2221 // Any logic required after a successful login 2222 if ( tp.user.isUserValid() ) { 2223 // Create or get Sailthru User 2224 FP.Utils.Piano.syncUserToST(data.user_token); 2225 2226 FP.Utils.Piano.sendSignedFbPixel( 'LogIntoAccount', { 2227 subscription_id: data.params.uid, 2228 is_subscriber: true 2229 }); 2230 2231 document.dispatchEvent(new CustomEvent('rudder:identify', { 2232 detail: { 2233 user_id: data.params.uid, 2234 traits: { 2235 first_name: data.params.firstName, 2236 last_name: data.params.lastName, 2237 email: data.params.email 2238 } 2239 } 2240 })); 2241 } 2242 2243 // Toggle display of authenticated user content in header 2244 FP.Utils.Piano.toggleHeaderContent(); 2245 2246 if( true === data.registration ) { 2247 // login came from registration 2248 } else if( "PIANOID" === data.source ) { 2249 // login came from standard login, not within an offer flow 2250 FP.Singletons.User.setUserCacheGroup( data.params.uid, true ); 2251 } 2252 }]); 2253 2254 2255 /** 2256 * ------------------------------------------------------------------------ 2257 * Load Piano API JS file 2258 * ------------------------------------------------------------------------ 2259 */ 2260 // Alert user if Piano script is blocked by their browser 2261 ((src) => { 2262 return new Promise( 2263 function(t,e) { 2264 let n = document.createElement("script"); 2265 n.src = src, 2266 n.type = "text/javascript", 2267 n.defer = "defer", 2268 n.onerror = (()=>e()), 2269 n.onload = ( 2270 () => { 2271 if("function" === typeof window.___tp) { 2272 ( tp=window.tp || [], tp.push(["init",function(){t()}]) ) 2273 } else { 2274 e(); 2275 } 2276 } 2277 ); 2278 2279 let o = document.getElementsByTagName("script")[0]; 2280 o.parentNode.insertBefore(n,o); 2281 } 2282 ); 2283 })(pianoAPIFile).then( 2284 () => { 2285 // tinypass.min.js is loaded and initialized 2286 }, 2287 () => { 2288 // The tinypass.min.js script was blocked due to a browser content filter 2289 // Show error modal to user 2290 FP.Utils.Piano.showBrowserCompatibilityErrorModal(); 2291 } 2292 ) 2293 2294 2295 // Initialize Piano 2296 tp.push(["init", function() { 2297 // ensure cross domain tracking 2298 tp.enableGACrossDomainLinking('UA-6874192-41'); 2299 2300 // Google Analytics 4 configuration 2301 tp.setGA4Config({ 2302 measurementId: 'G-T5CKP06L0Y', 2303 eventParameters: { 2304 send_page_view: false, 2305 } 2306 }); 2307 2308 // If user is logged in 2309 if (tp.user.isUserValid()) { 2310 // Get the stored cookie value 2311 var paramsCookie = tp.util.findCookieByName('__pianoParams'); 2312 var params; 2313 try { 2314 // Try to parse stored JSON data 2315 params = JSON.parse(paramsCookie); 2316 // Remove the old cookie 2317 document.cookie = "__pianoParams=null; expires=-1;" + 2318 " path=/; domain=.foreignpolicy.com"; 2319 } catch (e) { 2320 params = false;
2321 } 2322 } 2323 2324 // Check for gift URL parameters and validate if present 2325 // Send validation result to Piano as a custom variable 2326 // The custom variable must be set before the `tp.experience.init()` below 2327 tp.setCustomVariable( "gift_url_validation", FP.Utils.Piano.validateGiftingURL() ); 2328 2329 // Get meta page title for use in Piano experience text 2330 var pageTitle = document.querySelector(".article .hed-heading .hed"); 2331 if( pageTitle ) pageTitle = pageTitle.innerHTML; 2332 // The custom variable must be set before the `tp.experience.init()` below 2333 tp.setCustomVariable( "fp_page_title", pageTitle ); 2334 2335 // Initialize Piano experience 2336 // unless user is viewing article in our app and the article is not Insider only 2337 if( !FP.Utils.Piano.isUserFromApp() || ( FP.Utils.Piano.isUserFromApp() && FP.Utils.Piano.isInsiderContent() ) ) { 2338 tp.pianoId.init({ 2339 loggedOut: function() { 2340 // Reset rudder logout 2341 try { 2342 sessionStorage.setItem('rudder:skipNextTrackPage', '1'); 2343 } catch (e) { 2344 // sessionStorage unavailable â proceed with reload; duplicate page event is the acceptable fallback 2345 } 2346 document.dispatchEvent(new CustomEvent('rudder:reset', { 2347 detail: { options: true } 2348 })); 2349 // Reload the page after Piano has completed the logout process 2350 location.reload(); 2351 } 2352 }); 2353 2354 console.log('Quickstart -- Piano wallType = ' + ( window.sophi?.wallDecision ?? "timeout" ) ); 2355 console.log('Quickstart -- Piano assignedGroup = ' + ( window.sophi?.assignedGroup ?? "control" ) ); 2356 2357 // Set custom variables from Sophi decision for use in Piano experiences 2358 // to determine wall type and A/B test group 2359 // The custom variables must be set before the `tp.experience.init()` below 2360 tp.setCustomVariable( "wallType", window.sophi?.wallDecision ?? "timeout" ); 2361 tp.setCustomVariable( "assignedGroup", window.sophi?.assignedGroup ?? "control" ); 2362 2363 // Initialize experience 2364 tp.experience.init(); 2365 } 2366 2367 /** 2368 * ------------------------------------------------------------------------ 2369 * Check user access 2370 * ------------------------------------------------------------------------ 2371 */ 2372 2373 // Check for FP.Singletons instance 2374 FP.Singletons = FP.Singletons || {}; 2375 2376 // Create User class 2377 FP.Singletons.User = { 2378 2379 isInsider: false, 2380 isPrem: false, 2381 isSub: false, 2382 isISpyPlus: false, 2383 hasAccount: false, // has Piano account 2384 isReg: false, // has access to REGISTRATION Piano resource 2385 isIPAccess: false, 2386 isLinkAccess: false, 2387 userData: { 2388 uid: '', 2389 email: '', 2390 first_name: '', 2391 last_name: '', 2392 personal_name: '', 2393 customFields: {} 2394 }, 2395 ipAccessData: {}, 2396 2397 2398 /** 2399 * Listener for all subscription check events to finish 2400 */ 2401 accessCheckCompleteListener: function () { 2402 var that = this; 2403 2404 // Listener 2405 var MyRequestsCompleted = (function() { 2406 var numRequestToComplete, requestsCompleted, callBacks, singleCallBack; 2407 2408 return function(options) { 2409 if (!options) options = {}; 2410 2411 numRequestToComplete = options.numRequest || 0; 2412 requestsCompleted = options.requestsCompleted || 0; 2413 callBacks = []; 2414 var fireCallbacks = function() { 2415 for (var i = 0; i < callBacks.length; i++) callBacks[i](); 2416 }; 2417 if (options.singleCallback) callBacks.push(options.singleCallback); 2418 2419 this.addCallbackToQueue = function(isComplete, callback) { 2420 if (isComplete) requestsCompleted++; 2421 if (callback) callBacks.push(callback); 2422 if (requestsCompleted == numRequestToComplete) fireCallbacks(); 2423 }; 2424 this.requestComplete = function(isComplete) { 2425 if (isComplete) requestsCompleted++; 2426 if (requestsCompleted == numRequestToComplete) fireCallbacks(); 2427 }; 2428 this.setCallback = function(callback) { 2429 callBacks.push(callBack); 2430 }; 2431 }; 2432 })(); 2433 2434 // Set number of events and callback for listener 2435 that.requestCallback = new MyRequestsCompleted({ 2436 numRequest: 2, 2437 singleCallback: function(){ 2438 FP.Utils.Piano.toggleBodyClass(); 2439 FP.Utils.Piano.toggleHeaderContent(); 2440 FP.Utils.Piano.updateGiftingLink(); 2441 FP.Utils.Piano.buildManagePage(); 2442 2443 $.event.trigger('pianoAccessCheckComplete'); 2444 2445 FP.Singletons.User.trackLoginData(); 2446 2447 // Added to dispatch via vanilla JS 2448 const pianoEvt = new CustomEvent('accessPianoComplete'); 2449 window.dispatchEvent(pianoEvt, FP.Singletons.User); 2450 } 2451 }) 2452 }, 2453 2454 2455 /** 2456 * Helper that houses function calls to set user's access levels and Piano data 2457 * 2458 * @return {void} 2459 */
2460 setAccess: function () { 2461 var that = this; 2462 2463 that.accessCheckCompleteListener(); 2464 2465 that.isPianoAccess(); 2466 that.isOtherAccess(); 2467 2468 window.pianoReady = true; 2469 }, 2470 2471 2472 /** 2473 * Helper to evaluate user's Piano account access and 2474 * set data accordingly in the FP.Singletons.User object 2475 * 2476 * @return {void} 2477 */ 2478 isPianoAccess: function() { 2479 var that = this; 2480 2481 // Process the user access info that came from the server-side 2482 // via Foreignpolicy_User_Cache_Group_Helper::get_user_access_levels 2483 if ( window.pianoData.userLevels && tp.user.isUserValid() ) { 2484 var userLevels = window.pianoData.userLevels; 2485 that.setUserSubLevels( userLevels ); 2486 2487 if ( $.cookie( 'fp-user-data' ) ) { 2488 that.userData = JSON.parse( $.cookie( 'fp-user-data' ) ); 2489 } else { 2490 that.setPianoUserData(); 2491 } 2492 2493 that.fetchCustomFields( 'onboarding_flow' ); 2494 2495 that.fetchCustomFields( 'events_registration_fields' ); 2496 2497 that.fetchCustomFields( 'comments_form', function() { 2498 FP.Utils.Piano.enableCommenting(); 2499 } ); 2500 } 2501 2502 // VIP cache cookie has already been set 2503 // cookie duration is 1 day 2504 if ( typeof $.cookie( 'vip-go-seg' ) !== 'undefined' && ! FP.Singletons.UserAltAccess.isIPAccess ) { 2505 // 2506 // TO-DO 2507 // - set cookie with all the that.isInsider, etc. sub details and that.userData data as well 2508 // this can be evaluated here to set all the data relative to the FP.Singletons.User object 2509 // 2510 if( tp.user.isUserValid() ) { 2511 that.setPianoUserData(); 2512 } else { 2513 that.resetRudderIdentity(); 2514 } 2515 2516 that.requestCallback.requestComplete(true); 2517 return; 2518 2519 } else if( tp.user.isUserValid() ) { 2520 // VIP cache cookie has not been set 2521 var pianoUserData = tp.pianoId.getUser(); 2522 tpUserId = pianoUserData.uid; 2523 2524 // Reload page for Piano users 2525 var reloadPage = true; 2526 // Do not reload if user is also an IP Access user 2527 // as this causes a redirect loop 2528 if( FP.Singletons.UserAltAccess.isIPAccess ) reloadPage = false; 2529 2530 Promise.all([ 2531 that.setUserCacheGroup( tpUserId, reloadPage ), 2532 ]).then(function (results) { 2533 that.requestCallback.requestComplete(true); 2534 }).catch(function (reason) { 2535 //reject(reason); 2536 }); 2537 2538 // User is not logged into Piano 2539 } else { 2540 that.resetRudderIdentity(); 2541 that.requestCallback.requestComplete(true); 2542 } 2543 2544 }, 2545 2546 2547 /** 2548 * Helper to determine if user is coming from the app, 2549 * or has either IP access or link access 2550 * 2551 * @return {void} 2552 */ 2553 isOtherAccess: function () { 2554 var that = this; 2555 if( 2556 FP.Utils.Piano.isUserFromApp() 2557 || FP.Singletons.UserAltAccess.isIPAccess 2558 || FP.Singletons.UserAltAccess.isLinkAccess 2559 ) { 2560 that.isPrem = true; 2561 that.isSub = true; 2562 that.isISpyPlus = true; 2563 2564 // only set the gated content to show if the current post is not an FP Insider post 2565 if ( !postDataPianoFinal.includes('FP Insider') ) { 2566 // Workaround for IP access users coming from proxy URL 2567 // to ensure the full article content displays 2568 $( '.content-ungated' ).hide(); 2569 $( '.content-gated' ).show(); 2570 } 2571 2572 if( FP.Singletons.UserAltAccess.isIPAccess ) { 2573 // The VIP cache cookie is set server-side after IP/proxy auth. 2574 // However, the cookie may have been set after page load if this is the first pageview of the session. 2575 // Reload page to ensure VIP cache cookie is available to all VIP cache checks in PHP. 2576 // Check if the page has already been reloaded during this session. 2577 if ( !sessionStorage.getItem('page_reloaded') ) { 2578 // Set session flag to only reload once per session. 2579 sessionStorage.setItem('page_reloaded', 'true'); 2580 // Reload page 2581 location.reload(); 2582 } 2583 2584 that.isIPAccess = FP.Singletons.UserAltAccess.ipAccessData.access; 2585 that.ipAccessData = FP.Singletons.UserAltAccess.ipAccessData; 2586 if( 'Insider' === FP.Singletons.UserAltAccess.ipAccessData.access_level ) { 2587 that.isInsider = true; 2588 if( FP.Singletons.User.isInsider ) { 2589 $( 'body' ).addClass( 'insider_user_ip' ); 2590 } 2591 } 2592 2593 // Send pixel to Facebook to exclude IP access subs 2594 // from our paid marketing campaigns 2595 FP.Utils.Piano.sendSignedFbPixel( 'ip_access', { 2596 is_ip_access: 'true' 2597 } ); 2598 2599 // Hide comment-related elements from IP Access clients, for now 2600 $( '.hide-ip-access' ).remove(); 2601 } 2602 2603 if( FP.Singletons.UserAltAccess.isLinkAccess ) { 2604 that.isLinkAccess = FP.Singletons.UserAltAccess.isLinkAccess.access; 2605 that.linkAccessData = FP.Singletons.UserAltAccess.linkAccessData; 2606 } 2607 } 2608 2609 that.requestCallback.requestComplete(true); 2610 return; 2611 }, 2612 2613 2614 /** 2615 * Helper to set user's Piano custom fields in the FP.Singletons.User object 2616 */ 2617 fetchCustomFields: function( form_name, callback ) { 2618 tp.pianoId.loadExtendedUser( { 2619 extendedUserLoaded: function ( data ) { 2620 FP.Singletons.User.userData.customFields = FP.Singletons.User.userData.customFields || []; 2621 2622 for ( var i in data.custom_field_values ) { 2623 var fieldName = data.custom_field_values[i].field_name; 2624 var fieldValue = data.custom_field_values[i].value; 2625 2626 FP.Singletons.User.userData.customFields[fieldName] = fieldValue; 2627 } 2628 2629 if( 'onboarding_flow' === form_name ) { 2630 $.event.trigger('pianoOnboardingDataReady'); 2631 } 2632 2633 // Only continue below if processing custom fields from the comments form 2634 if( 'comments_form' !== form_name ) return; 2635 2636 if ( FP.Singletons.User.isSub ) { 2637 var username_set = !!FP.Singletons.User.userData.customFields.comments_username; 2638 if ( ! username_set ) { 2639 $( '.comment-username-text' ).hide(); 2640 2641 if(!FP.Singletons.User.userData.last_name) FP.Singletons.User.userData.last_name = ' '; 2642 FP.Singletons.User.userData.customFields.comments_username = FP.Singletons.User.userData.first_name + FP.Singletons.User.userData.last_name.charAt(0); 2643 $( '.comment-username-form.user-content' ).show(); 2644 } 2645 } 2646 2647 if ( 'true' === FP.Singletons.User.userData.customFields.commenting_guidelines_consent ){ 2648 $( 'input[name="commenting-guidelines-consent"]' ).attr( 'checked', 'checked' ); 2649 } 2650 2651 $.cookie( 'fp-user-data', JSON.stringify( FP.Singletons.User.userData ), { expires: 1, path: '/' } ); 2652 2653 if ( callback ) { 2654 callback(); 2655 } 2656 }, formName: form_name 2657 } ); 2658 }, 2659 2660 2661 /** 2662 * Helper to set user's Piano data in the FP.Singletons.User object 2663 * 2664 * @return {void} 2665 */ 2666 setPianoUserData: function() { 2667 var that = this; 2668 2669 var pianoUserData = tp.pianoId.getUser(); 2670 if( pianoUserData ) { 2671 // Set uid if not already present 2672 if ( ! that.userData.uid ) { 2673 that.userData.uid = pianoUserData.uid; 2674 } 2675 // Set remaining user data 2676 that.userData.email = pianoUserData.email; 2677 that.userData.first_name = pianoUserData.firstName; 2678 that.userData.last_name = pianoUserData.lastName; 2679 that.userData.personal_name = that.userData.first_name + ' ' + that.userData.last_name; 2680 2681 // Re-assert this user's identity for Rudder. loginSuccess only 2682 // fires on an interactive login, so without this a returning 2683 // subscriber emits every page/track event with a user_id but an 2684 // empty context.traits once the SDK's `rl_trait` cookie is gone. 2685 // tp.pianoId.getUser() is the authoritative source â the 2686 // loginSuccess `data.params` payload does not always carry email. 2687 // The rudder:identify listener dedupes on user_id + traits, so 2688 // this is a no-op on every load after the first. 2689 document.dispatchEvent(new CustomEvent('rudder:identify', { 2690 detail: { 2691 user_id: pianoUserData.uid, 2692 traits: { 2693 first_name: pianoUserData.firstName, 2694 last_name: pianoUserData.lastName, 2695 email: pianoUserData.email 2696 } 2697 } 2698 })); 2699 } 2700 }, 2701 2702 2703 /** 2704 * Helper to clear any Rudder identity left over from a previous login. 2705 * 2706 * Called only once Piano has evaluated the session and reports the 2707 * reader as signed out. `rl_user_id` persists for a year while the 2708 * Piano session does not, so without this a reader whose session 2709 * lapsed keeps having events attributed to them. Scoped to identity 2710 * entries so the anonymous id and current session survive. 2711 * 2712 * Deliberately NOT keyed off the `__utp` cookie at SDK init: Piano 2713 * re-mints that cookie a few seconds after load, so its absence at 2714 * init races against a live session and demoted signed-in page views 2715 * to anonymous. Piano's own verdict is the only safe trigger. 2716 * 2717 * @return {void} 2718 */ 2719 resetRudderIdentity: function() { 2720 document.dispatchEvent(new CustomEvent('rudder:reset', {
2721 detail: { options: { entries: { userId: true, userTraits: true } } } 2722 })); 2723 }, 2724 2725 2726 /** 2727 * Helper to set user's subscription levels in the FP.Singletons.User object 2728 * 2729 * @param {object} userLevels User level data from VIP cache cookie 2730 * 2731 * @return {void} 2732 */ 2733 setUserSubLevels: function( userLevels ) { 2734 var that = this; 2735 2736 that.isInsider = userLevels.isInsider; 2737 that.isPrem = userLevels.isPremium || userLevels.isInsider; 2738 that.isSub = userLevels.isSub || userLevels.isPremium || userLevels.isInsider; 2739 that.isISpyPlus = userLevels.isIspyPlus || userLevels.isPremium || userLevels.isInsider; 2740 that.isReg = userLevels.isReg; 2741 that.hasAccount = userLevels.hasAccount || userLevels.isReg || userLevels.isSub || userLevels.isPremium || userLevels.isInsider; 2742 }, 2743 2744 2745 /** 2746 * Helper to set user cache group with VIP 2747 * 2748 * @return {void} 2749 */ 2750 setUserCacheGroup: function ( pianoUid, reload ) { 2751 var that = this; 2752 2753 return new Promise( function( resolve, reject ) { 2754 $.ajax({ 2755 type: 'POST', 2756 url: '/wp-admin/admin-ajax.php', 2757 data: { 2758 action: 'set_user_cache_group', 2759 uid: pianoUid, 2760 token: window.pianoData.cache_group_nonce 2761 }, 2762 success: function( response ) { 2763 that.setUserSubLevels( response ); 2764 2765 if( tp.user.isUserValid() ) { 2766 that.setPianoUserData(); 2767 } 2768 2769 that.fetchCustomFields( 'onboarding_flow' ); 2770 2771 that.fetchCustomFields( 'comments_form', function() { 2772 FP.Utils.Piano.enableCommenting(); 2773 2774 if( true === reload ) { 2775 try { 2776 sessionStorage.setItem('rudder:skipNextTrackPage', '1'); 2777 } catch (e) { 2778 // sessionStorage unavailable â proceed with reload; duplicate page event is the acceptable fallback 2779 } 2780 location.reload(); 2781 } 2782 } ); 2783 } 2784 }).done( resolve ).fail( reject ); 2785 } ); 2786 }, 2787 2788 2789 /** 2790 * Helper to get user subscription info 2791 * 2792 * @return {void} 2793 */ 2794 getUserSubscriptionInfo: function () { 2795 var that = this; 2796 2797 return $.ajax({ 2798 url: '/piano-user-check/results/', 2799 data: { 2800 '__fp_endpoint_piano_ajax' : 1, 2801 '__fp_endpoint_piano_action' : 'user_subscription', 2802 '__fp_endpoint_piano_user_id' : that.userData.uid, 2803 }, 2804 cache: true 2805 }); 2806 }, 2807 2808 2809 /** 2810 * Check if the email address has a Piano account. 2811 * 2812 * @param {string} email 2813 * 2814 * @returns {Object} jQuery jqXHR object. 2815 */ 2816 checkEmailHasSiteAccount: function (email) { 2817 return $.ajax({ 2818 url: '/piano-user-check/results/', 2819 data: { 2820 '__fp_endpoint_piano_ajax' : 1, 2821 '__fp_endpoint_piano_action' : 'email', 2822 '__fp_endpoint_piano_user_email': email 2823 }, 2824 cache: false 2825 }); 2826 }, 2827 2828 /** 2829 * Log user into Piano account. 2830 * 2831 * @param {string} email 2832 * @param {string} password 2833 * 2834 * @returns {Object} jQuery jqXHR object. 2835 */ 2836 userLogin: function (email, password) { 2837 return $.ajax({ 2838 url: '/piano-user-check/results/', 2839 data: { 2840 '__fp_endpoint_piano_ajax' : 1, 2841 '__fp_endpoint_piano_action' : 'login', 2842 '__fp_endpoint_piano_user_email' : email, 2843 '__fp_endpoint_piano_user_password': password 2844 }, 2845 cache: false 2846 }); 2847 }, 2848 2849 /** 2850 * Register user account in Piano. 2851 * 2852 * @param {string} email 2853 * @param {string} password 2854 * @param {string} firstname 2855 * @param {string} lastname 2856 * 2857 * @returns {Object} jQuery jqXHR object. 2858 */ 2859 userRegister: function (email, password, firstname, lastname) { 2860 return $.ajax({ 2861 url: '/piano-user-check/results/', 2862 data: { 2863 '__fp_endpoint_piano_ajax' : 1, 2864 '__fp_endpoint_piano_action' : 'register', 2865 '__fp_endpoint_piano_user_email' : email, 2866 '__fp_endpoint_piano_user_password' : password, 2867 '__fp_endpoint_piano_user_firstname': firstname, 2868 '__fp_endpoint_piano_user_lastname' : lastname, 2869 '__fp_endpoint_piano_user_consent' : true 2870 }, 2871 cache: false 2872 }); 2873 }, 2874 2875 2876 /** 2877 * Helper to update user auto renew value 2878 * 2879 * @return {void} 2880 */ 2881 updateUserAutoRenew: function ( subscriptionId, autoRenew ) { 2882 var that = this; 2883 2884 return $.ajax({ 2885 url: '/piano-user-update/results/', 2886 data: { 2887 '__fp_endpoint_piano_ajax_update_user' : 1, 2888 '__fp_endpoint_piano_action_update_user' : 'update_user_auto_renew', 2889 '__fp_endpoint_piano_user_subscription_id' : subscriptionId, 2890 '__fp_endpoint_piano_user_auto_renew' : autoRenew, 2891 '__fp_endpoint_piano_user_nonce' : window.pianoData.cache_group_nonce || '', 2892 }, 2893 cache: false 2894 }); 2895 }, 2896 2897 2898 /** 2899 * Helper to send analytic data 2900 * 2901 * @return {void} 2902 */ 2903 trackLoginData: function() { 2904 var that = this; 2905 2906 // Set user group per subscription level 2907 var user_group = ''; 2908 var subscriber_state = ''; 2909 2910 if( that.isInsider ) { 2911 user_group = 'insider_subscriber'; 2912 subscriber_state = 'Subscribed - Insider'; 2913 } else if( that.isPrem ) { 2914 user_group = 'premium_subscriber'; 2915 subscriber_state = 'Subscribed - Premium'; 2916 } else if( that.isSub ) { 2917 user_group = 'basic_subscriber'; 2918 subscriber_state = 'Subscribed - Basic'; 2919 } else if( that.isISpyPlus ) { 2920 user_group = 'i_spy_plus_user'; 2921 subscriber_state = 'Subscribed - I Spy Plus'; 2922 } else if( that.isReg || that.hasAccount ) { 2923 user_group = 'registered_user'; 2924 subscriber_state = 'Registered'; 2925 } 2926 2927 // Continue if user is authenticated via Piano or IP/Link access 2928 if( '' !== user_group ) { 2929 2930 var user_id = ''; 2931 var event_category = ''; 2932 2933 if( FP.Singletons.UserAltAccess.isIPAccess ) { 2934 user_id = that.ipAccessData.client_guid; 2935 user_group = 'default-IP_access'; 2936 event_category = 'IP'; 2937 } else if( FP.Singletons.UserAltAccess.isLinkAccess ) { 2938 user_id = that.linkAccessData.ID; 2939 user_group = 'default-link_access';
2940 event_category = 'LinkAccess'; 2941 } else { 2942 user_id = that.userData.uid; 2943 event_category = 'Piano'; 2944 } 2945 2946 // Send data to GA 2947 gtag('event', 'track_login', {'LID': user_id}); 2948 gtag('event', 'track_login', {'RGRP': user_group}); 2949 gtag('event', 'track_login', {'VID': user_id}); 2950 2951 if(typeof zaraz !== 'undefined') { 2952 let pageScope = { scope: 'page' }; 2953 zaraz.set('subscriberState', subscriber_state, pageScope); 2954 zaraz.set('accessId', user_id, pageScope); 2955 zaraz.set('accessGroup', user_group, pageScope); 2956 } 2957 2958 dataLayer.push({ 2959 'subscriberState': subscriber_state, 2960 'accessId': user_id, 2961 'accessGroup': user_group 2962 }); 2963 2964 // Send data to GA 2965 gtag('event', 'matchedSubscriber', { 2966 'event_category': event_category 2967 }); 2968 } else { 2969 $('body').addClass('anon_user'); 2970 2971 // Send data to GA 2972 gtag('event', 'matchedNonSubscriber', { 2973 'event_category': 'Nonsub' 2974 }); 2975 } 2976 2977 // Only send the ViewContent event on article pages 2978 if ( -1 < postDataPiano.indexOf( 'article' ) ) { 2979 if ( window.fbq ) { 2980 fbq( 'track', 'ViewContent', {
2981 article_content_tier: 'metered', 2982 is_subscriber: ( '' !== user_group && 'registered_user' !== user_group ) 2983 } ); 2984 } 2985 } 2986 }, 2987 2988 }; 2989 2990 FP.Singletons.User.setAccess(); 2991 2992 }]); 2993 } 2994 2995 $(document).on('altAccessCheckComplete', function( event, postDataPianoFinal ) { 2996 initializePiano( postDataPianoFinal ); 2997 }); 2998 2999}(jQuery); 3000; 3001//~Singletons/UserAltAccess 3002// 3003// Helper funcs for evaluating alternate access - traffic from app, IP access, or link access 3004!function ($) { 3005 3006 // Check for FP.Singletons instance 3007 FP.Singletons = FP.Singletons || {}; 3008 3009 FP.Singletons.UserAltAccess = { 3010 3011 isIPAccess: false, 3012 isLinkAccess: false, 3013 ipAccessData: {}, 3014 linkAccessData: {}, 3015 3016 isAltAccess: function () { 3017 var that = this; 3018 3019 new Promise(function (resolve, reject) { 3020 return Promise.all([ 3021 that.getIpAccessData() 3022 /* that.getLinkAccessData() - REMOVED FOR NOW AS WE DON'T HAVE ANY LINK ACCESS CLIENTS */ 3023 ]) 3024 .then(function (results) { 3025 var ipAccessResults = results[0]; 3026 that.isIPAccess = ipAccessResults.access; 3027 3028 var postDataPianoFinal = postDataPiano; 3029 3030 if( that.isIPAccess ) { 3031 // set user data 3032 that.ipAccessData = ipAccessResults; 3033 3034 // Associate this visitor with their IP-access institution in Rudder 3035 document.dispatchEvent(new CustomEvent('rudder:group', { 3036 detail: { 3037 group_id: that.ipAccessData.client_guid, 3038 traits: { 3039 access_type: 'ip_access', 3040 client_name: that.ipAccessData.name, 3041 org_name: that.ipAccessData.org_name, 3042 piano_org_id: that.ipAccessData.piano_org_id, 3043 access_level: that.ipAccessData.access_level 3044 } 3045 } 3046 })); 3047 3048 // Reset 'article' value to avoid triggering paywall 3049 for (var i = 0; i < postDataPianoFinal.length; i++) { 3050 if (postDataPianoFinal[i] == 'article') postDataPianoFinal[i] = 'article-ipaccess'; 3051 } 3052 3053 // Add a new Piano tag to allow user access to Insider content 3054 if( that.ipAccessData.access_level === 'Insider' ) { 3055 postDataPianoFinal.push('article-ipaccess-insider'); 3056 } 3057 } else { 3058 // No IP access on this visit â clear any previously cached group association 3059 document.dispatchEvent(new CustomEvent('rudder:group', { 3060 detail: { group_id: null } 3061 })); 3062 } 3063 3064 // additional call to ensure vip-go-seg cookie gets set 3065 $.ajax({ 3066 type: 'POST', 3067 url: '/wp-admin/admin-ajax.php', 3068 data: { 3069 action: 'set_user_cache_group', 3070 ip_proxy_access_level: that.ipAccessData.access_level.toLowerCase(), 3071 token: pianoData.cache_group_nonce 3072 }, 3073 success: function( response ) { 3074 // handle response here if needed 3075 } 3076 }).done( resolve ).fail( reject ); 3077 3078 /* 3079 REMOVED FOR NOW AS WE DON'T HAVE ANY LINK ACCESS CLIENTS 3080 3081 var linkAccessResults = results[1]; 3082 that.isLinkAccess = linkAccessResults.access; 3083 3084 if( that.isLinkAccess ) { 3085 // set user data 3086 that.linkAccessData = linkAccessResults; 3087 // Reset 'article' value to avoid triggering paywall 3088 for (var i = 0; i < postDataPianoFinal.length; i++) { 3089 if (postDataPianoFinal[i] == 'article') postDataPianoFinal[i] = 'article-linkaccess'; 3090 } 3091 } 3092 */ 3093 3094 $.event.trigger('altAccessCheckComplete', [ postDataPianoFinal ]); 3095 3096 resolve(true); 3097 3098 }) 3099 .catch(function (results) { 3100 var ipAccessResults = results[0]; 3101 if( typeof ipAccessResults !== 'undefined' && typeof ipAccessResults.access !== 'undefined' ) { 3102 that.isIPAccess = ipAccessResults.access; 3103 } 3104 3105 $.event.trigger('altAccessCheckComplete', [ postDataPiano ]); 3106 resolve(true); 3107 }).finally(() => { 3108 // Added to dispatch event via vanilla JS in both instances 3109 const altEvt = new CustomEvent('accessAltComplete'); 3110 window.dispatchEvent(altEvt, FP.Singletons.UserAltAccess); 3111 }); 3112 }); 3113 return; 3114 3115 }, 3116 3117 3118 /** 3119 * Get IP access data from server 3120 * 3121 * E.g., 3122 * ```javascript 3123 * FP.Singletons.UserAltAccess.getIpAccessData( 3124 * function (data) { 3125 * // ... 3126 * }, 3127 * function (reason) { 3128 * // ... 3129 * } 3130 * ); 3131 * ``` 3132 * 3133 * @return {Promise} { 3134 * {Boolean} access 3135 * {null/String} access_type 3136 * {Number} expires 3137 * {null/String} client_guid 3138 * {null/String} message 3139 * } 3140 */ 3141 getIpAccessData: function () { 3142 return new Promise(getIpAccessDataHelper); 3143 }, 3144 3145 3146 /** 3147 * Get link access data from the server for the "Universal Link" concept 3148 * 3149 * E.g., 3150 * ```javascript 3151 * FP.Singletons.UserAltAccess.getLinkAccessData().then(data => console.log(data)); 3152 * // { access: false, message: '' } 3153 * ``` 3154 * 3155 * @return {Promise} { 3156 * {Number} ID 3157 * {Boolean} access 3158 * {String} message 3159 * } 3160 */ 3161 getLinkAccessData: function () { 3162 new Promise(function (resolve, reject) { 3163 var accessToken = getLinkAccessToken(); 3164 var cachedAccessToken = getCachedLinkAccessToken(); 3165 if (!accessToken && !cachedAccessToken) { 3166 setTimeout(function () { 3167 resolve({ 3168 ID: 0, 3169 access: false, 3170 message: '', 3171 }); 3172 }, 10); 3173 return; 3174 } 3175 3176 function format_string(format) { 3177 var args = Array.prototype.slice.call(arguments, 1); 3178 return format.replace(/{(\d+)}/g, function (match, index) { 3179 return undefined === args[index] ? match : args[index]; 3180 }); 3181 } 3182 3183 $.getJSON(format_string(FP.Config.api.link_access, (accessToken || cachedAccessToken))) 3184 .done(function (data) { 3185 resolve(data); 3186 if (accessToken && accessToken !== cachedAccessToken) { 3187 setCachedLinkAccessToken(accessToken); 3188 } 3189 }) 3190 .fail(reject); 3191 }) 3192 }, 3193 3194 3195 /** 3196 * Helper to determine whether user is coming from app; 3197 * if `true` we don't want to gate 3198 * 3199 * E.g., 3200 * ```javascript 3201 * console.log(FP.Singletons.UserAltAccess.isFromApp()); 3202 * // `true` or `false` 3203 * ``` 3204 * 3205 * @return {Boolean} 3206 */ 3207 isFromApp: (function () { 3208 var isFromApp = ( 3209 'true' === FP.Utils.url.getUrlParameter('app') 3210 ); 3211 return function () { 3212 return isFromApp; 3213 }; 3214 })(), 3215 }; 3216 3217 FP.Singletons.UserAltAccess.isAltAccess(); 3218 3219 3220 //=Constants 3221 var LOCALSTORAGE_ENC_KEY = 'FP-ip-access--enc'; 3222 var LOCALSTORAGE_LINK_ACCESS_KEY = 'FP-link-access--data'; 3223 var EXPIRATION_LINK_ACCESS_DATA = 1e3 * 60 * 60 * 24; //=24 hours in milliseconds 3224 3225 /** 3226 * Helper to retrieve IP access data 3227 * 3228 * @param {Function} resolve 3229 * @param {Function} reject 3230 */
3231 function getIpAccessDataHelper (resolve, reject) { 3232 // Retrieve data from server 3233 var data = {}; 3234 var enc = window.localStorage.getItem(LOCALSTORAGE_ENC_KEY); 3235 if (enc) { 3236 data.enc = enc; 3237 } else { 3238 data.proxy_host = document.location.hostname; 3239 } 3240 3241 $.ajax({ 3242 type: "POST", 3243 url: FP.Config.api.ip_access, 3244 data: data, 3245 timeout: 3000, 3246 success: function( response ) { 3247 if (response.enc) { 3248 window.localStorage.setItem(LOCALSTORAGE_ENC_KEY, response.enc); 3249 } else { 3250 window.localStorage.removeItem(LOCALSTORAGE_ENC_KEY); 3251 } 3252 resolve(response.pay); 3253 }, 3254 error: function( jqXHR, textStatus, errorThrown ) { 3255 window.localStorage.removeItem(LOCALSTORAGE_ENC_KEY); 3256 } 3257 }) 3258 .done( resolve ) 3259 .fail(function () { 3260 reject([{ 3261 access: false, 3262 access_type: null, 3263 expires: -1, 3264 client_guid: null, 3265 message: null 3266 }]); 3267 }); 3268 } 3269 3270 3271 /** 3272 * Helper to get link access token match from URL hash 3273 * 3274 * @return {String} 3275 */ 3276 function getLinkAccessToken () { 3277 var result = /(?:^k|\Wk)\/([%.~\w-]+)\//.exec(document.location.hash); 3278 return (result !== null && result[1]) || ''; 3279 } 3280 3281 3282 /** 3283 * Helper to get cached link access token if available 3284 * 3285 * @return {String} 3286 */ 3287 function getCachedLinkAccessToken () { 3288 var cachedData = JSON.parse(window.localStorage.getItem(LOCALSTORAGE_LINK_ACCESS_KEY)); 3289 if ( 3290 !cachedData || 3291 !cachedData.token || 3292 !cachedData.expires || 3293 (new Date()).getTime() >= cachedData.expires 3294 ) { 3295 window.localStorage.removeItem(LOCALSTORAGE_LINK_ACCESS_KEY); 3296 return ''; 3297 } 3298 return cachedData.token; 3299 } 3300 3301 3302 /** 3303 * Helper to set cached link access token 3304 * 3305 * @param {String} accessToken 3306 */ 3307 function setCachedLinkAccessToken (accessToken) { 3308 if (!accessToken) { 3309 return; 3310 } 3311 window.localStorage.setItem(LOCALSTORAGE_LINK_ACCESS_KEY, JSON.stringify({ 3312 token: accessToken, 3313 expires: (new Date()).getTime() + EXPIRATION_LINK_ACCESS_DATA 3314 })); 3315 } 3316 3317 3318 /** 3319 * Helper to show IP message to specific users 3320 * 3321 * @param {String} ipAccessRecord 3322 */ 3323 function showIPMessage (ipAccessRecord) { 3324 var guidsToTarget = [ 3325 '02ec422849c64bce852ddd1d0fef7dc2', // Ministry of Defence UK 3326 '54635fd3a57e4780aa661658f73f4ad2', // Australian Department of Foreign Affairs 3327 'dbaeae4f0b5442ef8a26a5aaeb65f87c', // Congressional Research Service 3328 'e4f4504bcb754855a923152216edf04b', // Council de EU 3329 '30863845273342dcaee3e48f86ce4990', // Canadian Parliament 3330 ]; 3331 if( guidsToTarget.indexOf(ipAccessRecord.client_guid) > -1 ) { 3332 $('.ip-access-note-in-post').show(); 3333 } 3334 } 3335 3336}(jQuery); 3337;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.