PageSourceSearch

https://foreignpolicy.com/_static/??-eJy1ksFOwzAMhl+I1AuamDggHmVKg…CtBguXymtvSXFDz7dVrfLG75421W/u0HT8B2a6OLQ==

js foreignpolicy.com collected 2026-09-24 06:33:29 UTC 275,856 bytes, 3,337 lines download raw bytes

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( '&#10003;&nbsp;&nbsp;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>&#10003;&nbsp;&nbsp;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.