{"version":3,"file":"default/js/search.js","sources":["webpack:///webpack/bootstrap","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/components/core/eventMgr.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/components/search.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/constructorio/clientWrapper.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/constructorio/components/refinements.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/constructorio/components/tiles.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/constructorio/constructorIO.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/constructorio/constructorIOPLP.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/constructorio/request.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/constructorio/utils/utils.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/layout.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/product/productIdCookie.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/search/search.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/util.js","webpack:///./cartridges/app_ua_core/cartridge/client/default/js/utils/device.js","webpack:///./cartridges/app_ua_emea/cartridge/client/default/js/search.js","webpack:///./cartridges/app_ua_emea/cartridge/client/default/js/search/search.js","webpack:///./cartridges/storefront-reference-architecture/cartridges/app_storefront_base/cartridge/client/default/js/util.js","webpack:///./node_modules/@babel/runtime/helpers/arrayLikeToArray.js","webpack:///./node_modules/@babel/runtime/helpers/arrayWithoutHoles.js","webpack:///./node_modules/@babel/runtime/helpers/classCallCheck.js","webpack:///./node_modules/@babel/runtime/helpers/createClass.js","webpack:///./node_modules/@babel/runtime/helpers/defineProperty.js","webpack:///./node_modules/@babel/runtime/helpers/interopRequireDefault.js","webpack:///./node_modules/@babel/runtime/helpers/iterableToArray.js","webpack:///./node_modules/@babel/runtime/helpers/nonIterableSpread.js","webpack:///./node_modules/@babel/runtime/helpers/toConsumableArray.js","webpack:///./node_modules/@babel/runtime/helpers/toPrimitive.js","webpack:///./node_modules/@babel/runtime/helpers/toPropertyKey.js","webpack:///./node_modules/@babel/runtime/helpers/typeof.js","webpack:///./node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/constructorio.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/modules/autocomplete.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/modules/browse.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/modules/quizzes.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/modules/recommendations.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/modules/search.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/modules/tracker.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/utils/botlist.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/utils/event-dispatcher.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/utils/helpers.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/utils/humanity-check.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/utils/request-queue.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/utils/store.js","webpack:///./node_modules/@constructor-io/constructorio-client-javascript/lib/utils/store.overflow.js","webpack:///./node_modules/@constructor-io/constructorio-id/src/constructorio-id.js","webpack:///./node_modules/branch-sdk/dist/build.min.js","webpack:///./node_modules/crc-32/crc32.js","webpack:///./node_modules/events/events.js","webpack:///./node_modules/fetch-ponyfill/build/fetch-browser.js","webpack:///./node_modules/js-cookie/dist/js.cookie.js","webpack:///./node_modules/lodash/_Symbol.js","webpack:///./node_modules/lodash/_baseGetTag.js","webpack:///./node_modules/lodash/_baseTrim.js","webpack:///./node_modules/lodash/_freeGlobal.js","webpack:///./node_modules/lodash/_getRawTag.js","webpack:///./node_modules/lodash/_objectToString.js","webpack:///./node_modules/lodash/_root.js","webpack:///./node_modules/lodash/_trimmedEndIndex.js","webpack:///./node_modules/lodash/debounce.js","webpack:///./node_modules/lodash/isObject.js","webpack:///./node_modules/lodash/isObjectLike.js","webpack:///./node_modules/lodash/isSymbol.js","webpack:///./node_modules/lodash/lodash.js","webpack:///./node_modules/lodash/now.js","webpack:///./node_modules/lodash/toNumber.js","webpack:///./node_modules/process/browser.js","webpack:///./node_modules/store2/dist/store2.js","webpack:///(webpack)/buildin/amd-options.js","webpack:///(webpack)/buildin/global.js","webpack:///(webpack)/buildin/module.js"],"sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./cartridges/app_ua_emea/cartridge/client/default/js/search.js\");\n","import EventEmitter from 'events';\n\nvar emitter = new EventEmitter();\nvar emitters = [];\nvar actions = {};\n\nemitter.setMaxListeners(3000);\n\nconst eventMgr = {\n getEmitter: (namespace) => {\n if (emitters.indexOf(namespace) > -1) {\n if (window.console) {\n window.console.log('EventMgr: Given namespace \"' + namespace\n + '\" already exists. Event emitter creation failed.');\n }\n return {\n emit: () => false\n };\n }\n emitters.push(namespace);\n return {\n emit: function (eventName) {\n arguments[0] = namespace + '.' + eventName;\n return emitter.emit(...arguments);\n }\n };\n },\n on: (eventName, cb) => emitter.on(eventName, cb),\n off: (eventName, cb) => emitter.removeListener(eventName, cb),\n once: (eventName, cb) => emitter.once(eventName, cb),\n registerAction: (actionName, handler) => {\n if (actions[actionName] && window.console) {\n window.console.warn(`Overriding \"${actionName}\"!`);\n }\n actions[actionName] = handler;\n }\n};\n\n// make it global\nwindow.eventMgr = eventMgr;\n\nexport default eventMgr;\n","'use strict';\n\nconst debounce = require('lodash/debounce');\nconst layout = require('../layout');\nconst productCookieId = require('../product/productIdCookie');\nconst constructorIOHelper = require('../constructorio/constructorIO');\nconst { getConstructorIOSettings } = require('../constructorio/clientWrapper');\n\nconst UP_KEY = 38;\nconst DOWN_KEY = 40;\nconst DIRECTION_DOWN = 1;\nconst DIRECTION_UP = -1;\n\nlet $body;\n\n/**\n * Starts the spinner.\n */\nconst startSpinner = () => {\n $.spinner().start();\n};\n\n/**\n * Stops the spinner.\n */\nconst stopSpinner = () => {\n $.spinner().stop();\n};\n\n/**\n * Retrieves Suggestions element relative to scope\n *\n * @param {Object} scope - Search input field DOM element\n * @return {JQuery} - .js-suggestions-wrapper element\n */\nfunction getSuggestionsWrapper(scope) {\n return $(scope).closest('.js-search-container').siblings('.js-suggestions-wrapper');\n}\n\n/**\n * Determines whether DOM element is inside the .search-mobile class\n *\n * @param {Object} scope - DOM element, usually the input.js-search-field element\n * @return {boolean} - Whether DOM element is inside div.search-mobile\n */\nfunction isMobileSearch(scope) {\n return !!$(scope).closest('.search-mobile').length;\n}\n\n/**\n * Remove modal classes needed for mobile suggestions\n *\n */\nfunction clearModals() {\n $body.removeClass('modal-open');\n $('header').siblings().attr('aria-hidden', 'false');\n $('.js-suggestions').removeClass('modal');\n}\n\n/**\n * Apply modal classes needed for mobile suggestions\n *\n * @param {Object} scope - Search input field DOM element\n */\nfunction applyModals(scope) {\n if (isMobileSearch(scope)) {\n $body.addClass('modal-open');\n $('header').siblings().attr('aria-hidden', 'true');\n getSuggestionsWrapper(scope).find('.js-suggestions').addClass('modal');\n }\n}\n\n/**\n * Tear down Suggestions panel\n */\nfunction tearDownSuggestions() {\n $('input.js-search-field').val('');\n clearModals();\n $('.search-mobile .js-suggestions').unbind('scroll');\n $('.js-suggestions-wrapper').empty();\n}\n\n/**\n * Toggle search field icon from search to close and vice-versa\n *\n * @param {string} action - Action to toggle to\n */\nfunction toggleSuggestionsIcon(action) {\n var mobileSearchIcon = '.search-mobile button.';\n var iconSearch = 'fa-search';\n var iconSearchClose = 'fa-close';\n\n if (action === 'close') {\n $(mobileSearchIcon + iconSearch).removeClass(iconSearch).addClass(iconSearchClose).attr('type', 'button');\n } else {\n $(mobileSearchIcon + iconSearchClose).removeClass(iconSearchClose).addClass(iconSearch).attr('type', 'submit');\n }\n}\n\n/**\n * Determines whether the \"More Content Below\" icon should be displayed\n *\n * @param {Object} scope - DOM element, usually the input.js-search-field element\n */\nfunction handleMoreContentBelowIcon(scope) {\n if (($(scope).scrollTop() + $(scope).innerHeight()) >= $(scope)[0].scrollHeight) {\n $('.more-below').fadeOut();\n } else {\n $('.more-below').fadeIn();\n }\n}\n\n/**\n * Positions Suggestions panel on page\n *\n * @param {Object} scope - DOM element, usually the input.js-search-field element\n */\nfunction positionSuggestions(scope) {\n var outerHeight;\n var $scope;\n var $suggestions;\n var top;\n\n if (isMobileSearch(scope)) {\n $scope = $(scope);\n top = $scope.offset().top;\n outerHeight = $scope.outerHeight();\n $suggestions = getSuggestionsWrapper(scope).find('.js-suggestions');\n $suggestions.css('top', top + outerHeight);\n\n handleMoreContentBelowIcon(scope);\n\n // Unfortunately, we have to bind this dynamically, as the live scroll event was not\n // properly detecting dynamic suggestions element's scroll event\n $suggestions.scroll(function () {\n handleMoreContentBelowIcon(this);\n });\n }\n}\n\n/**\n * Recently viewed cookie function\n */\nfunction recentlyViewedBadge() {\n // Get pvpIDs cookie\n var productIds = productCookieId.getCookie('pvpIDs').split(',');\n $('.b-tile_badge-recently-viewed').css('display', 'none');\n // if product ID is in cookie, find recently viewed & show\n if (productIds !== ['']) {\n productIds.forEach(value => {\n var values = document.querySelectorAll('[data-product=\"' + value + '\"]');\n if (values.length) {\n var recentlyViewed = values[0].querySelector('.b-tile_badge-recently-viewed');\n var hideTopLeftBadge = values[0].querySelector('.hide-top_left_badge');\n var hideFlameIconBadge = values[0].querySelector('.b-tile-badge_top_left.b-flameIcon');\n if (recentlyViewed) {\n recentlyViewed.style.display = 'block';\n if (hideTopLeftBadge) hideTopLeftBadge.style.display = 'none';\n if (hideFlameIconBadge) hideFlameIconBadge.style.display = 'none';\n }\n }\n });\n }\n}\n\n/**\n * Triggers the 'components:init' event on the body element.\n */\nconst triggerComponentsInit = () => {\n // Init swatch slider\n $body.trigger('components:init');\n};\n\n/**\n * Process Ajax response for SearchServices-GetSuggestions\n *\n * @param {Object|string} response - Empty object literal if null response or string with rendered\n * suggestions template contents\n * @returns {Promise} Promise resolving when all operations have completed.\n */\nconst processResponse = (response) => {\n return new Promise((resolve) => {\n const $suggestionsWrapper = $('.js-suggestions-wrapper').empty();\n const searchField = $('input.js-search-field');\n\n stopSpinner();\n\n if (typeof response !== 'object') {\n $suggestionsWrapper.append(response).show();\n\n $(this).closest('.js-search-container').addClass('m-suggestions-show');\n positionSuggestions(this);\n\n if (isMobileSearch(this)) {\n toggleSuggestionsIcon('close');\n applyModals(this);\n }\n\n // Trigger screen reader by setting aria-describedby with the new suggestion message.\n const suggestionsList = $('.js-suggestions .js-item');\n if (suggestionsList.length) {\n searchField.attr('aria-describedby', 'search-result-count');\n } else {\n searchField.removeAttr('aria-describedby');\n }\n\n recentlyViewedBadge();\n\n // Hide the product tile if no image configured\n $suggestionsWrapper.find('.b-tile.hide').parent('.b-suggestions_products-item').addClass('hide');\n } else {\n $suggestionsWrapper.hide();\n }\n\n $('body').trigger('wishlistSuggestion:update');\n\n resolve();\n });\n};\n\n/**\n * Retrieves default suggestions using an AJAX request.\n *\n * @param {Object} scope - Search field DOM element.\n * @returns {Promise} Promise that resolves with the default suggestions.\n */\nconst getDefaultSuggestions = (scope) => {\n const endpoint = $('.js-suggestions-wrapper').data('url');\n\n return new Promise((resolve, reject) => {\n $.ajax({\n context: scope,\n url: endpoint + encodeURIComponent($(scope).val()),\n method: 'GET',\n data: {\n isMobilePortraitView: layout.isExtraSmallView()\n },\n success: resolve,\n error: reject\n });\n });\n};\n\n/**\n * Falls back to default suggestions if an error occurs.\n *\n * @param {Object} scope - Search field DOM element.\n * @param {Function} processSuggestions - Function to process suggestions.\n * @returns {Promise} Promise that resolves to the default suggestions.\n */\nconst defaultSuggestions = (scope, processSuggestions) => {\n return getDefaultSuggestions(scope)\n .then(processSuggestions)\n .catch(stopSpinner());\n};\n\n/**\n * Retrieve suggestions\n *\n * @param {Object} scope - Search field DOM element\n */\nconst getSuggestions = (scope) => {\n const $scope = $(scope);\n const inputLength = $scope.val().length;\n const minChars = $scope.data('min-chars');\n\n if (inputLength >= minChars) {\n startSpinner();\n\n const processSuggestions = processResponse.bind(scope);\n const handleDefaultSuggestions = () => defaultSuggestions(scope, processSuggestions);\n\n const cIOSettings = getConstructorIOSettings();\n\n if (cIOSettings && cIOSettings.search_enabled) {\n constructorIOHelper.getConstructorioSuggestions($scope.val())\n .then(constructorIOHelper.convertCIOToHTMLString)\n .then(processSuggestions)\n .then(triggerComponentsInit)\n .catch(handleDefaultSuggestions);\n } else {\n handleDefaultSuggestions();\n }\n } else {\n toggleSuggestionsIcon('search');\n $scope.closest('.js-search-container').removeClass('m-suggestions-show');\n clearModals();\n getSuggestionsWrapper(scope).empty();\n }\n};\n\n/**\n * Handle Search Suggestion Keyboard Arrow Keys\n *\n * @param {Integer} direction takes positive or negative number constant, DIRECTION_UP (-1) or DIRECTION_DOWN (+1)\n */\nfunction handleArrow(direction) {\n // get all li elements in the suggestions list\n var suggestionsList = $('.js-suggestions .js-item');\n if (suggestionsList.filter('.selected').length === 0) {\n suggestionsList.first().addClass('selected');\n $('input.js-search-field').each(function () {\n $(this).attr('aria-activedescendant', suggestionsList.first()[0].id);\n });\n } else {\n suggestionsList.each(function (index) {\n var idx = index + direction;\n if ($(this).hasClass('selected')) {\n $(this).removeClass('selected');\n $(this).removeAttr('aria-selected');\n if (suggestionsList.eq(idx).length !== 0) {\n suggestionsList.eq(idx).addClass('selected');\n suggestionsList.eq(idx).attr('aria-selected', true);\n $(this).removeProp('aria-selected');\n $('input.js-search-field').each(function () {\n $(this).attr('aria-activedescendant', suggestionsList.eq(idx)[0].id);\n });\n } else {\n suggestionsList.first().addClass('selected');\n suggestionsList.first().attr('aria-selected', true);\n $('input.js-search-field').each(function () {\n $(this).attr('aria-activedescendant', suggestionsList.first()[0].id);\n });\n }\n return false;\n }\n return true;\n });\n }\n}\n\n/**\n * Set top position of filter and sort button section for mobile view\n */\nfunction setSectionTop() {\n setTimeout(() => {\n var headHeight = $('.l-body-page_header').height();\n $('.l-plp-mob_header.b-mob_header').css('top', (headHeight - 1) + 'px');\n $('.l-body-page').css('padding-top', headHeight + 'px');\n }, 500);\n}\n\nmodule.exports = {\n init: function () {\n $body = $('body');\n\n $('form[name=\"simpleSearch\"]').submit(function (e) {\n var currentSite = $(this).attr('data-currentsite');\n var minChar = $('.js-site-search .js-search-field').attr('data-min-chars');\n var inputLength = $('.js-site-search .js-search-field').val().length;\n\n var isValidSearch = true;\n\n if ((currentSite === 'UKIE' || currentSite === 'EU') && inputLength < minChar) {\n isValidSearch = false;\n }\n\n if (isValidSearch) {\n var suggestionsList = $('.js-suggestions .js-item');\n if (suggestionsList.filter('.selected').length !== 0) {\n e.preventDefault();\n suggestionsList.filter('.selected').find('a')[0].click();\n }\n } else {\n e.preventDefault();\n $('.js-site-search .js-search-field').val('');\n $('.js-site-search .js-search-field').blur();\n }\n });\n\n $('input.js-search-field').each(function () {\n /**\n * Use debounce to avoid making an Ajax call on every single key press by waiting a few\n * hundred milliseconds before making the request. Without debounce, the user sees the\n * browser blink with every key press.\n */\n var debounceSuggestions = debounce(getSuggestions, 300);\n $(this).on('keyup paste focus', function (e) {\n // Capture Down/Up Arrow Key Events\n switch (e.which) {\n case DOWN_KEY:\n handleArrow(DIRECTION_DOWN);\n e.preventDefault(); // prevent moving the cursor\n break;\n case UP_KEY:\n handleArrow(DIRECTION_UP);\n e.preventDefault(); // prevent moving the cursor\n break;\n default:\n debounceSuggestions(this, e);\n }\n });\n });\n\n $body.on('click', function (e) {\n if (!$('.js-suggestions').has(e.target).length && !$(e.target).hasClass('js-search-field')) {\n $('.js-suggestions').hide();\n }\n });\n\n $body.on('click touchend', '.search-mobile button.fa-close', function (e) {\n e.preventDefault();\n $('.js-suggestions').hide();\n toggleSuggestionsIcon('search');\n tearDownSuggestions();\n });\n\n $('.js-site-search .js-search-clear').on('click', function () {\n $(this).closest('.js-search-container').removeClass('m-suggestions-show');\n });\n\n setSectionTop();\n $(window).on('resize', setSectionTop());\n },\n recentlyViewedBadge\n};\n","'use strict';\n\nconst ConstructorioClient = require('@constructor-io/constructorio-client-javascript');\nconst { constructorIOSettings } = window;\nconst { cloneDeep } = require('lodash');\nlet constructorIOInstance;\nlet cIOSettings = null;\n\nconst parseJSON = (source, placeholder) =>{\n let result;\n try {\n result = JSON.parse(source);\n } catch (error) {\n result = placeholder;\n }\n return result || placeholder;\n};\n\n\nconst getCustomerGroups = () => {\n const customerGroupsSourceEl = document.querySelector('.b-header_account');\n cIOSettings.customerGroups = parseJSON(customerGroupsSourceEl && customerGroupsSourceEl.dataset ? customerGroupsSourceEl.dataset.customerGroups : '', []);\n};\n\n/**\n * Initializes and returns the ConstructorIO client.\n *\n * @returns {Object|null} - The initialized ConstructorIO client or null if apiKey is not provided.\n */\nconst initConstructorIO = () => {\n if (constructorIOSettings && constructorIOSettings.apiKey) {\n const settings = {\n apiKey: constructorIOSettings.apiKey\n };\n\n if (constructorIOSettings.serviceUrl) {\n settings.serviceUrl = constructorIOSettings.serviceUrl;\n }\n if (constructorIOSettings.customerEmail) {\n settings.userId = constructorIOSettings.customerEmail;\n }\n\n constructorIOInstance = new ConstructorioClient(settings);\n }\n\n return constructorIOInstance;\n};\n\n/**\n * Gets the ConstructorIO client. If not initialized, it will initialize it first.\n *\n * @returns {Object} - The ConstructorIO client.\n */\nconst getConstructorIOClient = () => {\n return constructorIOInstance || initConstructorIO();\n};\n\nconst getConstructorIOSettings = () => {\n if (!cIOSettings) {\n const {\n constructorIOSettings: constructorIOSettingsData = {}\n } = window;\n cIOSettings = cloneDeep(constructorIOSettingsData);\n cIOSettings.ROUTE_REFINEMENT_ATTRIBUTES = parseJSON(constructorIOSettingsData.routeRefinements, []);\n cIOSettings.SORT_OPTIONS_URL_MAP = parseJSON(constructorIOSettingsData.sortOptionsURLMap, {});\n cIOSettings.CIO_SORT_OPTIONS_MAP = parseJSON(constructorIOSettingsData.constructorIOSortOptionsMap, {});\n // eslint-disable-next-line no-nested-ternary\n cIOSettings.PRICE_RANGE = !constructorIOSettingsData ? {} : typeof constructorIOSettingsData.priceRange === 'string' ? parseJSON(constructorIOSettingsData.priceRange) : typeof constructorIOSettingsData.priceRange === 'object' && constructorIOSettingsData.priceRange ? constructorIOSettingsData.priceRange : {};\n\n cIOSettings.DEFAULT_CUTOFFTHRESHOLD = constructorIOSettingsData.defaultCutoffThreshold || 5;\n cIOSettings.DISPLAYABLE_REFINEMENT_CATEGORIES = parseJSON(constructorIOSettingsData.displayableRefinementCategories, {});\n cIOSettings.SIZE_SORT_RULES = parseJSON(constructorIOSettingsData.sizeSortRules, {});\n cIOSettings.SIZE_RANGE_MAP = parseJSON(constructorIOSettingsData.sizeRangeMap, {});\n\n\n cIOSettings.variationMap = parseJSON(constructorIOSettingsData.variationMap, undefined);\n cIOSettings.customerGroups = parseJSON(constructorIOSettingsData.customerGroups, []);\n if (document.readyState === 'complete') {\n getCustomerGroups();\n } else {\n document.addEventListener('DOMContentLoaded', getCustomerGroups);\n }\n }\n return cIOSettings;\n};\n\n/**\n * Wrapper around ConstructorIO client functionalities.\n * @typedef {Object} ClientWrapper\n * @property {function} getConstructorIOClient - Function to get the ConstructorIO client.\n */\nconst clientWrapper = {\n getConstructorIOSettings,\n getResource: (key)=> (window.constructorIOResources ? window.constructorIOResources[key] : ''),\n getURL: (key) => window.constructorIOURLs && typeof window.constructorIOURLs[key] === 'string' ? window.constructorIOURLs[key] : '',\n getConstructorIOClient\n};\n\nmodule.exports = clientWrapper;\n","/* eslint-disable no-restricted-globals */\n/* eslint-disable no-mixed-operators */\n\nconst {\n generatePLPURL,\n getPriceRange\n} = require('../utils/utils');\nconst {\n getConstructorIOSettings,\n getURL,\n getResource\n} = require('../clientWrapper');\nconst { cloneDeep } = require('lodash');\n\nconst getSizeSortIndex = (value) => {\n const { SIZE_SORT_RULES } = getConstructorIOSettings();\n if (SIZE_SORT_RULES && SIZE_SORT_RULES[value]) {\n return SIZE_SORT_RULES[value];\n }\n if (value.includes('K')) {\n const youthSizes = value.split('K');\n return parseInt(youthSizes[0], 10) + 100;\n }\n if (value.includes('/')) {\n const pants = value.split('/');\n return 300 + parseInt(pants[0], 10) + parseInt(pants[1], 10);\n }\n if (!isNaN(parseInt(value, 10))) {\n const shoeSizes = parseInt(value, 10);\n return 200 + shoeSizes;\n }\n\n return 10000;\n};\n\nconst getShowMoreButton = () => {\n const resources = {\n 'refinements.show.button': getResource('refinements.show.button'),\n 'refinements.hide.button': getResource('refinements.hide.button')\n };\n\n return `\n `;\n};\n\nconst getRefinementOptionsArray = (allFacets, facet) => {\n let options = facet.options;\n const category = facet.name;\n const lcCategory = category.toLowerCase();\n const { SIZE_RANGE_MAP, DISPLAYABLE_REFINEMENT_CATEGORIES } = getConstructorIOSettings();\n const isPrice = DISPLAYABLE_REFINEMENT_CATEGORIES[facet.name].isPrice;\n const isSize = !isPrice && lcCategory === 'size';\n\n if (isPrice) {\n if (window.searchParams && window.searchParams.buckets) {\n options = window.searchParams.buckets;\n } else {\n options = [];\n }\n\n allFacets.forEach((facetCategory) => {\n if (facetCategory.name === 'salePriceLow' || facetCategory.name.includes('Price ')) {\n const mergedArray = [...options, ...facetCategory.options];\n\n let set = new Set();\n options = mergedArray.filter((item) => {\n if (!set.has(item.display_name) && item.range) {\n set.add(item.display_name);\n return true;\n }\n return false;\n });\n }\n });\n const selectedOption = options.find(o => {\n const priceRange = getPriceRange(o);\n return JSON.stringify(priceRange) === JSON.stringify(window.searchParams.priceRange);\n });\n const searchBuckets = cloneDeep(window.searchParams.buckets);\n if (selectedOption && selectedOption.value) {\n options = searchBuckets.map((bucket) => bucket.display_name === selectedOption.display_name ? Object.assign(bucket, { status: 'selected' }) : bucket);\n } else {\n options = searchBuckets;\n }\n options = options.sort((a, b) => getPriceRange(window.searchParams.buckets.find(i => i.display_name === a.display_name))[0] - getPriceRange(window.searchParams.buckets.find(i => i.display_name === b.display_name))[0]);\n } else if (isSize) {\n options.sort((a, b) => getSizeSortIndex(a.value) - getSizeSortIndex(b.value));\n } else if (lcCategory === 'length') {\n // Update Size Range Filter names\n options = options.map((o) => {\n const opt = cloneDeep(o);\n if (SIZE_RANGE_MAP[o.value]) opt.display_name = SIZE_RANGE_MAP[o.value];\n return opt;\n });\n } else if (lcCategory === 'discountpercentage') {\n // Update Discount filter\n options = options.map((o) => {\n const opt = cloneDeep(o);\n let disVal = o.value;\n if (disVal) {\n opt.display_name = getResource('refinement.discountpercentage.' + disVal);\n }\n return opt;\n });\n options = options.sort((a, b) => a.value - b.value);\n }\n\n return options;\n};\n\nconst buildRefinementOptions = (facet, options, cutoffThreshold) => {\n let refinementOptions = '';\n const { DISPLAYABLE_REFINEMENT_CATEGORIES } = getConstructorIOSettings();\n const category = facet.name;\n const categoryDisplayName = DISPLAYABLE_REFINEMENT_CATEGORIES[facet.name].displayName;\n const isPrice = DISPLAYABLE_REFINEMENT_CATEGORIES[facet.name].isPrice;\n const lcCategory = category.toLowerCase();\n const isSize = !isPrice && lcCategory === 'size';\n\n const resources = {\n 'refine.title': getResource('refine.title')\n };\n\n if (lcCategory === 'colorgroup') {\n options.forEach((option, index) => {\n const urlConfig = { params: { filterParams: { [category]: option.value }, start: 0 }, action: 'toggle' };\n const hrefUrl = generatePLPURL(urlConfig);\n const dataUrl = generatePLPURL(Object.assign({}, urlConfig, { url: getURL('searchShowAjax') }));\n const isSelected = option.status === 'selected';\n const noBorderClass = (option.data && (option.data.hexCode === '#fff' || option.data.hexCode === '#ffffff')) ? '' : ' no-border';\n let backgroundStyle = '';\n\n if (option.data && option.data.hexCode) {\n backgroundStyle = `background-color: ${option.data.hexCode};`;\n } else if (option.data && option.data.imgUrl) {\n backgroundStyle = `background: ${option.data.imgUrl};`;\n }\n\n refinementOptions = refinementOptions.concat(\n `
  • \n \n \n \n
  • `\n );\n });\n } else if (isPrice) {\n options.forEach((option, index) => {\n const isSelected = option.status === 'selected';\n let priceRange;\n const optionData = window.searchParams.buckets.find(\n (item) => item.display_name === option.display_name\n );\n if (\n !isSelected\n && optionData\n ) {\n priceRange = getPriceRange(optionData);\n }\n const urlConfig = { params: { priceRange, start: 0 } };\n const hrefUrl = generatePLPURL(urlConfig);\n const dataUrl = generatePLPURL(Object.assign({}, urlConfig, { url: getURL('searchShowAjax') }));\n\n refinementOptions = refinementOptions.concat(\n `
  • \n \n ${option.display_name} (${option.count})\n \n
  • `\n );\n });\n } else if (isSize) {\n options.forEach((option, index) => {\n const urlConfig = { params: { filterParams: { [category]: option.value }, start: 0 }, action: 'toggle' };\n const hrefUrl = generatePLPURL(urlConfig);\n const dataUrl = generatePLPURL(Object.assign({}, urlConfig, { url: getURL('searchShowAjax') }));\n const isSelected = option.status === 'selected';\n\n refinementOptions = refinementOptions.concat(\n `
  • \n \n ${option.display_name}\n \n
  • `\n );\n });\n } else if (lcCategory === 'discountpercentage') {\n options.forEach((option, index) => {\n const urlConfig = { params: { filterParams: { [category]: option.value }, start: 0 }, action: 'toggle' };\n const hrefUrl = generatePLPURL(urlConfig);\n const dataUrl = generatePLPURL(Object.assign({}, urlConfig, { url: getURL('searchShowAjax') }));\n const isSelected = option.status === 'selected';\n const displayCnt = option.count > 0 ? '(' + option.count + ')' : '';\n\n refinementOptions = refinementOptions.concat(\n `
  • \n \n ${option.display_name}${displayCnt}\n \n
  • `\n );\n });\n } else {\n options.forEach((option, index) => {\n const urlConfig = { params: { filterParams: { [category]: option.value }, start: 0 }, action: 'toggle' };\n const hrefUrl = generatePLPURL(urlConfig);\n const dataUrl = generatePLPURL(Object.assign({}, urlConfig, { url: getURL('searchShowAjax') }));\n const isSelected = option.status === 'selected';\n\n if (option.value !== 'N/A') {\n refinementOptions = refinementOptions.concat(\n `
  • \n \n ${option.display_name}\n \n
  • `\n );\n }\n });\n }\n\n return refinementOptions;\n};\n\nconst buildRefinementCategory = (cioFacets, selectedFilters) => {\n let refinementCategories = '';\n const { DISPLAYABLE_REFINEMENT_CATEGORIES, DEFAULT_CUTOFFTHRESHOLD } = getConstructorIOSettings();\n\n cioFacets.forEach((facet) => {\n if (DISPLAYABLE_REFINEMENT_CATEGORIES[facet.name]) {\n const cutoffThreshold = DISPLAYABLE_REFINEMENT_CATEGORIES[facet.name].cutoffThreshold || DEFAULT_CUTOFFTHRESHOLD;\n const isPrice = DISPLAYABLE_REFINEMENT_CATEGORIES[facet.name].isPrice;\n const showFacetOptionsCutOff = cutoffThreshold && facet.options.length > cutoffThreshold;\n const options = getRefinementOptionsArray(cioFacets, facet);\n const optionsHtml = buildRefinementOptions(facet, options, showFacetOptionsCutOff && cutoffThreshold);\n let selectedValuesArr = selectedFilters[facet.name] && selectedFilters[facet.name].options || [];\n\n if (isPrice && options.length > 0) {\n selectedValuesArr = options.find((o) => o.status === 'selected') || [];\n }\n\n const selectedValuesLength = selectedValuesArr.length;\n const isCollapsed = selectedValuesLength === 0;\n const containerClass = isPrice ? 'b-refinements_price b-show_more m-collapsed js-refinements-parent' : 'b-refinements_attributes b-show_more js-refinements-parent m-collapsed';\n const ulClass = isPrice ? 'b-refinements_price-list b-show_more-list' : 'b-refinements_attributes-list b-swatches b-show_more-list';\n const resources = {\n 'refinements.amount': getResource('refinements.amount')\n };\n\n refinementCategories = refinementCategories.concat(\n `
    \n \n ${DISPLAYABLE_REFINEMENT_CATEGORIES[facet.name].displayName}\n ${selectedValuesLength > 0 ? resources['refinements.amount'].supplant([selectedValuesLength]) : ''}\n
    \n
    \n
    \n
      \n ${optionsHtml}\n
    \n ${showFacetOptionsCutOff ? getShowMoreButton() : ''}\n
    \n
    \n `\n );\n }\n });\n\n return refinementCategories;\n};\n\nconst getClearAllButton = (selectedFilters) => {\n const resources = {\n 'refinements.clear': getResource('refinements.clear')\n };\n const selectedFilterKeys = selectedFilters && Object.keys(selectedFilters) || [];\n const showClearAllButton = selectedFilterKeys.length > 0 && !(selectedFilterKeys.length === 1 && selectedFilterKeys.some(selectedFilterKey => ['isMFOItem', 'experienceType', 'premiumFilter'].indexOf(selectedFilterKey) > -1));\n if (!showClearAllButton) {\n return '';\n }\n\n const urlConfig = {\n params: {\n filterParams: {}, start: 0, priceRange: null, sortRule: null\n }\n };\n const hrefUrl = generatePLPURL(urlConfig);\n const dataUrl = generatePLPURL(Object.assign({}, urlConfig, { url: getURL('searchShowAjax') }));\n return `\n
    \n \n ${resources['refinements.clear']}\n \n
    `;\n};\n\nconst getMobileSorting = (sortingOptions) => {\n const resources = {\n sort: getResource('label.sort')\n };\n const sortingRules = getResource('sortingRules') || {};\n const { SORT_OPTIONS_URL_MAP } = getConstructorIOSettings();\n\n return `\n
    \n
    \n ${resources.sort}\n
    \n
    \n
      \n ${sortingOptions.map(sortingOption => {\n const id = SORT_OPTIONS_URL_MAP[sortingOption.sort_by][sortingOption.sort_order].name;\n const isSelected = sortingOption.status === 'selected';\n const displayName = sortingRules[[sortingOption.sort_by.toLowerCase(), sortingOption.sort_order.toLowerCase()].join('.')] || sortingRules[sortingOption.sort_by.toLowerCase()] || sortingOption.display_name;\n\n return `\n
    • \n \n \n
    • \n `;\n }).join('')}\n
    \n
    \n
    `;\n};\n\nconst getMobileFilterFooter = (productsCount) => {\n const resources = {\n 'refinements.apply': getResource('refinements.apply')\n };\n return `\n
    \n \n
    \n `;\n};\n\nconst getRefinementsHtml = ({\n facets, selectedFilters, sortingOptions = [], productsCount\n}) => {\n const categories = buildRefinementCategory(facets, selectedFilters);\n const categoryConfig = {\n initOnDevice: ['extra-small', 'small', 'medium', null, null]\n };\n\n const resources = {\n 'assistive.text.remove.filter.button': getResource('assistive.text.remove.filter.button'),\n close: getResource('refinements.close'),\n filter: getResource('refinements.title')\n };\n const currentURL = generatePLPURL({ url: getURL('searchShowAjax') });\n const queryStr = new URL(currentURL).search.substr(1);\n\n const mobileSorting = getMobileSorting(sortingOptions);\n\n return `\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    ${resources.filter}
    \n ${getClearAllButton(selectedFilters)}\n\n \n
    \n
      \n ${Object.keys(selectedFilters).map(key => {\n if (['premiumFilter', 'isMFOItem', 'availableForLocale', 'experienceType'].indexOf(key) > -1) {\n return '';\n }\n\n const selectedFilterAttribute = selectedFilters[key];\n return selectedFilterAttribute.options.map(selectedFilterValue => {\n const urlConfig = ['salePriceLow', 'price'].indexOf(key) > -1\n ? { params: { priceRange: undefined, start: 0 } }\n : { params: { filterParams: { [key]: selectedFilterValue.value }, start: 0 }, action: 'toggle' };\n const hrefUrl = generatePLPURL(urlConfig);\n const dataUrl = generatePLPURL(Object.assign({}, urlConfig, { url: getURL('searchShowAjax') }));\n var filterDisplayName = selectedFilterValue.display_name;\n if (['discountPercentage'].indexOf(key) > -1 && selectedFilterValue.value) {\n filterDisplayName = getResource('refinement.discountpercentage.' + selectedFilterValue.value);\n }\n\n return `\n
    • \n \n ${filterDisplayName}\n \n ${resources['assistive.text.remove.filter.button'].supplant([selectedFilterValue.value])}\n \n \n
    • \n `;\n }).join('');\n }).join('')}\n
    \n
    \n ${mobileSorting}\n ${categories}\n ${getMobileFilterFooter(productsCount)}\n
    \n
    \n
    \n
    \n
    `;\n};\n\nmodule.exports = {\n getRefinementsHtml\n};\n","/* eslint-disable no-useless-return */\n\n'use strict';\n\nconst { isEmpty, intersection } = require('lodash');\nconst { getConstructorIOSettings, getURL, getResource } = require('../clientWrapper');\nconst {\n determineNoBorderClass\n} = require('../utils/utils');\n\nconst numberWithCommas = (price, separators) => {\n var parts = price.toString().split('.');\n parts[0] = parts[0].replace(/\\B(?=(\\d{3})+(?!\\d))/g, separators.length > 1 ? separators[0] : ',');\n return parts.join(separators.length > 1 ? separators[1] : separators[0]);\n};\n\nconst convertNumberToPrice = (value) => {\n const { samplePrice = '0', samplePriceThousand = '0' } = getConstructorIOSettings();\n const separators = samplePrice.match(/[.,]/g);\n const separatorsThousand = samplePriceThousand.match(/[.,]/g);\n let modifiedPrice = numberWithCommas(value.toFixed(2), separators);\n if (value >= 1000) {\n modifiedPrice = numberWithCommas(value.toFixed(2), separatorsThousand);\n }\n\n return samplePrice.replace(/\\d{1,}[,.]{1}\\d{1,}/g, modifiedPrice);\n};\n\nconst padColorId = (value, padding = 3) => {\n if (!value) return undefined;\n\n let zeroes = new Array(4).join('0');\n return (zeroes + value).slice(-padding);\n};\n\nconst getCioColorWayId = (colorway = '001') => padColorId(typeof colorway === 'string' ? colorway : colorway.color, 3);\n\nconst getVisibleVariants = (variations) => {\n let uniqueColors = [];\n let visible = [];\n variations.forEach((variant) => {\n const variantColor = getCioColorWayId(variant.data.colorWayId);\n if (!variant.data.hideColorWay && variant.data.orderable && variant.data.image_url && !uniqueColors.includes(variantColor)) {\n visible.push(variant);\n uniqueColors.push(variantColor);\n }\n });\n\n return visible;\n};\n\n/**\n * Generates the default color way product tile data including image and hover image\n * to display on a single tile.\n *\n * @param {Object} product - Product data.\n * @returns {productTileData} product image details\n */\nfunction getDefaultColorWayDetails(product) {\n const colorwayId = product.data.colorWayId ? product.data.colorWayId.color : '';\n const defaultColorWayId = product.data.defaultColorwayId && product.data.defaultColorwayId.id ? product.data.defaultColorwayId.id.split(',')[0] : '';\n let selectedColorWayId = defaultColorWayId;\n var productTileData = {\n defaultColorWayId: null,\n image_url: null,\n imageName: null,\n gridTileHoverImageURL: null\n };\n\n if (defaultColorWayId && product.variations_map) {\n let variationProduct = product.variations_map.filter(variation => variation.colorWayId === defaultColorWayId)[0];\n\n // if defaultcolorway is not online, then use colorwayId to find variant\n if (!variationProduct) {\n variationProduct = product.variations_map.filter(variation => variation.colorWayId === colorwayId)[0];\n selectedColorWayId = colorwayId;\n }\n\n // if colorwayId variant is also not online, take the first color\n if (!variationProduct && product.variations_map.length > 0) {\n variationProduct = product.variations_map[0];\n selectedColorWayId = variationProduct.colorWayId;\n }\n\n if (variationProduct) {\n productTileData.image_url = (variationProduct.data.image_url || '').replace('http://', 'https://') || null;\n productTileData.gridTileHoverImageURL = (variationProduct.data.gridTileHoverImageURL || '').replace('http://', 'https://') || null;\n productTileData.imageName = variationProduct.data.imageName || null;\n }\n }\n\n productTileData.defaultColorWayId = defaultColorWayId ? padColorId(selectedColorWayId) : null;\n\n return productTileData;\n}\n\nconst getProductColorSwatches = (product, showColorCarousel) => {\n let swatches = '';\n\n const resources = {\n 'product.view.color': getResource('product.view.color')\n };\n\n const productVariations = product.variations ? product.variations : product.variations_map;\n let productColors = getVisibleVariants(productVariations)\n .map((variant) => {\n const imageUrl = variant.data.image_url ? variant.data.image_url.replace('http://', 'https://') : null;\n const hex = typeof variant.data.hexColor === 'number' ? padColorId(variant.data.hexColor, 6) : variant.data.hexColor;\n const colorId = getCioColorWayId(variant.data.colorWayId);\n\n if (colorId) {\n return {\n id: colorId,\n url: variant.data.url,\n upc: variant.data.upc,\n colorway: variant.data.colorWay || null,\n hex: `${hex}` || '',\n hideColorway: false,\n isLoyaltyExclusiveColor: variant.data.isLoyaltyExclusive || false,\n name: variant.data.colorValue || '',\n secondaryHex: variant.data.secondaryHexColor || null,\n orderable: variant.data.orderable || false,\n assets: {\n alt: variant.data.imageName || '',\n images: [\n {\n assetName: variant.data.imageName || '',\n url: imageUrl\n },\n {\n assetName: variant.data.imageName || '',\n url: variant.data.gridTileHoverImageURL ? variant.data.gridTileHoverImageURL.replace('http://', 'https://') : imageUrl\n }\n ],\n title: variant.value || null\n }\n };\n }\n return '';\n });\n\n productColors.forEach((color, index) => {\n const pid = product.data.id;\n const dataIndex = `${index}.0`;\n const includeFirstClass = index === 0 ? 'first' : '';\n const secondaryHex = color.secondaryHex || color.hex;\n const url = `${getURL('productShow')}${pid}&dwvar_${pid}_color=${color.id}`;\n const dataProductImage = color.assets.images[0].url;\n const numberOfColors = product.data.colorCount;\n const carouselAttributes = showColorCarousel ? (\n `role=\"group\"\n aria-label=\"${index + 1} / ${numberOfColors + 1}\"`) : '';\n const defaultColorwayDetails = getDefaultColorWayDetails(product);\n const productColor = !isEmpty(product.data.colorWayId) ? getCioColorWayId(product.data.colorWayId) : defaultColorwayDetails.defaultColorWayId;\n const isSelectedColor = color.id === productColor;\n\n let noBorderClass = '';\n noBorderClass = determineNoBorderClass(color.hex, color.secondaryHex);\n\n swatches = swatches.concat(`\n \n \n \n \n `);\n });\n\n return swatches;\n};\n\nconst getProductPrice = (product) => {\n const data = product.data;\n if (!data.listPriceHigh) return '';\n const list = { min: data.listPriceLow, max: data.listPriceHigh };\n const sale = { min: data.salePriceLow, max: data.salePriceHigh };\n\n const { customerGroups } = getConstructorIOSettings();\n\n if (product.data && product.data.groupPricing) {\n const matchedPriceGroup = Object.keys(product.data.groupPricing).find((groupName) => customerGroups.includes(groupName));\n\n if (matchedPriceGroup) {\n sale.min = product.data.groupPricing[matchedPriceGroup].min;\n sale.max = product.data.groupPricing[matchedPriceGroup].max;\n }\n }\n\n const showSalesPrice = list.max !== sale.max || list.min !== sale.min;\n const showRange = showSalesPrice\n ? sale.min !== sale.max\n : list.min !== list.max;\n\n const defaultPrice = convertNumberToPrice(list.max);\n if (showRange) {\n const low = convertNumberToPrice(showSalesPrice ? sale.min : list.min);\n const high = convertNumberToPrice(showSalesPrice ? sale.max : list.max);\n\n return (\n `${low}\n -\n ${high}`\n );\n }\n if (showSalesPrice) {\n const saleLow = convertNumberToPrice(sale.min);\n\n return (\n `${defaultPrice}\n ${saleLow}`\n );\n }\n return `${defaultPrice}`;\n};\n\nconst chooseActivePromotion = (currentPromotions, customerGroups) => {\n let promotionsWithRank = [];\n let promotionsWithStartDate = [];\n let filteredPromotions = [];\n\n if (currentPromotions.length > 0) {\n currentPromotions.forEach((promotion) => {\n if ((!('hasCoupon' in promotion) || promotion.hasCoupon === false) && !isEmpty(intersection(promotion.customerGroups, customerGroups))) {\n if (promotion.rank && promotion.rank !== '') {\n promotionsWithRank.push(promotion);\n } else if (promotion.startDate) {\n promotionsWithStartDate.push(promotion);\n } else {\n filteredPromotions.push(promotion);\n }\n }\n });\n }\n\n if (promotionsWithRank.length > 0) {\n promotionsWithRank.sort((first, second) => {\n const firstRank = typeof first.rank === 'string' ? Number(first.rank) : first.rank;\n const secondRank = typeof second.rank === 'string' ? Number(second.rank) : second.rank;\n return firstRank - secondRank;\n });\n\n return promotionsWithRank[0];\n }\n if (promotionsWithStartDate.length > 0) {\n promotionsWithStartDate.sort((first, second) => new Date(first.startDate) - new Date(second.startDate));\n\n return promotionsWithStartDate[0];\n }\n\n return filteredPromotions.length > 0 ? filteredPromotions[0] : undefined;\n};\n\nconst getProductPromotion = (promotions) => {\n let promotionHTML = '';\n const { customerGroups } = getConstructorIOSettings();\n const activePromotion = chooseActivePromotion(promotions, customerGroups);\n\n if (activePromotion && activePromotion.customerGroups && !isEmpty(intersection(activePromotion.customerGroups, customerGroups))) {\n promotionHTML = activePromotion.callOut ? (\n `
    \n \n ${activePromotion.callOut}\n ${activePromotion.toolTipText ? `\n \n \n ${activePromotion.toolTipText}\n \n ` : ''}\n \n \n ${activePromotion.callOut}\n ${activePromotion.toolTipText ? `\n \n \n \n \n ${activePromotion.toolTipText}\n ` : ''}\n \n
    `) : '';\n }\n\n return promotionHTML;\n};\n\n/**\n * Generates the HTML markup for a single tile using the product data.\n *\n * @param {Object} product - Product data.\n * @param {boolean} headerSearch - Tile is from header search or not.\n * @returns {string} HTML markup for the tile.\n */\nconst getTileHtml = (product, headerSearch) => {\n const pid = product.data.id;\n const defaultColorwayDetails = getDefaultColorWayDetails(product);\n const productColor = !isEmpty(product.data.colorWayId) ? getCioColorWayId(product.data.colorWayId) : defaultColorwayDetails.defaultColorWayId;\n const url = productColor ? `${getURL('productShow')}${pid}&dwvar_${pid}_color=${productColor}` : `${getURL('productShow')}${pid}`;\n var imageUrl = defaultColorwayDetails.image_url ? defaultColorwayDetails.image_url : product.data.image_url ? product.data.image_url.replace('http://', 'https://') : '';\n var hoverImageUrl = defaultColorwayDetails.gridTileHoverImageURL ? defaultColorwayDetails.gridTileHoverImageURL : product.data.gridTileHoverImageURL ? product.data.gridTileHoverImageURL.replace('http://', 'https://') : imageUrl;\n\n if (productColor) {\n imageUrl = product.data.image_url ? product.data.image_url.replace('http://', 'https://') : '';\n hoverImageUrl = product.data.gridTileHoverImageURL ? product.data.gridTileHoverImageURL.replace('http://', 'https://') : imageUrl;\n }\n\n const image = {\n url: imageUrl,\n urlHov: hoverImageUrl\n };\n const productVariations = product.variations ? product.variations : product.variations_map;\n const numColors = product.data.colorCount === 0 ? getVisibleVariants(productVariations).length : product.data.colorCount;\n const showColorCarousel = headerSearch ? numColors > 4 : numColors > 6;\n const colorSwatches = getProductColorSwatches(product, showColorCarousel);\n const productPrice = getProductPrice(product);\n const badge = product.data.badge || null;\n const upperLeftFlameIcon = product.data.badgeImage || null;\n const upperLeftSellingFast = getResource('sellingFastDisplayValues');\n const isSellingFast = upperLeftFlameIcon && upperLeftSellingFast.indexOf(upperLeftFlameIcon) > -1;\n const comingSoon = product.exclusiveType === 'COMING_SOON';\n const isOrderable = product.data.orderable || (product.variations && product.variations.length > 0) || (product.variations_map && product.variations_map.length > 0);\n const hasPromo = product.data.promotions && product.data.promotions.length > 0;\n const productTileJSONConfig = '{\"initOnDevice\": [null, null, null, \"large\", \"extra-large\"]}';\n const swatchTileJSONConfig = {\n direction: 'horizontal',\n centerInsufficientSlides: false,\n loop: false,\n navigation: {\n nextEl: '.js-swiper-button-next',\n prevEl: '.js-swiper-button-prev',\n disabledClass: 'm-disabled'\n },\n slidesPerView: headerSearch ? 4 : 6,\n spaceBetween: 0,\n slidesPerGroup: headerSearch ? 4 : 5,\n breakpoints: {\n 300: {\n slidesPerView: 3,\n spaceBetween: 2,\n slidesPerGroup: 3\n },\n 1024: {\n slidesPerView: headerSearch ? 4 : 6,\n spaceBetween: 1,\n slidesPerGroup: headerSearch ? 4 : 6\n }\n }\n };\n\n return `\n
    \n
    \n
    \n \n \n \n \n \n \n \n \n
    \n
    \n
    \n
    \n
    \n
    \n \n ${showColorCarousel\n ? ''\n : ''\n}\n
      \n ${colorSwatches}\n
    \n ${showColorCarousel\n ? ''\n : ''\n}\n
    \n
    \n ${numColors !== 0 && numColors > 3 ? (\n `\n ${'+' + (numColors - 3)}\n `\n ) : ''\n}\n
    \n ${!isSellingFast && upperLeftFlameIcon ? `\n
    \n \n \"${getResource('flameIconAlt')}\"\n ${upperLeftFlameIcon}\n \n
    \n ` : '' }\n ${isSellingFast ? `\n
    \n \n \"${getResource('sellingFastAlt')}\"\n ${upperLeftFlameIcon}\n \n
    \n ` : '' }\n ${!upperLeftFlameIcon && badge ? `
    ${badge}
    ` : ''}\n \n

    \n ${product.value}\n

    \n
    \n ${product.data.subHeader ? `
    ${product.data.subHeader}
    ` : ''}\n
    \n ${productPrice}\n
    \n
    \n
    ${ product.data.preorderable ? product.data.preorderMessage.tileMessage : '' }
    \n
    ${ !isOrderable && !comingSoon ? ('' + getResource('soldOut') + '') : '' }
    \n
    ${ !isOrderable && comingSoon ? `${product.data.comingSoonMessage || getResource('buttonComingsoon')}` : '' }
    \n
    \n ${hasPromo ? getProductPromotion(product.data.promotions) : ''}\n
    \n
    \n \n `;\n};\n\n/**\n * Converts an array of products into a string of HTML tiles.\n *\n * @param {Array} products - Array of products.\n * @returns {string} HTML tiles markup.\n */\nconst convertProductsToTiles = (products) => {\n let tiles = '';\n products.forEach((product, index) => {\n try {\n tiles = tiles.concat(`\n
  • \n ${getTileHtml(product, true)}\n
  • \n `);\n } catch (error) {\n // Return in case of tile data failure\n return;\n }\n });\n return tiles;\n};\n\nmodule.exports = {\n getTileHtml,\n convertProductsToTiles\n};\n","/**\n * @file Initializes ConstructorIO using settings from the global window object.\n * @module constructorIO\n */\n\n'use strict';\n\nimport Cookies from 'js-cookie';\n\nconst clientWrapper = require('./clientWrapper');\nconst cioTiles = require('./components/tiles');\nconst { getURL, getConstructorIOSettings, getResource } = require('./clientWrapper');\n\nconst RECENT_SEARCH_COOKIE_NAME = 'ua-recent-search';\n\nconst escapeHtml = (unsafe) => {\n return unsafe\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n};\n\nconst convertSuggestionsToLinks = (suggestions) => {\n let links = '';\n\n try {\n suggestions.forEach((suggestion, index) => {\n const value = suggestion.value;\n\n if (value !== undefined) {\n links = links.concat(`\n
  • \n \n \n ${value}\n \n \n
  • \n `);\n }\n });\n\n return links;\n } catch (error) {\n // Return an empty string or some default HTML in case of failure\n return links;\n }\n};\n\nconst getRecentSearches = () => {\n const recentSearches = Cookies.get(RECENT_SEARCH_COOKIE_NAME);\n if (recentSearches) {\n return (\n recentSearches\n .split(';')\n .filter((s) => !!s) || []\n );\n }\n\n return [];\n};\n\nconst addToRecentSearch = (searchTerm) => {\n if (!searchTerm) {\n return;\n }\n\n // This will get the current list of recent searches and prepend the new search result, dedupe it and return the top 3\n const oldRecentSearches = getRecentSearches();\n const recentSearches = ([searchTerm, ...oldRecentSearches]).filter((value, index, values) => values.indexOf(value) === index).slice(0, 3);\n\n // Update the cookie with the list.\n Cookies.set(RECENT_SEARCH_COOKIE_NAME, recentSearches.join(';'));\n};\n\nconst getCurrentSearchData = () => {\n const params = new URL(document.location).searchParams;\n const searchQuery = params.get('q');\n\n return searchQuery;\n};\n\nconst convertRecentSearchesToLinks = (recentSearches) => {\n let links = '';\n\n try {\n recentSearches.forEach((recentSearch, index) => {\n const value = escapeHtml(recentSearch);\n links = links.concat(`\n
  • \n \n \n ${value}\n \n \n
  • \n `);\n });\n\n return links;\n } catch (error) {\n // Return an empty string or some default HTML in case of failure\n return links;\n }\n};\n\n/**\n * Helper function used to convert ConstructorIO data into HTML string\n * that can be used in the processResponse function used to render\n * Search Suggestions popup\n *\n * @param {Object} response - ConstructorIO Autocomplete query response object\n * @return {string} - HTML string with ConstructorIO data\n */\nconst convertCIOToHTMLString = (response) => {\n const hasResponse = response && response.sections;\n const products = hasResponse && response.sections.Products;\n const suggestions = hasResponse && response.sections['Search Suggestions'];\n const tiles = cioTiles.convertProductsToTiles(products);\n const links = convertSuggestionsToLinks(suggestions);\n const query = hasResponse && response.request && response.request.term ? response.request.term : '';\n const currentSearch = getCurrentSearchData();\n addToRecentSearch(currentSearch);\n const recentSearches = getRecentSearches();\n const recentSearchLinks = convertRecentSearchesToLinks(recentSearches);\n\n return (`\n
    \n
    \n
    \n ${links ? `\n
    \n
    \n
    ${getResource('headerModalSuggestionsCategory') || ''}
    \n
      \n ${links}\n
    \n
    \n ${recentSearchLinks ? `\n
    \n
    ${getResource('headerModalSuggestionsRecentSearch') || ''}
    \n
      \n ${recentSearchLinks}\n
    \n
    \n ` : ''}\n
    \n ` : ''}\n ${!links && recentSearchLinks ? `\n
    \n
    \n
    ${getResource('headerModalSuggestionsRecentSearch') || ''}
    \n
      \n ${recentSearchLinks}\n
    \n
    \n
    \n ` : ''}\n
    \n
    \n ${products.length >= 4 ? (\n ``\n ) : ''}\n ${products.length > 0 ? (\n `
    ${getResource('headerModalSuggestionsProduct') || ''}
    \n
      \n ${tiles}\n
    `\n ) : (\n `
    ${getResource('noResultsFound')}
    \n
    \n
    ${getResource('noSearchSuggestions')}
    \n
    `\n )}\n
    \n
    \n
    \n
    \n
    \n `);\n};\n\n/**\n * Fetches Autocomplete search results.\n * @param {string} query - Query string.\n * @returns {Promise} Promise resolving with Autocomplete results.\n */\nconst getConstructorioSuggestions = (query) => {\n const cioClient = clientWrapper.getConstructorIOClient();\n\n if (cioClient && cioClient.autocomplete && cioClient.autocomplete.getAutocompleteResults) {\n const constructorIOSettings = getConstructorIOSettings();\n return cioClient.autocomplete.getAutocompleteResults(query, {\n variationsMap: constructorIOSettings.variationMap || undefined,\n resultsPerSection: {\n Products: 4,\n Categories: 0,\n 'Search Suggestions': 7\n },\n networkParameters: {\n timeout: constructorIOSettings.timeout\n }\n });\n }\n\n return Promise.reject(new Error('Failed to fetch ConstructorIO autocomplete results.'));\n};\n\nexport {\n convertCIOToHTMLString,\n getConstructorioSuggestions\n};\n","/**\n * @file Initializes ConstructorIO using settings from the global window object.\n * @module constructorIO\n */\n\n'use strict';\n\nconst { getRefinementsHtml } = require('./components/refinements');\nconst { getTileHtml } = require('./components/tiles');\nconst {\n getConstructorIOSettings,\n getResource,\n getURL\n} = require('./clientWrapper');\nconst {\n getPriceRange,\n generatePLPURL\n} = require('./utils/utils');\n\nconst getSortingOption = (sortingOption, isOption = false, withLink = false) => {\n const sortingRules = getResource('sortingRules') || {};\n const { SORT_OPTIONS_URL_MAP } = getConstructorIOSettings();\n const id = SORT_OPTIONS_URL_MAP[sortingOption.sort_by][sortingOption.sort_order].name;\n const sortURL = generatePLPURL({ url: getURL('updateGrid'), params: { sortRule: id, start: 0 } });\n const isSelected = sortingOption.status === 'selected';\n const displayName = sortingRules[[sortingOption.sort_by.toLowerCase(), sortingOption.sort_order.toLowerCase()].join('.')] || sortingRules[sortingOption.sort_by.toLowerCase()] || sortingOption.display_name;\n\n if (isOption) {\n return ``;\n }\n\n return `
  • \n ${!withLink ? displayName : ``}\n
  • `;\n};\n\nconst getSortSelect = (sortOptions) => {\n const resources = {\n sort: getResource('label.sort')\n };\n\n const selectedSortingRule = sortOptions.filter(sortingOption => sortingOption.status === 'selected');\n\n return `\n
    \n \n
    \n \n \n
    \n
    \n
      \n ${sortOptions.map(sortOption => getSortingOption(sortOption)).join('')}\n
    \n
    \n \n
    \n `;\n};\n\nconst getPageBreadcrumbs = (selectedFilters) => {\n let breadcrumbsHTML = '';\n const selectedFilterKeys = Object.keys(selectedFilters);\n\n if (selectedFilterKeys.length === 0) {\n return `\n
    \n
    \n
    \n
    \n
    \n `;\n }\n const { ROUTE_REFINEMENT_ATTRIBUTES } = getConstructorIOSettings();\n const shownFilterAttributeInBreadcrumbs = {};\n\n ROUTE_REFINEMENT_ATTRIBUTES.forEach(function (key) {\n if (!selectedFilters[key]) {\n return;\n }\n shownFilterAttributeInBreadcrumbs[key] = selectedFilters[key].options.map(selectedFilterValue => selectedFilterValue.value);\n const urlConfig = { params: { filterParams: shownFilterAttributeInBreadcrumbs, start: 0 } };\n const hrefUrl = generatePLPURL(urlConfig);\n const dataUrl = generatePLPURL(Object.assign({}, urlConfig, { url: getURL('searchShowAjax') }));\n const title = selectedFilters[key].options.map(selectedFilterValue => selectedFilterValue.display_name).join(' + ');\n\n breadcrumbsHTML = breadcrumbsHTML.concat(\n `
  • \n \n ${title}\n \n
  • `\n );\n });\n\n return `\n
    \n \n
    \n
      \n ${breadcrumbsHTML}\n
    \n
    \n
    \n `;\n};\n\nconst getSearchHeader = (response, request, selectedFilters) => {\n const resources = {\n 'search.results': getResource('label.search.title'),\n 'items.more': getResource('label.num.items.more'),\n items: getResource('label.num.items'),\n item: getResource('label.num.item')\n };\n\n const { term } = request;\n const { total_num_results: resultsCount, sort_options: sortOptions } = response;\n const countLabel = resultsCount > 1 ? resultsCount > 4 ? 'items.more' : 'items' : 'item';\n\n return `\n
    \n ${getPageBreadcrumbs(selectedFilters)}\n
    \n
    \n ${resources['search.results']}\n
    \n
    \n “${term}”\n
    \n
    ${resources[countLabel].supplant([resultsCount])}
    \n
    \n ${getSortSelect(sortOptions)}\n
    \n
    \n
    \n `;\n};\n\nconst getTopLoadMore = (response, request) => {\n if (request.offset > 0) {\n const resources = {\n 'label.load.more.products': getResource('label.load.more.products')\n };\n const loadMoreURL = generatePLPURL({ params: { start: null, sz: null } });\n\n return `\n \n `;\n }\n return '';\n};\n\nconst getBottomLoadMore = (response, request) => {\n const pageSize = request.num_results_per_page;\n const isShowMore = response.total_num_results > (request.offset + pageSize);\n if (isShowMore) {\n const pageNumber = Math.floor(request.offset / pageSize) + 1;\n const { SORT_OPTIONS_URL_MAP } = getConstructorIOSettings();\n\n const sortingOptions = Object.keys(SORT_OPTIONS_URL_MAP).map(id => {\n return {\n id,\n url: generatePLPURL({ url: getURL('updateGrid'), params: { sortRule: id, start: 0 } })\n };\n });\n const productSort = {\n options: sortingOptions\n };\n const params = {\n start: request.offset + pageSize,\n sz: pageSize\n };\n const showMoreUrl = generatePLPURL({ url: getURL('updateGrid'), params });\n const resources = {\n 'button.more': getResource('button.more')\n };\n\n return `\n \n `;\n }\n return '';\n};\n\nconst getSortContent = (sortOptions) => {\n const sortingRules = getResource('sortingRules') || {};\n const { SORT_OPTIONS_URL_MAP } = getConstructorIOSettings();\n return `\n
    \n
      \n ${sortOptions\n .map((sortOption) => {\n const id = SORT_OPTIONS_URL_MAP[sortOption.sort_by][sortOption.sort_order].name;\n const sortURL = generatePLPURL({\n url: getURL('updateGrid'),\n params: { sortRule: id, start: 0 }\n });\n const isSelected = sortOption.status === 'selected';\n const displayName = sortingRules[[sortOption.sort_by.toLowerCase(), sortOption.sort_order.toLowerCase()].join('.')] || sortingRules[sortOption.sort_by.toLowerCase()] || sortOption.display_name;\n return `\n
    • \n ${displayName}\n
    • `;\n })\n .join('')}\n
    \n
    \n `;\n};\n\nconst getPaginationItem = (pageIndex, pageSize, type) => {\n const resources = {\n 'title.previous': getResource('title.previous'),\n 'title.next': getResource('title.next'),\n 'title.default': getResource('title.default'),\n 'label.previous': getResource('label.previous'),\n 'label.next': getResource('label.next')\n };\n\n const pageNumber = pageIndex + 1;\n const URLParams = pageIndex > 0 ? { sz: pageSize, start: pageIndex * pageSize } : { sz: null, start: null };\n const url = generatePLPURL({ params: URLParams });\n\n let label = pageNumber;\n let title = resources['title.default'].supplant([pageNumber]);\n\n if (type === 'previous') {\n title = resources['title.previous'].supplant([pageNumber]);\n label = resources['label.previous'];\n } else if (type === 'next') {\n title = resources['title.next'].supplant([pageNumber]);\n label = resources['label.next'];\n }\n\n return `\n
  • \n \n \n ${label}\n \n \n
  • \n `;\n};\n\nconst getPagination = (response, request) => {\n const pageSize = request.num_results_per_page;\n const pagesCount = Math.floor(response.total_num_results / pageSize);\n const currentPageIndex = Math.floor(request.offset / pageSize);\n return `\n \n `;\n};\n\nconst getGridTiles = (response, request) => {\n const pageSize = request.num_results_per_page;\n const offset = request.offset;\n const permalink = generatePLPURL({ params: { start: 0, sz: (request.offset + pageSize) } });\n\n return `\n ${response.results.map((productData, i) => {\n const id = productData.data.id;\n\n return `
    \n ${getTileHtml(productData, false)}\n ${(offset + i) % pageSize === 1\n ? `\n
    ` : ''\n}\n
    `;\n }).join('')}\n\n ${getBottomLoadMore(response, request)}\n\n \n \n\n ${getSortContent(response.sort_options)}\n `;\n};\n\n/**\n * Helper function used to convert ConstructorIO data into HTML string\n * that can be used in the processResponse function used to render\n * Search Page\n *\n * @param {Object} res - ConstructorIO query response object\n * @param {string} scope - scope of response: 'gridTiles'\n * @return {string} - HTML string with ConstructorIO data\n */\nconst convertCIOToHTMLString = (res, scope) => {\n const { response, request } = res;\n if (scope === 'gridTiles') {\n return getGridTiles(response, request);\n }\n\n const selectedFilters = {};\n response.facets.forEach(facet => {\n const selectedFilterOptions = (facet && facet.options && facet.options.filter(option => option.status === 'selected')) || [];\n if (selectedFilterOptions.length > 0) {\n selectedFilters[facet.name] = {\n display_name: facet.display_name,\n name: facet.name,\n options: selectedFilterOptions\n };\n }\n });\n\n // Add price filter to list of selected filters\n const selectedPriceRange = window.searchParams.priceRange;\n const priceMap = window.searchParams.buckets || [];\n if (selectedPriceRange) {\n priceMap.forEach((value) => {\n const priceRange = getPriceRange(value);\n if (priceRange[0] === selectedPriceRange[0] && priceRange[1] === selectedPriceRange[1]) {\n selectedFilters.price = {\n display_name: 'Price',\n name: 'price',\n options: [\n {\n display_name: value.display_name,\n value: value.display_name,\n status: 'selected'\n }\n ]\n };\n }\n });\n }\n\n const canonicalUrl = generatePLPURL({ params: { start: null, sz: null } });\n return (`\n ${getSearchHeader(response, request, selectedFilters)}\n ${getTopLoadMore(response, request)}\n
    \n ${getRefinementsHtml({\n facets: response.facets, selectedFilters, sortingOptions: response.sort_options, productsCount: response.total_num_results\n })}\n
    \n
    \n ${getGridTiles(response, request)}\n
    \n
    \n
    \n
    \n \n
    \n ${getPagination(response, request)}\n `);\n};\nmodule.exports = {\n convertCIOToHTMLString\n};\n","/**\n * @file Initializes ConstructorIO using settings from the global window object.\n * @module constructorIO\n */\n\n'use strict';\n\nconst { cloneDeep } = require('lodash');\nconst {\n getPriceFacetOptions,\n getCioPreFilterExpression,\n parseControllerPLPURL\n} = require('./utils/utils');\nconst {\n getConstructorIOSettings, getConstructorIOClient\n} = require('./clientWrapper');\n\n/**\n * Fetches search results.\n * @param {Object} - config Object with search parameters, or url with data\n * @returns {Promise} Promise resolving with results.\n */\nconst getConstructorioSearch = ({ searchParams: _searchParams, url, data }) => {\n if (!window.constructorIOSettings) {\n return Promise.reject(new Error('no settings'));\n }\n const cioClient = getConstructorIOClient();\n const searchParams = parseControllerPLPURL({ url, data }) || _searchParams || window.searchParams || (window.constructorIOSettings && window.constructorIOSettings.initialSearchParams) || {};\n\n if (cioClient && cioClient.search && cioClient.search.getSearchResults && searchParams.query) {\n const filters = cloneDeep(searchParams.filterParams) || {};\n const hasPriceRange = searchParams.priceRange;\n const { CIO_SORT_OPTIONS_MAP, variationMap } = getConstructorIOSettings();\n\n const networkParams = {\n timeout: window.constructorIOSettings.timeout\n };\n const sortingRule = CIO_SORT_OPTIONS_MAP[searchParams.sortRule] ? CIO_SORT_OPTIONS_MAP[searchParams.sortRule] : {};\n const params = {\n sortBy: sortingRule.sortBy || undefined,\n sortOrder: sortingRule.sortOrder || undefined,\n offset: searchParams.start || 0,\n resultsPerPage: searchParams.pageSize || 12,\n variationsMap: variationMap,\n filters\n };\n\n // Convert Price Refinement to make compatible with CIO Facets\n let paramsWithPrice = cloneDeep(params);\n if (hasPriceRange) {\n paramsWithPrice.preFilterExpression = getCioPreFilterExpression(hasPriceRange);\n }\n\n let promises = [cioClient.search.getSearchResults(\n searchParams.query,\n paramsWithPrice,\n networkParams\n )];\n\n // Update price buckets, when a non-price filter is selected\n if (hasPriceRange) {\n promises.push(cioClient.search.getSearchResults(searchParams.query, params, networkParams));\n }\n\n return Promise.allSettled(promises).then((results) => {\n // Search for redirects\n let anyRedirect;\n [...results].some(\n (result) => {\n if (result && result.value && result.value.response && result.value.response.redirect && result.value.response.redirect.data && result.value.response.redirect.data.url) {\n anyRedirect = result.value.response.redirect.data.url;\n return true;\n }\n return false;\n }\n );\n if (anyRedirect) {\n window.location.href = anyRedirect;\n return true;\n }\n if (\n !results\n || results.some(\n (result) => result.status === 'rejected'\n || !result.value\n || result.value.response.results.length === 0\n )\n ) {\n return Promise.reject(new Error('Empty results.'));\n }\n\n // If price buckets exist, maintain their state as backup\n let buckets;\n if (window.searchParams && window.searchParams.buckets) {\n buckets = window.searchParams.buckets;\n }\n\n // update backets from last request without price filtering\n buckets = getPriceFacetOptions(results[results.length - 1].value);\n\n // Update window state and return\n window.searchParams = searchParams;\n window.searchParams.trailingFilters = filters;\n if (buckets) window.searchParams.buckets = buckets;\n return Object.assign(results[0].value, { searchParams });\n });\n }\n\n return Promise.reject(new Error('Failed to fetch ConstructorIO autocomplete results.'));\n};\n\nmodule.exports = {\n getConstructorioSearch\n};\n","/* eslint-disable no-multi-assign */\n\n'use strict';\n\nconst { cloneDeep } = require('lodash');\nconst { getConstructorIOSettings } = require('../clientWrapper');\n\nconst getGroupFacets = () => {\n const { customerGroups } = getConstructorIOSettings();\n return customerGroups.length > 0 && customerGroups.map((group) => `Price ${group}`);\n};\n\nconst getPriceFacetOptions = (res) => {\n let options = [];\n\n if (res && res.response && res.response.facets && res.response.facets.length > 0) {\n const salePriceFacet = res.response.facets.find(facet => facet.name === 'salePriceLow');\n\n if (salePriceFacet) {\n options = salePriceFacet.options;\n }\n\n // Add options for promotions that aren't currently captured\n const groupFacets = getGroupFacets();\n const optionDisplayNames = options.map(option=> option.display_name);\n const validUserGroups = groupFacets ? res.response.facets.filter(value => groupFacets.includes(value.name)) : [];\n validUserGroups.forEach((group) => {\n if (group.options) {\n group.options.forEach((option) => {\n if (optionDisplayNames.indexOf(option.display_name) === -1 && option.range) {\n options.push(option);\n optionDisplayNames.push(option.display_name);\n }\n });\n }\n });\n }\n\n return options;\n};\n\nconst getCioPreFilterExpression = (priceRange) => {\n const [selectedPriceLow, selectedPriceHigh] = priceRange;\n const { customerGroups } = getConstructorIOSettings();\n const groupPricingExpressions = customerGroups.length > 0 ? customerGroups.map((group) => ({\n name: `Price ${group}`,\n range: [selectedPriceLow, selectedPriceHigh]\n })) : [];\n\n return {\n or: [\n {\n name: 'salePriceLow',\n range: [selectedPriceLow, selectedPriceHigh]\n },\n ...groupPricingExpressions\n ]\n };\n};\n\nconst modifyValue = (prevVal, upValue, action) => {\n const value = (typeof prevVal === 'string') ? prevVal.split(',') : prevVal;\n const isUpdateValueExistInPrevValue = Array.isArray(value) ? value.includes(upValue) : value === upValue;\n\n let newValue;\n if (action === 'remove' || action === '-' || (action === 'toggle' && isUpdateValueExistInPrevValue)) {\n if (Array.isArray(value)) {\n newValue = value.filter(itemValue => itemValue !== upValue);\n }\n } else if (action === 'add' || action === '+' || (action === 'toggle' && !isUpdateValueExistInPrevValue)) {\n newValue = Array.isArray(value) ? value.slice(0) : [value];\n newValue.push(upValue);\n } else {\n newValue = upValue;\n }\n return Array.isArray(newValue) ? newValue.filter(val => [null, undefined, NaN, ''].indexOf(val) === -1).join('|') : newValue.toString();\n};\n\nconst searchToQueryParams = ({\n filterParams = {}, extraParams = {}, query = '', sortRule = '', priceRange, pageSize = '12', start = 0\n}) => {\n const filterQueryParams = {};\n Object.keys(filterParams).forEach(function (key, i) {\n const index = i + 1;\n const filterValue = filterParams[key];\n filterQueryParams['prefn' + index] = key;\n filterQueryParams['prefv' + index] = Array.isArray(filterValue) ? filterValue.join('|') : filterValue;\n });\n\n const regex = /(\\d)(?=(\\d{3})+$)/g;\n const queryParams = Object.assign({}, extraParams, filterQueryParams, {\n start: start,\n sz: pageSize,\n q: query,\n srule: sortRule,\n pmin: priceRange ? parseInt(priceRange[0], 10).toString().replaceAll(regex, '$1,') + '.00' : '',\n pmax: priceRange ? parseInt(priceRange[1], 10).toString().replaceAll(regex, '$1,') + '.00' : ''\n });\n return queryParams;\n};\n\nconst generatePLPURL = ({ url = window.location, params: allParams, action }) => {\n const params = allParams ? cloneDeep(allParams) : {};\n const filterParams = params.filterParams ? cloneDeep(params.filterParams) : null;\n if (params.filterParams) {\n delete params.filterParams;\n }\n\n const currentURL = new URL(url, window.location);\n const isControllerURL = currentURL.pathname.includes('/on/demandware.store/Sites-');\n const loadedSearchParams = window.searchParams || (window.constructorIOSettings && window.constructorIOSettings.initialSearchParams) || {};\n const pathname = currentURL.pathname;\n const querySearchParams = new URLSearchParams();\n let queryParams = {};\n let urlSearchParams = cloneDeep(loadedSearchParams);\n\n if (filterParams && typeof filterParams === 'object') {\n const isSetAction = !action || action === 'set';\n const sourceObj = isSetAction ? filterParams : loadedSearchParams.filterParams;\n urlSearchParams.filterParams = cloneDeep(sourceObj || {});\n\n if (!isSetAction) {\n Object.keys(filterParams).forEach(filterKey => {\n const filterValueArray = !Array.isArray(filterParams[filterKey]) ? [filterParams[filterKey]] : filterParams[filterKey];\n filterValueArray.forEach(filterValue => {\n if ([null, undefined, NaN, ''].indexOf(filterValue) === -1) {\n const modifiedValue = modifyValue(urlSearchParams.filterParams[filterKey], filterValue.toString(), action);\n if (modifiedValue.length === 0) {\n delete urlSearchParams.filterParams[filterKey];\n } else {\n urlSearchParams.filterParams[filterKey] = modifiedValue;\n }\n }\n });\n });\n }\n }\n\n Object.keys(params).forEach(key => {\n const paramValue = params[key];\n if ([null, undefined, NaN, ''].indexOf(paramValue) === -1) {\n urlSearchParams[key] = paramValue;\n } else {\n delete urlSearchParams[key];\n }\n });\n\n if (!isControllerURL) {\n // generate pathname and remove data from search params\n let activePathRefinements = [];\n\n const { ROUTE_REFINEMENT_ATTRIBUTES } = getConstructorIOSettings();\n\n ROUTE_REFINEMENT_ATTRIBUTES.forEach(function (key) {\n let value = urlSearchParams.filterParams[key] || undefined;\n\n if (value) {\n value = Array.isArray(value) ? value : [value];\n\n delete urlSearchParams.filterParams[key];\n activePathRefinements.push(\n value.map((ref) => encodeURIComponent(ref.toString().toLowerCase().replace('&', 'and').replace(' ', '_'))).join('+')\n );\n }\n });\n\n currentURL.pathname = pathname.replace(/\\/search(\\/.*)?/, `/search${(activePathRefinements.length > 0 ? '/' : '') + activePathRefinements.join('-')}`);\n }\n\n queryParams = searchToQueryParams(urlSearchParams);\n\n if (!queryParams.start) {\n delete queryParams.start;\n delete queryParams.sz;\n }\n\n Object.keys(queryParams).forEach(key => {\n const value = queryParams[key];\n if ([null, undefined, NaN, ''].indexOf(value) === -1) {\n querySearchParams.set(key, queryParams[key]);\n }\n });\n currentURL.search = querySearchParams.toString().replace(/[+]/g, ' ');\n return currentURL.toString();\n};\n\nconst parseControllerPLPURL = ({ url: _url, data }) => {\n const url = new URL(_url || '', window.location.href);\n if (!url.pathname.includes('/on/demandware.store/Sites-')) {\n return false;\n }\n url.searchParams.sort();\n let priceParams = {};\n let filterParams = {};\n let trailingFilters = {};\n let extraParams = {};\n let sortRule;\n let pageSize = (data && data.pageSize) || '12';\n let start = '';\n let query = '';\n let priceRange;\n url.searchParams.forEach(function (value, key) {\n if (key === 'srule') {\n sortRule = value;\n } else if (key === 'q') {\n query = value;\n } else if (key === 'sz') {\n pageSize = value;\n } else if (key === 'start') {\n start = value;\n } else if (['pmin', 'pmax'].indexOf(key) > -1) {\n priceParams[key] = parseInt(value.replace(',', ''), 10);\n } else if (/^(prefn|prefv)\\d+$/.test(key)) {\n const prefIndex = key.slice(5); // 'prefn'.length || 'prefv'.length\n const prefName = url.searchParams.get('prefn' + prefIndex);\n const prefValue = url.searchParams.get('prefv' + prefIndex);\n filterParams[prefName] = prefValue.split('|');\n } else {\n extraParams[key] = value;\n }\n });\n\n if (Object.keys(priceParams).length) {\n priceRange = [parseInt(priceParams.pmin, 10) || 0, parseInt(priceParams.pmax, 10) || 9999];\n }\n\n return {\n url,\n query,\n sortRule,\n start,\n pageSize,\n priceRange,\n filterParams,\n trailingFilters,\n extraParams\n };\n};\n\nconst getPriceRange = (value) => {\n const { PRICE_RANGE } = getConstructorIOSettings();\n const min = typeof value.range[0] === 'string'\n ? PRICE_RANGE[value.range[0]]\n : value.range[0];\n const max = typeof value.range[1] === 'string'\n ? PRICE_RANGE[value.range[1]]\n : value.range[1];\n return [min, max];\n};\n\n/**\n * Converts an HEX color value to RGB. Conversion formula\n * @param {number} hex The hex color value\n * @return {Array} The RGB representation\n */\nconst hexToRgb = (hex) => {\n var hexValue = hex;\n hexValue = hexValue.length === 4 ? '#' + hexValue[1] + hexValue[1] + hexValue[2] + hexValue[2] + hexValue[3] + hexValue[3] : hexValue;\n var result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hexValue);\n return result ? {\n r: parseInt(result[1], 16),\n g: parseInt(result[2], 16),\n b: parseInt(result[3], 16)\n } : null;\n};\n\n/**\n * Converts an RGB color value to HSL. Conversion formula\n * returns h, s, and l in the set [0, 1].\n * @param {number} r The red color value\n * @param {number} g The green color value\n * @param {number} b The blue color value\n * @return {Array} The HSL representation\n */\nconst rgbToHsl = (r, g, b) => {\n r /= 255, g /= 255, b /= 255; // eslint-disable-line\n var max = Math.max(r, g, b);\n var min = Math.min(r, g, b);\n var h, s, l = (max + min) / 2; // eslint-disable-line\n\n if (max === min) {\n h = s = 0; // achromatic\n } else {\n var d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n switch (max) { // eslint-disable-line\n case r: h = (g - b) / d + (g < b ? 6 : 0); break; // eslint-disable-line\n case g: h = (b - r) / d + 2; break; // eslint-disable-line\n case b: h = (r - g) / d + 4; break; // eslint-disable-line\n }\n h /= 6;\n }\n\n return [h, s, l];\n};\n\n/**\n * Checks and return the color Lightness values\n * @param {string} color The swatch color value\n * @return {boolean} HSL color or False\n */\nconst getLightnessValue = (color) => {\n if (color) {\n let RGBColor = hexToRgb(color);\n if (RGBColor) {\n let getHSLColor = rgbToHsl(RGBColor.r, RGBColor.g, RGBColor.b);\n return getHSLColor;\n }\n }\n return false;\n};\n\nconst determineNoBorderClass = (hexCode, hexCodeII) => {\n const stdLightness = 0.6;\n let swatchColor = hexCode || '#1d1d1d';\n let swatchColorII = hexCodeII || '#1d1d1d';\n let lightness;\n let lightnessII;\n\n lightness = getLightnessValue(swatchColor);\n if (swatchColor !== swatchColorII) {\n lightnessII = getLightnessValue(swatchColorII);\n }\n if (lightness && lightnessII) {\n return lightness[2] < stdLightness && lightnessII[2] < stdLightness ? 'no-border' : '';\n }\n if (lightness) {\n return lightness[2] < stdLightness ? 'no-border' : '';\n }\n return '';\n};\n\nmodule.exports = {\n getPriceRange,\n getPriceFacetOptions,\n getCioPreFilterExpression,\n searchToQueryParams,\n parseControllerPLPURL,\n generatePLPURL,\n determineNoBorderClass\n};\n","'use strict';\n\nconst eventMgr = require('./components/core/eventMgr').default;\nconst emitter = eventMgr.getEmitter('window');\n\nconst util = require('./util');\nconst viewportWidth = {\n extraSmall: { maxWidth: 480 },\n small: { maxWidth: 767, minWidth: 320 },\n medium: { maxWidth: 1023, minWidth: 768 },\n large: { maxWidth: 1439, minWidth: 1024 }\n};\n\nvar $cache = {};\nvar layout;\nvar initialized = false;\nvar currentHTMLClasses = '';\nvar deviceList;\n\n/**\n * @description Adds jQuery objects to cache\n */\nfunction initializeCache() {\n $cache = {\n $html: $('html')\n };\n}\n\n/**\n * @description Adding classes to html tag\n */\nfunction addHTMLClasses() {\n deviceList = deviceList || Object.assign({}, device);\n currentHTMLClasses = Object.keys(Object.getPrototypeOf(deviceList)).filter((item) => {\n return deviceList[item]() ? 1 : 0;\n });\n $cache.$html.addClass(currentHTMLClasses.join(' '));\n}\n\n/**\n * @description removing classes from html tag\n */\nfunction cleanupHTMLClasses() {\n currentHTMLClasses.forEach((currentValue) => {\n $cache.$html.removeClass(currentValue);\n });\n}\n\n/**\n * @description Binds events to DOM\n */\nfunction initializeEvents() {\n var viewMode = layout.getMode();\n\n $(window).on('resize', util.eventDelay(() => {\n $(document).trigger('window.resize');\n emitter.emit('resize');\n var layoutView = layout.getMode();\n\n if (viewMode !== layoutView) {\n viewMode = layoutView;\n cleanupHTMLClasses();\n addHTMLClasses();\n $(document).trigger('window.modechanged', { mode: viewMode });\n emitter.emit('modechanged');\n }\n }, 500));\n\n $(window).on('scroll', util.eventDelay(() => {\n $(document).trigger('window.scroll', { scrollTop: $(this).scrollTop() });\n emitter.emit('scroll');\n }, 300));\n}\n\nlayout = {\n getMode: function () {\n var windowWidth = window.innerWidth;\n\n if (windowWidth <= viewportWidth.extraSmall.maxWidth) {\n return 'extraSmall';\n }\n if (windowWidth <= viewportWidth.small.maxWidth) {\n return 'small';\n }\n if (windowWidth <= viewportWidth.medium.maxWidth) {\n return 'medium';\n }\n if (windowWidth <= viewportWidth.large.maxWidth) {\n return 'large';\n }\n\n return 'extra-large';\n },\n getCurrentBreakpointWidth: function () {\n return viewportWidth[this.getMode()] && viewportWidth[this.getMode()].maxWidth;\n },\n isExtraSmallView: function () {\n return this.getMode() === 'extraSmall';\n },\n isSmallView: function () {\n return this.getMode() === 'small';\n },\n isMediumView: function () {\n return this.getMode() === 'medium';\n },\n isLargeView: function () {\n return this.getMode() === 'large';\n },\n isExtraLargeView: function () {\n return this.getMode() === 'extra-large';\n },\n isMobileView: function () {\n return this.isExtraSmallView() || this.isSmallView() || this.isMediumView();\n },\n init: function () {\n if (initialized) {\n return this;\n }\n\n require('./utils/device');\n initializeCache();\n addHTMLClasses();\n initializeEvents();\n initialized = true;\n return this;\n },\n isMobile: function () {\n return typeof device.mobile === 'function' && device.mobile();\n },\n isTablet: function () {\n return typeof device.tablet === 'function' && device.tablet();\n },\n isDesktop: function () {\n return typeof device.desktop === 'function' && device.desktop();\n },\n isIOS: function () {\n return typeof device.ios === 'function' && device.ios();\n },\n isAndroid: function () {\n return typeof device.android === 'function' && device.android();\n },\n isLandscape: function () {\n return typeof device.landscape === 'function' && device.landscape();\n },\n isPortrait: function () {\n return typeof device.portrait === 'function' && device.portrait();\n }\n};\n\nmodule.exports = layout;\n","var rvbEnabled = $('.product-detail').data('rvbenabled');\n\n/**\n * sets a cookie\n * @param {string} cname - name of cookie\n * @param {string} cvalue - cookie value\n * @param {string} exdays - expiration date for cookie\n * @param {string} secure - on or off\n */\nfunction setPIDCookie(cname, cvalue, exdays) {\n var d = new Date();\n d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));\n var expires = 'expires=' + d.toGMTString();\n\n document.cookie = `${cname} = ${cvalue}; ${expires}; secure='on'; path=/;`;\n}\n\n/**\n * gets a cookie\n * @param {string} cname - name of cookie\n * @return {undefined}\n */\nfunction getCookie(cname) {\n var name = cname + '=';\n var ca = document.cookie.split(';');\n for (var i = 0; i < ca.length; i++) {\n var c = ca[i];\n while (c.charAt(0) === ' ') {\n c = c.substring(1);\n }\n if (c.indexOf(name) === 0) {\n return c.substring(name.length, c.length);\n }\n }\n return '';\n}\n/**\n * Init for cookie function\n */\nfunction init() {\n if (rvbEnabled) {\n var rvbExpireDate = $('.product-detail').data('rvbexpire');\n var pidCookie = [getCookie('pvpIDs')];\n var productId = [$('button.product').data('analytics-style')];\n var productIds = JSON.stringify(pidCookie);\n\n if (pidCookie[0] === '') {\n // if pvpIDs cookie doesn't exist, set it using the product ID\n setPIDCookie('pvpIDs', productId, rvbExpireDate);\n } else if (productIds.indexOf(productId) === -1) {\n // if cookie already exists, see if this product ID exists\n // if it does not exist, add it to the cookie\n var newValues = pidCookie.concat(productId);\n setPIDCookie('pvpIDs', newValues, rvbExpireDate);\n }\n }\n}\nmodule.exports = {\n getCookie: getCookie,\n init: init\n};\n","/* eslint-disable no-restricted-globals */\n\n'use strict';\n\nconst util = require('../util');\nconst search = require('../components/search');\nconst constructorIOPLP = require('../constructorio/constructorIOPLP');\nconst { getConstructorIOSettings } = require('../constructorio/clientWrapper');\nconst { generatePLPURL } = require('../constructorio/utils/utils');\nconst { getConstructorioSearch } = require('../constructorio/request');\nconst loadSlimScrollPlugin = () => util.loadScript('/lib/jquery/jquery.slimscroll.min.js');\n\nlet $page;\nlet $body;\nlet $header;\n\nlet isLoading = 0;\nlet filterSidebarOffset = $('.js-plp-sidebar').length > 0 ? $('.js-plp-sidebar').offset().top - $('.l-plp-header').height() : '';\n\nlet waitTimeout = 0;\n\n/**\n * Starts the spinner.\n */\nconst startSpinner = () => {\n if (typeof $.spinner === 'function') {\n $.spinner().start();\n }\n};\n\n/**\n * Stops the spinner.\n */\nconst stopSpinner = () => {\n if (typeof $.spinner === 'function') {\n $.spinner().stop();\n }\n};\n\n/**\n * Checks if the current page is a search page by checking the presence of '?q=' in the URL.\n *\n * @returns {number} -1 if '?q=' is not found in the URL (indicating that the page is not a search page), otherwise returns the index at which '?q=' starts in the URL.\n */\nconst isSearchPage = () => {\n return window.location.href.indexOf('?q=') > -1 ? window.location.href.indexOf('?q=') : window.location.href.indexOf('&q=');\n};\n\n/**\n * Update DOM elements with Ajax results\n *\n * @param {Object} $results - jQuery DOM element\n * @param {string} selector - DOM element to look up in the $results\n * @return {undefined}\n */\nfunction updateDom($results, selector) {\n var $updates = $results.find(selector);\n $(selector).empty().html($updates.html());\n}\n\n/**\n * Keep refinement panes expanded/collapsed after Ajax refresh\n *\n * @param {Object} $results - jQuery DOM element\n * @return {undefined}\n */\nfunction handleRefinements($results) {\n $('.refinement.active').each(function () {\n var $activeRefinement = $(this);\n $activeRefinement.removeClass('active');\n var activeDiv = $results.find('.' + $activeRefinement[0].className.replace(/ /g, '.'));\n activeDiv.addClass('active');\n activeDiv.find('button.title').attr('aria-expanded', 'true');\n });\n\n updateDom($results, '.refinements');\n}\n\n/**\n * Update data attribute value\n * @param {Object} $results - jQuery DOM element\n * @param {string} attrName - attribute name\n * @return {undefined}\n */\nfunction updateDataAttributeValue($results, attrName) {\n const selector = `[${attrName}]`;\n $(selector).attr(attrName, $results.find(selector).attr(attrName) || '');\n}\n\n/**\n * Update data-analytics-plp-count in dom from html response\n *\n * @param {Object} $results - jQuery DOM element\n * @return {undefined}\n */\nfunction handleAnalyticsValues($results) {\n updateDataAttributeValue($results, 'data-analytics-plp-count');\n updateDataAttributeValue($results, 'data-analytics-plp-sort-default');\n}\n\n// Update mobile sort options\n// eslint-disable-next-line require-jsdoc\nfunction updateMobileSortOptions() {\n var windowUrl = window.location.href;\n if (windowUrl.indexOf('srule=') !== -1) {\n var srule = util.getParameterValueFromUrl('srule', windowUrl);\n if (srule) {\n $(`input[type=radio][id=id-sort-${srule}]`).prop('checked', true);\n $(`input[type=radio][id=id-sort-${srule}]`).parents('.b-refinements-content').siblings('.b-refinements-header').removeClass('collapsed');\n $(`input[type=radio][id=id-sort-${srule}]`).parents('.b-refinements-content').addClass('show');\n }\n }\n}\n\n// Hide By team Refinement after one selection\n// eslint-disable-next-line require-jsdoc\nfunction onHideTeamRefinement() {\n if (isSearchPage() === -1) {\n var teamRefinement = $('.b-refinements-item[data-refinement-id=\"team\"]');\n var selectedTeam = teamRefinement ? teamRefinement.find('li a.m-selected') : '';\n if (teamRefinement.length && selectedTeam.length === 1) {\n teamRefinement.css('display', 'none');\n }\n }\n}\n\n/**\n * Updates page when we have no results response\n *\n * @param {Object} $results - jquery object of responsse html\n * @param {string} selector - selecter of no result element\n * @return {undefined}\n */\nfunction handleNoResultResponse($results, selector) {\n const $noResultData = $results.find(selector);\n if ($noResultData.length > 0) {\n const updateContainerSelector = '.l-plp-container';\n const $container = $noResultData.closest(updateContainerSelector);\n $(updateContainerSelector).empty().html($container.length > 0 ? $container.html() : $noResultData);\n }\n}\n\n/**\n * Parse Ajax results and updated select DOM elements\n *\n * @param {string} response - Ajax response HTML code\n * @param {Array} additionalSelectors - Additional selectors for update DOM\n * @return {undefined}\n */\nfunction parseResults(response, additionalSelectors) {\n const $results = $(response);\n const specialHandlers = {\n '.b-nosearch_results-title': handleNoResultResponse,\n '.refinements': handleRefinements\n };\n\n // Update DOM elements that do not require special handling\n [\n ...additionalSelectors,\n '.js-products_count',\n '.js-header-sort',\n '.js-products_grid',\n '.js-show_more',\n '.js-refinements',\n '.js-selected-refinements',\n '.canonical-div',\n '.b-plp_header-category_heading',\n '.b-plp_header-breadcrumbs',\n '.b-plp_header-search'\n ].forEach(function (selector) {\n updateDom($results, selector);\n });\n onHideTeamRefinement();\n\n Object.keys(specialHandlers).forEach(function (selector) {\n specialHandlers[selector]($results, selector);\n });\n\n handleAnalyticsValues($results);\n\n const url = $('input[data-canonical-url]').data('canonical-url');\n if (url) {\n history.replaceState({}, '', url);\n }\n updateMobileSortOptions();\n}\n\n/**\n * This function retrieves another page of content to display in the content search grid\n * @param {JQuery} $element - the jquery element that has the click event attached\n * @param {JQuery} $target - the jquery element that will receive the response\n * @return {undefined}\n */\nfunction getContent($element, $target) {\n var showMoreUrl = $element.data('url');\n startSpinner();\n $.ajax({\n url: showMoreUrl,\n method: 'GET',\n success: function (response) {\n $target.append(response);\n stopSpinner();\n },\n error: function () {\n stopSpinner();\n }\n });\n}\n\n/**\n * Update sort option URLs from Ajax response\n *\n * @param {string} response - Ajax response HTML code\n * @return {undefined}\n */\nfunction updateSortOptions(response) {\n const $tempDom = $('
    ').append($(response));\n const dataOptions = $tempDom.find('.js-grid_footer').data('sort-options');\n const sortOptions = dataOptions ? dataOptions.options : false;\n if (Array.isArray(sortOptions)) {\n sortOptions.forEach(function (option) {\n const trimmedId = option.id.replace(/\\s/g, '');\n $('option.' + trimmedId).val(option.url);\n $('li.js-sort-item[data-id=\"' + trimmedId + '\"]').data('value', option.url);\n });\n }\n}\n\n// eslint-disable-next-line require-jsdoc\nfunction modifyUrl(link) {\n if (link === undefined) {\n $('body .js-grid_footer button.triggerMore').click();\n } else {\n var href = link;\n var windowUrl = window.location.href.split('&start')[0];\n var appliedFilter = window.location.href.indexOf('?p');\n var url = new URL(window.location.href);\n var srule = url.searchParams.get('srule');\n var sruleParam = window.location.href.indexOf('?srule');\n var appliedSizeModel = window.location.href.indexOf('?viewPreference');\n var isShopAllUrl = window.location.href.indexOf('?isShopAllUrl');\n if (sruleParam !== -1 || appliedSizeModel !== -1 || isShopAllUrl !== -1) {\n appliedFilter = 0;\n }\n if (isSearchPage() !== -1 || appliedFilter !== -1) {\n if (href === '?start=0&sz=12') {\n href = windowUrl;\n } else {\n href = windowUrl + href.replace('?', '&');\n }\n }\n\n if (href === '?start=0&sz=12' && isSearchPage() === -1) {\n href = window.location.href.split('?')[0];\n if (srule) {\n href += '?srule=' + srule;\n }\n } else if (link === '?start=0&sz=12' && appliedFilter !== -1) {\n href = window.location.href.split('&start')[0];\n history.replaceState(null, null, href);\n }\n\n if (href === window.location.href.split('?')[0] || windowUrl.indexOf(href) === -1) {\n if (srule && href.indexOf('srule') === -1) {\n if (href.indexOf('?') > -1) {\n href += '&srule=' + srule;\n } else {\n href += '?srule=' + srule;\n }\n }\n if (windowUrl.indexOf(href) === -1) {\n history.replaceState(null, null, href);\n }\n }\n }\n}\n\n/**\n * Inits events for adding parameters to url after clicking on grid tiles\n */\nfunction gridTileClick() {\n $body.on('click', '.b-products_grid .b-products_grid-tile', function () {\n var startPageSize = $(this).attr('data-tile-num');\n var lastClickedClass = $(this).attr('data-pid');\n var locationParts = window.location.href.split('?');\n var newLocation = locationParts[0].split('#')[0];\n\n // set session variabele with clicked tile value\n var isSafari = /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent);\n if (isSafari) {\n sessionStorage.removeItem('plpLastClickedTile');\n sessionStorage.setItem('plpLastClickedTile', lastClickedClass);\n }\n\n // eslint-disable-next-line no-nested-ternary\n var newLocParams = window.params ? window.params : (locationParts[1] ? locationParts[1].split('#')[0] : '');\n var queryParams = newLocParams ? newLocParams.split('&') : '';\n if (!queryParams && !!startPageSize) {\n if (!(startPageSize === '0')) {\n newLocation = newLocation + '?start=' + startPageSize;\n }\n } else if (!!queryParams && newLocParams.indexOf('start=') < 0 && !!startPageSize) {\n if (startPageSize === '0') {\n newLocation = newLocation.concat('?' + newLocParams);\n } else {\n newLocation = newLocation.concat('?' + newLocParams + '&start' + startPageSize);\n }\n } else {\n for (var i = 0; i < queryParams.length; i++) {\n if (startPageSize !== '0') {\n if (i !== 0) {\n newLocation += '&';\n } else {\n newLocation += '?';\n }\n }\n\n if (queryParams[i].indexOf('start') > -1) {\n if (startPageSize !== '0') {\n newLocation = newLocation + 'start=' + startPageSize;\n }\n } else {\n newLocation += queryParams[i];\n }\n }\n }\n });\n}\n\n/**\n* Traverse dom tree and grabs analytics values and emits event\n* @param {JQuery} $filter jquery element of button clicked\n* @param {JQuery} $results jquery element of html from ajax filter response\n* @return {undefined}\n*/\nfunction analyticsNotifyFilter($filter, $results) {\n const titleSelector = 'data-analytics-plp-filter-title';\n const valueSelector = 'data-analytics-plp-filter-value';\n const totalCountSelector = 'data-analytics-plp-count';\n const productStyleSelector = 'data-analytics-style';\n const selectedFilterSelector = 'data-analytics-plp-selected-filter-value';\n\n const refinementTitle = $filter.parents(`[${titleSelector}]`).attr(titleSelector);\n const refinementValue = $filter.closest(`[${valueSelector}]`).attr(valueSelector);\n const totalCount = $results.find(`[${totalCountSelector}]`).attr(totalCountSelector);\n const productStyles = $results.find(`[${productStyleSelector}]`).map(function () {\n return $(this).attr(productStyleSelector);\n }).toArray();\n const selectedFilters = $body.find(`[${selectedFilterSelector}]`).map(function () {\n return $(this).attr(selectedFilterSelector);\n }).toArray();\n\n $body.trigger('grid:refinementComplete', {\n refinementTitle,\n refinementValue,\n totalCount,\n productStyles,\n selectedFilters\n });\n}\n\n/**\n * This function will check if an element is visible in viewport\n * @param {string} element - selector for element\n * @param {number} minTopPos - px value of space above the value that we should ignore\n * @return {boolean} value if element is visible\n */\nfunction isInViewport(element, minTopPos = 0) {\n const rect = document.querySelector(element).getBoundingClientRect();\n return (\n rect.top >= minTopPos\n && rect.left >= 0\n && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight)\n && rect.right <= (window.innerWidth || document.documentElement.clientWidth)\n );\n}\n\n// eslint-disable-next-line require-jsdoc\nfunction collapseTilesAndUpdateCount() {\n if (!isNaN($('.js-products_count').attr('data-analytics-plp-count')) && $('.js-products_count').text() !== null && $('.js-products_count').text() !== '' && $('.js-products_count').text().split(' ').length > 1) {\n $('.b-products_grid-tile').find('.b-tile.hide').parent('.b-products_grid-tile').addClass('hide');\n var searchResultCount = parseInt($('.js-products_count').attr('data-analytics-plp-count'), 10) - $('section.b-products_grid-tile').find('.b-tile-images_container .b-tile-main_image[title=\"No Image\"]').length;\n var searchResultText = searchResultCount + ' ' + $('.js-products_count').text().trim().split(' ')[1];\n $('.js-products_count').text(searchResultText);\n }\n}\n\n/**\n * Checking the Height of PLP Sidebar to add ScrollBar\n *\n */\nfunction checkFilterSize() {\n if ($(window).width() > 1023) {\n var sideBar = $('.js-plp-sidebar');\n var filterSidebarHeight = sideBar.height();\n var pageHeaderHeight = $('.l-plp-header').outerHeight();\n var headerHeight = $('.js-header').height();\n var doc = $(window).height() - headerHeight - pageHeaderHeight;\n var outerContentHeight = headerHeight + pageHeaderHeight;\n var scrollHeight;\n if (sideBar.hasClass('filter-sticky')) {\n scrollHeight = 'calc(100vh - ' + headerHeight + 'px)';\n } else {\n scrollHeight = 'calc(100vh - ' + outerContentHeight + 'px)';\n }\n sideBar.css('top', headerHeight);\n if (filterSidebarHeight > doc) {\n sideBar.addClass('b-scrollable-content');\n loadSlimScrollPlugin().then(() => {\n $('.js-slim-scrollbar').slimScroll({\n height: scrollHeight,\n railVisible: true,\n color: '#d0d0d0',\n railColor: '#ffffff',\n railOpacity: 1,\n size: '7px',\n alwaysVisible: true\n });\n });\n } else {\n sideBar.removeClass('b-scrollable-content');\n }\n }\n}\n\n// eslint-disable-next-line require-jsdoc\nfunction getSelectedModelSizeUrl(baseUrl) {\n if ($('.js-select-model-size:visible').length > 0) {\n var selectedSize = $('.js-select-model-size:visible').val();\n $body.find('.js-select-model-size:hidden').val(selectedSize).trigger('change', [true]);\n if (selectedSize) {\n var urlParams = {\n viewPreference: selectedSize\n };\n return util.appendParamsToUrl(baseUrl, urlParams);\n }\n }\n return baseUrl;\n}\n// eslint-disable-next-line require-jsdoc\nfunction getSelectedSortingRule(baseUrl) {\n if ($('select.b-sort-select').find('option:selected').length > 0) {\n var selectedsortingRule = $('select.b-sort-select').find('option:selected').data('id');\n if ($(window).width() < 1024) {\n selectedsortingRule = $('input[name=\"sortMobileOption\"]:checked').val();\n }\n\n if (selectedsortingRule) {\n var urlParams = {\n srule: selectedsortingRule\n };\n // remove from srule from url if present then add srule with latest updated values\n if (baseUrl.indexOf('srule=') !== -1) {\n baseUrl = util.removeParamFromURL(baseUrl, 'srule'); // eslint-disable-line no-param-reassign\n }\n return util.appendParamsToUrl(baseUrl, urlParams);\n }\n }\n return baseUrl;\n}\n\n// Disable unselected By Teams refinement values on PLP page\n// eslint-disable-next-line require-jsdoc\nfunction disableTeamRefinements(teamRefinement, selectedTeam, $this) {\n if (selectedTeam.length === 1) {\n teamRefinement.find('li a:not(.m-selected)').each(function () {\n $(this).addClass('disabled-team');\n });\n } else {\n // avoid the 2nd selection of team refinement during the page reload\n $this.removeClass('m-selected');\n teamRefinement.find('li a:not(.m-selected)').each(function () {\n $(this).addClass('disabled-team');\n });\n return false;\n }\n return true;\n}\n\nconst searchModule = {\n init: function () {\n $page = $('.js-page');\n $body = $('body');\n $header = $('.js-header');\n },\n gridTileClick: gridTileClick,\n methods: {\n resetLoading: () => {\n isLoading = 0;\n },\n constractorRequestErrorHandler: () => {\n const searchShowAjax = window.constructorIOURLs ? window.constructorIOURLs.searchShowAjax : '';\n // generate url only with q= , srule= and extra parameters\n const url = generatePLPURL({\n url: searchShowAjax,\n params: {\n filterParams: {}, priceRange: null, start: null, sz: null\n }\n });\n\n const $productsGrid = $('.b-products_grid');\n const data = {\n page: 1,\n selectedUrl: url,\n selectedFilter: []\n };\n delete window.searchParams;\n searchModule.methods.applyFilterRequest(url, data, $productsGrid);\n },\n applySortingRequest({\n url, data, $productsGrid, selectedOptionText\n }) {\n $.ajax({\n url: url,\n data: data,\n method: 'GET',\n success: (response) => {\n searchModule.methods.applySortingSuccessHandler(response, $productsGrid, selectedOptionText);\n },\n complete: stopSpinner\n });\n },\n applySortingSuccessHandler(response, $productsGrid, selectedOptionText) {\n const $response = $(response);\n $('.js-products_grid').empty().html(response);\n $('.b-sort').find('.b-sort-content:not(.js-categories-content)').empty().html($response.filter('.b-sort-content').html());\n $productsGrid.find('.b-sort-content').remove();\n search.recentlyViewedBadge();\n collapseTilesAndUpdateCount();\n\n const pageUrl = new URL(window.location.href);\n const $selectedSortingElement = $('select.b-sort-select').find('option:selected');\n if (pageUrl && $selectedSortingElement.length > 0) {\n pageUrl.searchParams.set('srule', $selectedSortingElement.data('id'));\n history.replaceState({}, '', pageUrl.toString());\n }\n\n updateMobileSortOptions();\n\n const productIDs = $response.filter('.wishlist-productIDs').length > 0 ? $response.filter('.wishlist-productIDs').val() : null;\n $body.trigger('wishlistSuggestion:update', productIDs);\n\n $body.trigger('search:sortComplete', { selectedOptionText: selectedOptionText });\n },\n applyFilterRequest(url, data, $clickTarget) {\n $.ajax({\n url: url,\n data: data,\n method: 'GET',\n success: (res) => searchModule.methods.applyFilterSuccessHandler(res, $clickTarget)\n });\n },\n applyFilterSuccessHandler(response, $clickTarget) {\n const additionalSelectors = [];\n if ($clickTarget.hasClass('js-category-link')) {\n additionalSelectors.push('.js-plp-banner');\n }\n\n parseResults(response, additionalSelectors);\n // scroll to top after filter is applied\n $(window).scrollTop(0);\n if ($clickTarget && $clickTarget.length > 0) {\n analyticsNotifyFilter($clickTarget, $(response));\n }\n collapseTilesAndUpdateCount();\n search.recentlyViewedBadge();\n\n $body.trigger('components:init');\n const productIDs = $(response).find('.wishlist-productIDs').length > 0 ? $(response).find('.wishlist-productIDs').val() : null;\n $body.trigger('wishlistSuggestion:update', productIDs);\n },\n beforeLoadMoreRequest() {\n const $gridFooter = $('.js-grid_footer');\n if (typeof $gridFooter.spinner === 'function') {\n $gridFooter.spinner().start();\n }\n },\n afterLoadMoreRequest() {\n isLoading = 0;\n const $gridFooter = $('.js-grid_footer');\n if (typeof $gridFooter.spinner === 'function') {\n $('body').removeClass('plp-loading');\n $gridFooter.spinner().stop();\n }\n },\n showMoreDefaultRequest: (url, data, $container, $clickTarget) => {\n return $.ajax({\n url: url,\n data: data,\n method: 'GET',\n beforeSend: searchModule.methods.beforeLoadMoreRequest,\n success: (response) => {\n searchModule.methods.showMoreSuccessHandler(response, $container, $clickTarget);\n },\n complete: searchModule.methods.afterLoadMoreRequest\n });\n },\n showMoreSuccessHandler: (response, $lazyWrapper, $clickTarget) => {\n updateSortOptions(response);\n isLoading = 0;\n const $gridFooter = $('.js-grid_footer');\n\n var headerHeight = $header.height();\n const urlParam = $(response).filter('.b-products_grid-tile').find('.currentPageNumber').val();\n\n if (isInViewport('.js-grid_footer', headerHeight)) {\n $gridFooter.eq(0).replaceWith(response);\n modifyUrl(urlParam);\n } else {\n $lazyWrapper.html(response);\n $lazyWrapper.find('.b-products_grid-tile').addClass('hide');\n $lazyWrapper.find('.updateBrowserUrl').addClass('hide');\n $lazyWrapper.addClass('loadedAlready');\n $gridFooter.eq(0).replaceWith($lazyWrapper.html());\n $lazyWrapper.empty();\n }\n\n $body.trigger('adobeTagManager:productArrayUpdate', $clickTarget);\n $body.find('.b-tile-swatches_slider').trigger('mainCarousel:update');\n $body.trigger('components:init');\n search.recentlyViewedBadge();\n collapseTilesAndUpdateCount();\n\n const productIDs = $(response).filter('.wishlist-productIDs').length > 0 ? $(response).filter('.wishlist-productIDs').val() : null;\n $body.trigger('wishlistSuggestion:update', productIDs);\n }\n },\n sort: () => {\n const $sortOrder = $('#sort-order');\n const $productsGrid = $('.b-products_grid');\n const $plpContainer = $('.l-plp-container');\n const $gSelectricBSortSelect = $('.g-selectric-b-sort-select');\n\n // Handle sort order menu selection\n $page.on('change', '[name=sort-order]', (e) => {\n e.preventDefault();\n\n startSpinner();\n\n const selectedOptionText = $sortOrder.find(`[value=\"${e.target.value}\"]`).text();\n let newUrl = getSelectedModelSizeUrl(e.target.value);\n const data = { selectedUrl: newUrl };\n\n if (window.constructorIOSettings && (window.constructorIOSettings.search_enabled || window.constructorIOSettings.browse_enabled) && window.searchParams) {\n getConstructorioSearch({ url: newUrl, data })\n .then((res) => {\n return constructorIOPLP.convertCIOToHTMLString(res, 'gridTiles');\n })\n .catch(() => {\n searchModule.methods.constractorRequestErrorHandler();\n })\n .then((response) => {\n if (!response) {\n return;\n }\n searchModule.methods.applySortingSuccessHandler(response, $productsGrid, selectedOptionText);\n stopSpinner();\n });\n } else {\n searchModule.methods.applySortingRequest({\n url: newUrl, data, $productsGrid, selectedOptionText\n });\n }\n });\n\n $productsGrid.find('.b-sort-content').remove();\n\n if ($plpContainer.find('li.b-sort-item.m-selected:first').length > 0) {\n const selectedId = $plpContainer.find('li.b-sort-item.m-selected:first').data('id');\n $gSelectricBSortSelect.find(`li.${selectedId}`).addClass('highlighted');\n $gSelectricBSortSelect.find('.g-selectric .label').text($gSelectricBSortSelect.find('li.highlighted').text());\n }\n\n // Mobile sort trigger\n $page.on('change', '[name=sortMobileOption]', (e) => {\n e.preventDefault();\n $('#sort-order').find(`[data-id=\"${$('input[name=\"sortMobileOption\"]:checked').val()}\"]`).prop('selected', 'selected');\n $('#sort-order').trigger('change');\n });\n },\n\n onScroll: () => {\n $(window).on('scroll', function () {\n var headerHeight = $header.height();\n if ($('.js-grid_footer button.triggerMore').length) {\n if (isLoading === 0 && isInViewport('.js-grid_footer', headerHeight)) {\n isLoading = 1;\n if ($('section.b-products_grid-tile.hide').length) {\n var urlParam = $('.updateBrowserUrl.hide').data('url');\n if (urlParam === undefined) {\n $('body .js-grid_footer button.triggerMore').click();\n } else {\n var windowUrl = window.location.href.split('&start')[0];\n if (windowUrl.indexOf(urlParam) === -1) {\n modifyUrl(urlParam);\n }\n $('section.b-products_grid-tile.hide').removeClass('hide').find('.js-cmp-inited').trigger('mainCarousel:update');\n $('.updateBrowserUrl.hide').removeClass('hide');\n $('body .js-grid_footer button.triggerMore').click();\n collapseTilesAndUpdateCount();\n }\n } else {\n $('body .js-grid_footer button.triggerMore').click();\n $('.lazyLoadwrapper').removeClass('loadedAlready');\n }\n }\n }\n\n var navlist = [];\n $('.updateBrowserUrl').each(function () {\n var $this = $(this);\n var thisId = $this.attr('data-url');\n var thisTarget = $(this); // eslint-disable-line\n navlist.push({\n 'anchor': $this, // eslint-disable-line\n 'id': thisId, // eslint-disable-line\n 'target': $this // eslint-disable-line\n });\n return true;\n });\n\n $.each(navlist, function (e, elem) { // eslint-disable-line\n var placement = elem.target[0].getBoundingClientRect();\n if (placement.top < window.innerHeight && placement.bottom > 0) {\n var attrCheck = window.location.href.split('?')[1];\n if (elem.id !== attrCheck) {\n modifyUrl(elem.id);\n }\n return false; /* Exit $.each loop */\n }\n });\n\n if (!$('.js-grid_footer button').hasClass('triggerMore')) {\n setTimeout(function () {\n $('.js-grid_footer button').addClass('triggerMore');\n }, 5000);\n }\n\n if ($(window).width() > 1023) {\n var pageHeaderHeight = $('.l-plp-header').outerHeight();\n var scrollPosition = $(window).scrollTop();\n var outerContentHeight = headerHeight + pageHeaderHeight;\n var scrollHeight;\n if (scrollPosition > filterSidebarOffset) {\n scrollHeight = 'calc(100vh - ' + headerHeight + 'px)';\n $('.js-plp-sidebar').addClass('filter-sticky');\n } else if (scrollPosition <= filterSidebarOffset) {\n scrollHeight = 'calc(100vh - ' + outerContentHeight + 'px)';\n $('.js-plp-sidebar').removeClass('filter-sticky');\n }\n loadSlimScrollPlugin().then(() => {\n $('.js-slim-scrollbar').slimScroll({\n height: scrollHeight,\n railVisible: true,\n color: '#d0d0d0',\n railColor: '#ffffff',\n railOpacity: 1,\n size: '7px',\n alwaysVisible: true\n });\n });\n }\n });\n },\n\n showMore: () => {\n // Show more products\n $page.on('click', '.js-grid_footer button.triggerMore', (e) => {\n e.stopPropagation();\n e.preventDefault();\n const $clickTarget = $(e.target);\n const $lazyWrapper = $('.lazyLoadwrapper');\n\n isLoading = 1;\n\n let showMoreUrl = $clickTarget.data('url');\n if (showMoreUrl === '') {\n return false;\n }\n\n if (showMoreUrl) {\n showMoreUrl = getSelectedModelSizeUrl(showMoreUrl);\n }\n\n const data = {\n showMore: true,\n previous: false,\n pageSize: $('.pageSize').val(),\n breadCrumbLast: $('.breadCrumbLast').val()\n };\n\n $clickTarget.trigger('search:showMore', e);\n $('body').addClass('plp-loading');\n\n if (window.constructorIOSettings && (window.constructorIOSettings.search_enabled || window.constructorIOSettings.browse_enabled) && window.searchParams) {\n searchModule.methods.beforeLoadMoreRequest();\n getConstructorioSearch({ url: showMoreUrl, data })\n .then((res)=>{\n return constructorIOPLP.convertCIOToHTMLString(res, 'gridTiles');\n })\n .catch(() => {\n searchModule.methods.afterLoadMoreRequest();\n searchModule.methods.constractorRequestErrorHandler();\n })\n .then((response) => {\n if (!response) {\n return;\n }\n searchModule.methods.afterLoadMoreRequest();\n searchModule.methods.showMoreSuccessHandler(response, $lazyWrapper, $clickTarget);\n });\n } else {\n searchModule.methods.showMoreDefaultRequest(showMoreUrl, data, $lazyWrapper, $clickTarget);\n }\n return true;\n });\n },\n\n applyFilter: () => {\n // Handle refinement value selection and reset click\n $page.on('click change', '.js-select-model-size, .js-plp-sidebar li a:not(\".b-refinements_category-link\"), .js-category-link, .js-plp-sidebar .js-refinements_clear, .js-refinement_swatch, .js-selected-refinements a',\n (e, isTriggered) => {\n e.preventDefault();\n e.stopPropagation();\n const $currentTarget = $(e.currentTarget);\n\n if (e.type === 'click' && $currentTarget.hasClass('js-select-model-size')) {\n return false;\n }\n\n if (isTriggered && $currentTarget.hasClass('js-select-model-size')) {\n return false;\n }\n\n // Disable unselected team refinement values on PLP page\n const teamRefinement = $('.b-refinements-item[data-refinement-id=\"team\"]:visible');\n const selectedTeam = teamRefinement ? teamRefinement.find('li a.m-selected') : '';\n if (isSearchPage() === -1 && teamRefinement && selectedTeam.length > 0) {\n const updateRefinement = disableTeamRefinements(teamRefinement, selectedTeam, $currentTarget);\n if (!updateRefinement) {\n return false;\n }\n }\n\n isLoading = 0;\n let newUrl = $currentTarget.data('href');\n\n if (newUrl === undefined) {\n const $canonicalUrl = $('.js-canonical-url');\n if ($canonicalUrl.attr('data-action-sizeModelUrl') !== null && $canonicalUrl.attr('data-queryString') !== null) {\n newUrl = $canonicalUrl.attr('data-action-sizeModelUrl') + '?' + $canonicalUrl.attr('data-queryString');\n }\n }\n\n newUrl = getSelectedModelSizeUrl(newUrl);\n\n if ($(window).width() < 1024) {\n const currentUrl = window.location.href;\n if (currentUrl.indexOf('isShopAllUrl') > -1) {\n const urlParams = {\n isShopAllUrl: true\n };\n newUrl = util.appendParamsToUrl(newUrl, urlParams);\n }\n }\n\n // Added selected sorting rules in refinement url if sorting option is in present url\n if (window.location.href.indexOf('srule=') !== -1) {\n newUrl = getSelectedSortingRule(newUrl);\n }\n\n // get the opened refinement items\n let showFilters = [];\n let filters = '';\n if ($('.b-refinements-content.show').length) {\n $('.b-refinements-content.show').each(() => {\n const filter = $(this).attr('data-refinementattr');\n showFilters.push(filter);\n });\n }\n\n filters = showFilters.join(',');\n\n if (!$currentTarget.hasClass('m-disabled')) {\n $currentTarget.trigger('search:filter', e);\n const $gridFooter = $('.js-grid_footer');\n\n const data = {\n page: $gridFooter.data('page-number'),\n selectedUrl: newUrl,\n selectedFilter: filters\n };\n\n const cIOSettings = getConstructorIOSettings();\n\n if ((cIOSettings.search_enabled || cIOSettings.browse_enabled) && window.searchParams) {\n getConstructorioSearch({ url: newUrl, data })\n .then((res) => {\n const a = constructorIOPLP.convertCIOToHTMLString(res, 'searchResultsNoDecorator');\n return a;\n })\n .catch(() => {\n searchModule.methods.constractorRequestErrorHandler();\n })\n .then((response) => {\n if (!response) {\n return;\n }\n searchModule.methods.applyFilterSuccessHandler(response, $currentTarget);\n });\n } else {\n searchModule.methods.applyFilterRequest(newUrl, data, $currentTarget);\n }\n }\n return true;\n });\n },\n\n showContentTab: () => {\n const $container = $('.container');\n const $contentSearchResults = $('#content-search-results');\n const $showMoreContentButton = $('.show-more-content button');\n\n $container.on('click', '.content-search', function () {\n if ($contentSearchResults.html() === '') {\n getContent($(this), $contentSearchResults);\n }\n });\n\n $container.on('click', '.show-more-content button', function () {\n getContent($(this), $contentSearchResults);\n $showMoreContentButton.remove();\n });\n\n setTimeout(() => {\n const $plpCategoryBanner = $('.l-plp-category_banner');\n if ($plpCategoryBanner.find('.hero').length > 0) {\n $plpCategoryBanner.removeClass('hide');\n } else {\n $plpCategoryBanner.addClass('hide');\n }\n }, 2000);\n },\n\n checkFilterHeight: () => {\n checkFilterSize();\n $body.on('click', '.b-refinements-header', function () {\n setTimeout(() => {\n checkFilterSize();\n }, 800);\n });\n },\n\n updateTilesAndCount: () => {\n collapseTilesAndUpdateCount();\n },\n\n waitCIOData: () => {\n const checkCIOData = () => {\n const $container = $('.l-plp-container');\n if (window.initialConstuctorResponse && window.initialConstuctorResponse.response.results.length > 0) {\n $container.html(constructorIOPLP.convertCIOToHTMLString(window.initialConstuctorResponse));\n $('body').trigger('components:init');\n checkFilterSize();\n delete window.initialConstuctorResponse;\n }\n $('.l-plp-container').removeClass('constructor-loading');\n };\n\n var initialRequestTSWithTimeout = window.cioClient ? ((window.initialTS || 0) + (window.constructorIOSettings.timeout || 0)) : 0;\n waitTimeout = initialRequestTSWithTimeout - new Date().getTime();\n if (waitTimeout > 0 && !window.initialConstuctorResponse) {\n setTimeout(() => {\n checkCIOData();\n }, waitTimeout + 50);\n $body.one('cio:initialDataLoaded', checkCIOData);\n } else {\n checkCIOData();\n }\n },\n\n initialLoadMore: () => {\n if (window.location.href.indexOf('start=') !== -1) {\n $('.js-grid_footer button.triggerMore').removeClass('triggerMore');\n } else {\n setTimeout(function () {\n $('body .js-grid_footer button.triggerMore').click();\n }, waitTimeout + 1000);\n }\n },\n\n onPageLoad: () => {\n $(window).ready(function () {\n const urlParam = window.location.search;\n if (urlParam.indexOf('srule') > -1) {\n const sortValue = new RegExp('[?&]' + 'srule' + '=([^&]*)').exec(urlParam); // eslint-disable-line\n $(`#sort-order [data-id=\"${sortValue[1]}\"]`).prop('selected', 'selected');\n $('#sort-order').trigger('change');\n }\n });\n\n $(window).on('load', function () {\n const urlParam = window.location.search;\n if (urlParam.indexOf('viewPreference') > -1) {\n const modelSize = new RegExp('[?&]' + 'viewPreference' + '=([^&]*)').exec(urlParam); // eslint-disable-line\n $body.find('.js-select-model-size', this.$el).val(modelSize[1]).trigger('change', [true]);\n }\n\n // browser back focus on the last clicked tile for safari\n var isSafari = /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent);\n if (isSafari) {\n if (window.location.href.indexOf('start=') !== -1 || $('[name=\"pdpBack\"]').data('comingbackfrompdp')) {\n var headerHeight = $('.js-header').height() + $('.l-plp-mob_header').height();\n var lastClickedTile = sessionStorage.getItem('plpLastClickedTile');\n var $lastClickedTileDiv = $('.' + lastClickedTile);\n if ($lastClickedTileDiv && $lastClickedTileDiv.length > 0) {\n $('html, body').animate({\n scrollTop: $($lastClickedTileDiv).offset().top - headerHeight\n }, 500).promise().done(function () {\n sessionStorage.removeItem('plpLastClickedTile');\n });\n }\n } else {\n sessionStorage.removeItem('plpLastClickedTile');\n }\n }\n\n updateMobileSortOptions();\n onHideTeamRefinement();\n });\n },\n\n updateWishlistIndicatorOnLoad: () => {\n const productIDs = $('.wishlist-productIDs:last').length > 0 ? $('.wishlist-productIDs:last').val() : null;\n $body.trigger('wishlistSuggestion:update', productIDs);\n }\n};\n\nmodule.exports = searchModule;\n","'use strict';\n\n/* eslint-disable */\nvar inScroll = false;\n\nvar util = {\n /**\n * @function\n * @description Scrolls a browser window to a given x point or DOM object\n * @param {String} x coordinate or {Object} to which to scroll\n * @param {Number} duration of animation in milliseconds\n * @param {Function} callback after animation is complete\n */\n scrollTo: function (topOffsetOrElement, duration, cb) {\n var $scrollElement,\n scrollToElement = typeof topOffsetOrElement === 'object',\n duration = duration || 10,\n topOffset;\n\n if (inScroll) {\n return;\n }\n\n inScroll = true;\n\n if (scrollToElement) {\n topOffset = topOffsetOrElement.offset().top;\n } else {\n topOffset = topOffsetOrElement;\n }\n\n $scrollElement = $('html, body');\n\n $scrollElement.animate({\n scrollTop: topOffset\n }, duration, () => {\n if (typeof cb === 'function') {\n cb();\n }\n\n inScroll = false;\n }\n );\n },\n /**\n * @function\n * @description appends the parameter with the given name and value to the given url and returns the changed url\n * @param {String} url the url to which the parameter will be added\n * @param {String} name the name of the parameter\n * @param {String} value the value of the parameter\n */\n appendParamToURL: function (url, name, value) {\n // quit if the param already exists\n if (url.indexOf(name + '=') !== -1) {\n return url;\n }\n var separator = url.indexOf('?') !== -1 ? '&' : '?';\n return url + separator + name + '=' + encodeURIComponent(value);\n },\n\n /**\n * @function\n * @description remove the parameter and its value from the given url and returns the changed url\n * @param {String} url the url from which the parameter will be removed\n * @param {String} name the name of parameter that will be removed from url\n */\n removeParamFromURL: function (url, name) {\n if (url.indexOf('?') === -1 || url.indexOf(name + '=') === -1) {\n return url;\n }\n var hash;\n var params;\n var domain = url.split('?')[0];\n var paramUrl = url.split('?')[1];\n var newParams = [];\n // if there is a hash at the end, store the hash\n if (paramUrl.indexOf('#') > -1) {\n hash = paramUrl.split('#')[1] || '';\n paramUrl = paramUrl.split('#')[0];\n }\n params = paramUrl.split('&');\n for (var i = 0; i < params.length; i++) {\n // put back param to newParams array if it is not the one to be removed\n if (params[i].split('=')[0] !== name) {\n newParams.push(params[i]);\n }\n }\n return domain + '?' + newParams.join('&') + (hash ? '#' + hash : '');\n },\n\n /**\n * @function\n * @description appends the parameters to the given url and returns the changed url\n * @param {String} url the url to which the parameters will be added\n * @param {Object} params\n */\n appendParamsToUrl: function (url, params) {\n var _url = url;\n for (var key in params) {\n _url = this.appendParamToURL(_url, key, params[key]);\n }\n return _url;\n },\n /**\n * @function\n * @description extract the query string from URL\n * @param {String} url the url to extra query string from\n **/\n getQueryString: function (url) {\n var qs;\n if (typeof url !== 'string') { return; }\n var a = document.createElement('a');\n a.href = url;\n if (a.search) {\n qs = a.search.substr(1); // remove the leading ?\n }\n return qs;\n },\n\n /**\n * @function\n * @description\n * @param {String}\n * @param {String}\n */\n elementInViewport: function (el, offsetToTop) {\n var top = el.offsetTop,\n left = el.offsetLeft,\n width = el.offsetWidth,\n height = el.offsetHeight;\n\n while (el.offsetParent) {\n el = el.offsetParent;\n top += el.offsetTop;\n left += el.offsetLeft;\n }\n\n if (typeof (offsetToTop) !== 'undefined') {\n top -= offsetToTop;\n }\n\n if (window.pageXOffset !== null) {\n return (\n top < (window.pageYOffset + window.innerHeight) &&\n left < (window.pageXOffset + window.innerWidth) &&\n (top + height) > window.pageYOffset &&\n (left + width) > window.pageXOffset\n );\n }\n\n if (document.compatMode === 'CSS1Compat') {\n return (\n top < (window.document.documentElement.scrollTop + window.document.documentElement.clientHeight) &&\n left < (window.document.documentElement.scrollLeft + window.document.documentElement.clientWidth) &&\n (top + height) > window.document.documentElement.scrollTop &&\n (left + width) > window.document.documentElement.scrollLeft\n );\n }\n },\n\n /**\n * @function\n * @description Appends the parameter 'format=ajax' to a given path\n * @param {String} path the relative path\n */\n ajaxUrl: function (path) {\n return this.appendParamToURL(path, 'format', 'ajax');\n },\n\n /**\n * @function\n * @description Extracts all parameters from a given query string into an object\n * @param {String} qs The query string from which the parameters will be extracted\n */\n getQueryStringParams: function (qs) {\n if (!qs || qs.length === 0) { return {}; }\n var params = {};\n // Use the String::replace method to iterate over each\n // name-value pair in the string.\n qs.replace(new RegExp('([^?=&]+)(=([^&]*))?', 'g'),\n function ($0, $1, $2, $3) {\n params[$1] = decodeURIComponent($3).replace(/\\+/g, ' ');\n }\n );\n return params;\n },\n\n getParameterValueFromUrl: function (parameterName, url) {\n var currentQueryString = url || window.location.search;\n var currentQueryStringParams = this.getQueryStringParams(currentQueryString);\n\n return currentQueryStringParams[parameterName];\n },\n\n /**\n * @description funtion that check storage Availability on window object\n * @param {String} storage type(name)\n * @return {Boolean}\n */\n storageAvailable: function(type) {\n var storage = [];\n try {\n storage = window[type];\n var test = '__storage_test__';\n storage.setItem(test, test);\n storage.removeItem(test);\n return true;\n } catch (e) {\n //ignore storage error\n }\n },\n\n eventDelay: function (callback, threshhold, scope, skipInitialCall) {\n threshhold || (threshhold = 250);\n var last,\n deferTimer;\n\n /**\n * @todo Add description\n */\n return function () {\n var context = scope || this,\n now = (new Date()).getTime(),\n args = arguments;\n\n if (last && now < last + threshhold) {\n clearTimeout(deferTimer);\n deferTimer = setTimeout(function () {\n last = now;\n callback.apply(context, args);\n }, threshhold);\n } else {\n last = now;\n\n if (!skipInitialCall) {\n callback.apply(context, args);\n }\n }\n };\n },\n\n /**\n * Throttling Function Calls\n *\n * @see http://www.nczonline.net/blog/2007/11/30/the-throttle-function/\n * @param {Function} callback Callback function to call\n * @param {Number} delay Delay before callback fire\n * @param {Object} scope The context to for callback fire\n */\n throttle: function (callback, delay, scope) {\n clearTimeout(callback._tId);\n callback._tId = setTimeout(function () {\n callback.call(scope);\n }, delay || 100);\n },\n\n getTimer: function () {\n return {\n id: null,\n clear: function () {\n if (this.id) {\n window.clearTimeout(this.id);\n delete this.id;\n }\n },\n start: function (duration, callback) {\n this.id = setTimeout(callback, duration);\n }\n };\n },\n\n getInterval: function () {\n return {\n id: null,\n clear: function () {\n if (this.id) {\n window.clearInterval(this.id);\n delete this.id;\n }\n },\n start: function (duration, callback) {\n this.id = setInterval(callback, duration);\n }\n };\n },\n\n /**\n * [getUri description]\n * @param {[type]} o [description]\n * @return {[type]} [description]\n */\n getUri: function (o) {\n var a;\n\n if (o.tagName && $(o).attr('href')) {\n a = o;\n } else if (typeof o === 'string') {\n a = document.createElement(\"a\");\n a.href = o;\n } else {\n return null;\n }\n\n // overcome some stupid ie behaviour\n if (a.host === '') {\n a.href = a.href;\n }\n\n // all actual version of IE not so smart to correctly process\n // protocol independent locations, so wee need to help them\n if (a.protocol === ':') {\n a.protocol = window.location.protocol;\n }\n\n // fix for some IE browsers\n if (a.pathname.indexOf('/') !== 0) {\n a.pathname = '/' + a.pathname;\n }\n\n return Object.create({\n 'protocol': a.protocol, //http:\n 'host': a.host, //www.myexample.com\n 'hostname': a.hostname, //www.myexample.com'\n 'port': a.port, //:80\n 'path': a.pathname, // /sub1/sub2\n 'query': a.search, // ?param1=val1¶m2=val2\n 'queryParams': a.search.length > 1 ? this.getQueryStringParams(a.search.substr(1)) : {},\n 'hash': a.hash, // #OU812,5150\n 'url': a.protocol + '//' + a.host + a.pathname,\n 'toString': function () {\n return this.protocol + '//' + this.host + this.port + this.pathname + this.search + this.hash;\n }\n });\n },\n\n /**\n * Genereal wrapper for JSON.parse(...) with error catching\n * @result {Object}\n */\n jsonParse : function (stringified) {\n var parsed = {};\n\n if (!stringified) {\n return parsed;\n }\n\n try {\n parsed = JSON.parse(stringified);\n } catch (e) {\n return parsed;\n }\n\n return parsed;\n },\n\n /**\n * @description Tests if localStorage is available, useful in Safari where localStorage can't be used when browsing privately.\n * @returns {boolean}\n */\n canAccessSessionStorage : function () {\n var item = 'test';\n try {\n sessionStorage.setItem(item, item);\n sessionStorage.removeItem(item);\n return true;\n } catch (e) {\n return false;\n }\n },\n isObject: function (value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n },\n\n debounce: function (func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError('Expected a function');\n }\n\n wait = Number(wait) || 0;\n\n if (this.isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? Math.max(Number(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc (time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `maxWait` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n timeWaiting = wait - timeSinceLastCall;\n\n return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `maxWait` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = Date.now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `lastArgs` which means `func` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(Date.now());\n }\n\n function debounced() {\n var time = Date.now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n },\n\n /**\n * loadScript: appends a script tag to document and returns a promise that resolves when loaded.\n *\n * It's kind of like $.getScript, but promisified, de-duped, and resolves relative urls\n *\n * @param {*} src - the src of the script\n * @returns - Promise\n */\n loadScript: src => {\n if (loadedScripts.has(src)) return loadedScripts.get(src);\n const p = new Promise(onload => {\n if (src[0] !== 'h') src = window.assetPath + src // if relative url, make abs\n let script = document.createElement(\"script\");\n Object.assign(script, {src, async: 1, onload});\n document.body.appendChild(script);\n })\n loadedScripts.set(src, p);\n return p;\n },\n\n branchCloseJourney: function () {\n var branch = require('branch-sdk');\n branch.closeJourney();\n var el = document.getElementById('branch-banner-iframe');\n var elbody = document.getElementById('l-body');\n var elbodypage = document.getElementById('bodyPage');\n if (el) {\n elbody.classList.remove('branch-banner-is-active');\n el.style.display = 'none';\n elbody.style.margin = '0';\n elbodypage.style.margin = '0';\n }\n },\n\n /**\n * Scale size to fit Canvas pixel limitation for Safari mobile\n * @param {number} width canvas required width\n * @param {number} height canvas required height\n * @returns {Object} scaled size\n */\n limitMobileCanvasSize: function (width, height) {\n var maximumPixels = 16777216; // Safari Canvas area maximum limit\n const requiredPixels = width * height;\n if (requiredPixels <= maximumPixels) {\n return {\n width: width,\n height: height,\n scalar: 1\n };\n }\n const scalar = Math.sqrt(maximumPixels) / Math.sqrt(requiredPixels);\n return {\n width: Math.floor(width * scalar),\n height: Math.floor(height * scalar),\n scalar: scalar\n };\n }\n};\nconst loadedScripts = new Map() // Map\n\nmodule.exports = util;\n","/*! device.js 0.2.7 */\n(function(){var a,b,c,d,e,f,g,h,i,j;b=window.device,a={},window.device=a,d=window.document.documentElement,j=window.navigator.userAgent.toLowerCase(),a.ios=function(){return a.iphone()||a.ipod()||a.ipad()},a.iphone=function(){return!a.windows()&&e(\"iphone\")},a.ipod=function(){return e(\"ipod\")},a.ipad=function(){return e(\"ipad\")},a.android=function(){return!a.windows()&&e(\"android\")},a.androidPhone=function(){return a.android()&&e(\"mobile\")},a.androidTablet=function(){return a.android()&&!e(\"mobile\")},a.blackberry=function(){return e(\"blackberry\")||e(\"bb10\")||e(\"rim\")},a.blackberryPhone=function(){return a.blackberry()&&!e(\"tablet\")},a.blackberryTablet=function(){return a.blackberry()&&e(\"tablet\")},a.windows=function(){return e(\"windows\")},a.windowsPhone=function(){return a.windows()&&e(\"phone\")},a.windowsTablet=function(){return a.windows()&&e(\"touch\")&&!a.windowsPhone()},a.fxos=function(){return(e(\"(mobile;\")||e(\"(tablet;\"))&&e(\"; rv:\")},a.fxosPhone=function(){return a.fxos()&&e(\"mobile\")},a.fxosTablet=function(){return a.fxos()&&e(\"tablet\")},a.meego=function(){return e(\"meego\")},a.cordova=function(){return window.cordova&&\"file:\"===location.protocol},a.nodeWebkit=function(){return\"object\"==typeof window.process},a.mobile=function(){return a.androidPhone()||a.iphone()||a.ipod()||a.windowsPhone()||a.blackberryPhone()||a.fxosPhone()||a.meego()},a.tablet=function(){return a.ipad()||a.androidTablet()||a.blackberryTablet()||a.windowsTablet()||a.fxosTablet()},a.desktop=function(){return!a.tablet()&&!a.mobile()},a.television=function(){var a;for(television=[\"googletv\",\"viera\",\"smarttv\",\"internet.tv\",\"netcast\",\"nettv\",\"appletv\",\"boxee\",\"kylo\",\"roku\",\"dlnadoc\",\"roku\",\"pov_tv\",\"hbbtv\",\"ce-html\"],a=0;a1},a.landscape=function(){return window.innerHeight/window.innerWidth<1},a.noConflict=function(){return window.device=b,this},e=function(a){return-1!==j.indexOf(a)},g=function(a){var b;return b=new RegExp(a,\"i\"),d.className.match(b)},c=function(a){var b=null;g(a)||(b=d.className.replace(/^\\s+|\\s+$/g,\"\"),d.className=b+\" \"+a)},i=function(a){g(a)&&(d.className=d.className.replace(\" \"+a,\"\"))},a.ios()?a.ipad()?c(\"ios ipad tablet\"):a.iphone()?c(\"ios iphone mobile\"):a.ipod()&&c(\"ios ipod mobile\"):a.android()?c(a.androidTablet()?\"android tablet\":\"android mobile\"):a.blackberry()?c(a.blackberryTablet()?\"blackberry tablet\":\"blackberry mobile\"):a.windows()?c(a.windowsTablet()?\"windows tablet\":a.windowsPhone()?\"windows mobile\":\"desktop\"):a.fxos()?c(a.fxosTablet()?\"fxos tablet\":\"fxos mobile\"):a.meego()?c(\"meego mobile\"):a.nodeWebkit()?c(\"node-webkit\"):a.television()?c(\"television\"):a.desktop()&&c(\"desktop\"),a.cordova()&&c(\"cordova\"),f=function(){a.landscape()?(i(\"portrait\"),c(\"landscape\")):(i(\"landscape\"),c(\"portrait\"))},h=Object.prototype.hasOwnProperty.call(window,\"onorientationchange\")?\"orientationchange\":\"resize\",window.addEventListener?window.addEventListener(h,f,!1):window.attachEvent?window.attachEvent(h,f):window[h]=f,f(),\"function\"==typeof define&&\"object\"==typeof define.amd&&define.amd?define(function(){return a}):\"undefined\"!=typeof module&&module.exports?module.exports=a:window.device=a}).call(this);\n","'use strict';\n\nvar processInclude = require('base/util');\n\n$(document).ready(function () {\n processInclude(require('./search/search'));\n});\n","/* eslint-disable no-restricted-globals */\n\n'use strict';\n\nconst constructorIOPLP = require('org/constructorio/constructorIOPLP');\nconst { getConstructorIOSettings } = require('org/constructorio/clientWrapper');\nconst { getConstructorioSearch } = require('org/constructorio/request');\nconst util = require('org/util');\nvar searchModuleBase = require('org/search/search');\n\n/**\n * Disable unselected By Teams refinement values on PLP page.\n * @param {Object} teamRefinement - team refinement to work on\n * @param {Object} selectedTeam - selected team\n * @param {Object} $this - the scope of execution\n *\n * @returns {boolean} if operation success of not\n */\nfunction disableTeamRefinements(teamRefinement, selectedTeam, $this) {\n if (selectedTeam.length === 1) {\n teamRefinement.find('li a:not(.m-selected)').each(function () {\n $(this).addClass('disabled-team');\n });\n } else {\n // avoid the 2nd selection of team refinement during the page reload\n $this.removeClass('m-selected');\n teamRefinement.find('li a:not(.m-selected)').each(function () {\n $(this).addClass('disabled-team');\n });\n return false;\n }\n return true;\n}\n\n/**\n * Append selected size to the existing url\n * @param {string} baseUrl - base url to append to\n *\n * @returns {string} Updated url\n */\nfunction getSelectedModelSizeUrl(baseUrl) {\n if ($('.js-select-model-size:visible').length > 0) {\n var selectedSize = $('.js-select-model-size:visible').val();\n $('body').find('.js-select-model-size:hidden').val(selectedSize).trigger('change', [true]);\n if (selectedSize) {\n var urlParams = {\n viewPreference: selectedSize\n };\n return util.appendParamsToUrl(baseUrl, urlParams);\n }\n }\n return baseUrl;\n}\n\n/**\n * Update the url with selected sorting rule\n * @param {string} baseUrl - base url to modify\n *\n * @returns {string} Updated url\n */\nfunction getSelectedSortingRule(baseUrl) {\n if ($('select.b-sort-select').find('option:selected').length > 0) {\n var selectedsortingRule = $('select.b-sort-select').find('option:selected').data('id');\n if ($(window).width() < 1024) {\n selectedsortingRule = $('input[name=\"sortMobileOption\"]:checked').val();\n }\n\n if (selectedsortingRule) {\n var urlParams = {\n srule: selectedsortingRule\n };\n // remove from srule from url if present then add srule with latest updated values\n if (baseUrl.indexOf('srule=') !== -1) {\n baseUrl = util.removeParamFromURL(baseUrl, 'srule'); // eslint-disable-line no-param-reassign\n }\n return util.appendParamsToUrl(baseUrl, urlParams);\n }\n }\n return baseUrl;\n}\n\n/**\n * Checks if the current page is a search page by checking the presence of '?q=' in the URL.\n *\n * @returns {number} -1 if '?q=' is not found in the URL (indicating that the page is not a search page), otherwise returns the index at which '?q=' starts in the URL.\n */\nconst isSearchPage = () => {\n return window.location.href.indexOf('?q=') > -1 ? window.location.href.indexOf('?q=') : window.location.href.indexOf('&q=');\n};\n\n/**\n * Initialize window event listener for onpopstate to reload page with the updated url.\n */\nsearchModuleBase.postInit = () => {\n // Function to handle the popstate event\n window.onpopstate = function () {\n location.reload();\n };\n};\n\nsearchModuleBase.applyFilter = () => {\n // Handle refinement value selection and reset click\n $('.js-page').on('click change', '.js-select-model-size, .js-plp-sidebar li a:not(\".b-refinements_category-link\"), .js-category-link, .js-plp-sidebar .js-refinements_clear, .js-refinement_swatch, .js-selected-refinements a',\n (e, isTriggered) => {\n e.preventDefault();\n e.stopPropagation();\n const $currentTarget = $(e.currentTarget);\n\n if (e.type === 'click' && $currentTarget.hasClass('js-select-model-size')) {\n return false;\n }\n\n if (isTriggered && $currentTarget.hasClass('js-select-model-size')) {\n return false;\n }\n\n // Disable unselected team refinement values on PLP page\n const teamRefinement = $('.b-refinements-item[data-refinement-id=\"team\"]:visible');\n const selectedTeam = teamRefinement ? teamRefinement.find('li a.m-selected') : '';\n if (isSearchPage() === -1 && teamRefinement && selectedTeam.length > 0) {\n const updateRefinement = disableTeamRefinements(teamRefinement, selectedTeam, $currentTarget);\n if (!updateRefinement) {\n return false;\n }\n }\n\n searchModuleBase.methods.resetLoading();\n let newUrl = $currentTarget.data('href');\n\n if (newUrl === undefined) {\n const $canonicalUrl = $('.js-canonical-url');\n if ($canonicalUrl.attr('data-action-sizeModelUrl') !== null && $canonicalUrl.attr('data-queryString') !== null) {\n newUrl = $canonicalUrl.attr('data-action-sizeModelUrl') + '?' + $canonicalUrl.attr('data-queryString');\n }\n }\n\n newUrl = getSelectedModelSizeUrl(newUrl);\n\n if ($(window).width() < 1024) {\n const currentUrl = window.location.href;\n if (currentUrl.indexOf('isShopAllUrl') > -1) {\n const urlParams = {\n isShopAllUrl: true\n };\n newUrl = util.appendParamsToUrl(newUrl, urlParams);\n }\n }\n\n // Added selected sorting rules in refinement url if sorting option is in present url\n if (window.location.href.indexOf('srule=') !== -1) {\n newUrl = getSelectedSortingRule(newUrl);\n }\n\n // get the opened refinement items\n let showFilters = [];\n let filters = '';\n if ($('.b-refinements-content.show').length) {\n $('.b-refinements-content.show').each(() => {\n const filter = $(this).attr('data-refinementattr');\n showFilters.push(filter);\n });\n }\n\n filters = showFilters.join(',');\n\n if (!$currentTarget.hasClass('m-disabled')) {\n $currentTarget.trigger('search:filter', e);\n const $gridFooter = $('.js-grid_footer');\n\n const data = {\n page: $gridFooter.data('page-number'),\n selectedUrl: newUrl,\n selectedFilter: filters\n };\n\n const cIOSettings = getConstructorIOSettings();\n\n history.pushState({ type: 267 }, null, window.location.href);\n\n if ((cIOSettings.search_enabled || cIOSettings.browse_enabled) && window.searchParams) {\n getConstructorioSearch({ url: newUrl, data })\n .then((res) => {\n const a = constructorIOPLP.convertCIOToHTMLString(res, 'searchResultsNoDecorator');\n return a;\n })\n .catch(() => {\n searchModuleBase.methods.constractorRequestErrorHandler();\n })\n .then((response) => {\n if (!response) {\n return;\n }\n searchModuleBase.methods.applyFilterSuccessHandler(response, $currentTarget);\n });\n } else {\n searchModuleBase.methods.applyFilterRequest(newUrl, data, $currentTarget);\n }\n }\n return true;\n });\n};\n\nmodule.exports = searchModuleBase;\n","'use strict';\n\nmodule.exports = function (include) {\n if (typeof include === 'function') {\n include();\n } else if (typeof include === 'object') {\n Object.keys(include).forEach(function (key) {\n if (typeof include[key] === 'function') {\n include[key]();\n }\n });\n }\n};\n","function _arrayLikeToArray(arr, len) {\n if (len == null || len > arr.length) len = arr.length;\n for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n return arr2;\n}\nmodule.exports = _arrayLikeToArray, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var arrayLikeToArray = require(\"./arrayLikeToArray.js\");\nfunction _arrayWithoutHoles(arr) {\n if (Array.isArray(arr)) return arrayLikeToArray(arr);\n}\nmodule.exports = _arrayWithoutHoles, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n}\nmodule.exports = _classCallCheck, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var toPropertyKey = require(\"./toPropertyKey.js\");\nfunction _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, toPropertyKey(descriptor.key), descriptor);\n }\n}\nfunction _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n Object.defineProperty(Constructor, \"prototype\", {\n writable: false\n });\n return Constructor;\n}\nmodule.exports = _createClass, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var toPropertyKey = require(\"./toPropertyKey.js\");\nfunction _defineProperty(obj, key, value) {\n key = toPropertyKey(key);\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n return obj;\n}\nmodule.exports = _defineProperty, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","function _interopRequireDefault(obj) {\n return obj && obj.__esModule ? obj : {\n \"default\": obj\n };\n}\nmodule.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","function _iterableToArray(iter) {\n if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter);\n}\nmodule.exports = _iterableToArray, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","function _nonIterableSpread() {\n throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}\nmodule.exports = _nonIterableSpread, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var arrayWithoutHoles = require(\"./arrayWithoutHoles.js\");\nvar iterableToArray = require(\"./iterableToArray.js\");\nvar unsupportedIterableToArray = require(\"./unsupportedIterableToArray.js\");\nvar nonIterableSpread = require(\"./nonIterableSpread.js\");\nfunction _toConsumableArray(arr) {\n return arrayWithoutHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableSpread();\n}\nmodule.exports = _toConsumableArray, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var _typeof = require(\"./typeof.js\")[\"default\"];\nfunction toPrimitive(t, r) {\n if (\"object\" != _typeof(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\" != _typeof(i)) return i;\n throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n }\n return (\"string\" === r ? String : Number)(t);\n}\nmodule.exports = toPrimitive, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var _typeof = require(\"./typeof.js\")[\"default\"];\nvar toPrimitive = require(\"./toPrimitive.js\");\nfunction toPropertyKey(t) {\n var i = toPrimitive(t, \"string\");\n return \"symbol\" == _typeof(i) ? i : i + \"\";\n}\nmodule.exports = toPropertyKey, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","function _typeof(o) {\n \"@babel/helpers - typeof\";\n\n return (module.exports = _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 }, module.exports.__esModule = true, module.exports[\"default\"] = module.exports), _typeof(o);\n}\nmodule.exports = _typeof, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","var arrayLikeToArray = require(\"./arrayLikeToArray.js\");\nfunction _unsupportedIterableToArray(o, minLen) {\n if (!o) return;\n if (typeof o === \"string\") return arrayLikeToArray(o, minLen);\n var n = Object.prototype.toString.call(o).slice(8, -1);\n if (n === \"Object\" && o.constructor) n = o.constructor.name;\n if (n === \"Map\" || n === \"Set\") return Array.from(o);\n if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen);\n}\nmodule.exports = _unsupportedIterableToArray, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\n/* eslint-disable camelcase, no-unneeded-ternary, max-len, complexity */\nvar ConstructorioID = require('@constructor-io/constructorio-id');\n\nvar fetchPonyfill = require('fetch-ponyfill'); // Modules\n\n\nvar Search = require('./modules/search');\n\nvar Browse = require('./modules/browse');\n\nvar Autocomplete = require('./modules/autocomplete');\n\nvar Recommendations = require('./modules/recommendations');\n\nvar Tracker = require('./modules/tracker');\n\nvar EventDispatcher = require('./utils/event-dispatcher');\n\nvar helpers = require('./utils/helpers');\n\nvar _require = require('../package.json'),\n packageVersion = _require.version;\n\nvar Quizzes = require('./modules/quizzes'); // Compute package version string\n\n\nvar computePackageVersion = function computePackageVersion() {\n var versionPrefix = 'ciojs-client-';\n var versionModifiers = [];\n\n if (!helpers.canUseDOM()) {\n versionModifiers.push('domless');\n }\n\n if (typeof process !== 'undefined' && typeof process.env !== 'undefined' && process.env.BUNDLED) {\n versionModifiers.push('bundled');\n }\n\n return \"\".concat(versionPrefix).concat(versionModifiers.join('-')).concat(versionModifiers.length ? '-' : '').concat(packageVersion);\n};\n/**\n * Class to instantiate the ConstructorIO client.\n */\n\n\nvar ConstructorIO = /*#__PURE__*/function () {\n /**\n * @param {object} parameters - Parameters for client instantiation\n * @param {string} parameters.apiKey - Constructor.io API key\n * @param {string} [parameters.serviceUrl='https://ac.cnstrc.com'] - API URL endpoint\n * @param {string} [parameters.quizzesServiceUrl='https://quizzes.cnstrc.com'] - Quizzes API URL endpoint\n * @param {array} [parameters.segments] - User segments\n * @param {object} [parameters.testCells] - User test cells\n * @param {string} [parameters.clientId] - Client ID, defaults to value supplied by 'constructorio-id' module\n * @param {string} [parameters.sessionId] - Session ID, defaults to value supplied by 'constructorio-id' module\n * @param {string} [parameters.userId] - User ID\n * @param {function} [parameters.fetch] - If supplied, will be utilized for requests rather than default Fetch API\n * @param {number} [parameters.trackingSendDelay=250] - Amount of time to wait before sending tracking events (in ms)\n * @param {boolean} [parameters.sendReferrerWithTrackingEvents=true] - Indicates if the referrer is sent with tracking events\n * @param {boolean} [parameters.sendTrackingEvents=false] - Indicates if tracking events should be dispatched\n * @param {object} [parameters.idOptions] - Options object to be supplied to 'constructorio-id' module\n * @param {object} [parameters.eventDispatcher] - Options related to 'EventDispatcher' class\n * @param {boolean} [parameters.eventDispatcher.enabled=true] - Determine if events should be dispatched\n * @param {boolean} [parameters.eventDispatcher.waitForBeacon=true] - Wait for beacon before dispatching events\n * @param {object} [parameters.networkParameters] - Parameters relevant to network requests\n * @param {number} [parameters.networkParameters.timeout] - Request timeout (in milliseconds) - may be overridden within individual method calls\n * @property {object} search - Interface to {@link module:search}\n * @property {object} browse - Interface to {@link module:browse}\n * @property {object} autocomplete - Interface to {@link module:autocomplete}\n * @property {object} recommendations - Interface to {@link module:recommendations}\n * @property {object} tracker - Interface to {@link module:tracker}\n * @property {object} quizzes - Interface to {@link module:quizzes}\n * @returns {class}\n */\n function ConstructorIO() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n (0, _classCallCheck2[\"default\"])(this, ConstructorIO);\n var apiKey = options.apiKey,\n versionFromOptions = options.version,\n serviceUrl = options.serviceUrl,\n quizzesServiceUrl = options.quizzesServiceUrl,\n segments = options.segments,\n testCells = options.testCells,\n clientId = options.clientId,\n sessionId = options.sessionId,\n userId = options.userId,\n fetch = options.fetch,\n trackingSendDelay = options.trackingSendDelay,\n sendReferrerWithTrackingEvents = options.sendReferrerWithTrackingEvents,\n sendTrackingEvents = options.sendTrackingEvents,\n eventDispatcher = options.eventDispatcher,\n idOptions = options.idOptions,\n beaconMode = options.beaconMode,\n networkParameters = options.networkParameters;\n\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('API key is a required parameter of type string');\n }\n\n var session_id;\n var client_id;\n var versionFromGlobal = typeof global !== 'undefined' && global.CLIENT_VERSION; // Initialize ID session if DOM context is available\n\n if (helpers.canUseDOM()) {\n var _ConstructorioID = new ConstructorioID(idOptions || {});\n\n session_id = _ConstructorioID.session_id;\n client_id = _ConstructorioID.client_id;\n } else {\n // Validate session ID is provided\n if (!sessionId || typeof sessionId !== 'number') {\n throw new Error('sessionId is a required user parameter of type number');\n } // Validate client ID is provided\n\n\n if (!clientId || typeof clientId !== 'string') {\n throw new Error('clientId is a required user parameter of type string');\n }\n }\n\n this.options = {\n apiKey: apiKey,\n version: versionFromOptions || versionFromGlobal || computePackageVersion(),\n serviceUrl: serviceUrl && serviceUrl.replace(/\\/$/, '') || 'https://ac.cnstrc.com',\n quizzesServiceUrl: quizzesServiceUrl && quizzesServiceUrl.replace(/\\/$/, '') || 'https://quizzes.cnstrc.com',\n sessionId: sessionId || session_id,\n clientId: clientId || client_id,\n userId: userId,\n segments: segments,\n testCells: testCells,\n fetch: fetch || fetchPonyfill({\n Promise: Promise\n }).fetch,\n trackingSendDelay: trackingSendDelay,\n sendTrackingEvents: sendTrackingEvents,\n sendReferrerWithTrackingEvents: sendReferrerWithTrackingEvents,\n eventDispatcher: eventDispatcher,\n beaconMode: beaconMode === false ? false : true,\n // Defaults to 'true',\n networkParameters: networkParameters || {}\n }; // Expose global modules\n\n this.search = new Search(this.options);\n this.browse = new Browse(this.options);\n this.autocomplete = new Autocomplete(this.options);\n this.recommendations = new Recommendations(this.options);\n this.tracker = new Tracker(this.options);\n this.quizzes = new Quizzes(this.options); // Dispatch initialization event\n\n new EventDispatcher(options.eventDispatcher).queue('instantiated', this.options);\n }\n /**\n * Sets the client options\n *\n * @param {string} apiKey - Constructor.io API key\n * @param {array} [segments] - User segments\n * @param {object} [testCells] - User test cells\n * @param {string} [userId] - User ID\n */\n\n\n (0, _createClass2[\"default\"])(ConstructorIO, [{\n key: \"setClientOptions\",\n value: function setClientOptions(options) {\n if (Object.keys(options).length) {\n var apiKey = options.apiKey,\n segments = options.segments,\n testCells = options.testCells,\n userId = options.userId;\n\n if (apiKey) {\n this.options.apiKey = apiKey;\n }\n\n if (segments) {\n this.options.segments = segments;\n }\n\n if (testCells) {\n this.options.testCells = testCells;\n }\n\n if (userId) {\n this.options.userId = userId;\n }\n }\n }\n }]);\n return ConstructorIO;\n}(); // Exposed for testing\n\n\nConstructorIO.Tracker = Tracker; // Expose on window object if available\n\nif (helpers.canUseDOM()) {\n window.ConstructorioClient = ConstructorIO;\n}\n\nmodule.exports = ConstructorIO;","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\n/* eslint-disable object-curly-newline, no-underscore-dangle */\nvar EventDispatcher = require('../utils/event-dispatcher');\n\nvar _require = require('../utils/helpers'),\n throwHttpErrorFromResponse = _require.throwHttpErrorFromResponse,\n cleanParams = _require.cleanParams,\n applyNetworkTimeout = _require.applyNetworkTimeout,\n trimNonBreakingSpaces = _require.trimNonBreakingSpaces,\n encodeURIComponentRFC3986 = _require.encodeURIComponentRFC3986,\n stringify = _require.stringify; // Create URL from supplied query (term) and parameters\n\n\nfunction createAutocompleteUrl(query, parameters, options) {\n var apiKey = options.apiKey,\n version = options.version,\n serviceUrl = options.serviceUrl,\n sessionId = options.sessionId,\n clientId = options.clientId,\n userId = options.userId,\n segments = options.segments,\n testCells = options.testCells;\n var queryParams = {\n c: version\n };\n queryParams.key = apiKey;\n queryParams.i = clientId;\n queryParams.s = sessionId; // Validate query (term) is provided\n\n if (!query || typeof query !== 'string') {\n throw new Error('query is a required parameter of type string');\n } // Pull test cells from options\n\n\n if (testCells) {\n Object.keys(testCells).forEach(function (testCellKey) {\n queryParams[\"ef-\".concat(testCellKey)] = testCells[testCellKey];\n });\n } // Pull user segments from options\n\n\n if (segments && segments.length) {\n queryParams.us = segments;\n } // Pull user id from options and ensure string\n\n\n if (userId) {\n queryParams.ui = String(userId);\n }\n\n if (parameters) {\n var numResults = parameters.numResults,\n resultsPerSection = parameters.resultsPerSection,\n filters = parameters.filters,\n hiddenFields = parameters.hiddenFields,\n variationsMap = parameters.variationsMap; // Pull results number from parameters\n\n if (numResults) {\n queryParams.num_results = numResults;\n } // Pull results number per section from parameters\n\n\n if (resultsPerSection) {\n Object.keys(resultsPerSection).forEach(function (section) {\n queryParams[\"num_results_\".concat(section)] = resultsPerSection[section];\n });\n } // Pull filters from parameters\n\n\n if (filters) {\n queryParams.filters = filters;\n } // Pull hidden fields from parameters\n\n\n if (hiddenFields) {\n if (queryParams.fmt_options) {\n queryParams.fmt_options.hidden_fields = hiddenFields;\n } else {\n queryParams.fmt_options = {\n hidden_fields: hiddenFields\n };\n }\n } // Pull variations map from parameters\n\n\n if (variationsMap) {\n queryParams.variations_map = JSON.stringify(variationsMap);\n }\n }\n\n queryParams._dt = Date.now();\n queryParams = cleanParams(queryParams);\n var queryString = stringify(queryParams);\n var cleanedQuery = query.replace(/^\\//, '|'); // For compatibility with backend API\n\n return \"\".concat(serviceUrl, \"/autocomplete/\").concat(encodeURIComponentRFC3986(trimNonBreakingSpaces(cleanedQuery)), \"?\").concat(queryString);\n}\n/**\n * Interface to autocomplete related API calls.\n *\n * @module autocomplete\n * @inner\n * @returns {object}\n */\n\n\nvar Autocomplete = /*#__PURE__*/function () {\n function Autocomplete(options) {\n (0, _classCallCheck2[\"default\"])(this, Autocomplete);\n this.options = options || {};\n this.eventDispatcher = new EventDispatcher(options.eventDispatcher);\n }\n /**\n * Retrieve autocomplete results from API\n *\n * @function getAutocompleteResults\n * @description Retrieve autocomplete results from Constructor.io API\n * @param {string} query - Term to use to perform an autocomplete search\n * @param {object} [parameters] - Additional parameters to refine result set\n * @param {number} [parameters.numResults] - The total number of results to return\n * @param {object} [parameters.filters] - Key / value mapping (dictionary) of filters used to refine results\n * @param {object} [parameters.resultsPerSection] - Number of results to return (value) per section (key)\n * @param {string[]} [parameters.hiddenFields] - Hidden metadata fields to return\n * @param {object} [parameters.variationsMap] - The variations map object to aggregate variations. Please refer to https://docs.constructor.io/rest_api/variations_mapping for details\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/autocomplete_queries\n * @example\n * constructorio.autocomplete.getAutocompleteResults('t-shirt', {\n * resultsPerSection: {\n * Products: 5,\n * 'Search Suggestions': 10,\n * },\n * filters: {\n * size: 'medium'\n * },\n * });\n */\n\n\n (0, _createClass2[\"default\"])(Autocomplete, [{\n key: \"getAutocompleteResults\",\n value: function getAutocompleteResults(query, parameters) {\n var _this = this;\n\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var requestUrl;\n var fetch = this.options.fetch;\n var signal;\n\n if (typeof AbortController === 'function') {\n var controller = new AbortController();\n signal = controller && controller.signal; // Handle network timeout if specified\n\n applyNetworkTimeout(this.options, networkParameters, controller);\n }\n\n try {\n requestUrl = createAutocompleteUrl(query, parameters, this.options);\n } catch (e) {\n return Promise.reject(e);\n }\n\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n if (json.sections) {\n if (json.result_id) {\n var sectionKeys = Object.keys(json.sections);\n sectionKeys.forEach(function (section) {\n var sectionItems = json.sections[section];\n\n if (sectionItems.length) {\n // Append `result_id` to each section item\n sectionItems.forEach(function (item) {\n // eslint-disable-next-line no-param-reassign\n item.result_id = json.result_id;\n });\n }\n });\n }\n\n _this.eventDispatcher.queue('autocomplete.getAutocompleteResults.completed', json);\n\n return json;\n }\n\n throw new Error('getAutocompleteResults response data is malformed');\n });\n }\n }]);\n return Autocomplete;\n}();\n\nmodule.exports = Autocomplete;","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2[\"default\"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }\n\n/* eslint-disable object-curly-newline, no-underscore-dangle, max-len, complexity */\nvar EventDispatcher = require('../utils/event-dispatcher');\n\nvar helpers = require('../utils/helpers'); // Create query params from parameters and options\n\n\nfunction createQueryParams(parameters, options) {\n var apiKey = options.apiKey,\n version = options.version,\n sessionId = options.sessionId,\n clientId = options.clientId,\n userId = options.userId,\n segments = options.segments,\n testCells = options.testCells;\n var queryParams = {\n c: version\n };\n queryParams.key = apiKey;\n queryParams.i = clientId;\n queryParams.s = sessionId; // Pull test cells from options\n\n if (testCells) {\n Object.keys(testCells).forEach(function (testCellKey) {\n queryParams[\"ef-\".concat(testCellKey)] = testCells[testCellKey];\n });\n } // Pull user segments from options\n\n\n if (segments && segments.length) {\n queryParams.us = segments;\n } // Pull user id from options and ensure string\n\n\n if (userId) {\n queryParams.ui = String(userId);\n }\n\n if (parameters) {\n var page = parameters.page,\n offset = parameters.offset,\n resultsPerPage = parameters.resultsPerPage,\n filters = parameters.filters,\n sortBy = parameters.sortBy,\n sortOrder = parameters.sortOrder,\n section = parameters.section,\n fmtOptions = parameters.fmtOptions,\n hiddenFields = parameters.hiddenFields,\n hiddenFacets = parameters.hiddenFacets,\n variationsMap = parameters.variationsMap,\n qsParam = parameters.qsParam,\n preFilterExpression = parameters.preFilterExpression; // Pull page from parameters\n\n if (!helpers.isNil(page)) {\n queryParams.page = page;\n } // Pull offset from parameters\n\n\n if (!helpers.isNil(offset)) {\n queryParams.offset = offset;\n } // Pull results per page from parameters\n\n\n if (!helpers.isNil(resultsPerPage)) {\n queryParams.num_results_per_page = resultsPerPage;\n }\n\n if (filters) {\n queryParams.filters = filters;\n } // Pull sort by from parameters\n\n\n if (sortBy) {\n queryParams.sort_by = sortBy;\n } // Pull sort order from parameters\n\n\n if (sortOrder) {\n queryParams.sort_order = sortOrder;\n } // Pull section from parameters\n\n\n if (section) {\n queryParams.section = section;\n } // Pull format options from parameters\n\n\n if (fmtOptions) {\n queryParams.fmt_options = fmtOptions;\n } // Pull hidden fields from parameters\n\n\n if (hiddenFields) {\n if (queryParams.fmt_options) {\n queryParams.fmt_options.hidden_fields = hiddenFields;\n } else {\n queryParams.fmt_options = {\n hidden_fields: hiddenFields\n };\n }\n } // Pull hidden facets from parameters\n\n\n if (hiddenFacets) {\n if (queryParams.fmt_options) {\n queryParams.fmt_options.hidden_facets = hiddenFacets;\n } else {\n queryParams.fmt_options = {\n hidden_facets: hiddenFacets\n };\n }\n } // Pull variations map from parameters\n\n\n if (variationsMap) {\n queryParams.variations_map = JSON.stringify(variationsMap);\n } // Pull pre_filter_expression from parameters\n\n\n if (preFilterExpression) {\n queryParams.pre_filter_expression = JSON.stringify(preFilterExpression);\n } // pull qs param from parameters\n\n\n if (qsParam) {\n queryParams.qs = JSON.stringify(qsParam);\n }\n }\n\n queryParams._dt = Date.now();\n queryParams = helpers.cleanParams(queryParams);\n return queryParams;\n} // Create URL from supplied filter name, value and parameters\n\n\nfunction createBrowseUrlFromFilter(filterName, filterValue, parameters, options) {\n var serviceUrl = options.serviceUrl; // Validate filter name is provided\n\n if (!filterName || typeof filterName !== 'string') {\n throw new Error('filterName is a required parameter of type string');\n } // Validate filter value is provided\n\n\n if (!filterValue || typeof filterValue !== 'string') {\n throw new Error('filterValue is a required parameter of type string');\n }\n\n var queryParams = createQueryParams(parameters, options);\n var queryString = helpers.stringify(queryParams);\n return \"\".concat(serviceUrl, \"/browse/\").concat(helpers.encodeURIComponentRFC3986(helpers.trimNonBreakingSpaces(filterName)), \"/\").concat(helpers.encodeURIComponentRFC3986(helpers.trimNonBreakingSpaces(filterValue)), \"?\").concat(queryString);\n} // Create URL from supplied id's\n\n\nfunction createBrowseUrlFromIDs(ids, parameters, options) {\n var serviceUrl = options.serviceUrl; // Validate id's are provided\n\n if (!ids || !Array.isArray(ids) || !ids.length) {\n throw new Error('ids is a required parameter of type array');\n }\n\n var queryParams = _objectSpread(_objectSpread({}, createQueryParams(parameters, options)), {}, {\n ids: ids\n });\n\n var queryString = helpers.stringify(queryParams);\n return \"\".concat(serviceUrl, \"/browse/items?\").concat(queryString);\n} // Create URL for facets\n\n\nfunction createBrowseUrlForFacets(parameters, options) {\n var serviceUrl = options.serviceUrl;\n\n var queryParams = _objectSpread({}, createQueryParams(parameters, options)); // Endpoint does not accept _dt\n\n\n delete queryParams._dt;\n var queryString = helpers.stringify(queryParams);\n return \"\".concat(serviceUrl, \"/browse/facets?\").concat(queryString);\n} // Create URL from supplied facet name and parameters\n\n\nfunction createBrowseUrlForFacetOptions(facetName, parameters, options) {\n var serviceUrl = options.serviceUrl; // Validate facet name is provided\n\n if (!facetName || typeof facetName !== 'string') {\n throw new Error('facetName is a required parameter of type string');\n }\n\n var queryParams = _objectSpread({}, createQueryParams(parameters, options));\n\n queryParams.facet_name = facetName; // Endpoint does not accept _dt\n\n delete queryParams._dt;\n var queryString = helpers.stringify(queryParams);\n return \"\".concat(serviceUrl, \"/browse/facet_options?\").concat(queryString);\n}\n/**\n * Interface to browse related API calls\n *\n * @module browse\n * @inner\n * @returns {object}\n */\n\n\nvar Browse = /*#__PURE__*/function () {\n function Browse(options) {\n (0, _classCallCheck2[\"default\"])(this, Browse);\n this.options = options || {};\n this.eventDispatcher = new EventDispatcher(options.eventDispatcher);\n }\n /**\n * Retrieve browse results from API\n *\n * @function getBrowseResults\n * @description Retrieve browse results from Constructor.io API\n * @param {string} filterName - Filter name to display results from\n * @param {string} filterValue - Filter value to display results from\n * @param {object} [parameters] - Additional parameters to refine result set\n * @param {number} [parameters.page] - The page number of the results (Can't be used together with offset)\n * @param {number} [parameters.offset] - The number of results to skip from the beginning (Can't be used together with page)\n * @param {number} [parameters.resultsPerPage] - The number of results per page to return\n * @param {object} [parameters.filters] - Key / value mapping (dictionary) of filters used to refine results\n * @param {string} [parameters.sortBy='relevance'] - The sort method for results\n * @param {string} [parameters.sortOrder='descending'] - The sort order for results\n * @param {string} [parameters.section='Products'] - The section name for results\n * @param {object} [parameters.fmtOptions] - The format options used to refine result groups. Please refer to https://docs.constructor.io/rest_api/browse/queries/ for details\n * @param {object} [parameters.preFilterExpression] - Faceting expression to scope browse results. Please refer to https://docs.constructor.io/rest_api/collections#add-items-dynamically\n * @param {string[]} [parameters.hiddenFields] - Hidden metadata fields to return\n * @param {string[]} [parameters.hiddenFacets] - Hidden facets to return\n * @param {object} [parameters.variationsMap] - The variations map object to aggregate variations. Please refer to https://docs.constructor.io/rest_api/variations_mapping for details\n * @param {object} [parameters.qsParam] - Parameters listed above can be serialized into a JSON object and parsed through this parameter. Please refer to https://docs.constructor.io/rest_api/browse/queries/\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/browse/results\n * @example\n * constructorio.browse.getBrowseResults('group_id', 't-shirts', {\n * resultsPerPage: 40,\n * filters: {\n * size: 'medium'\n * },\n * });\n */\n\n\n (0, _createClass2[\"default\"])(Browse, [{\n key: \"getBrowseResults\",\n value: function getBrowseResults(filterName, filterValue, parameters) {\n var _this = this;\n\n var networkParameters = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};\n var requestUrl;\n var fetch = this.options.fetch;\n var signal;\n\n if (typeof AbortController === 'function') {\n var controller = new AbortController();\n signal = controller && controller.signal; // Handle network timeout if specified\n\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n }\n\n try {\n requestUrl = createBrowseUrlFromFilter(filterName, filterValue, parameters, this.options);\n } catch (e) {\n return Promise.reject(e);\n }\n\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return helpers.throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n if (json.response && json.response.results) {\n if (json.result_id) {\n // Append `result_id` to each result item\n json.response.results.forEach(function (result) {\n // eslint-disable-next-line no-param-reassign\n result.result_id = json.result_id;\n });\n }\n\n _this.eventDispatcher.queue('browse.getBrowseResults.completed', json);\n\n return json;\n }\n\n throw new Error('getBrowseResults response data is malformed');\n });\n }\n /**\n * Retrieve browse results from API using item id's\n *\n * @function getBrowseResultsForItemIds\n * @param {string[]} itemIds - Item id's of results to fetch\n * @param {object} [parameters] - Additional parameters to refine result set\n * @param {number} [parameters.page] - The page number of the results (Can't be used together with offset)\n * @param {number} [parameters.offset] - The number of results to skip from the beginning (Can't be used together with page)\n * @param {number} [parameters.resultsPerPage] - The number of results per page to return\n * @param {object} [parameters.filters] - Filters used to refine results\n * @param {string} [parameters.sortBy='relevance'] - The sort method for results\n * @param {string} [parameters.sortOrder='descending'] - The sort order for results\n * @param {string} [parameters.section='Products'] - The section name for results\n * @param {object} [parameters.fmtOptions] - The format options used to refine result groups. Please refer to https://docs.constructor.io/rest_api/browse/queries/ for details\n * @param {string[]} [parameters.hiddenFields] - Hidden metadata fields to return\n * @param {string[]} [parameters.hiddenFacets] - Hidden facets to return\n * @param {object} [parameters.variationsMap] - The variations map object to aggregate variations. Please refer to https://docs.constructor.io/rest_api/variations_mapping for details\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/browse/items/\n * @example\n * constructorio.browse.getBrowseResultsForItemIds(['shirt-123', 'shirt-456', 'shirt-789'], {\n * filters: {\n * size: 'medium'\n * },\n * });\n */\n\n }, {\n key: \"getBrowseResultsForItemIds\",\n value: function getBrowseResultsForItemIds(itemIds, parameters) {\n var _this2 = this;\n\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var requestUrl;\n var fetch = this.options.fetch;\n var signal;\n\n if (typeof AbortController === 'function') {\n var controller = new AbortController();\n signal = controller && controller.signal; // Handle network timeout if specified\n\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n }\n\n try {\n requestUrl = createBrowseUrlFromIDs(itemIds, parameters, this.options);\n } catch (e) {\n return Promise.reject(e);\n }\n\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return helpers.throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n if (json.response && json.response.results) {\n if (json.result_id) {\n // Append `result_id` to each result item\n json.response.results.forEach(function (result) {\n // eslint-disable-next-line no-param-reassign\n result.result_id = json.result_id;\n });\n }\n\n _this2.eventDispatcher.queue('browse.getBrowseResultsForItemIds.completed', json);\n\n return json;\n }\n\n throw new Error('getBrowseResultsForItemIds response data is malformed');\n });\n }\n /**\n * Retrieve browse groups from API\n *\n * @function getBrowseGroups\n * @param {object} [parameters.filters] - Filters used to refine results\n * @param {string} [parameters.section='Products'] - The section name for results\n * @param {object} [parameters.fmtOptions] - The format options used to refine result groups. Please refer to https://docs.constructor.io/rest_api/browse/groups/ for details\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/browse/groups\n * @example\n * constructorio.browse.getBrowseGroups({\n * filters: {\n * group_id: 'drill_collection'\n * },\n * fmtOptions: {\n * groups_max_depth: 2\n * }\n * });\n */\n\n }, {\n key: \"getBrowseGroups\",\n value: function getBrowseGroups(parameters) {\n var _this3 = this;\n\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var fetch = this.options.fetch;\n var serviceUrl = this.options.serviceUrl;\n var queryParams = createQueryParams(parameters, this.options);\n var signal;\n\n if (typeof AbortController === 'function') {\n var controller = new AbortController();\n signal = controller && controller.signal; // Handle network timeout if specified\n\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n }\n\n delete queryParams._dt;\n var queryString = helpers.stringify(queryParams);\n var requestUrl = \"\".concat(serviceUrl, \"/browse/groups?\").concat(queryString);\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return helpers.throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n if (json.response && json.response.groups) {\n _this3.eventDispatcher.queue('browse.getBrowseGroups.completed', json);\n\n return json;\n }\n\n throw new Error('getBrowseGroups response data is malformed');\n });\n }\n /**\n * Retrieve browse facets from API\n *\n * @function getBrowseFacets\n * @param {object} [parameters] - Additional parameters to refine result set\n * @param {number} [parameters.page] - The page number of the results (Can't be used together with offset)\n * @param {number} [parameters.offset] - The number of results to skip from the beginning (Can't be used together with page)\n * @param {string} [parameters.section='Products'] - The section name for results\n * @param {object} [parameters.fmtOptions] - The format options used to refine result groups. Please refer to https://docs.constructor.io/rest_api/browse/facets/ for details\n * @param {number} [parameters.resultsPerPage] - The number of results per page to return\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/browse/facets\n * @example\n * constructorio.browse.getBrowseFacets({\n * page: 1,\n * resultsPerPage: 10,\n * });\n */\n\n }, {\n key: \"getBrowseFacets\",\n value: function getBrowseFacets(parameters, networkParameters) {\n var _this4 = this;\n\n var requestUrl;\n var fetch = this.options.fetch;\n var signal;\n\n if (typeof AbortController === 'function') {\n var controller = new AbortController();\n signal = controller && controller.signal; // Handle network timeout if specified\n\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n }\n\n try {\n requestUrl = createBrowseUrlForFacets(parameters, this.options);\n } catch (e) {\n return Promise.reject(e);\n }\n\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return helpers.throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n if (json.response && json.response.facets) {\n _this4.eventDispatcher.queue('browse.getBrowseFacets.completed', json);\n\n return json;\n }\n\n throw new Error('getBrowseFacets response data is malformed');\n });\n }\n /**\n * Retrieve facet options from API\n *\n * @function getBrowseFacetOptions\n * @param {string} facetName - Name of the facet whose options to return\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @param {object} [parameters] - Additional parameters to refine result set\n * @param {string} [parameters.section='Products'] - The section name for results\n * @param {object} [parameters.fmtOptions] - The format options used to refine result groups. Please refer to https://docs.constructor.io/rest_api/browse/facet_options/ for details\n * @param {}\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/browse/facet_options/\n * @example\n * constructorio.browse.getBrowseFacetOptions('price', {\n * });\n */\n\n }, {\n key: \"getBrowseFacetOptions\",\n value: function getBrowseFacetOptions(facetName) {\n var _this5 = this;\n\n var parameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var requestUrl;\n var fetch = this.options.fetch;\n var signal;\n\n if (typeof AbortController === 'function') {\n var controller = new AbortController();\n signal = controller && controller.signal; // Handle network timeout if specified\n\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n }\n\n try {\n requestUrl = createBrowseUrlForFacetOptions(facetName, parameters, this.options);\n } catch (e) {\n return Promise.reject(e);\n }\n\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return helpers.throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n if (json.response && json.response.facets) {\n _this5.eventDispatcher.queue('browse.getBrowseFacetOptions.completed', json);\n\n return json;\n }\n\n throw new Error('getBrowseFacetOptions response data is malformed');\n });\n }\n }]);\n return Browse;\n}();\n\nmodule.exports = Browse;","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\nvar _toConsumableArray2 = _interopRequireDefault(require(\"@babel/runtime/helpers/toConsumableArray\"));\n\nvar _typeof2 = _interopRequireDefault(require(\"@babel/runtime/helpers/typeof\"));\n\n/* eslint-disable object-curly-newline, no-underscore-dangle */\nvar EventDispatcher = require('../utils/event-dispatcher');\n\nvar helpers = require('../utils/helpers'); // Create URL from supplied quizId and parameters\n\n\nfunction createQuizUrl(quizId, parameters, options, path) {\n var apiKey = options.apiKey,\n clientId = options.clientId,\n sessionId = options.sessionId,\n segments = options.segments,\n userId = options.userId,\n version = options.version,\n quizzesServiceUrl = options.quizzesServiceUrl;\n var queryParams = {\n c: version\n };\n var answersParamString = '';\n queryParams.key = apiKey;\n queryParams.i = clientId;\n queryParams.s = sessionId; // Pull user segments from options\n\n if (segments && segments.length) {\n queryParams.us = segments;\n } // Pull user id from options and ensure string\n\n\n if (userId) {\n queryParams.ui = String(userId);\n } // Validate quiz id is provided\n\n\n if (!quizId || typeof quizId !== 'string') {\n throw new Error('quizId is a required parameter of type string');\n }\n\n if (path === 'results' && ((0, _typeof2[\"default\"])(parameters.answers) !== 'object' || !Array.isArray(parameters.answers) || parameters.answers.length === 0)) {\n throw new Error('answers is a required parameter of type array');\n }\n\n if (parameters) {\n var section = parameters.section,\n answers = parameters.answers,\n quizSessionId = parameters.quizSessionId,\n quizVersionId = parameters.quizVersionId,\n page = parameters.page,\n resultsPerPage = parameters.resultsPerPage,\n filters = parameters.filters; // Pull section from parameters\n\n if (section) {\n queryParams.section = section;\n } // Pull quiz_version_id from parameters\n\n\n if (quizVersionId) {\n queryParams.quiz_version_id = quizVersionId;\n } // Pull quiz_session_id from parameters\n\n\n if (quizSessionId) {\n queryParams.quiz_session_id = quizSessionId;\n } // Pull a (answers) from parameters and transform\n\n\n if (answers && answers.length) {\n answersParamString = \"&\".concat(helpers.stringify({\n a: answers.map(function (ans) {\n return (0, _toConsumableArray2[\"default\"])(ans).join(',');\n })\n }));\n } // Pull page from parameters\n\n\n if (!helpers.isNil(page)) {\n queryParams.page = page;\n } // Pull results per page from parameters\n\n\n if (!helpers.isNil(resultsPerPage)) {\n queryParams.num_results_per_page = resultsPerPage;\n }\n\n if (filters) {\n queryParams.filters = filters;\n }\n }\n\n queryParams._dt = Date.now();\n queryParams = helpers.cleanParams(queryParams);\n var queryString = helpers.stringify(queryParams);\n return \"\".concat(quizzesServiceUrl, \"/v1/quizzes/\").concat(encodeURIComponent(quizId), \"/\").concat(encodeURIComponent(path), \"/?\").concat(queryString).concat(answersParamString);\n}\n/**\n * Interface to quiz related API calls\n *\n * @module quizzes\n * @inner\n * @returns {object}\n */\n\n\nvar Quizzes = /*#__PURE__*/function () {\n function Quizzes(options) {\n (0, _classCallCheck2[\"default\"])(this, Quizzes);\n this.options = options || {};\n this.eventDispatcher = new EventDispatcher(options.eventDispatcher);\n }\n /**\n * Retrieve next question from API\n *\n * @function getQuizNextQuestion\n * @description Retrieve next question from Constructor.io API\n * @param {string} quizId - The identifier of the quiz\n * @param {string} [parameters] - Additional parameters to refine result set\n * @param {string} [parameters.section] - Product catalog section\n * @param {array} [parameters.answers] - An array of answers in the format [[1,2],[1]]\n * @param {string} [parameters.quizVersionId] - Version identifier for the quiz. Version ID will be returned with the first request and it should be passed with subsequent requests. More information can be found: https://docs.constructor.io/rest_api/quiz/using_quizzes/#quiz-versioning\n * @param {string} [parameters.quizSessionId] - Session identifier for the quiz. Session ID will be returned with the first request and it should be passed with subsequent requests. More information can be found: https://docs.constructor.io/rest_api/quiz/using_quizzes/#quiz-sessions\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/quiz/using_quizzes/#answering-a-quiz\n * @example\n * constructorio.quizzes.getQuizNextQuestion('quizId', {\n * answers: [[1,2],[1]],\n * section: '123',\n * quizVersionId: '123',\n * quizSessionId: '1234',\n * });\n */\n\n\n (0, _createClass2[\"default\"])(Quizzes, [{\n key: \"getQuizNextQuestion\",\n value: function getQuizNextQuestion(quizId, parameters) {\n var _this = this;\n\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var requestUrl;\n var fetch = this.options.fetch;\n var controller = new AbortController();\n var signal = controller.signal;\n\n try {\n requestUrl = createQuizUrl(quizId, parameters, this.options, 'next');\n } catch (e) {\n return Promise.reject(e);\n } // Handle network timeout if specified\n\n\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return helpers.throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n if (json.quiz_version_id) {\n _this.eventDispatcher.queue('quizzes.getQuizNextQuestion.completed', json);\n\n return json;\n }\n\n throw new Error('getQuizNextQuestion response data is malformed');\n });\n }\n /**\n * Retrieves filter expression and recommendation URL from given answers\n *\n * @function getQuizResults\n * @description Retrieve quiz recommendation and filter expression from Constructor.io API\n * @param {string} quizId - The identifier of the quiz\n * @param {string} parameters - Additional parameters to refine result set\n * @param {array} parameters.answers - An array of answers in the format [[1,2],[1]]\n * @param {string} [parameters.section] - Product catalog section\n * @param {string} [parameters.quizVersionId] - Version identifier for the quiz. Version ID will be returned with the first request and it should be passed with subsequent requests. More information can be found: https://docs.constructor.io/rest_api/quiz/using_quizzes/#quiz-versioning\n * @param {string} [parameters.quizSessionId] - Session identifier for the quiz. Session ID will be returned with the first request and it should be passed with subsequent requests. More information can be found: https://docs.constructor.io/rest_api/quiz/using_quizzes/#quiz-sessions\n * @param {number} [parameters.page] - The page number of the results\n * @param {number} [parameters.resultsPerPage] - The number of results per page to return\n * @param {object} [parameters.filters] - Key / value mapping (dictionary) of filters used to refine results\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/quiz/using_quizzes/#completing-the-quiz\n * @example\n * constructorio.quizzes.getQuizResults('quizId', {\n * answers: [[1,2],[1]],\n * section: '123',\n * quizVersionId: '123',\n * quizSessionId: '234'\n * });\n */\n\n }, {\n key: \"getQuizResults\",\n value: function getQuizResults(quizId, parameters) {\n var _this2 = this;\n\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var requestUrl;\n var fetch = this.options.fetch;\n var controller = new AbortController();\n var signal = controller.signal;\n\n try {\n requestUrl = createQuizUrl(quizId, parameters, this.options, 'results');\n } catch (e) {\n return Promise.reject(e);\n } // Handle network timeout if specified\n\n\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return helpers.throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n if (json.quiz_version_id) {\n _this2.eventDispatcher.queue('quizzes.getQuizResults.completed', json);\n\n return json;\n }\n\n throw new Error('getQuizResults response data is malformed');\n });\n }\n }]);\n return Quizzes;\n}();\n\nmodule.exports = Quizzes;","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\n/* eslint-disable object-curly-newline, no-param-reassign */\nvar EventDispatcher = require('../utils/event-dispatcher');\n\nvar helpers = require('../utils/helpers'); // Create URL from supplied parameters\n\n\nfunction createRecommendationsUrl(podId, parameters, options) {\n var apiKey = options.apiKey,\n version = options.version,\n serviceUrl = options.serviceUrl,\n sessionId = options.sessionId,\n userId = options.userId,\n clientId = options.clientId,\n segments = options.segments;\n var queryParams = {\n c: version\n };\n queryParams.key = apiKey;\n queryParams.i = clientId;\n queryParams.s = sessionId; // Validate pod identifier is provided\n\n if (!podId || typeof podId !== 'string') {\n throw new Error('podId is a required parameter of type string');\n } // Pull user segments from options\n\n\n if (segments && segments.length) {\n queryParams.us = segments;\n } // Pull user id from options and ensure string\n\n\n if (userId) {\n queryParams.ui = String(userId);\n }\n\n if (parameters) {\n var numResults = parameters.numResults,\n itemIds = parameters.itemIds,\n section = parameters.section,\n term = parameters.term,\n filters = parameters.filters,\n variationsMap = parameters.variationsMap; // Pull num results number from parameters\n\n if (!helpers.isNil(numResults)) {\n queryParams.num_results = numResults;\n } // Pull item ids from parameters\n\n\n if (itemIds) {\n queryParams.item_id = itemIds;\n } // Pull section from parameters\n\n\n if (section) {\n queryParams.section = section;\n } // Pull term from parameters\n\n\n if (term) {\n queryParams.term = term;\n } // Pull filters from parameters\n\n\n if (filters) {\n queryParams.filters = filters;\n } // Pull variations map from parameters\n\n\n if (variationsMap) {\n queryParams.variations_map = JSON.stringify(variationsMap);\n }\n }\n\n queryParams = helpers.cleanParams(queryParams);\n var queryString = helpers.stringify(queryParams);\n return \"\".concat(serviceUrl, \"/recommendations/v1/pods/\").concat(helpers.encodeURIComponentRFC3986(helpers.trimNonBreakingSpaces(podId)), \"?\").concat(queryString);\n}\n/**\n * Interface to recommendations related API calls\n *\n * @module recommendations\n * @inner\n * @returns {object}\n */\n\n\nvar Recommendations = /*#__PURE__*/function () {\n function Recommendations(options) {\n (0, _classCallCheck2[\"default\"])(this, Recommendations);\n this.options = options || {};\n this.eventDispatcher = new EventDispatcher(options.eventDispatcher);\n }\n /**\n * Get recommendations for supplied pod identifier\n *\n * @function getRecommendations\n * @description Retrieve recommendation results from Constructor.io API\n * @param {string} podId - Pod identifier\n * @param {object} [parameters] - Additional parameters to refine results\n * @param {string|array} [parameters.itemIds] - Item ID(s) to retrieve recommendations for (strategy specific)\n * @param {number} [parameters.numResults] - The number of results to return\n * @param {string} [parameters.section] - The section to return results from\n * @param {string} [parameters.term] - The term to use to refine results (strategy specific)\n * @param {object} [parameters.filters] - Key / value mapping of filters used to refine results\n * @param {object} [parameters.variationsMap] - The variations map object to aggregate variations. Please refer to https://docs.constructor.io/rest_api/variations_mapping for details\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/recommendations\n * @example\n * constructorio.recommendations.getRecommendations('t-shirt-best-sellers', {\n * numResults: 5,\n * filters: {\n * size: 'medium'\n * },\n * });\n */\n\n\n (0, _createClass2[\"default\"])(Recommendations, [{\n key: \"getRecommendations\",\n value: function getRecommendations(podId, parameters) {\n var _this = this;\n\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var requestUrl;\n var fetch = this.options.fetch;\n var signal;\n\n if (typeof AbortController === 'function') {\n var controller = new AbortController();\n signal = controller && controller.signal; // Handle network timeout if specified\n\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n }\n\n try {\n requestUrl = createRecommendationsUrl(podId, parameters, this.options);\n } catch (e) {\n return Promise.reject(e);\n }\n\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return helpers.throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n if (json.response && json.response.results) {\n if (json.result_id) {\n // Append `result_id` to each result item\n json.response.results.forEach(function (result) {\n // eslint-disable-next-line no-param-reassign\n result.result_id = json.result_id;\n });\n }\n\n _this.eventDispatcher.queue('recommendations.getRecommendations.completed', json);\n\n return json;\n }\n\n throw new Error('getRecommendations response data is malformed');\n });\n }\n }]);\n return Recommendations;\n}();\n\nmodule.exports = Recommendations;","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\n/* eslint-disable complexity */\n\n/* eslint-disable max-len */\n\n/* eslint-disable object-curly-newline, no-underscore-dangle */\nvar EventDispatcher = require('../utils/event-dispatcher');\n\nvar helpers = require('../utils/helpers'); // Create URL from supplied query (term) and parameters\n\n\nfunction createSearchUrl(query, parameters, options) {\n var isVoiceSearch = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n var apiKey = options.apiKey,\n version = options.version,\n serviceUrl = options.serviceUrl,\n sessionId = options.sessionId,\n clientId = options.clientId,\n userId = options.userId,\n segments = options.segments,\n testCells = options.testCells;\n var queryParams = {\n c: version\n };\n queryParams.key = apiKey;\n queryParams.i = clientId;\n queryParams.s = sessionId; // Validate query (term) is provided\n\n if (!query || typeof query !== 'string') {\n throw new Error('query is a required parameter of type string');\n } // Pull test cells from options\n\n\n if (testCells) {\n Object.keys(testCells).forEach(function (testCellKey) {\n queryParams[\"ef-\".concat(testCellKey)] = testCells[testCellKey];\n });\n } // Pull user segments from options\n\n\n if (segments && segments.length) {\n queryParams.us = segments;\n } // Pull user id from options and ensure string\n\n\n if (userId) {\n queryParams.ui = String(userId);\n }\n\n if (parameters) {\n var offset = parameters.offset,\n page = parameters.page,\n resultsPerPage = parameters.resultsPerPage,\n filters = parameters.filters,\n sortBy = parameters.sortBy,\n sortOrder = parameters.sortOrder,\n section = parameters.section,\n fmtOptions = parameters.fmtOptions,\n hiddenFields = parameters.hiddenFields,\n hiddenFacets = parameters.hiddenFacets,\n variationsMap = parameters.variationsMap,\n qsParam = parameters.qsParam,\n preFilterExpression = parameters.preFilterExpression; // Pull offset from parameters\n\n if (!helpers.isNil(offset)) {\n queryParams.offset = offset;\n } // Pull page from parameters\n\n\n if (!helpers.isNil(page)) {\n queryParams.page = page;\n } // Pull results per page from parameters\n\n\n if (!helpers.isNil(resultsPerPage)) {\n queryParams.num_results_per_page = resultsPerPage;\n } // Pull filters from parameters\n\n\n if (filters) {\n queryParams.filters = filters;\n } // Pull sort by from parameters\n\n\n if (sortBy) {\n queryParams.sort_by = sortBy;\n } // Pull sort order from parameters\n\n\n if (sortOrder) {\n queryParams.sort_order = sortOrder;\n } // Pull section from parameters\n\n\n if (section) {\n queryParams.section = section;\n } // Pull format options from parameters\n\n\n if (fmtOptions) {\n queryParams.fmt_options = fmtOptions;\n } // Pull hidden fields from parameters\n\n\n if (hiddenFields) {\n if (queryParams.fmt_options) {\n queryParams.fmt_options.hidden_fields = hiddenFields;\n } else {\n queryParams.fmt_options = {\n hidden_fields: hiddenFields\n };\n }\n } // Pull hidden facets from parameters\n\n\n if (hiddenFacets) {\n if (queryParams.fmt_options) {\n queryParams.fmt_options.hidden_facets = hiddenFacets;\n } else {\n queryParams.fmt_options = {\n hidden_facets: hiddenFacets\n };\n }\n } // Pull variations map from parameters\n\n\n if (variationsMap) {\n queryParams.variations_map = JSON.stringify(variationsMap);\n } // Pull pre_filter_expression from parameters\n\n\n if (preFilterExpression) {\n queryParams.pre_filter_expression = JSON.stringify(preFilterExpression);\n } // pull qs param from parameters\n\n\n if (qsParam) {\n queryParams.qs = JSON.stringify(qsParam);\n }\n }\n\n queryParams._dt = Date.now();\n queryParams = helpers.cleanParams(queryParams);\n var queryString = helpers.stringify(queryParams);\n var searchUrl = isVoiceSearch ? 'search/natural_language' : 'search';\n return \"\".concat(serviceUrl, \"/\").concat(searchUrl, \"/\").concat(helpers.encodeURIComponentRFC3986(helpers.trimNonBreakingSpaces(query)), \"?\").concat(queryString);\n}\n/**\n * Interface to search related API calls\n *\n * @module search\n * @inner\n * @returns {object}\n */\n\n\nvar Search = /*#__PURE__*/function () {\n function Search(options) {\n (0, _classCallCheck2[\"default\"])(this, Search);\n this.options = options || {};\n this.eventDispatcher = new EventDispatcher(options.eventDispatcher);\n }\n /**\n * Retrieve search results from API\n *\n * @function getSearchResults\n * @description Retrieve search results from Constructor.io API\n * @param {string} query - Term to use to perform a search\n * @param {object} [parameters] - Additional parameters to refine result set\n * @param {number} [parameters.page] - The page number of the results(Can't be used together with offset)\n * @param {number} [parameters.offset] - The number of results to skip from the beginning (Can't be used together with page)\n * @param {number} [parameters.resultsPerPage] - The number of results per page to return\n * @param {object} [parameters.filters] - Key / value mapping (dictionary) of filters used to refine results\n * @param {string} [parameters.sortBy='relevance'] - The sort method for results\n * @param {string} [parameters.sortOrder='descending'] - The sort order for results\n * @param {string} [parameters.section='Products'] - The section name for results\n * @param {object} [parameters.fmtOptions] - The format options used to refine result groups. Please refer to https://docs.constructor.io/rest_api/search/queries for details\n * @param {object} [parameters.preFilterExpression] - Faceting expression to scope search results. Please refer to https://docs.constructor.io/rest_api/collections#add-items-dynamically\n * @param {string[]} [parameters.hiddenFields] - Hidden metadata fields to return\n * @param {string[]} [parameters.hiddenFacets] - Hidden facets to return\n * @param {object} [parameters.variationsMap] - The variations map object to aggregate variations. Please refer to https://docs.constructor.io/rest_api/variations_mapping for details\n * @param {object} [parameters.qsParam] - Parameters listed above can be serialized into a JSON object and parsed through this parameter. Please refer to https://docs.constructor.io/rest_api/search/queries/\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/search/\n * @example\n * constructorio.search.getSearchResults('t-shirt', {\n * resultsPerPage: 40,\n * filters: {\n * size: 'medium'\n * },\n * });\n */\n\n\n (0, _createClass2[\"default\"])(Search, [{\n key: \"getSearchResults\",\n value: function getSearchResults(query, parameters) {\n var _this = this;\n\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var requestUrl;\n var fetch = this.options.fetch;\n var signal;\n\n if (typeof AbortController === 'function') {\n var controller = new AbortController();\n signal = controller && controller.signal; // Handle network timeout if specified\n\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n }\n\n try {\n requestUrl = createSearchUrl(query, parameters, this.options);\n } catch (e) {\n return Promise.reject(e);\n }\n\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return helpers.throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n // Search results\n if (json.response && json.response.results) {\n if (json.result_id) {\n // Append `result_id` to each result item\n json.response.results.forEach(function (result) {\n // eslint-disable-next-line no-param-reassign\n result.result_id = json.result_id;\n });\n }\n\n _this.eventDispatcher.queue('search.getSearchResults.completed', json);\n\n return json;\n } // Redirect rules\n\n\n if (json.response && json.response.redirect) {\n _this.eventDispatcher.queue('search.getSearchResults.completed', json);\n\n return json;\n }\n\n throw new Error('getSearchResults response data is malformed');\n });\n }\n /**\n * Retrieve voice search results from API\n *\n * @function getVoiceSearchResults\n * @description Retrieve voice search results from Constructor.io API\n * @param {string} query - Term to use to perform a voice search\n * @param {object} [parameters] - Additional parameters to refine result set\n * @param {number} [parameters.page] - The page number of the results (Can't be used together with offset)\n * @param {number} [parameters.offset] - The number of results to skip from the beginning (Can't be used together with page)\n * @param {number} [parameters.resultsPerPage] - The number of results per page to return\n * @param {string} [parameters.section='Products'] - The section name for results\n * @param {object} [parameters.fmtOptions] - The format options used to refine result groups. Please refer to https://docs.constructor.io/rest_api/search/queries for details\n * @param {object} [parameters.preFilterExpression] - Faceting expression to scope search results. Please refer to https://docs.constructor.io/rest_api/collections#add-items-dynamically\n * @param {object} [parameters.variationsMap] - The variations map object to aggregate variations. Please refer to https://docs.constructor.io/rest_api/variations_mapping for details\n * @param {string[]} [parameters.hiddenFields] - Hidden metadata fields to return\n * @param {string[]} [parameters.hiddenFacets] - Hidden facets to return\n * @param {object} [parameters.qsParam] - Parameters listed above can be serialized into a JSON object and parsed through this parameter. Please refer to https://docs.constructor.io/rest_api/search/queries/\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {Promise}\n * @see https://docs.constructor.io/rest_api/search/natural_language_search/\n * @example\n * constructorio.search.getVoiceSearchResults('show me lipstick');\n */\n\n }, {\n key: \"getVoiceSearchResults\",\n value: function getVoiceSearchResults(query, parameters) {\n var _this2 = this;\n\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var requestUrl;\n var fetch = this.options.fetch;\n var signal;\n\n if (typeof AbortController === 'function') {\n var controller = new AbortController();\n signal = controller && controller.signal; // Handle network timeout if specified\n\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n }\n\n try {\n var isVoiceSearch = true;\n requestUrl = createSearchUrl(query, parameters, this.options, isVoiceSearch);\n } catch (e) {\n return Promise.reject(e);\n }\n\n return fetch(requestUrl, {\n signal: signal\n }).then(function (response) {\n if (response.ok) {\n return response.json();\n }\n\n return helpers.throwHttpErrorFromResponse(new Error(), response);\n }).then(function (json) {\n // Search results\n if (json.response && json.response.results) {\n if (json.result_id) {\n // Append `result_id` to each result item\n json.response.results.forEach(function (result) {\n // eslint-disable-next-line no-param-reassign\n result.result_id = json.result_id;\n });\n }\n\n _this2.eventDispatcher.queue('search.getVoiceSearchResults.completed', json);\n\n return json;\n } // Redirect rules\n\n\n if (json.response && json.response.redirect) {\n _this2.eventDispatcher.queue('search.getVoiceSearchResults.completed', json);\n\n return json;\n }\n\n throw new Error('getVoiceSearchResults response data is malformed');\n });\n }\n }]);\n return Search;\n}();\n\nmodule.exports = Search;","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _defineProperty2 = _interopRequireDefault(require(\"@babel/runtime/helpers/defineProperty\"));\n\nvar _typeof2 = _interopRequireDefault(require(\"@babel/runtime/helpers/typeof\"));\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2[\"default\"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }\n\n/* eslint-disable object-curly-newline, no-underscore-dangle, camelcase, no-unneeded-ternary */\nvar EventEmitter = require('events');\n\nvar helpers = require('../utils/helpers');\n\nvar RequestQueue = require('../utils/request-queue');\n\nfunction applyParams(parameters, options) {\n var apiKey = options.apiKey,\n version = options.version,\n sessionId = options.sessionId,\n clientId = options.clientId,\n userId = options.userId,\n segments = options.segments,\n testCells = options.testCells,\n requestMethod = options.requestMethod,\n beaconMode = options.beaconMode;\n\n var _helpers$getWindowLoc = helpers.getWindowLocation(),\n host = _helpers$getWindowLoc.host,\n pathname = _helpers$getWindowLoc.pathname;\n\n var sendReferrerWithTrackingEvents = options.sendReferrerWithTrackingEvents === false ? false : true; // Defaults to 'true'\n\n var aggregateParams = Object.assign(parameters);\n\n if (version) {\n aggregateParams.c = version;\n }\n\n if (clientId) {\n aggregateParams.i = clientId;\n }\n\n if (sessionId) {\n aggregateParams.s = sessionId;\n }\n\n if (userId) {\n aggregateParams.ui = String(userId);\n }\n\n if (segments && segments.length) {\n aggregateParams.us = segments;\n }\n\n if (apiKey) {\n aggregateParams.key = apiKey;\n }\n\n if (testCells) {\n Object.keys(testCells).forEach(function (testCellKey) {\n aggregateParams[\"ef-\".concat(testCellKey)] = testCells[testCellKey];\n });\n }\n\n if (beaconMode && requestMethod && requestMethod.match(/POST/i)) {\n aggregateParams.beacon = true;\n }\n\n if (sendReferrerWithTrackingEvents && host) {\n aggregateParams.origin_referrer = host;\n\n if (pathname) {\n aggregateParams.origin_referrer += pathname;\n }\n }\n\n aggregateParams._dt = Date.now();\n aggregateParams = helpers.cleanParams(aggregateParams);\n return aggregateParams;\n} // Append common parameters to supplied parameters object and return as string\n\n\nfunction applyParamsAsString(parameters, options) {\n return helpers.stringify(applyParams(parameters, options));\n}\n/**\n * Interface to tracking related API calls\n *\n * @module tracker\n * @inner\n * @returns {object}\n */\n\n\nvar Tracker = /*#__PURE__*/function () {\n function Tracker(options) {\n (0, _classCallCheck2[\"default\"])(this, Tracker);\n this.options = options || {};\n this.eventemitter = new EventEmitter();\n this.requests = new RequestQueue(options, this.eventemitter);\n this.behavioralV2Url = 'https://ac.cnstrc.com/v2/behavioral_action/';\n }\n /**\n * Send session start event to API\n * @private\n * @function trackSessionStartV2\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @example\n * constructorio.tracker.trackSessionStartV2();\n */\n\n\n (0, _createClass2[\"default\"])(Tracker, [{\n key: \"trackSessionStartV2\",\n value: function trackSessionStartV2() {\n var networkParameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var url = \"\".concat(this.behavioralV2Url, \"session_start?\");\n this.requests.queue(\"\".concat(url).concat(applyParamsAsString({}, this.options)), 'POST', undefined, networkParameters);\n this.requests.send();\n return true;\n }\n /**\n * Send session start event to API\n *\n * @function trackSessionStart\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @example\n * constructorio.tracker.trackSessionStart();\n */\n\n }, {\n key: \"trackSessionStart\",\n value: function trackSessionStart() {\n var networkParameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var url = \"\".concat(this.options.serviceUrl, \"/behavior?\");\n var queryParams = {\n action: 'session_start'\n };\n this.requests.queue(\"\".concat(url).concat(applyParamsAsString(queryParams, this.options)), undefined, undefined, networkParameters);\n this.requests.send();\n return true;\n }\n /**\n * Send input focus event to API\n * @private\n * @function trackInputFocusV2\n * @param {string} user_input - Input at the time user focused on the search bar\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User focused on search input element\n * @example\n * constructorio.tracker.trackInputFocusV2(\"text\");\n */\n\n }, {\n key: \"trackInputFocusV2\",\n value: function trackInputFocusV2() {\n var user_input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var baseUrl = \"\".concat(this.behavioralV2Url, \"focus?\");\n var bodyParams = {};\n var networkParametersNew = networkParameters;\n var userInputNew = user_input;\n\n if ((0, _typeof2[\"default\"])(user_input) === 'object') {\n networkParametersNew = user_input;\n userInputNew = '';\n }\n\n bodyParams.user_input = userInputNew;\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(\"\".concat(baseUrl).concat(applyParamsAsString({}, this.options)), requestMethod, requestBody, networkParametersNew);\n this.requests.send();\n return true;\n }\n /**\n * Send input focus event to API\n *\n * @function trackInputFocus\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User focused on search input element\n * @example\n * constructorio.tracker.trackInputFocus();\n */\n\n }, {\n key: \"trackInputFocus\",\n value: function trackInputFocus() {\n var networkParameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var url = \"\".concat(this.options.serviceUrl, \"/behavior?\");\n var queryParams = {\n action: 'focus'\n };\n this.requests.queue(\"\".concat(url).concat(applyParamsAsString(queryParams, this.options)), undefined, undefined, networkParameters);\n this.requests.send();\n return true;\n }\n /**\n * Send item detail load event to API\n *\n * @function trackItemDetailLoad\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.item_name - Product item name\n * @param {string} parameters.item_id - Product item unique identifier\n * @param {string} parameters.url - Current page URL\n * @param {string} [parameters.variation_id] - Product item variation unique identifier\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User loaded an item detail page\n * @example\n * constructorio.tracker.trackItemDetailLoad(\n * {\n * item_name: 'Red T-Shirt',\n * item_id: 'KMH876',\n * url: 'https://constructor.io/product/KMH876',\n * },\n * );\n */\n\n }, {\n key: \"trackItemDetailLoad\",\n value: function trackItemDetailLoad(parameters) {\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var requestUrlPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/item_detail_load?\");\n var queryParams = {};\n var bodyParams = {};\n var item_name = parameters.item_name,\n name = parameters.name,\n item_id = parameters.item_id,\n customer_id = parameters.customer_id,\n variation_id = parameters.variation_id,\n url = parameters.url; // Ensure support for both item_name and name as parameters\n\n if (item_name) {\n bodyParams.item_name = item_name;\n } else if (name) {\n bodyParams.item_name = name;\n } // Ensure support for both item_id and customer_id as parameters\n\n\n if (item_id) {\n bodyParams.item_id = item_id;\n } else if (customer_id) {\n bodyParams.item_id = customer_id;\n }\n\n if (variation_id) {\n bodyParams.variation_id = variation_id;\n }\n\n if (url) {\n bodyParams.url = url;\n }\n\n var requestURL = \"\".concat(requestUrlPath).concat(applyParamsAsString(queryParams, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n /**\n * Send autocomplete select event to API\n * @private\n * @function trackAutocompleteSelectV2\n * @param {string} item_name - Name of selected autocomplete item\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.user_input - The current autocomplete search query\n * @param {string} [parameters.section] - Section the selected item resides within\n * @param {string} [parameters.tr] - Trigger used to select the item (click, etc.)\n * @param {string} [parameters.item_id] - Item id of the selected item\n * @param {string} [parameters.variation_id] - Variation id of the selected item\n * @param {string} [parameters.group_id] - Group identifier of selected item\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User selected (clicked, or navigated to via keyboard) a result that appeared within autocomplete\n * @example\n * constructorio.tracker.trackAutocompleteSelectV2(\n * 'T-Shirt',\n * {\n * user_input: 'Shirt',\n * section: 'Products',\n * tr: 'click',\n * group_id: '88JU230',\n * item_id: '12345',\n * variation_id: '12345-A',\n * },\n * );\n */\n\n }, {\n key: \"trackAutocompleteSelectV2\",\n value: function trackAutocompleteSelectV2(item_name, parameters) {\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n // Ensure term is provided (required)\n if (item_name && typeof item_name === 'string') {\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var baseUrl = \"\".concat(this.behavioralV2Url, \"autocomplete_select?\");\n var original_query = parameters.original_query,\n _parameters$user_inpu = parameters.user_input,\n user_input = _parameters$user_inpu === void 0 ? original_query : _parameters$user_inpu,\n original_section = parameters.original_section,\n _parameters$section = parameters.section,\n section = _parameters$section === void 0 ? original_section : _parameters$section,\n tr = parameters.tr,\n group_id = parameters.group_id,\n item_id = parameters.item_id,\n variation_id = parameters.variation_id;\n var queryParams = {};\n var bodyParams = {\n user_input: user_input,\n tr: tr,\n group_id: group_id,\n item_id: item_id,\n variation_id: variation_id,\n item_name: item_name,\n section: section\n };\n\n if (section) {\n queryParams.section = section;\n }\n\n var requestURL = \"\".concat(baseUrl).concat(applyParamsAsString(queryParams, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n\n this.requests.send();\n return new Error('term is a required parameter of type string');\n }\n /**\n * Send autocomplete select event to API\n *\n * @function trackAutocompleteSelect\n * @param {string} term - Term of selected autocomplete item\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.original_query - The current autocomplete search query\n * @param {string} parameters.section - Section the selected item resides within\n * @param {string} [parameters.tr] - Trigger used to select the item (click, etc.)\n * @param {string} [parameters.group_id] - Group identifier of selected item\n * @param {string} [parameters.display_name] - Display name of group of selected item\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User selected (clicked, or navigated to via keyboard) a result that appeared within autocomplete\n * @example\n * constructorio.tracker.trackAutocompleteSelect(\n * 'T-Shirt',\n * {\n * original_query: 'Shirt',\n * section: 'Products',\n * tr: 'click',\n * group_id: '88JU230',\n * display_name: 'apparel',\n * },\n * );\n */\n\n }, {\n key: \"trackAutocompleteSelect\",\n value: function trackAutocompleteSelect(term, parameters) {\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n // Ensure term is provided (required)\n if (term && typeof term === 'string') {\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var url = \"\".concat(this.options.serviceUrl, \"/autocomplete/\").concat(helpers.encodeURIComponentRFC3986(helpers.trimNonBreakingSpaces(term)), \"/select?\");\n var queryParams = {};\n var original_query = parameters.original_query,\n section = parameters.section,\n original_section = parameters.original_section,\n tr = parameters.tr,\n group_id = parameters.group_id,\n display_name = parameters.display_name;\n\n if (original_query) {\n queryParams.original_query = original_query;\n }\n\n if (tr) {\n queryParams.tr = tr;\n }\n\n if (original_section || section) {\n queryParams.section = original_section || section;\n }\n\n if (group_id) {\n queryParams.group = {\n group_id: group_id,\n display_name: display_name\n };\n }\n\n this.requests.queue(\"\".concat(url).concat(applyParamsAsString(queryParams, this.options)), undefined, undefined, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n\n this.requests.send();\n return new Error('term is a required parameter of type string');\n }\n /**\n * Send autocomplete search event to API\n * @private\n * @function trackSearchSubmitV2\n * @param {string} search_term - Term of submitted autocomplete event\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.user_input - The current autocomplete search query\n * @param {string} [parameters.group_id] - Group identifier of selected item\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User submitted a search (pressing enter within input element, or clicking submit element)\n * @example\n * constructorio.tracker.trackSearchSubmitV2(\n * 'T-Shirt',\n * {\n * user_input: 'Shirt',\n * group_id: '88JU230',\n * },\n * );\n */\n\n }, {\n key: \"trackSearchSubmitV2\",\n value: function trackSearchSubmitV2(search_term, parameters) {\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n // Ensure term is provided (required)\n if (search_term && typeof search_term === 'string') {\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var baseUrl = \"\".concat(this.behavioralV2Url, \"search_submit?\");\n var original_query = parameters.original_query,\n _parameters$user_inpu2 = parameters.user_input,\n user_input = _parameters$user_inpu2 === void 0 ? original_query : _parameters$user_inpu2,\n group_id = parameters.group_id,\n section = parameters.section;\n var queryParams = {};\n var bodyParams = {\n user_input: user_input,\n search_term: search_term,\n section: section\n };\n\n if (group_id) {\n bodyParams.filters = {\n group_id: group_id\n };\n }\n\n if (section) {\n queryParams.section = section;\n }\n\n var requestURL = \"\".concat(baseUrl).concat(applyParamsAsString(queryParams, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n\n this.requests.send();\n return new Error('term is a required parameter of type string');\n }\n /**\n * Send autocomplete search event to API\n *\n * @function trackSearchSubmit\n * @param {string} term - Term of submitted autocomplete event\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.original_query - The current autocomplete search query\n * @param {string} [parameters.group_id] - Group identifier of selected item\n * @param {string} [parameters.display_name] - Display name of group of selected item\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User submitted a search (pressing enter within input element, or clicking submit element)\n * @example\n * constructorio.tracker.trackSearchSubmit(\n * 'T-Shirt',\n * {\n * original_query: 'Shirt',\n * group_id: '88JU230',\n * display_name: 'apparel',\n * },\n * );\n */\n\n }, {\n key: \"trackSearchSubmit\",\n value: function trackSearchSubmit(term, parameters) {\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n // Ensure term is provided (required)\n if (term && typeof term === 'string') {\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var url = \"\".concat(this.options.serviceUrl, \"/autocomplete/\").concat(helpers.encodeURIComponentRFC3986(helpers.trimNonBreakingSpaces(term)), \"/search?\");\n var queryParams = {};\n var original_query = parameters.original_query,\n group_id = parameters.group_id,\n display_name = parameters.display_name;\n\n if (original_query) {\n queryParams.original_query = original_query;\n }\n\n if (group_id) {\n queryParams.group = {\n group_id: group_id,\n display_name: display_name\n };\n }\n\n this.requests.queue(\"\".concat(url).concat(applyParamsAsString(queryParams, this.options)), undefined, undefined, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n\n this.requests.send();\n return new Error('term is a required parameter of type string');\n }\n /**\n * Send search results loaded v2 event to API\n * @private\n * @function trackSearchResultsLoadedV2\n * @param {string} search_term - Search results query term\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.url - URL of the search results page\n * @param {number} [parameters.result_count] - Total number of results\n * @param {number} [parameters.result_page] - Current page of search results\n * @param {string} [parameters.result_id] - Browse result identifier (returned in response from Constructor)\n * @param {object} [parameters.selected_filters] - Selected filters\n * @param {string} [parameters.sort_order] - Sort order ('ascending' or 'descending')\n * @param {string} [parameters.sort_by] - Sorting method\n * @param {object[]} [parameters.items] - List of product item unique identifiers in search results listing\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User viewed a search product listing page\n * @example\n * constructorio.tracker.trackSearchResultsLoadedV2(\n * 'T-Shirt',\n * {\n * result_count: 167,\n * items: [{item_id: 'KMH876'}, {item_id: 'KMH140'}, {item_id: 'KMH437'}],\n * sort_order: 'ascending'\n * sort_by: 'price',\n * result_page: 3,\n * result_count: 20\n * },\n * );\n */\n\n }, {\n key: \"trackSearchResultsLoadedV2\",\n value: function trackSearchResultsLoadedV2(search_term, parameters) {\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n // Ensure term is provided (required)\n if (search_term && typeof search_term === 'string') {\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var baseUrl = \"\".concat(this.behavioralV2Url, \"search_result_load?\");\n var num_results = parameters.num_results,\n _parameters$result_co = parameters.result_count,\n result_count = _parameters$result_co === void 0 ? num_results : _parameters$result_co,\n customer_ids = parameters.customer_ids,\n item_ids = parameters.item_ids,\n _parameters$items = parameters.items,\n items = _parameters$items === void 0 ? customer_ids || item_ids : _parameters$items,\n result_page = parameters.result_page,\n result_id = parameters.result_id,\n sort_order = parameters.sort_order,\n sort_by = parameters.sort_by,\n selected_filters = parameters.selected_filters,\n url = parameters.url,\n section = parameters.section;\n var queryParams = {};\n var transformedItems;\n\n if (items && Array.isArray(items) && items.length !== 0) {\n transformedItems = items;\n\n if (typeof items[0] === 'string' || typeof items[0] === 'number') {\n transformedItems = items.map(function (itemId) {\n return {\n item_id: String(itemId)\n };\n });\n }\n }\n\n if (section) {\n queryParams.section = section;\n }\n\n var bodyParams = {\n search_term: search_term,\n result_count: result_count,\n items: transformedItems,\n result_page: result_page,\n result_id: result_id,\n sort_order: sort_order,\n sort_by: sort_by,\n selected_filters: selected_filters,\n url: url,\n section: section\n };\n var requestURL = \"\".concat(baseUrl).concat(applyParamsAsString(queryParams, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n\n this.requests.send();\n return new Error('term is a required parameter of type string');\n }\n /**\n * Send search results loaded event to API\n *\n * @function trackSearchResultsLoaded\n * @param {string} term - Search results query term\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {number} parameters.num_results - Total number of results\n * @param {string[]} [parameters.item_ids] - List of product item unique identifiers in search results listing\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User viewed a search product listing page\n * @example\n * constructorio.tracker.trackSearchResultsLoaded(\n * 'T-Shirt',\n * {\n * num_results: 167,\n * item_ids: ['KMH876', 'KMH140', 'KMH437'],\n * },\n * );\n */\n\n }, {\n key: \"trackSearchResultsLoaded\",\n value: function trackSearchResultsLoaded(term, parameters) {\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n // Ensure term is provided (required)\n if (term && typeof term === 'string') {\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var url = \"\".concat(this.options.serviceUrl, \"/behavior?\");\n var queryParams = {\n action: 'search-results',\n term: term\n };\n var num_results = parameters.num_results,\n customer_ids = parameters.customer_ids,\n item_ids = parameters.item_ids;\n var customerIDs;\n\n if (!helpers.isNil(num_results)) {\n queryParams.num_results = num_results;\n } // Ensure support for both item_ids and customer_ids as parameters\n\n\n if (item_ids && Array.isArray(item_ids) && item_ids.length) {\n customerIDs = item_ids;\n } else if (customer_ids && Array.isArray(customer_ids) && customer_ids.length) {\n customerIDs = customer_ids;\n }\n\n if (customerIDs && customerIDs.length) {\n queryParams.customer_ids = customerIDs.slice(0, 100).join(',');\n }\n\n this.requests.queue(\"\".concat(url).concat(applyParamsAsString(queryParams, this.options)), undefined, undefined, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n\n this.requests.send();\n return new Error('term is a required parameter of type string');\n }\n /**\n * Send click through event to API\n * @private\n * @function trackSearchResultClickV2\n * @param {string} term - Search results query term\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.item_name - Product item name (Either item_name or item_id is required)\n * @param {string} parameters.item_id - Product item unique identifier\n * @param {string} [parameters.variation_id] - Product item variation unique identifier\n * @param {string} [parameters.result_id] - Search result identifier (returned in response from Constructor)\n * @param {number} [parameters.result_count] - Number of results in total\n * @param {number} [parameters.result_page] - Current page of results\n * @param {string} [parameters.result_position_on_page] - Position of selected items on page\n * @param {string} [parameters.num_results_per_page] - Number of results per page\n * @param {object} [parameters.selected_filters] - Key - Value map of selected filters\n * @param {string} [parameters.section] - The section name for the item Ex. \"Products\"\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User clicked a result that appeared within a search product listing page\n * @example\n * constructorio.tracker.trackSearchResultClickV2(\n * 'T-Shirt',\n * {\n * item_name: 'Red T-Shirt',\n * item_id: 'KMH876',\n * result_id: '019927c2-f955-4020-8b8d-6b21b93cb5a2',\n * },\n * );\n */\n\n }, {\n key: \"trackSearchResultClickV2\",\n value: function trackSearchResultClickV2(term, parameters) {\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n // Ensure term is provided (required)\n if (term && typeof term === 'string') {\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var baseUrl = \"\".concat(this.behavioralV2Url, \"search_result_click?\");\n var customer_id = parameters.customer_id,\n _parameters$item_id = parameters.item_id,\n item_id = _parameters$item_id === void 0 ? customer_id : _parameters$item_id,\n name = parameters.name,\n _parameters$item_name = parameters.item_name,\n item_name = _parameters$item_name === void 0 ? name : _parameters$item_name,\n variation_id = parameters.variation_id,\n result_id = parameters.result_id,\n result_count = parameters.result_count,\n result_page = parameters.result_page,\n result_position_on_page = parameters.result_position_on_page,\n num_results_per_page = parameters.num_results_per_page,\n selected_filters = parameters.selected_filters,\n section = parameters.section;\n var bodyParams = {\n item_name: item_name,\n item_id: item_id,\n variation_id: variation_id,\n result_id: result_id,\n result_count: result_count,\n result_page: result_page,\n result_position_on_page: result_position_on_page,\n num_results_per_page: num_results_per_page,\n selected_filters: selected_filters,\n section: section,\n search_term: term\n };\n var queryParams = {};\n\n if (section) {\n queryParams.section = section;\n }\n\n var requestURL = \"\".concat(baseUrl).concat(applyParamsAsString(queryParams, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n\n this.requests.send();\n return new Error('term is a required parameter of type string');\n }\n /**\n * Send click through event to API\n *\n * @function trackSearchResultClick\n * @param {string} term - Search results query term\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.item_name - Product item name\n * @param {string} parameters.item_id - Product item unique identifier\n * @param {string} [parameters.variation_id] - Product item variation unique identifier\n * @param {string} [parameters.result_id] - Search result identifier (returned in response from Constructor)\n * @param {string} [parameters.item_is_convertible] - Whether or not an item is available for a conversion\n * @param {string} [parameters.section] - The section name for the item Ex. \"Products\"\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User clicked a result that appeared within a search product listing page\n * @example\n * constructorio.tracker.trackSearchResultClick(\n * 'T-Shirt',\n * {\n * item_name: 'Red T-Shirt',\n * item_id: 'KMH876',\n * result_id: '019927c2-f955-4020-8b8d-6b21b93cb5a2',\n * },\n * );\n */\n\n }, {\n key: \"trackSearchResultClick\",\n value: function trackSearchResultClick(term, parameters) {\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n // Ensure term is provided (required)\n if (term && typeof term === 'string') {\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var url = \"\".concat(this.options.serviceUrl, \"/autocomplete/\").concat(helpers.encodeURIComponentRFC3986(helpers.trimNonBreakingSpaces(term)), \"/click_through?\");\n var queryParams = {};\n var item_name = parameters.item_name,\n name = parameters.name,\n item_id = parameters.item_id,\n customer_id = parameters.customer_id,\n variation_id = parameters.variation_id,\n result_id = parameters.result_id,\n section = parameters.section,\n item_is_convertible = parameters.item_is_convertible; // Ensure support for both item_name and name as parameters\n\n if (item_name) {\n queryParams.name = item_name;\n } else if (name) {\n queryParams.name = name;\n } // Ensure support for both item_id and customer_id as parameters\n\n\n if (item_id) {\n queryParams.customer_id = item_id;\n } else if (customer_id) {\n queryParams.customer_id = customer_id;\n }\n\n if (variation_id) {\n queryParams.variation_id = variation_id;\n }\n\n if (result_id) {\n queryParams.result_id = result_id;\n }\n\n if (typeof item_is_convertible === 'boolean') {\n queryParams.item_is_convertible = item_is_convertible;\n }\n\n if (section) {\n queryParams.section = section;\n }\n\n this.requests.queue(\"\".concat(url).concat(applyParamsAsString(queryParams, this.options)), undefined, undefined, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n\n this.requests.send();\n return new Error('term is a required parameter of type string');\n }\n /**\n * Send conversion event to API\n *\n * @function trackConversion\n * @param {string} [term] - Search results query term that led to conversion event\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.item_id - Product item unique identifier\n * @param {number} [parameters.revenue] - Sale price if available, otherwise the regular (retail) price of item\n * @param {string} [parameters.item_name] - Product item name\n * @param {string} [parameters.variation_id] - Product item variation unique identifier\n * @param {string} [parameters.type='add_to_cart'] - Conversion type\n * @param {boolean} [parameters.is_custom_type] - Specify if type is custom conversion type\n * @param {string} [parameters.display_name] - Display name for the custom conversion type\n * @param {string} [parameters.result_id] - Result identifier (returned in response from Constructor)\n * @param {string} [parameters.section=\"Products\"] - Index section\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User performed an action indicating interest in an item (add to cart, add to wishlist, etc.)\n * @see https://docs.constructor.io/rest_api/behavioral_logging/conversions\n * @example\n * constructorio.tracker.trackConversion(\n * 'T-Shirt',\n * {\n * item_id: 'KMH876',\n * revenue: 12.00,\n * item_name: 'Red T-Shirt',\n * variation_id: 'KMH879-7632',\n * type: 'like',\n * result_id: '019927c2-f955-4020-8b8d-6b21b93cb5a2',\n * section: 'Products',\n * },\n * );\n */\n\n }, {\n key: \"trackConversion\",\n value: function trackConversion(term, parameters) {\n var networkParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var searchTerm = term || 'TERM_UNKNOWN';\n var requestPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/conversion?\");\n var queryParams = {};\n var bodyParams = {};\n var name = parameters.name,\n item_name = parameters.item_name,\n item_id = parameters.item_id,\n customer_id = parameters.customer_id,\n variation_id = parameters.variation_id,\n revenue = parameters.revenue,\n _parameters$section2 = parameters.section,\n section = _parameters$section2 === void 0 ? 'Products' : _parameters$section2,\n display_name = parameters.display_name,\n type = parameters.type,\n is_custom_type = parameters.is_custom_type; // Ensure support for both item_id and customer_id as parameters\n\n if (item_id) {\n bodyParams.item_id = item_id;\n } else if (customer_id) {\n bodyParams.item_id = customer_id;\n } // Ensure support for both item_name and name as parameters\n\n\n if (item_name) {\n bodyParams.item_name = item_name;\n } else if (name) {\n bodyParams.item_name = name;\n }\n\n if (variation_id) {\n bodyParams.variation_id = variation_id;\n }\n\n if (revenue) {\n bodyParams.revenue = revenue.toString();\n }\n\n if (section) {\n queryParams.section = section;\n bodyParams.section = section;\n }\n\n if (searchTerm) {\n bodyParams.search_term = searchTerm;\n }\n\n if (type) {\n bodyParams.type = type;\n }\n\n if (is_custom_type) {\n bodyParams.is_custom_type = is_custom_type;\n }\n\n if (display_name) {\n bodyParams.display_name = display_name;\n }\n\n var requestURL = \"\".concat(requestPath).concat(applyParamsAsString(queryParams, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n /**\n * Send purchase event to API\n *\n * @function trackPurchase\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {object[]} parameters.items - List of product item objects\n * @param {number} parameters.revenue - The subtotal (not including taxes, shipping, etc.) of the entire order\n * @param {string} [parameters.order_id] - Unique order identifier\n * @param {string} [parameters.section=\"Products\"] - Index section\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User completed an order (usually fired on order confirmation page)\n * @example\n * constructorio.tracker.trackPurchase(\n * {\n * items: [{ item_id: 'KMH876' }, { item_id: 'KMH140' }],\n * revenue: 12.00,\n * order_id: 'OUNXBG2HMA',\n * section: 'Products',\n * },\n * );\n */\n\n }, {\n key: \"trackPurchase\",\n value: function trackPurchase(parameters) {\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var requestPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/purchase?\");\n var queryParams = {};\n var bodyParams = {};\n var items = parameters.items,\n revenue = parameters.revenue,\n order_id = parameters.order_id,\n section = parameters.section;\n\n if (order_id) {\n // Don't send another purchase event if we have already tracked the order\n if (helpers.hasOrderIdRecord(order_id)) {\n return false;\n }\n\n helpers.addOrderIdRecord(order_id); // Add order_id to the tracking params\n\n bodyParams.order_id = order_id;\n }\n\n if (items && Array.isArray(items)) {\n bodyParams.items = items.slice(0, 100);\n }\n\n if (revenue) {\n bodyParams.revenue = revenue;\n }\n\n if (section) {\n queryParams.section = section;\n } else {\n queryParams.section = 'Products';\n }\n\n var requestURL = \"\".concat(requestPath).concat(applyParamsAsString(queryParams, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n /**\n * Send recommendation view event to API\n *\n * @function trackRecommendationView\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.url - Current page URL\n * @param {string} parameters.pod_id - Pod identifier\n * @param {number} parameters.num_results_viewed - Number of results viewed\n * @param {object[]} [parameters.items] - List of Product Item Objects\n * @param {number} [parameters.result_count] - Total number of results\n * @param {number} [parameters.result_page] - Page number of results\n * @param {string} [parameters.result_id] - Recommendation result identifier (returned in response from Constructor)\n * @param {string} [parameters.section=\"Products\"] - Results section\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User viewed a set of recommendations\n * @example\n * constructorio.tracker.trackRecommendationView(\n * {\n * items: [{ item_id: 'KMH876' }, { item_id: 'KMH140' }],\n * result_count: 22,\n * result_page: 2,\n * result_id: '019927c2-f955-4020-8b8d-6b21b93cb5a2',\n * url: 'https://demo.constructor.io/sandbox/farmstand',\n * pod_id: '019927c2-f955-4020',\n * num_results_viewed: 3,\n * },\n * );\n */\n\n }, {\n key: \"trackRecommendationView\",\n value: function trackRecommendationView(parameters) {\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var requestPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/recommendation_result_view?\");\n var bodyParams = {};\n var result_count = parameters.result_count,\n result_page = parameters.result_page,\n result_id = parameters.result_id,\n section = parameters.section,\n url = parameters.url,\n pod_id = parameters.pod_id,\n num_results_viewed = parameters.num_results_viewed,\n items = parameters.items;\n\n if (!helpers.isNil(result_count)) {\n bodyParams.result_count = result_count;\n }\n\n if (!helpers.isNil(result_page)) {\n bodyParams.result_page = result_page;\n }\n\n if (result_id) {\n bodyParams.result_id = result_id;\n }\n\n if (section) {\n bodyParams.section = section;\n } else {\n bodyParams.section = 'Products';\n }\n\n if (url) {\n bodyParams.url = url;\n }\n\n if (pod_id) {\n bodyParams.pod_id = pod_id;\n }\n\n if (!helpers.isNil(num_results_viewed)) {\n bodyParams.num_results_viewed = num_results_viewed;\n }\n\n if (items && Array.isArray(items)) {\n bodyParams.items = items.slice(0, 100);\n }\n\n var requestURL = \"\".concat(requestPath).concat(applyParamsAsString({}, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n /**\n * Send recommendation click event to API\n *\n * @function trackRecommendationClick\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.pod_id - Pod identifier\n * @param {string} parameters.strategy_id - Strategy identifier\n * @param {string} parameters.item_id - Product item unique identifier\n * @param {string} parameters.item_name - Product name\n * @param {string} [parameters.variation_id] - Product item variation unique identifier\n * @param {string} [parameters.section=\"Products\"] - Index section\n * @param {string} [parameters.result_id] - Recommendation result identifier (returned in response from Constructor)\n * @param {number} [parameters.result_count] - Total number of results\n * @param {number} [parameters.result_page] - Page number of results\n * @param {number} [parameters.result_position_on_page] - Position of result on page\n * @param {number} [parameters.num_results_per_page] - Number of results on page\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User clicked an item that appeared within a list of recommended results\n * @example\n * constructorio.tracker.trackRecommendationClick(\n * {\n * variation_id: 'KMH879-7632',\n * result_id: '019927c2-f955-4020-8b8d-6b21b93cb5a2',\n * result_count: 22,\n * result_page: 2,\n * result_position_on_page: 2,\n * num_results_per_page: 12,\n * pod_id: '019927c2-f955-4020',\n * strategy_id: 'complimentary',\n * item_name: 'Socks',\n * item_id: 'KMH876',\n * },\n * );\n */\n\n }, {\n key: \"trackRecommendationClick\",\n value: function trackRecommendationClick(parameters) {\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var requestPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/recommendation_result_click?\");\n var bodyParams = {};\n var variation_id = parameters.variation_id,\n section = parameters.section,\n result_id = parameters.result_id,\n result_count = parameters.result_count,\n result_page = parameters.result_page,\n result_position_on_page = parameters.result_position_on_page,\n num_results_per_page = parameters.num_results_per_page,\n pod_id = parameters.pod_id,\n strategy_id = parameters.strategy_id,\n item_id = parameters.item_id,\n item_name = parameters.item_name;\n\n if (variation_id) {\n bodyParams.variation_id = variation_id;\n }\n\n if (section) {\n bodyParams.section = section;\n } else {\n bodyParams.section = 'Products';\n }\n\n if (result_id) {\n bodyParams.result_id = result_id;\n }\n\n if (!helpers.isNil(result_count)) {\n bodyParams.result_count = result_count;\n }\n\n if (!helpers.isNil(result_page)) {\n bodyParams.result_page = result_page;\n }\n\n if (!helpers.isNil(result_position_on_page)) {\n bodyParams.result_position_on_page = result_position_on_page;\n }\n\n if (!helpers.isNil(num_results_per_page)) {\n bodyParams.num_results_per_page = num_results_per_page;\n }\n\n if (pod_id) {\n bodyParams.pod_id = pod_id;\n }\n\n if (strategy_id) {\n bodyParams.strategy_id = strategy_id;\n }\n\n if (item_id) {\n bodyParams.item_id = item_id;\n }\n\n if (item_name) {\n bodyParams.item_name = item_name;\n }\n\n var requestURL = \"\".concat(requestPath).concat(applyParamsAsString({}, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n /**\n * Send browse results loaded event to API\n *\n * @function trackBrowseResultsLoaded\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.url - Current page URL\n * @param {string} parameters.filter_name - Filter name\n * @param {string} parameters.filter_value - Filter value\n * @param {string} [parameters.section=\"Products\"] - Index section\n * @param {number} [parameters.result_count] - Total number of results\n * @param {number} [parameters.result_page] - Page number of results\n * @param {string} [parameters.result_id] - Browse result identifier (returned in response from Constructor)\n * @param {object} [parameters.selected_filters] - Selected filters\n * @param {string} [parameters.sort_order] - Sort order ('ascending' or 'descending')\n * @param {string} [parameters.sort_by] - Sorting method\n * @param {object[]} [parameters.items] - List of product item objects\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User viewed a browse product listing page\n * @example\n * constructorio.tracker.trackBrowseResultsLoaded(\n * {\n * result_count: 22,\n * result_page: 2,\n * result_id: '019927c2-f955-4020-8b8d-6b21b93cb5a2',\n * selected_filters: { brand: ['foo'], color: ['black'] },\n * sort_order: 'ascending',\n * sort_by: 'price',\n * items: [{ item_id: 'KMH876' }, { item_id: 'KMH140' }],\n * url: 'https://demo.constructor.io/sandbox/farmstand',\n * filter_name: 'brand',\n * filter_value: 'XYZ',\n * },\n * );\n */\n\n }, {\n key: \"trackBrowseResultsLoaded\",\n value: function trackBrowseResultsLoaded(parameters) {\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var requestPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/browse_result_load?\");\n var bodyParams = {};\n var section = parameters.section,\n result_count = parameters.result_count,\n result_page = parameters.result_page,\n result_id = parameters.result_id,\n selected_filters = parameters.selected_filters,\n url = parameters.url,\n sort_order = parameters.sort_order,\n sort_by = parameters.sort_by,\n filter_name = parameters.filter_name,\n filter_value = parameters.filter_value,\n items = parameters.items;\n\n if (section) {\n bodyParams.section = section;\n } else {\n bodyParams.section = 'Products';\n }\n\n if (!helpers.isNil(result_count)) {\n bodyParams.result_count = result_count;\n }\n\n if (!helpers.isNil(result_page)) {\n bodyParams.result_page = result_page;\n }\n\n if (result_id) {\n bodyParams.result_id = result_id;\n }\n\n if (selected_filters) {\n bodyParams.selected_filters = selected_filters;\n }\n\n if (url) {\n bodyParams.url = url;\n }\n\n if (sort_order) {\n bodyParams.sort_order = sort_order;\n }\n\n if (sort_by) {\n bodyParams.sort_by = sort_by;\n }\n\n if (filter_name) {\n bodyParams.filter_name = filter_name;\n }\n\n if (filter_value) {\n bodyParams.filter_value = filter_value;\n }\n\n if (items && Array.isArray(items)) {\n bodyParams.items = items.slice(0, 100);\n }\n\n var requestURL = \"\".concat(requestPath).concat(applyParamsAsString({}, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n /**\n * Send browse result click event to API\n *\n * @function trackBrowseResultClick\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.filter_name - Filter name\n * @param {string} parameters.filter_value - Filter value\n * @param {string} parameters.item_id - Product item unique identifier\n * @param {string} parameters.item_name - Product item name\n * @param {string} [parameters.section=\"Products\"] - Index section\n * @param {string} [parameters.variation_id] - Product item variation unique identifier\n * @param {string} [parameters.result_id] - Browse result identifier (returned in response from Constructor)\n * @param {number} [parameters.result_count] - Total number of results\n * @param {number} [parameters.result_page] - Page number of results\n * @param {number} [parameters.result_position_on_page] - Position of clicked item\n * @param {number} [parameters.num_results_per_page] - Number of results shown\n * @param {object} [parameters.selected_filters] - Selected filters\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User clicked a result that appeared within a browse product listing page\n * @example\n * constructorio.tracker.trackBrowseResultClick(\n * {\n * variation_id: 'KMH879-7632',\n * result_id: '019927c2-f955-4020-8b8d-6b21b93cb5a2',\n * result_count: 22,\n * result_page: 2,\n * result_position_on_page: 2,\n * num_results_per_page: 12,\n * selected_filters: { brand: ['foo'], color: ['black'] },\n * filter_name: 'brand',\n * filter_value: 'XYZ',\n * item_id: 'KMH876',\n * },\n * );\n */\n\n }, {\n key: \"trackBrowseResultClick\",\n value: function trackBrowseResultClick(parameters) {\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var requestPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/browse_result_click?\");\n var bodyParams = {};\n var section = parameters.section,\n variation_id = parameters.variation_id,\n result_id = parameters.result_id,\n result_count = parameters.result_count,\n result_page = parameters.result_page,\n result_position_on_page = parameters.result_position_on_page,\n num_results_per_page = parameters.num_results_per_page,\n selected_filters = parameters.selected_filters,\n filter_name = parameters.filter_name,\n filter_value = parameters.filter_value,\n item_id = parameters.item_id,\n customer_id = parameters.customer_id,\n item_name = parameters.item_name,\n name = parameters.name;\n\n if (section) {\n bodyParams.section = section;\n } else {\n bodyParams.section = 'Products';\n }\n\n if (variation_id) {\n bodyParams.variation_id = variation_id;\n }\n\n if (result_id) {\n bodyParams.result_id = result_id;\n }\n\n if (!helpers.isNil(result_count)) {\n bodyParams.result_count = result_count;\n }\n\n if (!helpers.isNil(result_page)) {\n bodyParams.result_page = result_page;\n }\n\n if (!helpers.isNil(result_position_on_page)) {\n bodyParams.result_position_on_page = result_position_on_page;\n }\n\n if (!helpers.isNil(num_results_per_page)) {\n bodyParams.num_results_per_page = num_results_per_page;\n }\n\n if (selected_filters) {\n bodyParams.selected_filters = selected_filters;\n }\n\n if (filter_name) {\n bodyParams.filter_name = filter_name;\n }\n\n if (filter_value) {\n bodyParams.filter_value = filter_value;\n } // Ensure support for both item_id and customer_id as parameters\n\n\n if (item_id) {\n bodyParams.item_id = item_id;\n } else if (customer_id) {\n bodyParams.item_id = customer_id;\n } // Ensure support for both item_name and name as parameters\n\n\n if (item_name) {\n bodyParams.item_name = item_name;\n } else if (name) {\n bodyParams.item_name = name;\n }\n\n var requestURL = \"\".concat(requestPath).concat(applyParamsAsString({}, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n /**\n * Send generic result click event to API\n *\n * @function trackGenericResultClick\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.item_id - Product item unique identifier\n * @param {string} [parameters.item_name] - Product item name\n * @param {string} [parameters.variation_id] - Product item variation unique identifier\n * @param {string} [parameters.section=\"Products\"] - Index section\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User clicked a result that appeared outside of the scope of search / browse / recommendations\n * @example\n * constructorio.tracker.trackGenericResultClick(\n * {\n * item_id: 'KMH876',\n * item_name: 'Red T-Shirt',\n * variation_id: 'KMH879-7632',\n * },\n * );\n */\n\n }, {\n key: \"trackGenericResultClick\",\n value: function trackGenericResultClick(parameters) {\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n // Ensure required parameters are provided\n if ((0, _typeof2[\"default\"])(parameters) === 'object' && !!parameters.item_id) {\n var requestPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/result_click?\");\n var bodyParams = {};\n var item_id = parameters.item_id,\n item_name = parameters.item_name,\n variation_id = parameters.variation_id,\n section = parameters.section;\n bodyParams.section = section || 'Products';\n bodyParams.item_id = item_id;\n\n if (item_name) {\n bodyParams.item_name = item_name;\n }\n\n if (variation_id) {\n bodyParams.variation_id = variation_id;\n }\n\n var requestURL = \"\".concat(requestPath).concat(applyParamsAsString({}, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('A parameters object with an \"item_id\" property is required.');\n }\n /**\n * Send quiz results loaded event to API\n *\n * @function trackQuizResultsLoaded\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.quiz_id - Quiz identifier\n * @param {string} parameters.quiz_version_id - Quiz version identifier\n * @param {string} parameters.quiz_session_id - Quiz session identifier associated with this conversion event\n * @param {string} parameters.url - Current page url\n * @param {string} [parameters.section='Products'] - Index section\n * @param {number} [parameters.result_count] - Total number of results\n * @param {number} [parameters.result_page] - The page of the results\n * @param {string} [parameters.result_id] - Quiz result identifier (returned in response from Constructor)\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User viewed a quiz results page\n * @example\n * constructorio.tracker.trackQuizResultsLoaded(\n * {\n * quiz_id: 'coffee-quiz',\n * quiz_version_id: '1231244',\n * quiz_session_id: '3123',\n * url: 'www.example.com',\n * result_count: 167,\n * },\n * );\n */\n\n }, {\n key: \"trackQuizResultsLoaded\",\n value: function trackQuizResultsLoaded(parameters) {\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var requestPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/quiz_result_load?\");\n var quiz_id = parameters.quiz_id,\n quiz_version_id = parameters.quiz_version_id,\n quiz_session_id = parameters.quiz_session_id,\n url = parameters.url,\n _parameters$section3 = parameters.section,\n section = _parameters$section3 === void 0 ? 'Products' : _parameters$section3,\n result_count = parameters.result_count,\n result_id = parameters.result_id,\n result_page = parameters.result_page;\n var queryParams = {};\n var bodyParams = {};\n\n if (typeof quiz_id !== 'string') {\n return new Error('\"quiz_id\" is a required parameter of type string');\n }\n\n if (typeof quiz_version_id !== 'string') {\n return new Error('\"quiz_version_id\" is a required parameter of type string');\n }\n\n if (typeof quiz_session_id !== 'string') {\n return new Error('\"quiz_session_id\" is a required parameter of type string');\n }\n\n if (typeof url !== 'string') {\n return new Error('\"url\" is a required parameter of type string');\n }\n\n bodyParams.quiz_id = quiz_id;\n bodyParams.quiz_version_id = quiz_version_id;\n bodyParams.quiz_session_id = quiz_session_id;\n bodyParams.url = url;\n\n if (!helpers.isNil(section)) {\n if (typeof section !== 'string') {\n return new Error('\"section\" must be a string');\n }\n\n queryParams.section = section;\n bodyParams.section = section;\n }\n\n if (!helpers.isNil(result_count)) {\n if (typeof result_count !== 'number') {\n return new Error('\"result_count\" must be a number');\n }\n\n bodyParams.result_count = result_count;\n }\n\n if (!helpers.isNil(result_id)) {\n if (typeof result_id !== 'string') {\n return new Error('\"result_id\" must be a string');\n }\n\n bodyParams.result_id = result_id;\n }\n\n if (!helpers.isNil(result_page)) {\n if (typeof result_page !== 'number') {\n return new Error('\"result_page\" must be a number');\n }\n\n bodyParams.result_page = result_page;\n }\n\n bodyParams.action_class = 'result_load';\n var requestURL = \"\".concat(requestPath).concat(applyParamsAsString(queryParams, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n /**\n * Send quiz result click event to API\n *\n * @function trackQuizResultClick\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.quiz_id - Quiz identifier\n * @param {string} parameters.quiz_version_id - Quiz version identifier\n * @param {string} parameters.quiz_session_id - Quiz session identifier associated with this conversion event\n * @param {string} [parameters.item_id] - Product item unique identifier (Either item_id or item_name is required)\n * @param {string} [parameters.item_name] - Product item name\n * @param {string} [parameters.section='Products'] - Index section\n * @param {number} [parameters.result_count] - Total number of results\n * @param {number} [parameters.result_page] - The page of the results\n * @param {string} [parameters.result_id] - Quiz result identifier (returned in response from Constructor)\n * @param {number} [parameters.result_position_on_page] - Position of clicked item\n * @param {number} [parameters.num_results_per_page] - Number of results shown\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User viewed a quiz results page\n * @example\n * constructorio.tracker.trackQuizResultClick(\n * {\n * quiz_id: 'coffee-quiz',\n * quiz_version_id: '1231244',\n * quiz_session_id: '123',\n * item_id: '123',\n * item_name: 'espresso'\n * },\n * );\n */\n // eslint-disable-next-line complexity\n\n }, {\n key: \"trackQuizResultClick\",\n value: function trackQuizResultClick(parameters) {\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var requestPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/quiz_result_click?\");\n var quiz_id = parameters.quiz_id,\n quiz_version_id = parameters.quiz_version_id,\n quiz_session_id = parameters.quiz_session_id,\n item_id = parameters.item_id,\n item_name = parameters.item_name,\n result_count = parameters.result_count,\n result_id = parameters.result_id,\n result_page = parameters.result_page,\n num_results_per_page = parameters.num_results_per_page,\n result_position_on_page = parameters.result_position_on_page,\n _parameters$section4 = parameters.section,\n section = _parameters$section4 === void 0 ? 'Products' : _parameters$section4;\n var queryParams = {};\n var bodyParams = {}; // Ensure required parameters provided\n\n if (typeof quiz_id !== 'string') {\n return new Error('\"quiz_id\" is a required parameter of type string');\n }\n\n if (typeof quiz_version_id !== 'string') {\n return new Error('\"quiz_version_id\" is a required parameter of type string');\n }\n\n if (typeof quiz_session_id !== 'string') {\n return new Error('\"quiz_session_id\" is a required parameter of type string');\n }\n\n if (typeof item_id !== 'string' && typeof item_name !== 'string') {\n return new Error('\"item_id\" or \"item_name\" is a required parameter of type string');\n }\n\n bodyParams.quiz_id = quiz_id;\n bodyParams.quiz_version_id = quiz_version_id;\n bodyParams.quiz_session_id = quiz_session_id;\n\n if (!helpers.isNil(item_id)) {\n if (typeof item_id !== 'string') {\n return new Error('\"item_id\" must be a string');\n }\n\n bodyParams.item_id = item_id;\n }\n\n if (!helpers.isNil(item_name)) {\n if (typeof item_name !== 'string') {\n return new Error('\"item_name\" must be a string');\n }\n\n bodyParams.item_name = item_name;\n }\n\n if (!helpers.isNil(section)) {\n if (typeof section !== 'string') {\n return new Error('\"section\" must be a string');\n }\n\n queryParams.section = section;\n }\n\n if (!helpers.isNil(result_count)) {\n if (typeof result_count !== 'number') {\n return new Error('\"result_count\" must be a number');\n }\n\n bodyParams.result_count = result_count;\n }\n\n if (!helpers.isNil(result_id)) {\n if (typeof result_id !== 'string') {\n return new Error('\"result_id\" must be a string');\n }\n\n bodyParams.result_id = result_id;\n }\n\n if (!helpers.isNil(result_page)) {\n if (typeof result_page !== 'number') {\n return new Error('\"result_page\" must be a number');\n }\n\n bodyParams.result_page = result_page;\n }\n\n if (!helpers.isNil(num_results_per_page)) {\n if (typeof num_results_per_page !== 'number') {\n return new Error('\"num_results_per_page\" must be a number');\n }\n\n bodyParams.num_results_per_page = num_results_per_page;\n }\n\n if (!helpers.isNil(result_position_on_page)) {\n if (typeof result_position_on_page !== 'number') {\n return new Error('\"result_position_on_page\" must be a number');\n }\n\n bodyParams.result_position_on_page = result_position_on_page;\n }\n\n bodyParams.action_class = 'result_click';\n var requestURL = \"\".concat(requestPath).concat(applyParamsAsString(queryParams, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n /**\n * Send quiz conversion event to API\n *\n * @function trackQuizConversion\n * @param {object} parameters - Additional parameters to be sent with request\n * @param {string} parameters.quiz_id - Quiz identifier\n * @param {string} parameters.quiz_version_id - Quiz version identifier\n * @param {string} parameters.quiz_session_id - Quiz session identifier associated with this conversion event\n * @param {string} [parameters.item_id] - Product item unique identifier (Either item_id or item_name is required)\n * @param {string} [parameters.item_name] - Product item name\n * @param {string} [parameters.variation_id] - Product item variation unique identifier\n * @param {string} [parameters.revenue] - Sale price if available, otherwise the regular (retail) price of item\n * @param {string} [parameters.section='Products'] - Index section\n * @param {string} [parameters.type='add_to_cart'] - Conversion type\n * @param {boolean} [parameters.is_custom_type] - Specify if type is custom conversion type\n * @param {string} [parameters.display_name] - Display name for the custom conversion type\n * @param {object} [networkParameters] - Parameters relevant to the network request\n * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)\n * @returns {(true|Error)}\n * @description User viewed a quiz results page\n * @example\n * constructorio.tracker.trackQuizConversion(\n * {\n * quiz_id: 'coffee-quiz',\n * quiz_version_id: '1231244',\n * quiz_session_id: '3123',\n * item_name: 'espresso',\n * variation_id: '167',\n * type: 'add_to_cart\",\n * revenue: '1.0\"\n * },\n * );\n */\n // eslint-disable-next-line complexity\n\n }, {\n key: \"trackQuizConversion\",\n value: function trackQuizConversion(parameters) {\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n // Ensure parameters are provided (required)\n if (parameters && (0, _typeof2[\"default\"])(parameters) === 'object' && !Array.isArray(parameters)) {\n var requestPath = \"\".concat(this.options.serviceUrl, \"/v2/behavioral_action/quiz_conversion?\");\n var quiz_id = parameters.quiz_id,\n quiz_version_id = parameters.quiz_version_id,\n quiz_session_id = parameters.quiz_session_id,\n item_id = parameters.item_id,\n item_name = parameters.item_name,\n variation_id = parameters.variation_id,\n revenue = parameters.revenue,\n _parameters$section5 = parameters.section,\n section = _parameters$section5 === void 0 ? 'Products' : _parameters$section5,\n type = parameters.type,\n is_custom_type = parameters.is_custom_type,\n display_name = parameters.display_name;\n var queryParams = {};\n var bodyParams = {}; // Ensure required parameters provided\n\n if (typeof quiz_id !== 'string') {\n return new Error('\"quiz_id\" is a required parameter of type string');\n }\n\n if (typeof quiz_version_id !== 'string') {\n return new Error('\"quiz_version_id\" is a required parameter of type string');\n }\n\n if (typeof quiz_session_id !== 'string') {\n return new Error('\"quiz_session_id\" is a required parameter of type string');\n }\n\n if (typeof item_id !== 'string' && typeof item_name !== 'string') {\n return new Error('\"item_id\" or \"item_name\" is a required parameter of type string');\n }\n\n bodyParams.quiz_id = quiz_id;\n bodyParams.quiz_version_id = quiz_version_id;\n bodyParams.quiz_session_id = quiz_session_id;\n\n if (!helpers.isNil(item_id)) {\n if (typeof item_id !== 'string') {\n return new Error('\"item_id\" must be a string');\n }\n\n bodyParams.item_id = item_id;\n }\n\n if (!helpers.isNil(item_name)) {\n if (typeof item_name !== 'string') {\n return new Error('\"item_name\" must be a string');\n }\n\n bodyParams.item_name = item_name;\n }\n\n if (!helpers.isNil(variation_id)) {\n if (typeof variation_id !== 'string') {\n return new Error('\"variation_id\" must be a string');\n }\n\n bodyParams.variation_id = variation_id;\n }\n\n if (!helpers.isNil(revenue)) {\n if (typeof revenue !== 'string') {\n return new Error('\"revenue\" must be a string');\n }\n\n bodyParams.revenue = revenue;\n }\n\n if (!helpers.isNil(section)) {\n if (typeof section !== 'string') {\n return new Error('\"section\" must be a string');\n }\n\n bodyParams.section = section;\n }\n\n if (!helpers.isNil(type)) {\n if (typeof type !== 'string') {\n return new Error('\"type\" must be a string');\n }\n\n bodyParams.type = type;\n }\n\n if (!helpers.isNil(is_custom_type)) {\n if (typeof is_custom_type !== 'boolean') {\n return new Error('\"is_custom_type\" must be a boolean');\n }\n\n bodyParams.is_custom_type = is_custom_type;\n }\n\n if (!helpers.isNil(display_name)) {\n if (typeof display_name !== 'string') {\n return new Error('\"display_name\" must be a string');\n }\n\n bodyParams.display_name = display_name;\n }\n\n bodyParams.action_class = 'conversion';\n var requestURL = \"\".concat(requestPath).concat(applyParamsAsString(queryParams, this.options));\n var requestMethod = 'POST';\n var requestBody = applyParams(bodyParams, _objectSpread(_objectSpread({}, this.options), {}, {\n requestMethod: requestMethod\n }));\n this.requests.queue(requestURL, requestMethod, requestBody, networkParameters);\n this.requests.send();\n return true;\n }\n\n this.requests.send();\n return new Error('parameters are required of type object');\n }\n /**\n * Subscribe to success or error messages emitted by tracking requests\n *\n * @function on\n * @param {string} messageType - Type of message to listen for ('success' or 'error')\n * @param {function} callback - Callback to be invoked when message received\n * @returns {(true|Error)}\n * @example\n * constructorio.tracker.on('error', (data) => {\n * // Handle tracking error\n * });\n */\n\n }, {\n key: \"on\",\n value: function on(messageType, callback) {\n if (messageType !== 'success' && messageType !== 'error') {\n return new Error('messageType must be a string of value \"success\" or \"error\"');\n }\n\n if (!callback || typeof callback !== 'function') {\n return new Error('callback is required and must be a function');\n }\n\n this.eventemitter.on(messageType, callback);\n return true;\n }\n }]);\n return Tracker;\n}(); // Exposed for testing\n\n\nTracker.RequestQueue = RequestQueue;\nmodule.exports = Tracker;","\"use strict\";\n\n/* eslint-disable no-useless-escape */\n\n/* cspell:disable */\nmodule.exports = ['Googlebot\\/', 'Googlebot-Mobile', 'Googlebot-Image', 'Googlebot-News', 'Googlebot-Video', 'AdsBot-Google([^-]|$)', 'AdsBot-Google-Mobile', 'Feedfetcher-Google', 'Mediapartners-Google', 'Mediapartners \\\\(Googlebot\\\\)', 'APIs-Google', 'bingbot', 'Slurp', '[wW]get', 'curl', 'LinkedInBot', 'Python-urllib', 'python-requests', 'libwww', 'httpunit', 'nutch', 'Go-http-client', 'phpcrawl', 'msnbot', 'jyxobot', 'FAST-WebCrawler', 'FAST Enterprise Crawler', 'BIGLOTRON', 'Teoma', 'convera', 'seekbot', 'Gigabot', 'Gigablast', 'exabot', 'ia_archiver', 'GingerCrawler', 'webmon ', 'HTTrack', 'grub\\\\.org', 'UsineNouvelleCrawler', 'antibot', 'netresearchserver', 'speedy', 'fluffy', 'bibnum\\\\.bnf', 'findlink', 'msrbot', 'panscient', 'yacybot', 'AISearchBot', 'ips-agent', 'tagoobot', 'MJ12bot', 'woriobot', 'yanga', 'buzzbot', 'mlbot', 'YandexBot', 'yandex\\\\.com\\/bots', 'purebot', 'Linguee Bot', 'CyberPatrol', 'voilabot', 'Baiduspider', 'citeseerxbot', 'spbot', 'twengabot', 'postrank', 'turnitinbot', 'scribdbot', 'page2rss', 'sitebot', 'linkdex', 'Adidxbot', 'blekkobot', 'ezooms', 'dotbot', 'Mail\\\\.RU_Bot', 'discobot', 'heritrix', 'findthatfile', 'europarchive\\\\.org', 'NerdByNature\\\\.Bot', 'sistrix crawler', 'Ahrefs(Bot|SiteAudit)', 'fuelbot', 'CrunchBot', 'centurybot9', 'IndeedBot', 'mappydata', 'woobot', 'ZoominfoBot', 'PrivacyAwareBot', 'Multiviewbot', 'SWIMGBot', 'Grobbot', 'eright', 'Apercite', 'semanticbot', 'Aboundex', 'domaincrawler', 'wbsearchbot', 'summify', 'CCBot', 'edisterbot', 'seznambot', 'ec2linkfinder', 'gslfbot', 'aiHitBot', 'intelium_bot', 'facebookexternalhit', 'Yeti', 'RetrevoPageAnalyzer', 'lb-spider', 'Sogou', 'lssbot', 'careerbot', 'wotbox', 'wocbot', 'ichiro', 'DuckDuckBot', 'lssrocketcrawler', 'drupact', 'webcompanycrawler', 'acoonbot', 'openindexspider', 'gnam gnam spider', 'web-archive-net\\\\.com\\\\.bot', 'backlinkcrawler', 'coccoc', 'integromedb', 'content crawler spider', 'toplistbot', 'it2media-domain-crawler', 'ip-web-crawler\\\\.com', 'siteexplorer\\\\.info', 'elisabot', 'proximic', 'changedetection', 'arabot', 'WeSEE:Search', 'niki-bot', 'CrystalSemanticsBot', 'rogerbot', '360Spider', 'psbot', 'InterfaxScanBot', 'CC Metadata Scaper', 'g00g1e\\\\.net', 'GrapeshotCrawler', 'urlappendbot', 'brainobot', 'fr-crawler', 'binlar', 'SimpleCrawler', 'Twitterbot', 'cXensebot', 'smtbot', 'bnf\\\\.fr_bot', 'A6-Indexer', 'ADmantX', 'Facebot', 'OrangeBot\\/', 'memorybot', 'AdvBot', 'MegaIndex', 'SemanticScholarBot', 'ltx71', 'nerdybot', 'xovibot', 'BUbiNG', 'Qwantify', 'archive\\\\.org_bot', 'Applebot', 'TweetmemeBot', 'crawler4j', 'findxbot', 'S[eE][mM]rushBot', 'yoozBot', 'lipperhey', 'Y!J', 'Domain Re-Animator Bot', 'AddThis', 'Screaming Frog SEO Spider', 'MetaURI', 'Scrapy', 'Livelap[bB]ot', 'OpenHoseBot', 'CapsuleChecker', 'collection@infegy\\\\.com', 'IstellaBot', 'DeuSu\\/', 'betaBot', 'Cliqzbot\\/', 'MojeekBot\\/', 'netEstate NE Crawler', 'SafeSearch microdata crawler', 'Gluten Free Crawler\\/', 'Sonic', 'Sysomos', 'Trove', 'deadlinkchecker', 'Slack-ImgProxy', 'Embedly', 'RankActiveLinkBot', 'iskanie', 'SafeDNSBot', 'SkypeUriPreview', 'Veoozbot', 'Slackbot', 'redditbot', 'datagnionbot', 'Google-Adwords-Instant', 'adbeat_bot', 'WhatsApp', 'contxbot', 'pinterest', 'electricmonk', 'GarlikCrawler', 'BingPreview\\/', 'vebidoobot', 'FemtosearchBot', 'Yahoo Link Preview', 'MetaJobBot', 'DomainStatsBot', 'mindUpBot', 'Daum\\/', 'Jugendschutzprogramm-Crawler', 'Xenu Link Sleuth', 'Pcore-HTTP', 'moatbot', 'KosmioBot', 'pingdom', 'PhantomJS', 'Gowikibot', 'PiplBot', 'Discordbot', 'TelegramBot', 'Jetslide', 'newsharecounts', 'James BOT', 'Barkrowler', 'TinEye', 'SocialRankIOBot', 'trendictionbot', 'Ocarinabot', 'epicbot', 'Primalbot', 'DuckDuckGo-Favicons-Bot', 'GnowitNewsbot', 'Leikibot', 'LinkArchiver', 'YaK\\/', 'PaperLiBot', 'Digg Deeper', 'dcrawl', 'Snacktory', 'AndersPinkBot', 'Fyrebot', 'EveryoneSocialBot', 'Mediatoolkitbot', 'Luminator-robots', 'ExtLinksBot', 'SurveyBot', 'NING\\/', 'okhttp', 'Nuzzel', 'omgili', 'PocketParser', 'YisouSpider', 'um-LN', 'ToutiaoSpider', 'MuckRack', \"Jamie's Spider\", 'AHC\\/', 'NetcraftSurveyAgent', 'Laserlikebot', 'Apache-HttpClient', 'AppEngine-Google', 'Jetty', 'Upflow', 'Thinklab', 'Traackr\\\\.com', 'Twurly', 'Mastodon', 'http_get', 'DnyzBot', 'botify', '007ac9 Crawler', 'BehloolBot', 'BrandVerity', 'check_http', 'BDCbot', 'ZumBot', 'EZID', 'ICC-Crawler', 'ArchiveBot', '^LCC ', 'filterdb\\\\.iss\\\\.net\\/crawler', 'BLP_bbot', 'BomboraBot', 'Buck\\/', 'Companybook-Crawler', 'Genieo', 'magpie-crawler', 'MeltwaterNews', 'Moreover', 'newspaper\\/', 'ScoutJet', '(^| )sentry\\/', 'StorygizeBot', 'UptimeRobot', 'OutclicksBot', 'seoscanners', 'Hatena', 'Google Web Preview', 'MauiBot', 'AlphaBot', 'SBL-BOT', 'IAS crawler', 'adscanner', 'Netvibes', 'acapbot', 'Baidu-YunGuanCe', 'bitlybot', 'blogmuraBot', 'Bot\\\\.AraTurka\\\\.com', 'bot-pge\\\\.chlooe\\\\.com', 'BoxcarBot', 'BTWebClient', 'ContextAd Bot', 'Digincore bot', 'Disqus', 'Feedly', 'Fetch\\/', 'Fever', 'Flamingo_SearchEngine', 'FlipboardProxy', 'g2reader-bot', 'imrbot', 'K7MLWCBot', 'Kemvibot', 'Landau-Media-Spider', 'linkapediabot', 'vkShare', 'Siteimprove\\\\.com', 'BLEXBot\\/', 'DareBoost', 'ZuperlistBot\\/', 'Miniflux\\/', 'Feedspotbot\\/', 'Diffbot\\/', 'SEOkicks', 'tracemyfile', 'Nimbostratus-Bot'];","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\n/* eslint-disable no-unneeded-ternary */\nvar helpers = require('./helpers');\n\nvar EventDispatcher = /*#__PURE__*/function () {\n function EventDispatcher(options) {\n var _this = this;\n\n (0, _classCallCheck2[\"default\"])(this, EventDispatcher);\n this.events = [];\n this.enabled = options && options.enabled === false ? false : true; // Defaults to 'true'\n\n this.waitForBeacon = options && options.waitForBeacon === false ? false : true; // Defaults to 'true'\n // `enabled` is a supplied option\n // - if false, events will never be dispatched\n // `active` is a variable determining if events will be dispatched\n // - if `waitForBeacon` is set to true, `active` will be false until beacon event is received\n\n this.active = this.enabled; // If `waitForBeacon` option is set, only enable event dispatching once event is received from beacon\n\n if (this.waitForBeacon) {\n this.active = false; // Check browser environment to determine if beacon has been loaded\n // - Important for the case where the beacon has loaded before client library instantiated\n\n if (helpers.canUseDOM() && (window.ConstructorioAutocomplete || window.ConstructorioBeacon || window.ConstructorioTracker)) {\n if (this.enabled) {\n this.active = true;\n this.dispatchEvents();\n }\n } // Bind listener to beacon loaded event\n // - Important for the case where client library instantiated before beacon has loaded\n\n\n helpers.addEventListener('cio.beacon.loaded', function () {\n if (_this.enabled) {\n _this.active = true;\n\n _this.dispatchEvents();\n }\n });\n }\n } // Push event data to queue\n\n\n (0, _createClass2[\"default\"])(EventDispatcher, [{\n key: \"queue\",\n value: function queue(name, data) {\n this.events.push({\n name: name,\n data: data\n });\n\n if (this.active) {\n this.dispatchEvents();\n }\n } // Dispatch all custom events within queue on `window` of supplied name with data\n\n }, {\n key: \"dispatchEvents\",\n value: function dispatchEvents() {\n while (this.events.length) {\n var item = this.events.shift();\n var name = item.name,\n data = item.data;\n var eventName = \"cio.client.\".concat(name);\n helpers.dispatchEvent(helpers.createCustomEvent(eventName, data));\n }\n }\n }]);\n return EventDispatcher;\n}();\n\nmodule.exports = EventDispatcher;","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _typeof2 = _interopRequireDefault(require(\"@babel/runtime/helpers/typeof\"));\n\n/* eslint-disable no-param-reassign */\nvar CRC32 = require('crc-32');\n\nvar store = require('./store');\n\nvar purchaseEventStorageKey = '_constructorio_purchase_order_ids';\nvar utils = {\n trimNonBreakingSpaces: function trimNonBreakingSpaces(string) {\n return string.replace(/\\s/g, ' ').trim();\n },\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent\n encodeURIComponentRFC3986: function encodeURIComponentRFC3986(string) {\n return encodeURIComponent(string).replace(/[!'()*]/g, function (c) {\n return \"%\".concat(c.charCodeAt(0).toString(16).toUpperCase());\n });\n },\n cleanParams: function cleanParams(paramsObj) {\n var cleanedParams = {};\n Object.keys(paramsObj).forEach(function (paramKey) {\n var paramValue = paramsObj[paramKey];\n\n if (typeof paramValue === 'string') {\n // Replace non-breaking spaces (or any other type of spaces caught by the regex)\n // - with a regular white space\n cleanedParams[paramKey] = utils.trimNonBreakingSpaces(paramValue);\n } else {\n cleanedParams[paramKey] = paramValue;\n }\n });\n return cleanedParams;\n },\n throwHttpErrorFromResponse: function throwHttpErrorFromResponse(error, response) {\n return response.json().then(function (json) {\n error.message = json.message;\n error.status = response.status;\n error.statusText = response.statusText;\n error.url = response.url;\n error.headers = response.headers;\n throw error;\n });\n },\n canUseDOM: function canUseDOM() {\n return !!(typeof window !== 'undefined' && window.document && window.document.createElement);\n },\n addEventListener: function addEventListener(eventType, callback, useCapture) {\n if (utils.canUseDOM()) {\n window.addEventListener(eventType, callback, useCapture);\n }\n },\n removeEventListener: function removeEventListener(eventType, callback, useCapture) {\n if (utils.canUseDOM()) {\n window.removeEventListener(eventType, callback, useCapture);\n }\n },\n getNavigator: function getNavigator() {\n if (utils.canUseDOM()) {\n return window.navigator;\n }\n\n return {\n userAgent: '',\n webdriver: false\n };\n },\n isNil: function isNil(value) {\n return value == null;\n },\n getWindowLocation: function getWindowLocation() {\n if (utils.canUseDOM()) {\n return window.location;\n }\n\n return {};\n },\n dispatchEvent: function dispatchEvent(event) {\n if (utils.canUseDOM()) {\n window.dispatchEvent(event);\n }\n },\n createCustomEvent: function createCustomEvent(eventName, detail) {\n if (utils.canUseDOM()) {\n try {\n return new window.CustomEvent(eventName, {\n detail: detail\n });\n } catch (e) {\n var evt = document.createEvent('CustomEvent');\n evt.initCustomEvent(eventName, false, false, detail);\n return evt;\n }\n }\n\n return null;\n },\n hasOrderIdRecord: function hasOrderIdRecord(orderId) {\n var orderIdHash = CRC32.str(orderId.toString());\n var purchaseEventStorage = store.local.get(purchaseEventStorageKey);\n\n if (typeof purchaseEventStorage === 'string') {\n purchaseEventStorage = JSON.parse(purchaseEventStorage);\n }\n\n if (purchaseEventStorage && purchaseEventStorage.includes(orderIdHash)) {\n return true;\n }\n\n return null;\n },\n addOrderIdRecord: function addOrderIdRecord(orderId) {\n var orderIdHash = CRC32.str(orderId.toString());\n var purchaseEventStorage = store.local.get(purchaseEventStorageKey);\n\n if (typeof purchaseEventStorage === 'string') {\n purchaseEventStorage = JSON.parse(purchaseEventStorage);\n }\n\n if (purchaseEventStorage) {\n // If the order already exists, do nothing\n if (purchaseEventStorage.includes(orderIdHash)) {\n return;\n }\n\n if (purchaseEventStorage.length >= 10) {\n purchaseEventStorage = purchaseEventStorage.slice(-9);\n }\n\n purchaseEventStorage.push(orderIdHash);\n } else {\n // Create a new object map for the order ids\n purchaseEventStorage = [orderIdHash];\n } // Push the order id map into local storage\n\n\n store.local.set(purchaseEventStorageKey, purchaseEventStorage);\n },\n // Abort network request based on supplied timeout interval (in milliseconds)\n // - method call parameter takes precedence over global options parameter\n applyNetworkTimeout: function applyNetworkTimeout() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n var networkParameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n var controller = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;\n var optionsTimeout = options && options.networkParameters && options.networkParameters.timeout;\n var networkParametersTimeout = networkParameters && networkParameters.timeout;\n var timeout = networkParametersTimeout || optionsTimeout;\n\n if (typeof timeout === 'number' && controller) {\n setTimeout(function () {\n return controller.abort();\n }, timeout);\n }\n },\n stringify: function stringify(object, prefix, objectType) {\n if (!object) {\n return '';\n }\n\n var allValues = [];\n Object.keys(object).forEach(function (key) {\n var value = object[key];\n var encodedKey = utils.encodeURIComponentRFC3986(key);\n var stringifiedValue; // Check for both null and undefined\n\n if (value != null) {\n var nextPrefix = prefix ? \"\".concat(prefix, \"%5B\").concat(encodedKey, \"%5D\") : encodedKey;\n\n if (Array.isArray(value)) {\n stringifiedValue = utils.stringify(value, nextPrefix, 'array');\n } else if ((0, _typeof2[\"default\"])(value) === 'object') {\n stringifiedValue = utils.stringify(value, nextPrefix, 'object');\n } else if (objectType === 'object') {\n stringifiedValue = \"\".concat(nextPrefix, \"=\").concat(utils.encodeURIComponentRFC3986(value));\n } else {\n stringifiedValue = \"\".concat(prefix || encodedKey, \"=\").concat(utils.encodeURIComponentRFC3986(value));\n }\n\n allValues.push(stringifiedValue);\n }\n });\n return allValues.join('&');\n }\n};\nmodule.exports = utils;","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\n/* eslint-disable class-methods-use-this */\nvar store = require('./store');\n\nvar botList = require('./botlist');\n\nvar helpers = require('./helpers');\n\nvar storageKey = '_constructorio_is_human';\nvar humanEvents = ['scroll', 'resize', 'touchmove', 'mouseover', 'mousemove', 'keydown', 'keypress', 'keyup', 'focus'];\n\nvar HumanityCheck = /*#__PURE__*/function () {\n function HumanityCheck() {\n var _this = this;\n\n (0, _classCallCheck2[\"default\"])(this, HumanityCheck);\n this.isHumanBoolean = this.getIsHumanFromSessionStorage(); // Humanity proved, remove handlers to prove humanity\n\n var remove = function remove() {\n _this.isHumanBoolean = true;\n store.session.set(storageKey, true);\n humanEvents.forEach(function (eventType) {\n helpers.removeEventListener(eventType, remove, true);\n });\n }; // Add handlers to prove humanity\n\n\n if (!this.isHumanBoolean) {\n humanEvents.forEach(function (eventType) {\n helpers.addEventListener(eventType, remove, true);\n });\n }\n }\n\n (0, _createClass2[\"default\"])(HumanityCheck, [{\n key: \"getIsHumanFromSessionStorage\",\n value: function getIsHumanFromSessionStorage() {\n return !!store.session.get(storageKey) || false;\n } // Return boolean indicating if is human\n\n }, {\n key: \"isHuman\",\n value: function isHuman() {\n return this.isHumanBoolean || !!store.session.get(storageKey);\n } // Return boolean indicating if useragent matches botlist\n\n }, {\n key: \"isBot\",\n value: function isBot() {\n if (this.getIsHumanFromSessionStorage()) {\n return false;\n }\n\n var _helpers$getNavigator = helpers.getNavigator(),\n userAgent = _helpers$getNavigator.userAgent,\n webdriver = _helpers$getNavigator.webdriver;\n\n var botRegex = new RegExp(\"(\".concat(botList.join('|'), \")\"));\n return Boolean(userAgent.match(botRegex)) || Boolean(webdriver);\n }\n }]);\n return HumanityCheck;\n}();\n\nmodule.exports = HumanityCheck;","\"use strict\";\n\nvar _interopRequireDefault = require(\"@babel/runtime/helpers/interopRequireDefault\");\n\nvar _classCallCheck2 = _interopRequireDefault(require(\"@babel/runtime/helpers/classCallCheck\"));\n\nvar _createClass2 = _interopRequireDefault(require(\"@babel/runtime/helpers/createClass\"));\n\n/* eslint-disable brace-style, no-unneeded-ternary */\nvar store = require('./store');\n\nvar HumanityCheck = require('./humanity-check');\n\nvar helpers = require('./helpers');\n\nvar storageKey = '_constructorio_requests';\nvar requestTTL = 180000; // 3 minutes in milliseconds\n\nvar RequestQueue = /*#__PURE__*/function () {\n function RequestQueue(options, eventemitter) {\n var _this = this;\n\n (0, _classCallCheck2[\"default\"])(this, RequestQueue);\n this.options = options;\n this.eventemitter = eventemitter;\n this.humanity = new HumanityCheck();\n this.requestPending = false;\n this.pageUnloading = false;\n this.sendTrackingEvents = options && options.sendTrackingEvents === true ? true : false; // Defaults to 'false'\n // Mark if page environment is unloading\n\n helpers.addEventListener('beforeunload', function () {\n _this.pageUnloading = true;\n });\n\n if (this.sendTrackingEvents) {\n this.send();\n }\n } // Add request to queue to be dispatched\n\n\n (0, _createClass2[\"default\"])(RequestQueue, [{\n key: \"queue\",\n value: function queue(url) {\n var method = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'GET';\n var body = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n var networkParameters = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};\n\n if (this.sendTrackingEvents && !this.humanity.isBot()) {\n var queue = RequestQueue.get();\n queue.push({\n url: url,\n method: method,\n body: body,\n networkParameters: networkParameters\n });\n RequestQueue.set(queue);\n }\n } // Read from queue and send events to server\n\n }, {\n key: \"sendEvents\",\n value: function sendEvents() {\n var _this2 = this;\n\n var fetch = this.options.fetch;\n var queue = RequestQueue.get();\n\n if ( // Consider user \"human\" if no DOM context is available\n (!helpers.canUseDOM() || this.humanity.isHuman()) && !this.requestPending && !this.pageUnloading && queue.length) {\n var request;\n var nextInQueue = queue.shift();\n var _nextInQueue = nextInQueue,\n networkParameters = _nextInQueue.networkParameters;\n var signal;\n var instance = this;\n RequestQueue.set(queue);\n\n if (networkParameters && typeof AbortController === 'function') {\n var controller = new AbortController();\n signal = controller.signal;\n helpers.applyNetworkTimeout(this.options, networkParameters, controller);\n } // Backwards compatibility with versions <= 2.0.0, can be removed in future\n // - Request queue entries used to be strings with 'GET' method assumed\n\n\n if (typeof nextInQueue === 'string') {\n nextInQueue = {\n url: nextInQueue,\n method: 'GET'\n };\n } // If events older than `requestTTL` exist in queue, clear request queue\n // - Prevents issue where stale items are sent in perpetuity\n // - No request should go unsent for longer than `requestTTL`\n\n\n if (nextInQueue.url) {\n // Pull `dt` parameter from URL, indicating origin time of request\n var dtMatch = nextInQueue.url.match(/\\?.*_dt=([^&]+)/);\n var requestOriginTime = parseInt(dtMatch && dtMatch[1], 10);\n var now = +new Date();\n\n if (requestOriginTime && Number.isInteger(requestOriginTime) && now - requestOriginTime > requestTTL) {\n this.sendTrackingEvents = false;\n RequestQueue.remove();\n return;\n }\n }\n\n if (nextInQueue.method === 'GET') {\n request = fetch(nextInQueue.url, {\n signal: signal\n });\n }\n\n if (nextInQueue.method === 'POST') {\n request = fetch(nextInQueue.url, {\n method: nextInQueue.method,\n body: JSON.stringify(nextInQueue.body),\n mode: 'cors',\n headers: {\n 'Content-Type': 'text/plain'\n },\n signal: signal\n });\n }\n\n if (request) {\n this.requestPending = true;\n request.then(function (response) {\n // Request was successful, and returned a 2XX status code\n if (response.ok) {\n if (instance.eventemitter) {\n instance.eventemitter.emit('success', {\n url: nextInQueue.url,\n method: nextInQueue.method,\n message: 'ok'\n });\n }\n\n _this2.requestPending = false;\n\n _this2.send();\n } // Request was successful, but returned a non-2XX status code\n else {\n response.json().then(function (json) {\n if (instance.eventemitter) {\n instance.eventemitter.emit('error', {\n url: nextInQueue.url,\n method: nextInQueue.method,\n message: json && json.message\n });\n }\n\n _this2.requestPending = false;\n\n _this2.send();\n })[\"catch\"](function (error) {\n if (instance.eventemitter) {\n instance.eventemitter.emit('error', {\n url: nextInQueue.url,\n method: nextInQueue.method,\n message: error.type\n });\n }\n\n _this2.requestPending = false;\n\n _this2.send();\n });\n }\n })[\"catch\"](function (error) {\n if (instance.eventemitter) {\n instance.eventemitter.emit('error', {\n url: nextInQueue.url,\n method: nextInQueue.method,\n message: error && error.toString && error.toString()\n });\n }\n\n _this2.requestPending = false;\n\n _this2.send();\n });\n }\n }\n } // Read from queue and send requests to server\n\n }, {\n key: \"send\",\n value: function send() {\n if (this.sendTrackingEvents) {\n if (this.options && this.options.trackingSendDelay === 0) {\n this.sendEvents();\n } else {\n // Defer sending of events to give beforeunload time to register (avoids race condition)\n setTimeout(this.sendEvents.bind(this), this.options && this.options.trackingSendDelay || 250);\n }\n }\n } // Return current request queue\n\n }], [{\n key: \"get\",\n value: function get() {\n return store.local.get(storageKey) || [];\n } // Update current request queue\n\n }, {\n key: \"set\",\n value: function set(queue) {\n // If queue length is zero, remove entry entirely\n if (!queue || Array.isArray(queue) && queue.length === 0) {\n RequestQueue.remove();\n } else {\n store.local.set(storageKey, queue);\n }\n\n var localStorageQueue = RequestQueue.get(); // Ensure storage queue was set correctly in storage by checking length\n // - Otherwise remove all pending requests as preventative measure\n // - Firefox seeing identical events being transmitted multiple times\n\n if (Array.isArray(localStorageQueue) && localStorageQueue.length !== queue.length) {\n this.sendTrackingEvents = false;\n RequestQueue.remove();\n }\n } // Remove current request queue key\n\n }, {\n key: \"remove\",\n value: function remove() {\n store.local.remove(storageKey);\n }\n }]);\n return RequestQueue;\n}();\n\nmodule.exports = RequestQueue;","\"use strict\";\n\nvar store = require('store2');\n\nvar overflow = require('./store.overflow'); // Inject overflow into store\n// https://raw.githubusercontent.com/nbubna/store/master/src/store.overflow.js\n\n\noverflow(store, store._);\nmodule.exports = store;","\"use strict\";\n\n/* eslint-disable */\n\n/**\n * Copyright (c) 2013 ESHA Research\n * Dual licensed under the MIT and GPL licenses:\n * http://www.opensource.org/licenses/mit-license.php\n * http://www.gnu.org/licenses/gpl.html\n *\n * When quota is reached on a storage area, this shifts incoming values to \n * fake storage, so they last only as long as the page does. This is useful\n * because it is more burdensome for localStorage to recover from quota errors\n * than incomplete caches. In other words, it is wiser to rely on store.js\n * never complaining than never missing data. You should already be checking\n * the integrity of cached data on every page load.\n *\n * Status: BETA\n */\nmodule.exports = function (store, _) {\n var _set = _.set,\n _get = _.get,\n _remove = _.remove,\n _key = _.key,\n _length = _.length,\n _clear = _.clear;\n\n _.overflow = function (area, create) {\n var name = area === _.areas.local ? '+local+' : area === _.areas.session ? '+session+' : false;\n\n if (name) {\n var overflow = _.areas[name];\n\n if (create && !overflow) {\n overflow = store.area(name)._area; // area() copies to _.areas\n } else if (create === false) {\n delete _.areas[name];\n delete store[name];\n }\n\n return overflow;\n }\n };\n\n _.set = function (area, key, string) {\n try {\n _set.apply(this, arguments);\n } catch (e) {\n if (e.name === 'QUOTA_EXCEEDED_ERR' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED' || e.toString().indexOf(\"QUOTA_EXCEEDED_ERR\") !== -1 || e.toString().indexOf(\"QuotaExceededError\") !== -1) {\n // the e.toString is needed for IE9 / IE10, cos name is empty there\n return _.set(_.overflow(area, true), key, string);\n }\n\n throw e;\n }\n };\n\n _.get = function (area, key) {\n var overflow = _.overflow(area);\n\n return overflow && _get.call(this, overflow, key) || _get.apply(this, arguments);\n };\n\n _.remove = function (area, key) {\n var overflow = _.overflow(area);\n\n if (overflow) {\n _remove.call(this, overflow, key);\n }\n\n _remove.apply(this, arguments);\n };\n\n _.key = function (area, i) {\n var overflow = _.overflow(area);\n\n if (overflow) {\n var l = _length.call(this, area);\n\n if (i >= l) {\n i = i - l; // make i overflow-relative\n\n for (var j = 0, m = _length.call(this, overflow); j < m; j++) {\n if (j === i) {\n // j is overflow index\n return _key.call(this, overflow, j);\n }\n }\n }\n }\n\n return _key.apply(this, arguments);\n };\n\n _.length = function (area) {\n var length = _length(area),\n overflow = _.overflow(area);\n\n return overflow ? length + _length(overflow) : length;\n };\n\n _.clear = function (area) {\n _.overflow(area, false);\n\n _clear.apply(this, arguments);\n };\n};","(function () {\n // Object.assign polyfill\n // - https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill\n Object.assign || Object.defineProperty(Object, 'assign', {enumerable: !1, configurable: !0, writable: !0, value: function (e) {'use strict'; if (void 0 === e || e === null) throw new TypeError('Cannot convert first argument to object'); for (var r = Object(e), t = 1; t < arguments.length; t++) {var n = arguments[t]; if (void 0 !== n && n !== null) {n = Object(n); for (var o = Object.keys(Object(n)), a = 0, c = o.length; c > a; a++) {var i = o[a], b = Object.getOwnPropertyDescriptor(n, i); void 0 !== b && b.enumerable && (r[i] = n[i]);}}} return r;}}); // eslint-disable-line\n\n var ConstructorioID = function (options) {\n var defaults = {\n user_agent: null,\n persist: true,\n cookie_name_client_id: 'ConstructorioID_client_id',\n cookie_name_session_id: 'ConstructorioID_session_id',\n cookie_name_session_data: 'ConstructorioID_session',\n cookie_domain: null,\n cookie_secure: null, // null, true\n cookie_samesite: null, // null, Lax, Strict\n cookie_days_to_live: 365,\n local_name_client_id: '_constructorio_search_client_id',\n local_name_session_id: '_constructorio_search_session_id',\n local_name_session_data: '_constructorio_search_session',\n on_node: typeof window === 'undefined',\n session_is_new: null,\n new_to_beacon: null,\n client_id_storage_location: 'cookie',\n session_id_storage_location: 'local'\n };\n\n Object.assign(this, defaults, options);\n\n if (!this.client_id) {\n if (!this.on_node && this.persist) {\n var persisted_id;\n\n if (this.client_id_storage_location === 'cookie') {\n persisted_id = this.get_cookie(this.cookie_name_client_id);\n }\n\n if (this.client_id_storage_location === 'local') {\n persisted_id = this.get_local_object(this.local_name_client_id);\n }\n\n this.client_id = persisted_id ? persisted_id : this.generate_client_id();\n } else {\n this.client_id = this.generate_client_id();\n }\n }\n\n if (!this.session_id) {\n if (!this.on_node && this.persist) {\n this.session_id = this.generate_session_id();\n } else {\n this.session_id = 1;\n }\n }\n\n if (!this.on_node) {\n this.user_agent = this.user_agent || (window && window.navigator && window.navigator.userAgent);\n }\n };\n\n ConstructorioID.prototype.set_cookie = function (name, value) {\n if (!this.on_node && this.persist) {\n var expires = new Date(Date.now() + this.cookie_days_to_live * 24 * 60 * 60 * 1000);\n var cookie_data = name + '=' + value + '; expires=' + expires.toUTCString() + '; path=/';\n if (this.cookie_domain) {\n cookie_data += '; domain=' + this.cookie_domain;\n }\n if (this.cookie_secure) {\n cookie_data += '; secure';\n }\n if (this.cookie_samesite) {\n cookie_data += '; samesite=' + this.cookie_samesite;\n }\n document.cookie = cookie_data;\n\n // For testing purposes\n return cookie_data;\n }\n\n return null;\n };\n\n ConstructorioID.prototype.get_cookie = function (name) {\n var cookieName = name + '=';\n var cookieBits = document.cookie.split(';');\n for (var i = 0; i < cookieBits.length; i++) {\n var thisCookie = cookieBits[i];\n\n try {\n var decodedCookie = decodeURIComponent(thisCookie);\n\n while (decodedCookie.charAt(0) === ' ') { // remove leading spaces\n decodedCookie = decodedCookie.substring(1);\n }\n\n if (decodedCookie.indexOf(cookieName) === 0) {\n return decodedCookie.substring(cookieName.length, decodedCookie.length);\n }\n } catch (e) {\n // do nothing\n }\n }\n\n return undefined; // eslint-disable-line\n };\n\n ConstructorioID.prototype.delete_cookie = function (name) {\n document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';\n };\n\n ConstructorioID.prototype.generate_client_id = function () {\n var client_id;\n\n if (!this.on_node) {\n var cookie_persisted_client_id = this.get_cookie(this.cookie_name_client_id);\n var local_persisted_client_id = this.get_local_object(this.local_name_client_id);\n\n if (this.client_id_storage_location === 'cookie') {\n if (local_persisted_client_id) {\n client_id = local_persisted_client_id;\n this.set_cookie(this.cookie_name_client_id, client_id);\n this.delete_local_object(this.local_name_client_id);\n }\n }\n\n if (this.client_id_storage_location === 'local') {\n if (cookie_persisted_client_id) {\n client_id = cookie_persisted_client_id;\n this.set_local_object(this.local_name_client_id, client_id);\n this.delete_cookie(this.cookie_name_client_id);\n }\n }\n }\n\n if (!client_id) {\n client_id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n var r = Math.random() * 16 | 0;\n var v = c === 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n\n if (this.client_id_storage_location === 'cookie') {\n this.set_cookie(this.cookie_name_client_id, client_id);\n }\n\n if (this.client_id_storage_location === 'local') {\n this.set_local_object(this.local_name_client_id, client_id);\n }\n }\n\n return client_id;\n };\n\n ConstructorioID.prototype.get_local_object = function (key) {\n var data;\n var localStorage = window && window.localStorage;\n if (localStorage && typeof key === 'string') {\n try {\n data = JSON.parse(localStorage.getItem(key));\n } catch (e) {\n data = localStorage.getItem(key);\n }\n }\n return data;\n };\n\n ConstructorioID.prototype.set_local_object = function (key, data) {\n var localStorage = window && window.localStorage;\n\n if (localStorage && typeof key === 'string') {\n if (typeof data === 'object') {\n try {\n localStorage.setItem(key, JSON.stringify(data));\n } catch (e) {\n // fail silently\n }\n }\n\n if (typeof data === 'string' || typeof data === 'number') {\n try {\n localStorage.setItem(key, data);\n } catch (e) {\n // fail silently\n }\n }\n }\n };\n\n ConstructorioID.prototype.delete_local_object = function (key) {\n var localStorage = window && window.localStorage;\n\n if (localStorage && typeof key === 'string') {\n try {\n localStorage.removeItem(key);\n } catch (e) {\n // fail silently\n }\n }\n };\n\n ConstructorioID.prototype.generate_session_id = function () {\n var cookie_persisted_session_data = this.get_cookie(this.cookie_name_session_data);\n var local_persisted_session_data = this.get_local_object(this.local_name_session_data);\n var now = Date.now();\n var thirtyMinutes = 1000 * 60 * 30;\n var sessionData;\n\n if (this.session_id_storage_location === 'local') {\n sessionData = this.get_local_object(this.local_name_session_data);\n\n if (!sessionData && cookie_persisted_session_data) {\n sessionData = cookie_persisted_session_data;\n\n this.delete_cookie(this.cookie_name_session_data);\n }\n }\n\n if (this.session_id_storage_location === 'cookie') {\n sessionData = this.get_cookie(this.cookie_name_session_data);\n\n try {\n sessionData = JSON.parse(sessionData);\n } catch (e) {\n // fail silently\n }\n\n if (!sessionData && local_persisted_session_data) {\n sessionData = local_persisted_session_data;\n\n this.delete_local_object(this.local_name_session_data);\n }\n }\n\n var sessionId = 1;\n var sessionDataId = 1;\n\n if (sessionData && typeof sessionData === 'object') {\n sessionDataId = parseInt(sessionData.sessionId, 10) || 1;\n\n if (sessionData.lastTime > now - thirtyMinutes) {\n sessionId = sessionDataId;\n } else {\n sessionId = sessionDataId + 1;\n }\n }\n\n this.session_id = sessionId;\n this.session_is_new = sessionData && sessionDataId === sessionId ? false : true;\n\n // persist new status for when ciojs-client is instantiated before beacon\n if (sessionData && sessionData.newToBeacon) {\n this.new_to_beacon = true;\n }\n\n const storedData = {\n sessionId: sessionId,\n lastTime: now\n };\n\n // persist new status for when ciojs-client is instantiated before beacon\n if (this.session_is_new) {\n storedData.newToBeacon = true;\n }\n\n if (this.session_id_storage_location === 'local') {\n this.set_local_object(this.local_name_session_id, sessionId);\n this.set_local_object(this.local_name_session_data, storedData);\n }\n\n if (this.session_id_storage_location === 'cookie') {\n this.set_cookie(this.cookie_name_session_id, sessionId);\n this.set_cookie(this.cookie_name_session_data, JSON.stringify(storedData));\n }\n\n return sessionId;\n };\n\n // export module for node or environments with module loaders, such as webpack\n if (typeof module !== 'undefined' && typeof require !== 'undefined') {\n module.exports = ConstructorioID;\n }\n})();\n","(function() {/*\n\n Copyright The Closure Library Authors.\n SPDX-License-Identifier: Apache-2.0\n*/\nvar aa=\"function\"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};function ba(a){a=[\"object\"==typeof globalThis&&globalThis,a,\"object\"==typeof window&&window,\"object\"==typeof self&&self,\"object\"==typeof global&&global];for(var b=0;bc&&(c=Math.max(c+e,0));c=(b||11))return!0}catch(c){}return!1}\nfunction F(){var a=navigator.userAgent;return a.match(/android/i)?\"android\":a.match(/ipad/i)||a&&Na(a)&&a&&-1screen.width?\"ipad\":a.match(/i(os|p(hone|od))/i)?\"ios\":a.match(/\\(BB[1-9][0-9]*;/i)?\"blackberry\":a.match(/Windows Phone/i)?\"windows_phone\":a.match(/Kindle/i)||a.match(/Silk/i)||a.match(/KFTT/i)||a.match(/KFOT/i)||a.match(/KFJWA/i)||a.match(/KFJWI/i)||a.match(/KFSOWI/i)||a.match(/KFTHWA/i)||a.match(/KFTHWI/i)||a.match(/KFAPWA/i)||a.match(/KFAPWI/i)?\n\"kindle\":a.match(/(Windows|Macintosh|Linux)/i)?\"desktop\":\"other\"}function Pa(){var a=navigator.userAgent;return Na(a)?Oa(a,11):!1}function Qa(){var a=navigator.userAgent;return!!window.webkitURL&&a&&a&&/(iPad|iPod|iPhone)/.test(a)&&!/(chrome|crios)/i.test(a)&&!/(fxios|firefox)/i.test(a)&&!/edg/i.test(a)&&!/(opt|opr)/i.test(a)&&!/yabrowser/i.test(a)}\nfunction Ra(a){try{var b=(B()&&Ma()?window.top.location.search:window.location.search).substring(1).match(new RegExp(a+\"=([^&]*)\"));if(b&&1<=b.length)return b[1]}catch(c){}}function Sa(a){return a.replace(/(\\-\\w)/g,function(b){return b[1].toUpperCase()})}\nfunction Da(a){var b=\"\",c,d=0;a=a.replace(/\\r\\n/g,\"\\n\");var e=\"\";for(c=0;cf?e+=String.fromCharCode(f):(127f?e+=String.fromCharCode(f>>6|192):(e+=String.fromCharCode(f>>12|224),e+=String.fromCharCode(f>>6&63|128)),e+=String.fromCharCode(f&63|128))}for(a=e;d>2;m=(m&3)<<4|e>>4;var k=(e&15)<<2|c>>6;var g=c&63;isNaN(e)?g=k=64:isNaN(c)&&(g=64);b=b+\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\".charAt(f)+\n\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\".charAt(m)+\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\".charAt(k)+\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\".charAt(g)}return b}function Ta(a){return Ua(a)?atob(a):a}function Ua(a){if(\"string\"!==typeof a||\"\"===a||\"\"===a.trim())return!1;try{return btoa(atob(a))===a}catch(b){return!1}}\nfunction Va(a){a&&a.browser_fingerprint_id&&!Ua(a.browser_fingerprint_id)&&(a.browser_fingerprint_id=btoa(a.browser_fingerprint_id));a&&a.alternative_browser_fingerprint_id&&!Ua(a.alternative_browser_fingerprint_id)&&(a.alternative_browser_fingerprint_id=btoa(a.alternative_browser_fingerprint_id));return a}\nfunction Wa(a){a&&Ua(a.browser_fingerprint_id)&&(a.browser_fingerprint_id=atob(a.browser_fingerprint_id));a&&Ua(a.alternative_browser_fingerprint_id)&&(a.alternative_browser_fingerprint_id=atob(a.alternative_browser_fingerprint_id));return a}function Xa(a,b,c){\"function\"===typeof a.addEventListener?a.addEventListener(b,c,void 0):\"function\"===typeof a.attachEvent?a.attachEvent(\"on\"+b,c):a[\"on\"+b]=c}\nfunction Ya(a){if(!a)return null;-1/g,\">\")}function G(a,b,c){if(null!==c&&void 0!==c){if(\"object\"===typeof c&&0===Object.keys(c||{}).length)return a;a[b]=c}return a}\nfunction gb(){var a={};var b={};b=G(b,\"$og_title\",C(\"title\"));b=G(b,\"$og_description\",C(\"description\"));b=G(b,\"$og_image_url\",C(\"image\"));b=G(b,\"$og_video\",C(\"video\"));b=(b=G(b,\"$og_type\",C(\"type\")))&&0=b?a():setTimeout(a,b)}\nfunction qb(){navigator.userAgentData?navigator.userAgentData.getHighEntropyValues([\"model\",\"platformVersion\"]).then(function(a){var b=a.model;if(a=a.platformVersion){var c=/^([1-9]\\d*)\\.(0\\d*)(\\.[0]\\d*){1,}$/;-1!==a.indexOf(\".\")&&(a=a.replace(c,a.substring(0,a.indexOf(\".\"))))}y={model:b,platformVersion:a}}):y=null}function mb(a,b,c){\"string\"===typeof c&&c&&(a[b]=c);return a}\nfunction rb(a,b={},c){const d=[\"/v2/event/standard\",\"/v2/event/custom\"],e={};e.dma_eea=b.eeaRegion;e.dma_ad_personalization=b.adPersonalizationConsent;e.dma_ad_user_data=b.adUserDataUsageConsent;if([\"/v1/open\",\"/v1/pageview\"].includes(c))Object.assign(a,e);else if(d.includes(c))try{let f;a.user_data?f=JSON.parse(a.user_data):f={};Object.assign(f,e);a.user_data=JSON.stringify(f)}catch(f){console.error(`setDMAParams:: ${a.user_data} is not a valid JSON string`)}};var sb={};\nfunction K(a,b){return function(c,d,e){if(z)return!1;if(\"number\"===typeof e||e)if(0===b){if(\"object\"!==typeof e)return A(\"API request $1, parameter $2 is not $3\",[c,d,\"an object\"])}else if(3===b){if(!(e instanceof Array))return A(\"API request $1, parameter $2 is not $3\",[c,d,\"an array\"])}else if(2===b){if(\"number\"!==typeof e)return A(\"API request $1, parameter $2 is not $3\",[c,d,\"a number\"])}else if(4===b){if(\"boolean\"!==typeof e)return A(\"API request $1, parameter $2 is not $3\",[c,d,\"a boolean\"])}else{if(\"string\"!==typeof e)return A(\"API request $1, parameter $2 is not $3\",\n[c,d,\"a string\"]);if(1!==b&&!b.test(e))return A(\"API request $1, parameter $2 is not $3\",[c,d,\"in the proper format\"])}else if(a)return A(\"API request $1 missing parameter $2\",[c,d]);return!1}}function tb(a){return D(a,{browser_fingerprint_id:K(!0,1),identity_id:K(!0,1),sdk:K(!0,1),session_id:K(!0,1)})}\nvar ub={destination:r,endpoint:\"/v1/open\",method:\"POST\",h:{browser_fingerprint_id:K(!1,1),alternative_browser_fingerprint_id:K(!1,1),identity_id:K(!1,1),identity:K(!1,1),link_identifier:K(!1,1),sdk:K(!1,1),options:K(!1,0),initial_referrer:K(!1,1),tracking_disabled:K(!1,4),current_url:K(!1,1),screen_height:K(!1,2),screen_width:K(!1,2),model:K(!1,1),os_version:K(!1,1)}},vb={destination:\"https://app.link\",endpoint:\"/_r\",method:\"GET\",S:!0,h:{sdk:K(!0,1),_t:K(!1,1),branch_key:K(!0,1)}},wb={destination:r,\nendpoint:\"/v1/url\",method:\"POST\",ta:\"obj\",h:tb({alias:K(!1,1),campaign:K(!1,1),channel:K(!1,1),data:K(!1,1),feature:K(!1,1),identity_id:K(!0,1),stage:K(!1,1),tags:K(!1,3),type:K(!1,2),source:K(!1,1),instrumentation:K(!1,1)})},xb={destination:r,endpoint:\"/v1/qr-code\",method:\"POST\",ta:\"obj\",h:tb({alias:K(!1,1),campaign:K(!1,1),channel:K(!1,1),data:K(!1,1),qr_code_settings:K(!1,1),feature:K(!1,1),identity_id:K(!0,1),stage:K(!1,1),tags:K(!1,3),type:K(!1,2),source:K(!1,1)})},yb={destination:r,endpoint:\"/v1/deepview\",\nS:!0,method:\"POST\",h:tb({campaign:K(!1,1),_t:K(!1,1),channel:K(!1,1),data:K(!0,1),feature:K(!1,1),link_click_id:K(!1,1),open_app:K(!1,4),append_deeplink_path:K(!1,4),stage:K(!1,1),tags:K(!1,3),deepview_type:K(!0,1),source:K(!0,1)})},zb={destination:r,endpoint:\"/v2/event/standard\",method:\"POST\",h:{name:K(!0,1),user_data:K(!0,1),custom_data:K(!1,1),event_data:K(!1,1),content_items:K(!1,1),customer_event_alias:K(!1,1)}},Ab={destination:r,endpoint:\"/v2/event/custom\",method:\"POST\",h:{name:K(!0,1),user_data:K(!0,\n1),custom_data:K(!1,1),event_data:K(!1,1),content_items:K(!1,1),customer_event_alias:K(!1,1)}},Bb={destination:r,endpoint:\"/v1/pageview\",method:\"POST\",h:tb({event:K(!0,1),metadata:K(!1,0),initial_referrer:K(!1,1),tracking_disabled:K(!1,4),branch_view_id:K(!1,1),no_journeys:K(!1,4),user_language:K(!1,1),open_app:K(!1,4),has_app_websdk:K(!1,4),source:K(!1,1),feature:K(!1,1),is_iframe:K(!1,4),data:K(!1,0),callback_string:K(!1,1),journey_displayed:K(!1,4),audience_rule_id:K(!1,1),journey_dismissals:K(!1,\n0),identity_id:K(!1,1),identity:K(!0,1),session_referring_link_data:K(!1,1),session_link_click_id:K(!1,1)})},Cb={destination:r,endpoint:\"/v1/dismiss\",method:\"POST\",h:tb({event:K(!0,1),metadata:K(!1,0),initial_referrer:K(!1,1),tracking_disabled:K(!1,4),branch_view_id:K(!1,1),no_journeys:K(!1,4),user_language:K(!1,1),open_app:K(!1,4),has_app_websdk:K(!1,4),source:K(!1,1),feature:K(!1,1),is_iframe:K(!1,4),data:K(!1,0),callback_string:K(!1,1),journey_displayed:K(!1,4),audience_rule_id:K(!1,1),journey_dismissals:K(!1,\n0),dismissal_source:K(!1,1)})},Db={destination:r,endpoint:\"/v1/cpid\",method:\"POST\",h:{user_data:K(!0,1)}},Eb={destination:r,endpoint:\"/v1/cpid/latd\",method:\"POST\",h:{user_data:K(!0,1)}};function Fb(){for(var a=[\"session\",\"cookie\",\"pojo\"],b=0;ba.length?\"function\"===typeof b&&b():(a[0].appendChild(d),\"function\"===typeof b&&Xa(d,\"error\",b),\"function\"===typeof c&&Xa(d,\"load\",c))};\nfunction Ob(a,b,c,d,e){var f=Date.now(),m=ua;0===a.l&&Pa()&&a.l++;var k=\"branch_callback__\"+a.l++,g=0<=b.indexOf(\"branch.io\")?\"&data=\":\"&post_data=\";c=\"POST\"===d?encodeURIComponent(Da(h(c))):\"\";var u=window.setTimeout(function(){window[k]=function(){};G(x,m,wa(f));e(Error(\"Request timed out\"),null,504)},qa);window[k]=function(l){window.clearTimeout(u);e(null,l)};a.createScript(b+(0>b.indexOf(\"?\")?\"?\":\"\")+(c?g+c:\"\")+(0<=b.indexOf(\"/c/\")?\"&click=1\":\"\")+\"&callback=\"+k,function(){e(Error(\"Request blocked by client, probably adblock\"),\nnull)},function(){G(x,m,wa(f));try{\"function\"===typeof this.remove?this.remove():this.parentNode.removeChild(this)}catch(l){}delete window[k]})}\nfunction Pb(a,b,c,d,e,f,m,k){var g=Date.now(),u=ua,l=window.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject(\"Microsoft.XMLHTTP\");k&&(l.responseType=k);l.ontimeout=function(){G(x,u,wa(g));f(Error(\"Request timed out\"),null,504)};l.onerror=function(p){f(Error(p.error||\"Error in API: \"+l.status),null,l.status)};l.onreadystatechange=function(){if(4===l.readyState)if(G(x,u,wa(g)),200===l.status){if(\"arraybuffer\"===l.responseType)var p=l.response;else if(m)p=l.responseText;else try{p=v(l.responseText)}catch(t){p=\n{}}f(null,p,l.status)}else if(\"4\"===l.status.toString().substring(0,1)||\"5\"===l.status.toString().substring(0,1))l.responseURL&&l.responseURL.includes(\"v2/event\")?f(l.responseText,null,l.status):f(Error(\"Error in API: \"+l.status),null,l.status)};try{l.open(d,b,!0),l.timeout=qa,l.setRequestHeader(\"Content-Type\",\"application/x-www-form-urlencoded\"),l.send(c)}catch(p){e.set(\"use_jsonp\",!0),Ob(a,b,c,d,f)}}\nfunction Qb(a,b,c,d,e){function f(){d.get(\"use_jsonp\")||b.S?Ob(a,l,c,b.method,m):Pb(a,l,u,b.method,d,m,Y,n)}function m(q,H,E){\"function\"===typeof a.ga&&a.ga(l,b.method,p,q,E,H);q&&0=new Date(a):!a;var c=b.R;\"number\"===typeof c&&(c=!1);return!document.getElementById(\"branch-banner\")&&!document.getElementById(\"branch-banner-iframe\")&&(a||c)&&(b.V&&\"android\"===F()||b.va&&\"ipad\"===F()||b.Z&&\"ios\"===F()||b.W&&\"blackberry\"===F()||b.Y&&\"windows_phone\"===F()||b.X&&\"kindle\"===F())};function Xb(a,b){var c=\".branch-banner-is-active { -webkit-transition: all 0.375s ease; transition: all 00.375s ease; }\\n#branch-banner { width:100%; z-index: 99999; font-family: Helvetica Neue, Sans-serif; -webkit-font-smoothing: antialiased; -webkit-user-select: none; -moz-user-select: none; user-select: none; -webkit-transition: all 0.25s ease; transition: all 00.25s ease; }\\n#branch-banner .button{ border: 1px solid \"+(a.buttonBorderColor||(\"dark\"===a.theme?\"transparent\":\"#ccc\"))+\"; background: \"+\n(a.buttonBackgroundColor||\"#fff\")+\"; color: \"+(a.buttonFontColor||\"#000\")+\"; cursor: pointer; margin-top: 0px; font-size: 14px; display: inline-block; margin-left: 5px; font-weight: 400; text-decoration: none; border-radius: 4px; padding: 6px 12px; transition: all .2s ease;}\\n#branch-banner .button:hover { border: 1px solid \"+(a.buttonBorderColorHover||(\"dark\"===a.theme?\"transparent\":\"#BABABA\"))+\"; background: \"+(a.buttonBackgroundColorHover||\"#E0E0E0\")+\"; color: \"+(a.buttonFontColorHover||\"#000\")+\n\";}\\n#branch-banner .button:focus { outline: none; }\\n#branch-banner * { margin-right: 4px; position: relative; line-height: 1.2em; }\\n#branch-banner-close { font-weight: 400; cursor: pointer; float: left; z-index: 2;padding: 0 5px 0 5px; margin-right: 0; }\\n#branch-banner .content { width:100%; overflow: hidden; height: 76px; background: rgba(255, 255, 255, 0.95); color: #333; \"+(\"top\"===a.position?\"border-bottom\":\"border-top\")+': 1px solid #ddd; }\\n#branch-banner-close { color: #000; font-size: 24px; top: 14px; opacity: .5; transition: opacity .3s ease; }\\n#branch-banner-close:hover { opacity: 1; }\\n#branch-banner .title { font-size: 18px; font-weight:bold; color: #555; }\\n#branch-banner .description { font-size: 12px; font-weight: normal; color: #777; max-height: 30px; overflow: hidden; }\\n#branch-banner .icon { float: left; padding-bottom: 40px; margin-right: 10px; margin-left: 5px; }\\n#branch-banner .icon img { width: 63px; height: 63px; margin-right: 0; }\\n#branch-banner .reviews { font-size:13px; margin: 1px 0 3px 0; color: #777; }\\n#branch-banner .reviews .star { display:inline-block; position: relative; margin-right:0; }\\n#branch-banner .reviews .star span { display: inline-block; margin-right: 0; color: #555; position: absolute; top: 0; left: 0; }\\n#branch-banner .reviews .review-count { font-size:10px; }\\n#branch-banner .reviews .star .half { width: 50%; overflow: hidden; display: block; }\\n#branch-banner .content .left { padding: 6px 5px 6px 5px; }\\n#branch-banner .vertically-align-middle { top: 50%; transform: translateY(-50%); -webkit-transform: translateY(-50%); -ms-transform: translateY(-50%); }\\n#branch-banner .details > * { display: block; }\\n#branch-banner .content .left { height: 63px; }\\n#branch-banner .content .right { float: right; height: 63px; margin-bottom: 50px; padding-top: 22px; z-index: 1; }\\n#branch-banner .right > div { float: left; }\\n#branch-banner-action { top: 17px; }\\n#branch-banner .content:after { content: \"\"; position: absolute; left: 0; right: 0; top: 100%; height: 1px; background: rgba(0, 0, 0, 0.2); }\\n#branch-banner .theme-dark.content { background: rgba(51, 51, 51, 0.95); }\\n#branch-banner .theme-dark #branch-banner-close{ color: #fff; text-shadow: 0 1px 1px rgba(0, 0, 0, .15); }\\n#branch-banner .theme-dark .details { text-shadow: 0 1px 1px rgba(0, 0, 0, .15); }\\n#branch-banner .theme-dark .title { color: #fff; }\\n#branch-banner .theme-dark .description { color: #fff; }\\n#branch-banner .theme-dark .reviews { color: #888; }\\n#branch-banner .theme-dark .reviews .star span{ color: #fff; }\\n#branch-banner .theme-dark .reviews .review-count{ color: #fff; }\\n',\nd=F();\"ios\"!==d&&\"ipad\"!==d||!a.Z?\"android\"===d&&a.V?c+=\"#branch-banner { position: absolute; }\\n#branch-banner .content .left .details .title { font-size: 12px; }\\n#branch-mobile-action { white-space: nowrap; }\\n#branch-banner .content .left .details .description { font-size: 11px; font-weight: normal; }\\n@media only screen and (min-device-width: 320px) and (max-device-width: 350px) { #branch-banner .content .right { max-width: 120px; } }\\n@media only screen and (min-device-width: 351px) and (max-device-width: 400px) and (orientation: landscape) { #branch-banner .content .right { max-width: 150px; } }\\n@media only screen and (min-device-width: 401px) and (max-device-width: 480px) and (orientation: landscape) { #branch-banner .content .right { max-width: 180px; } }\\n#branch-banner #branch-banner-close,#branch-banner .theme-dark #branch-banner-close { height:17px; width: 17px; text-align: center; font-size: 15px; top: 24px; border-radius:14px; border:0; line-height:14px; color:#b1b1b3; background:#efefef; padding: 0; opacity: 1; }\\n#branch-banner .button { top: 0; text-decoration:none; border-bottom: 3px solid #A4C639; padding: 0 10px; height: 24px; line-height: 24px; text-align: center; color: #fff; margin-top: 2px; font-weight: bold; background-color: #A4C639; border-radius: 5px; }\\n#branch-banner .button:hover { border-bottom:3px solid #8c9c29; background-color: #c1d739; }\\n\":\n\"blackberry\"===d&&a.W?c+=\"#branch-banner { position: absolute; }\\n#branch-banner .content .left .details .title { font-size: 12px; }\\n#branch-mobile-action { white-space: nowrap; }\\n#branch-banner .content .left .details .description { font-size: 11px; font-weight: normal; }\\n@media only screen and (min-device-width: 320px) and (max-device-width: 350px) { #branch-banner .content .right { max-width: 120px; } }\\n@media only screen and (min-device-width: 351px) and (max-device-width: 400px) and (orientation: landscape) { #branch-banner .content .right { max-width: 150px; } }\\n@media only screen and (min-device-width: 401px) and (max-device-width: 480px) and (orientation: landscape) { #branch-banner .content .right { max-width: 180px; } }\\n\":\n\"windows_phone\"===d&&a.Y?c+=\"#branch-banner { position: absolute; }\\n#branch-banner .content .left .details .title { font-size: 12px; }\\n#branch-mobile-action { white-space: nowrap; }\\n#branch-banner .content .left .details .description { font-size: 11px; font-weight: normal; }\\n@media only screen and (min-device-width: 320px) and (max-device-width: 350px) { #branch-banner .content .right { max-width: 120px; } }\\n@media only screen and (min-device-width: 351px) and (max-device-width: 400px) and (orientation: landscape) { #branch-banner .content .right { max-width: 150px; } }\\n@media only screen and (min-device-width: 401px) and (max-device-width: 480px) and (orientation: landscape) { #branch-banner .content .right { max-width: 180px; } }\\n\":\n\"kindle\"===d&&a.X&&(c+=\"#branch-banner { position: absolute; }\\n#branch-banner .content .left .details .title { font-size: 12px; }\\n#branch-mobile-action { white-space: nowrap; }\\n#branch-banner .content .left .details .description { font-size: 11px; font-weight: normal; }\\n@media only screen and (min-device-width: 320px) and (max-device-width: 350px) { #branch-banner .content .right { max-width: 120px; } }\\n@media only screen and (min-device-width: 351px) and (max-device-width: 400px) and (orientation: landscape) { #branch-banner .content .right { max-width: 150px; } }\\n@media only screen and (min-device-width: 401px) and (max-device-width: 480px) and (orientation: landscape) { #branch-banner .content .right { max-width: 180px; } }\\n\"):\nc+=\"#branch-banner { position: absolute; }\\n#branch-banner .content .left .details .title { font-size: 12px; }\\n#branch-mobile-action { white-space: nowrap; }\\n#branch-banner .content .left .details .description { font-size: 11px; font-weight: normal; }\\n@media only screen and (min-device-width: 320px) and (max-device-width: 350px) { #branch-banner .content .right { max-width: 120px; } }\\n@media only screen and (min-device-width: 351px) and (max-device-width: 400px) and (orientation: landscape) { #branch-banner .content .right { max-width: 150px; } }\\n@media only screen and (min-device-width: 401px) and (max-device-width: 480px) and (orientation: landscape) { #branch-banner .content .right { max-width: 180px; } }\\n\";\nc+=a.ma;a.M&&(c+=\"body { margin: 0; }\\n\",d=document.createElement(\"style\"),d.type=\"text/css\",d.id=\"branch-iframe-css\",J(d),d.innerHTML=\"body { -webkit-transition: all 0.375s ease; transition: all 00.375s ease; }\\n#branch-banner-iframe { box-shadow: 0 0 5px rgba(0, 0, 0, .35); width: 1px; min-width:100%; left: 0; right: 0; border: 0; height: 76px; z-index: 99999; -webkit-transition: all 0.25s ease; transition: all 00.25s ease; }\\n#branch-banner-iframe { position: \"+((\"top\"!==a.position||a.qa?\"fixed\":\n\"absolute\")+\"; }\\n\"),(document.head||document.getElementsByTagName(\"head\")[0]).appendChild(d));d=document.createElement(\"style\");d.type=\"text/css\";d.id=\"branch-css\";d.innerHTML=c;J(d);c=a.M?b.contentWindow.document:document;(c=c.head||c.getElementsByTagName(\"head\")[0])&&\"function\"===typeof c.appendChild&&c.appendChild(d);\"top\"===a.position?b.style.top=\"-76px\":\"bottom\"===a.position&&(b.style.bottom=\"-76px\")};function N(a,b){try{var c=v(a.get(b?\"branch_session_first\":\"branch_session\",b))||null;return Wa(c)}catch(d){return null}}function Fa(a,b,c){c&&b.referring_link&&ya&&(b.referringLinkExpiry=(new Date).getTime()+sa);b=Va(b);a.set(\"branch_session\",h(b));c&&a.set(\"branch_session_first\",h(b),!0)}function Yb(a,b){if(b){var c=N(a)||{};b=h(Va(D(c,b)));a.set(\"branch_session\",b)}}\nfunction Zb(a,b,c){function d(f,m){return Va(D(v(f),m,c))}var e=a.get(\"branch_session\",!1)||{};a.set(\"branch_session\",h(d(e,b)));e=a.get(\"branch_session_first\",!0)||{};a.set(\"branch_session_first\",h(d(e,b)),!0)};function $b(a,b,c){var d=document.createElement(\"iframe\");d.src=\"about:blank\";d.style.overflow=\"hidden\";d.scrolling=\"no\";d.id=\"branch-banner-iframe\";d.className=\"branch-animation\";J(d);d.onload=function(){var e=F(),f=d.contentDocument||d.contentWindow.document;f.head=f.createElement(\"head\");f.body=f.createElement(\"body\");f.body.className=\"ios\"===e||\"ipad\"===e?\"branch-banner-ios\":\"android\"===e?\"branch-banner-android\":\"branch-banner-other\";bc(a,b,f);c(d)};document.body.appendChild(d)}\nfunction bc(a,b,c){c=c||document;var d=c.createElement(\"div\");d.id=\"branch-banner\";d.className=\"branch-animation\";if(a.I||a.T){if(a.I){var e=\"\";for(var f=0;5>f;f++)e+='\\u2606',\na.I>f&&(e+=f+1>a.I&&a.I%1?'\\u2605':\n'\\u2605 '),e+=\"\";e=''+e+\"\"}else e=\"\";e='
    '+e+(a.T?''+a.T+\"\":\"\")+\"
    \"}else e=\n\"\";d.innerHTML='
    '+b+'
    '+(a.na?\"\":'
    ×
    ')+'
    \"Application
    '+a.title+\"
    \"+e+'
    '+a.description+\"
    \";c.body.appendChild(d);return d}\nfunction cc(a,b,c){b='\");a.M?$b(a,b,c):(a=bc(a,b,document),c(a))};function dc(a,b,c,d){function e(g,u){\"function\"===typeof g&&(u=g,g={});g=g||{};\"top\"===b.position?f.style.top=\"-76px\":\"bottom\"===b.position&&(f.style.bottom=\"-76px\");\"number\"===typeof b.R?d.set(\"hideBanner\",Tb(b.R),!0):d.set(\"hideBanner\",!0,!0);g.da?(\"top\"===b.position?document.body.style.marginTop=m:\"bottom\"===b.position&&(document.body.style.marginBottom=k),Sb(\"branch-banner-is-active\"),M(f),M(document.getElementById(\"branch-css\")),u()):(setTimeout(function(){M(f);M(document.getElementById(\"branch-css\"));\nu()},270),setTimeout(function(){\"top\"===b.position?document.body.style.marginTop=m:\"bottom\"===b.position&&(document.body.style.marginBottom=k);Sb(\"branch-banner-is-active\")},20))}if(!Wb(d,b))return O(a,\"willNotShowBanner\"),null;O(a,\"willShowBanner\");var f,m=document.body.style.marginTop,k=document.body.style.marginBottom;cc(b,d,function(g){function u(){\"top\"===b.position?f.style.top=\"0\":\"bottom\"===b.position&&(f.style.bottom=\"0\");O(a,\"didShowBanner\")}f=g;Xb(b,f);c.channel=c.channel||\"app banner\";\ng=b.M?f.contentWindow.document:document;if(![\"other\",\"desktop\"].includes(F())){b.open_app=b.sa;b.append_deeplink_path=b.ka;b.make_new_link=b.pa;b.deepview_type=\"banner\";a.deepview(c,b);var l=g.getElementById(\"branch-mobile-action\");l&&(l.onclick=function(t){t.preventDefault();a.deepviewCta()})}l=Ub(\"margin-top\");var p=Ub(\"margin-bottom\");Rb(document.body,\"branch-banner-is-active\");\"top\"===b.position?document.body.style.marginTop=Vb(l):\"bottom\"===b.position&&(document.body.style.marginBottom=Vb(p));\nif(l=g.getElementById(\"branch-banner-close\"))l.onclick=function(t){t.preventDefault();O(a,\"willCloseBanner\");e({},function(){O(a,\"didCloseBanner\")})};if(g=g.getElementById(\"branch-banner-modal-background\"))g.onclick=function(t){t.preventDefault();O(a,\"willCloseBanner\");e({},function(){O(a,\"didCloseBanner\")})};b.da?u():setTimeout(u,20)});return e};function ec(){function a(){if(b.length)b[0](function(){b.shift();a()})}var b=[];return function(c){b.push(c);1===b.length&&a()}};var fc={},P,Q,R,gc,hc,ic,jc,kc,lc=1;function mc(){P=\"top\";Q=\"absolute\";R=\"76px\";hc=gc=!1}mc();var nc=[],oc=!1,pc=window.innerHeight,qc=window.innerWidth;window.innerHeight((.|\\s)*?)<\\/script>/,vc=/