| Current Path : /home/rtorresani/www/pub/static/frontend/Magento/blank/it_IT/js/bundle/ |
| Current File : //home/rtorresani/www/pub/static/frontend/Magento/blank/it_IT/js/bundle/bundle2.js |
require.config({"config": {
"jsbuild":{"Magento_Payment/js/model/credit-card-validation/expiration-date-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n 'mageUtils',\n 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/parse-date',\n 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator',\n 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator'\n], function (utils, parseDate, expirationMonth, expirationYear) {\n 'use strict';\n\n /**\n * @param {*} isValid\n * @param {*} isPotentiallyValid\n * @param {*} month\n * @param {*} year\n * @return {Object}\n */\n function resultWrapper(isValid, isPotentiallyValid, month, year) {\n return {\n isValid: isValid,\n isPotentiallyValid: isPotentiallyValid,\n month: month,\n year: year\n };\n }\n\n return function (value) {\n var date,\n monthValid,\n yearValid;\n\n if (utils.isEmpty(value)) {\n return resultWrapper(false, false, null, null);\n }\n\n value = value.replace(/^(\\d\\d) (\\d\\d(\\d\\d)?)$/, '$1/$2');\n date = parseDate(value);\n monthValid = expirationMonth(date.month);\n yearValid = expirationYear(date.year);\n\n if (monthValid.isValid && yearValid.isValid) {\n return resultWrapper(true, true, date.month, date.year);\n }\n\n if (monthValid.isPotentiallyValid && yearValid.isPotentiallyValid) {\n return resultWrapper(false, true, null, null);\n }\n\n return resultWrapper(false, false, null, null);\n };\n});\n","Magento_Payment/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n 'use strict';\n\n /**\n * Luhn algorithm verification\n */\n return function (a, b, c, d, e) {\n for (d = +a[b = a.length - 1], e = 0; b--;) {\n c = +a[b];\n d += ++e % 2 ? 2 * c % 10 + (c > 4) : c;\n }\n\n return !(d % 10);\n };\n});\n","Magento_Payment/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n 'jquery',\n 'mageUtils'\n], function ($, utils) {\n 'use strict';\n\n var types = [\n {\n title: 'Visa',\n type: 'VI',\n pattern: '^4\\\\d*$',\n gaps: [4, 8, 12],\n lengths: [16],\n code: {\n name: 'CVV',\n size: 3\n }\n },\n {\n title: 'MasterCard',\n type: 'MC',\n pattern: '^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$',\n gaps: [4, 8, 12],\n lengths: [16],\n code: {\n name: 'CVC',\n size: 3\n }\n },\n {\n title: 'American Express',\n type: 'AE',\n pattern: '^3([47]\\\\d*)?$',\n isAmex: true,\n gaps: [4, 10],\n lengths: [15],\n code: {\n name: 'CID',\n size: 4\n }\n },\n {\n title: 'Diners',\n type: 'DN',\n pattern: '^(3(0[0-5]|095|6|[8-9]))\\\\d*$',\n gaps: [4, 10],\n lengths: [14, 16, 17, 18, 19],\n code: {\n name: 'CVV',\n size: 3\n }\n },\n {\n title: 'Discover',\n type: 'DI',\n pattern: '^(6011(0|[2-4]|74|7[7-9]|8[6-9]|9)|6(4[4-9]|5))\\\\d*$',\n gaps: [4, 8, 12],\n lengths: [16, 17, 18, 19],\n code: {\n name: 'CID',\n size: 3\n }\n },\n {\n title: 'JCB',\n type: 'JCB',\n pattern: '^35(2[8-9]|[3-8])\\\\d*$',\n gaps: [4, 8, 12],\n lengths: [16, 17, 18, 19],\n code: {\n name: 'CVV',\n size: 3\n }\n },\n {\n title: 'UnionPay',\n type: 'UN',\n pattern: '^(622(1(2[6-9]|[3-9])|[3-8]|9([[0-1]|2[0-5]))|62[4-6]|628([2-8]))\\\\d*?$',\n gaps: [4, 8, 12],\n lengths: [16, 17, 18, 19],\n code: {\n name: 'CVN',\n size: 3\n }\n },\n {\n title: 'Maestro International',\n type: 'MI',\n pattern: '^(5(0|[6-9])|63|67(?!59|6770|6774))\\\\d*$',\n gaps: [4, 8, 12],\n lengths: [12, 13, 14, 15, 16, 17, 18, 19],\n code: {\n name: 'CVC',\n size: 3\n }\n },\n {\n title: 'Maestro Domestic',\n type: 'MD',\n pattern: '^6759(?!24|38|40|6[3-9]|70|76)|676770|676774\\\\d*$',\n gaps: [4, 8, 12],\n lengths: [12, 13, 14, 15, 16, 17, 18, 19],\n code: {\n name: 'CVC',\n size: 3\n }\n },\n {\n title: 'Hipercard',\n type: 'HC',\n pattern: '^((606282)|(637095)|(637568)|(637599)|(637609)|(637612))\\\\d*$',\n gaps: [4, 8, 12],\n lengths: [13, 16],\n code: {\n name: 'CVC',\n size: 3\n }\n },\n {\n title: 'Elo',\n type: 'ELO',\n pattern: '^((509091)|(636368)|(636297)|(504175)|(438935)|(40117[8-9])|(45763[1-2])|' +\n '(457393)|(431274)|(50990[0-2])|(5099[7-9][0-9])|(50996[4-9])|(509[1-8][0-9][0-9])|' +\n '(5090(0[0-2]|0[4-9]|1[2-9]|[24589][0-9]|3[1-9]|6[0-46-9]|7[0-24-9]))|' +\n '(5067(0[0-24-8]|1[0-24-9]|2[014-9]|3[0-379]|4[0-9]|5[0-3]|6[0-5]|7[0-8]))|' +\n '(6504(0[5-9]|1[0-9]|2[0-9]|3[0-9]))|' +\n '(6504(8[5-9]|9[0-9])|6505(0[0-9]|1[0-9]|2[0-9]|3[0-8]))|' +\n '(6505(4[1-9]|5[0-9]|6[0-9]|7[0-9]|8[0-9]|9[0-8]))|' +\n '(6507(0[0-9]|1[0-8]))|(65072[0-7])|(6509(0[1-9]|1[0-9]|20))|' +\n '(6516(5[2-9]|6[0-9]|7[0-9]))|(6550(0[0-9]|1[0-9]))|' +\n '(6550(2[1-9]|3[0-9]|4[0-9]|5[0-8])))\\\\d*$',\n gaps: [4, 8, 12],\n lengths: [16],\n code: {\n name: 'CVC',\n size: 3\n }\n },\n {\n title: 'Aura',\n type: 'AU',\n pattern: '^5078\\\\d*$',\n gaps: [4, 8, 12],\n lengths: [19],\n code: {\n name: 'CVC',\n size: 3\n }\n }\n ];\n\n return {\n /**\n * @param {*} cardNumber\n * @return {Array}\n */\n getCardTypes: function (cardNumber) {\n var i, value,\n result = [];\n\n if (utils.isEmpty(cardNumber)) {\n return result;\n }\n\n if (cardNumber === '') {\n return $.extend(true, {}, types);\n }\n\n for (i = 0; i < types.length; i++) {\n value = types[i];\n\n if (new RegExp(value.pattern).test(cardNumber)) {\n result.push($.extend(true, {}, value));\n }\n }\n\n return result;\n }\n };\n});\n","Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n 'use strict';\n\n /**\n * @param {*} isValid\n * @param {*} isPotentiallyValid\n * @return {Object}\n */\n function resultWrapper(isValid, isPotentiallyValid) {\n return {\n isValid: isValid,\n isPotentiallyValid: isPotentiallyValid\n };\n }\n\n return function (value) {\n var month,\n monthValid;\n\n if (value.replace(/\\s/g, '') === '' || value === '0') {\n return resultWrapper(false, true);\n }\n\n if (!/^\\d*$/.test(value)) {\n return resultWrapper(false, false);\n }\n\n if (isNaN(value)) {\n return resultWrapper(false, false);\n }\n\n month = parseInt(value, 10);\n monthValid = month > 0 && month < 13;\n\n return resultWrapper(monthValid, monthValid);\n };\n});\n","Magento_Payment/js/model/credit-card-validation/expiration-date-validator/parse-date.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n 'use strict';\n\n return function (value) {\n var month, len;\n\n if (value.match('/')) {\n value = value.split(/\\s*\\/\\s*/g);\n\n return {\n month: value[0],\n year: value.slice(1).join()\n };\n }\n\n len = value[0] === '0' || value.length > 5 || value.length === 4 || value.length === 3 ? 2 : 1;\n month = value.substr(0, len);\n\n return {\n month: month,\n year: value.substr(month.length, 4)\n };\n };\n});\n","Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n 'use strict';\n\n /**\n * @param {*} isValid\n * @param {*} isPotentiallyValid\n * @return {Object}\n */\n function resultWrapper(isValid, isPotentiallyValid) {\n return {\n isValid: isValid,\n isPotentiallyValid: isPotentiallyValid\n };\n }\n\n return function (value) {\n var currentYear = new Date().getFullYear(),\n len = value.length,\n valid,\n expMaxLifetime = 19;\n\n if (value.replace(/\\s/g, '') === '') {\n return resultWrapper(false, true);\n }\n\n if (!/^\\d*$/.test(value)) {\n return resultWrapper(false, false);\n }\n\n if (len !== 4) {\n return resultWrapper(false, true);\n }\n\n value = parseInt(value, 10);\n valid = value >= currentYear && value <= currentYear + expMaxLifetime;\n\n return resultWrapper(valid, valid);\n };\n});\n","Magento_ReCaptchaStorePickup/js/reCaptchaStorePickup.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['Magento_ReCaptchaFrontendUi/js/reCaptcha'], function (reCaptcha) {\n 'use strict';\n\n return reCaptcha.extend({\n\n /**\n * @inheritdoc\n */\n renderReCaptcha: function () {\n this.captchaInitialized = false;\n this._super();\n }\n });\n});\n","js-cookie/cookie-wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'js-cookie/js.cookie'\n], function ($, cookie) {\n 'use strict';\n\n window.Cookies = window.Cookies || cookie;\n\n var config = $.cookie = function (key, value, options) {\n if (value !== undefined) {\n options = $.extend({}, config.defaults, options);\n\n return cookie.set(key, value, options);\n }\n\n var result = key ? undefined : {},\n cookies = document.cookie ? document.cookie.split('; ') : [],\n i;\n\n for (i = 0; i < cookies.length; i++) {\n var parts = cookies[i].split('='),\n name = config.raw ? parts.shift() : decodeURIComponent(parts.shift()),\n cookieValue = parts.join('=');\n\n if (key && key === name) {\n result = decodeURIComponent(cookieValue.replace('/\\\\+/g', ' '));\n break;\n }\n\n if (!key && (cookieValue = decodeURIComponent(cookieValue.replace('/\\\\+/g', ' '))) !== undefined) {\n result[name] = cookieValue;\n }\n }\n\n return result;\n };\n\n config.defaults = {};\n\n $.removeCookie = function (key, options) {\n if ($.cookie(key) === undefined) {\n return false;\n }\n\n $.cookie(key, '', $.extend({}, options, { expires: -1 }));\n return !$.cookie(key);\n };\n});\n","js-cookie/js.cookie.js":"/*! js-cookie v3.0.1 | MIT */\n;\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (global = global || self, (function () {\n var current = global.Cookies;\n var exports = global.Cookies = factory();\n exports.noConflict = function () { global.Cookies = current; return exports; };\n }()));\n}(this, (function () { 'use strict';\n\n /* eslint-disable no-var */\n function assign (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n for (var key in source) {\n target[key] = source[key];\n }\n }\n return target\n }\n /* eslint-enable no-var */\n\n /* eslint-disable no-var */\n var defaultConverter = {\n read: function (value) {\n if (value[0] === '\"') {\n value = value.slice(1, -1);\n }\n return value.replace(/(%[\\dA-F]{2})+/gi, decodeURIComponent)\n },\n write: function (value) {\n return encodeURIComponent(value).replace(\n /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,\n decodeURIComponent\n )\n }\n };\n /* eslint-enable no-var */\n\n /* eslint-disable no-var */\n\n function init (converter, defaultAttributes) {\n function set (key, value, attributes) {\n if (typeof document === 'undefined') {\n return\n }\n\n attributes = assign({}, defaultAttributes, attributes);\n\n if (typeof attributes.expires === 'number') {\n attributes.expires = new Date(Date.now() + attributes.expires * 864e5);\n }\n if (attributes.expires) {\n attributes.expires = attributes.expires.toUTCString();\n }\n\n key = encodeURIComponent(key)\n .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)\n .replace(/[()]/g, escape);\n\n var stringifiedAttributes = '';\n for (var attributeName in attributes) {\n if (!attributes[attributeName]) {\n continue\n }\n\n stringifiedAttributes += '; ' + attributeName;\n\n if (attributes[attributeName] === true) {\n continue\n }\n\n // Considers RFC 6265 section 5.2:\n // ...\n // 3. If the remaining unparsed-attributes contains a %x3B (\";\")\n // character:\n // Consume the characters of the unparsed-attributes up to,\n // not including, the first %x3B (\";\") character.\n // ...\n stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];\n }\n\n return (document.cookie =\n key + '=' + converter.write(value, key) + stringifiedAttributes)\n }\n\n function get (key) {\n if (typeof document === 'undefined' || (arguments.length && !key)) {\n return\n }\n\n // To prevent the for loop in the first place assign an empty array\n // in case there are no cookies at all.\n var cookies = document.cookie ? document.cookie.split('; ') : [];\n var jar = {};\n for (var i = 0; i < cookies.length; i++) {\n var parts = cookies[i].split('=');\n var value = parts.slice(1).join('=');\n\n try {\n var foundKey = decodeURIComponent(parts[0]);\n jar[foundKey] = converter.read(value, foundKey);\n\n if (key === foundKey) {\n break\n }\n } catch (e) {}\n }\n\n return key ? jar[key] : jar\n }\n\n return Object.create(\n {\n set: set,\n get: get,\n remove: function (key, attributes) {\n set(\n key,\n '',\n assign({}, attributes, {\n expires: -1\n })\n );\n },\n withAttributes: function (attributes) {\n return init(this.converter, assign({}, this.attributes, attributes))\n },\n withConverter: function (converter) {\n return init(assign({}, this.converter, converter), this.attributes)\n }\n },\n {\n attributes: { value: Object.freeze(defaultAttributes) },\n converter: { value: Object.freeze(converter) }\n }\n )\n }\n\n var api = init(defaultConverter, { path: '/' });\n /* eslint-enable no-var */\n\n return api;\n\n})));\n","Magento_InstantPurchase/js/view/instant-purchase.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n 'jquery',\n 'underscore',\n 'uiComponent',\n 'Magento_Ui/js/modal/confirm',\n 'Magento_Customer/js/customer-data',\n 'mage/url',\n 'mage/template',\n 'mage/translate',\n 'text!Magento_InstantPurchase/template/confirmation.html',\n 'mage/validation'\n], function (ko, $, _, Component, confirm, customerData, urlBuilder, mageTemplate, $t, confirmationTemplate) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Magento_InstantPurchase/instant-purchase',\n buttonText: $t('Instant Purchase'),\n purchaseUrl: urlBuilder.build('instantpurchase/button/placeOrder'),\n showButton: false,\n paymentToken: null,\n shippingAddress: null,\n billingAddress: null,\n shippingMethod: null,\n productFormSelector: '#product_addtocart_form',\n confirmationTitle: $t('Instant Purchase Confirmation'),\n confirmationData: {\n message: $t('Are you sure you want to place order and pay?'),\n shippingAddressTitle: $t('Shipping Address'),\n billingAddressTitle: $t('Billing Address'),\n paymentMethodTitle: $t('Payment Method'),\n shippingMethodTitle: $t('Shipping Method')\n }\n },\n\n /** @inheritdoc */\n initialize: function () {\n var instantPurchase = customerData.get('instant-purchase');\n\n this._super();\n\n this.setPurchaseData(instantPurchase());\n instantPurchase.subscribe(this.setPurchaseData, this);\n },\n\n /** @inheritdoc */\n initObservable: function () {\n this._super()\n .observe('showButton paymentToken shippingAddress billingAddress shippingMethod');\n\n return this;\n },\n\n /**\n * Set data from customerData.\n *\n * @param {Object} data\n */\n setPurchaseData: function (data) {\n this.showButton(data.available);\n this.paymentToken(data.paymentToken);\n this.shippingAddress(data.shippingAddress);\n this.billingAddress(data.billingAddress);\n this.shippingMethod(data.shippingMethod);\n },\n\n /**\n * Confirmation method\n */\n instantPurchase: function () {\n var form = $(this.productFormSelector),\n confirmTemplate = mageTemplate(confirmationTemplate),\n confirmData = _.extend({}, this.confirmationData, {\n paymentToken: this.paymentToken().summary,\n shippingAddress: this.shippingAddress().summary,\n billingAddress: this.billingAddress().summary,\n shippingMethod: this.shippingMethod().summary\n });\n\n if (!(form.validation() && form.validation('isValid'))) {\n return;\n }\n\n confirm({\n title: this.confirmationTitle,\n content: confirmTemplate({\n data: confirmData\n }),\n actions: {\n /** @inheritdoc */\n confirm: function () {\n $.ajax({\n url: this.purchaseUrl,\n data: form.serialize(),\n type: 'post',\n dataType: 'json',\n\n /** Show loader before send */\n beforeSend: function () {\n $('body').trigger('processStart');\n }\n }).always(function () {\n $('body').trigger('processStop');\n });\n }.bind(this)\n }\n });\n }\n });\n});\n","Magento_Tax/js/price/adjustment.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Ui/js/grid/columns/column',\n 'mage/translate'\n], function (Element, $t) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n bodyTmpl: 'Magento_Tax/price/adjustment',\n taxPriceType: 'final_price',\n taxPriceCssClass: 'price-including-tax',\n bothPrices: 3,\n inclTax: 2,\n exclTax: 1,\n modules: {\n price: '${ $.parentName }'\n },\n listens: {\n price: 'initializePriceAttributes'\n }\n },\n\n /**\n * {@inheritdoc}\n */\n initialize: function () {\n this._super()\n .initializePriceAttributes();\n\n return this;\n },\n\n /**\n * Update parent price.\n *\n * @returns {Object} Chainable.\n */\n initializePriceAttributes: function () {\n if (this.displayBothPrices && this.price()) {\n this.price().priceWrapperCssClasses = this.taxPriceCssClass;\n this.price().priceWrapperAttr = {\n 'data-label': $t('Incl. Tax')\n };\n }\n\n return this;\n },\n\n /**\n * Get price tax adjustment.\n *\n * @param {Object} row\n * @return {HTMLElement} tax html\n */\n getTax: function (row) {\n return row['price_info']['extension_attributes']['tax_adjustments']['formatted_prices'][this.taxPriceType];\n },\n\n /**\n * UnsanitizedHtml version of getTax.\n *\n * @param {Object} row\n * @return {HTMLElement} tax html\n */\n getTaxUnsanitizedHtml: function (row) {\n return this.getTax(row);\n },\n\n /**\n * Set price tax type.\n *\n * @param {String} priceType\n * @return {Object}\n */\n setPriceType: function (priceType) {\n this.taxPriceType = priceType;\n\n return this;\n },\n\n /**\n * Return whether display setting is to display\n * both price including tax and price excluding tax.\n *\n * @return {Boolean}\n */\n displayBothPrices: function () {\n return +this.source.data.displayTaxes === this.bothPrices;\n },\n\n /**\n * Return whether display setting is to display price including tax.\n *\n * @return {Boolean}\n */\n displayPriceIncludeTax: function () {\n return +this.source.data.displayTaxes === this.inclTax;\n },\n\n /**\n * Return whether display setting is to display price excluding tax.\n *\n * @return {Boolean}\n */\n displayPriceExclTax: function () {\n return +this.source.data.displayTaxes === this.exclTax;\n }\n });\n});\n","Magento_Tax/js/view/checkout/cart/totals/tax.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'Magento_Tax/js/view/checkout/summary/tax',\n 'Magento_Checkout/js/model/totals'\n], function (Component, totals) {\n 'use strict';\n\n var isFullTaxSummaryDisplayed = window.checkoutConfig.isFullTaxSummaryDisplayed,\n isZeroTaxDisplayed = window.checkoutConfig.isZeroTaxDisplayed;\n\n return Component.extend({\n /**\n * @override\n */\n ifShowValue: function () {\n if (parseInt(this.getPureValue()) === 0) { //eslint-disable-line radix\n return isZeroTaxDisplayed;\n }\n\n return true;\n },\n\n /**\n * @override\n */\n ifShowDetails: function () {\n return this.getPureValue() > 0 && isFullTaxSummaryDisplayed;\n },\n\n /**\n * @override\n */\n isCalculated: function () {\n return this.totals() && totals.getSegment('tax') !== null;\n }\n });\n});\n","Magento_Tax/js/view/checkout/cart/totals/shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'Magento_Tax/js/view/checkout/summary/shipping',\n 'Magento_Checkout/js/model/quote'\n], function (Component, quote) {\n 'use strict';\n\n return Component.extend({\n /**\n * @override\n */\n isCalculated: function () {\n return !!quote.shippingMethod();\n },\n\n /**\n * @override\n */\n getShippingMethodTitle: function () {\n return '(' + this._super() + ')';\n }\n });\n});\n","Magento_Tax/js/view/checkout/cart/totals/grand-total.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'Magento_Tax/js/view/checkout/summary/grand-total'\n], function (Component) {\n 'use strict';\n\n return Component.extend({\n /**\n * @override\n */\n isDisplayed: function () {\n return true;\n }\n });\n});\n","Magento_Tax/js/view/checkout/minicart/subtotal/totals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'ko',\n 'uiComponent',\n 'Magento_Customer/js/customer-data'\n], function (ko, Component, customerData) {\n 'use strict';\n\n return Component.extend({\n displaySubtotal: ko.observable(true),\n\n /**\n * @override\n */\n initialize: function () {\n this._super();\n this.cart = customerData.get('cart');\n }\n });\n});\n","Magento_Tax/js/view/checkout/summary/tax.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'ko',\n 'Magento_Checkout/js/view/summary/abstract-total',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/totals',\n 'mage/translate',\n 'underscore'\n], function (ko, Component, quote, totals, $t, _) {\n 'use strict';\n\n var isTaxDisplayedInGrandTotal = window.checkoutConfig.includeTaxInGrandTotal,\n isFullTaxSummaryDisplayed = window.checkoutConfig.isFullTaxSummaryDisplayed,\n isZeroTaxDisplayed = window.checkoutConfig.isZeroTaxDisplayed,\n taxAmount = 0,\n rates = 0;\n\n return Component.extend({\n defaults: {\n isTaxDisplayedInGrandTotal: isTaxDisplayedInGrandTotal,\n notCalculatedMessage: $t('Not yet calculated'),\n template: 'Magento_Tax/checkout/summary/tax'\n },\n totals: quote.getTotals(),\n isFullTaxSummaryDisplayed: isFullTaxSummaryDisplayed,\n\n /**\n * @return {Boolean}\n */\n ifShowValue: function () {\n if (this.isFullMode() && this.getPureValue() == 0) { //eslint-disable-line eqeqeq\n return isZeroTaxDisplayed;\n }\n\n return true;\n },\n\n /**\n * @return {Boolean}\n */\n ifShowDetails: function () {\n if (!this.isFullMode()) {\n return false;\n }\n\n return this.getPureValue() > 0 && isFullTaxSummaryDisplayed;\n },\n\n /**\n * @return {Number}\n */\n getPureValue: function () {\n var amount = 0,\n taxTotal;\n\n if (this.totals()) {\n taxTotal = totals.getSegment('tax');\n\n if (taxTotal) {\n amount = taxTotal.value;\n }\n }\n\n return amount;\n },\n\n /**\n * @return {*|Boolean}\n */\n isCalculated: function () {\n return this.totals() && this.isFullMode() && totals.getSegment('tax') != null;\n },\n\n /**\n * @return {*}\n */\n getValue: function () {\n var amount;\n\n if (!this.isCalculated()) {\n return this.notCalculatedMessage;\n }\n amount = totals.getSegment('tax').value;\n\n return this.getFormattedPrice(amount);\n },\n\n /**\n * @param {*} amount\n * @return {*|String}\n */\n formatPrice: function (amount) {\n return this.getFormattedPrice(amount);\n },\n\n /**\n * @param {*} parent\n * @param {*} percentage\n * @return {*|String}\n */\n getTaxAmount: function (parent, percentage) {\n var totalPercentage = 0;\n\n taxAmount = parent.amount;\n rates = parent.rates;\n _.each(rates, function (rate) {\n totalPercentage += parseFloat(rate.percent);\n });\n\n return this.getFormattedPrice(this.getPercentAmount(taxAmount, totalPercentage, percentage));\n },\n\n /**\n * @param {*} amount\n * @param {*} totalPercentage\n * @param {*} percentage\n * @return {*|String}\n */\n getPercentAmount: function (amount, totalPercentage, percentage) {\n return parseFloat(amount * percentage / totalPercentage);\n },\n\n /**\n * @return {Array}\n */\n getDetails: function () {\n var taxSegment = totals.getSegment('tax');\n\n if (taxSegment && taxSegment['extension_attributes']) {\n return taxSegment['extension_attributes']['tax_grandtotal_details'];\n }\n\n return [];\n }\n });\n});\n","Magento_Tax/js/view/checkout/summary/subtotal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'Magento_Checkout/js/view/summary/abstract-total',\n 'Magento_Checkout/js/model/quote'\n], function (Component, quote) {\n 'use strict';\n\n var displaySubtotalMode = window.checkoutConfig.reviewTotalsDisplayMode;\n\n return Component.extend({\n defaults: {\n displaySubtotalMode: displaySubtotalMode,\n template: 'Magento_Tax/checkout/summary/subtotal'\n },\n totals: quote.getTotals(),\n\n /**\n * @return {*|String}\n */\n getValue: function () {\n var price = 0;\n\n if (this.totals()) {\n price = this.totals().subtotal;\n }\n\n return this.getFormattedPrice(price);\n },\n\n /**\n * @return {Boolean}\n */\n isBothPricesDisplayed: function () {\n return this.displaySubtotalMode == 'both'; //eslint-disable-line eqeqeq\n },\n\n /**\n * @return {Boolean}\n */\n isIncludingTaxDisplayed: function () {\n return this.displaySubtotalMode == 'including'; //eslint-disable-line eqeqeq\n },\n\n /**\n * @return {*|String}\n */\n getValueInclTax: function () {\n var price = 0;\n\n if (this.totals()) {\n price = this.totals()['subtotal_incl_tax'];\n }\n\n return this.getFormattedPrice(price);\n }\n });\n});\n","Magento_Tax/js/view/checkout/summary/shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'jquery',\n 'Magento_Checkout/js/view/summary/shipping',\n 'Magento_Checkout/js/model/quote'\n], function ($, Component, quote) {\n 'use strict';\n\n var displayMode = window.checkoutConfig.reviewShippingDisplayMode;\n\n return Component.extend({\n defaults: {\n displayMode: displayMode,\n template: 'Magento_Tax/checkout/summary/shipping'\n },\n\n /**\n * @return {Boolean}\n */\n isBothPricesDisplayed: function () {\n return this.displayMode == 'both'; //eslint-disable-line eqeqeq\n },\n\n /**\n * @return {Boolean}\n */\n isIncludingDisplayed: function () {\n return this.displayMode == 'including'; //eslint-disable-line eqeqeq\n },\n\n /**\n * @return {Boolean}\n */\n isExcludingDisplayed: function () {\n return this.displayMode == 'excluding'; //eslint-disable-line eqeqeq\n },\n\n /**\n * @return {*|Boolean}\n */\n isCalculated: function () {\n return this.totals() && this.isFullMode() && quote.shippingMethod() != null;\n },\n\n /**\n * @return {*}\n */\n getIncludingValue: function () {\n var price;\n\n if (!this.isCalculated()) {\n return this.notCalculatedMessage;\n }\n price = this.totals()['shipping_incl_tax'];\n\n return this.getFormattedPrice(price);\n },\n\n /**\n * @return {*}\n */\n getExcludingValue: function () {\n var price;\n\n if (!this.isCalculated()) {\n return this.notCalculatedMessage;\n }\n price = this.totals()['shipping_amount'];\n\n return this.getFormattedPrice(price);\n }\n });\n});\n","Magento_Tax/js/view/checkout/summary/grand-total.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'Magento_Checkout/js/view/summary/abstract-total',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Catalog/js/price-utils',\n 'Magento_Checkout/js/model/totals'\n], function (Component, quote, priceUtils, totals) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n isFullTaxSummaryDisplayed: window.checkoutConfig.isFullTaxSummaryDisplayed || false,\n template: 'Magento_Tax/checkout/summary/grand-total'\n },\n totals: quote.getTotals(),\n isTaxDisplayedInGrandTotal: window.checkoutConfig.includeTaxInGrandTotal || false,\n\n /**\n * @return {*}\n */\n isDisplayed: function () {\n return this.isFullMode();\n },\n\n /**\n * @return {*|String}\n */\n getValue: function () {\n var price = 0;\n\n if (this.totals()) {\n price = totals.getSegment('grand_total').value;\n }\n\n return this.getFormattedPrice(price);\n },\n\n /**\n * @return {*|String}\n */\n getBaseValue: function () {\n var price = 0;\n\n if (this.totals()) {\n price = this.totals()['base_grand_total'];\n }\n\n return priceUtils.formatPriceLocale(price, quote.getBasePriceFormat());\n },\n\n /**\n * @return {*}\n */\n getGrandTotalExclTax: function () {\n var total = this.totals(),\n amount;\n\n if (!total) {\n return 0;\n }\n\n amount = total['grand_total'] - total['tax_amount'];\n\n if (amount < 0) {\n amount = 0;\n }\n\n return this.getFormattedPrice(amount);\n },\n\n /**\n * @return {Boolean}\n */\n isBaseGrandTotalDisplayNeeded: function () {\n var total = this.totals();\n\n if (!total) {\n return false;\n }\n\n return total['base_currency_code'] != total['quote_currency_code']; //eslint-disable-line eqeqeq\n }\n });\n});\n","Magento_Tax/js/view/checkout/summary/item/details/subtotal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'Magento_Checkout/js/view/summary/item/details/subtotal'\n], function (subtotal) {\n 'use strict';\n\n var displayPriceMode = window.checkoutConfig.reviewItemPriceDisplayMode || 'including';\n\n return subtotal.extend({\n defaults: {\n displayPriceMode: displayPriceMode,\n template: 'Magento_Tax/checkout/summary/item/details/subtotal'\n },\n\n /**\n * @return {Boolean}\n */\n isPriceInclTaxDisplayed: function () {\n return displayPriceMode == 'both' || displayPriceMode == 'including'; //eslint-disable-line eqeqeq\n },\n\n /**\n * @return {Boolean}\n */\n isPriceExclTaxDisplayed: function () {\n return displayPriceMode == 'both' || displayPriceMode == 'excluding'; //eslint-disable-line eqeqeq\n },\n\n /**\n * @param {Object} quoteItem\n * @return {*|String}\n */\n getValueInclTax: function (quoteItem) {\n return this.getFormattedPrice(quoteItem['row_total_incl_tax']);\n },\n\n /**\n * @param {Object} quoteItem\n * @return {*|String}\n */\n getValueExclTax: function (quoteItem) {\n return this.getFormattedPrice(quoteItem['row_total']);\n }\n\n });\n});\n","Magento_Tax/js/view/checkout/shipping_method/price.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n 'uiComponent',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Catalog/js/price-utils'\n], function (Component, quote, priceUtils) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Magento_Tax/checkout/shipping_method/price'\n },\n isDisplayShippingPriceExclTax: window.checkoutConfig.isDisplayShippingPriceExclTax,\n isDisplayShippingBothPrices: window.checkoutConfig.isDisplayShippingBothPrices,\n\n /**\n * @param {Object} item\n * @return {Boolean}\n */\n isPriceEqual: function (item) {\n return item['price_excl_tax'] != item['price_incl_tax']; //eslint-disable-line eqeqeq\n },\n\n /**\n * @param {*} price\n * @return {*|String}\n */\n getFormattedPrice: function (price) {\n //todo add format data\n return priceUtils.formatPriceLocale(price, quote.getPriceFormat());\n }\n });\n});\n","Magento_Translation/js/add-class.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery'], function ($) {\n 'use strict';\n\n return function (config, element) {\n $(element).addClass(config.class);\n };\n});\n","Magento_Translation/js/i18n-config.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function () {\n 'use strict';\n\n require.config({\n config: {\n 'Magento_Ui/js/lib/knockout/bindings/i18n': {\n inlineTranslation: true\n }\n }\n });\n})();\n","Magento_Translation/js/mage-translation-dictionary.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'text!js-translation.json'\n], function (dict) {\n 'use strict';\n\n return JSON.parse(dict);\n});\n","Magento_CatalogSearch/js/search-terms-log.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mageUtils'\n], function ($, utils) {\n 'use strict';\n\n return function (data) {\n $.ajax({\n method: 'GET',\n url: data.url,\n data: {\n 'q': utils.getUrlParameters(window.location.href).q\n }\n });\n };\n});\n","Amasty_Rewards/js/guest-highlight.js":"define([\n 'uiComponent',\n 'mage/translate',\n], function (Component, $t) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Amasty_Rewards/guest-highlight',\n captionStartText : $t('You can earn'),\n captionAfterText: '',\n captionRegistrationText: $t('for registration!'),\n captionEndText: '',\n frontend_class: '',\n highlight: []\n },\n\n initObservable: function () {\n this._super().observe([ 'highlight' ]);\n if (this.highlight._latestValue.need_to_change_message === 1) {\n this.captionAfterText = $t('for making a purchase! Available for');\n this.captionRegistrationText = $t('registered');\n this.captionEndText = $t('customers only.');\n }\n\n return this;\n }\n });\n});\n","Amasty_Rewards/js/amreward-points.js":"/*jshint browser:true jquery:true*/\ndefine([\n \"jquery\",\n \"Magento_Ui/js/modal/modal\"\n], function($){\n \"use strict\";\n\n $.widget('mage.amrewardPoints', {\n options: {\n },\n _create: function () {\n this.rewardAmount = $(this.options.rewardAmount);\n\n this.removeReward = $(this.options.removeRewardSelector);\n\n $(this.options.applyButton).on('click', $.proxy(function () {\n this.rewardAmount.attr('data-validate', '{required:true}');\n\n this.removeReward.attr('value', '0');\n $(this.element).validation().submit();\n }, this));\n\n $(this.options.cancelButton).on('click', $.proxy(function () {\n this.rewardAmount.removeAttr('data-validate');\n this.removeReward.attr('value', '1');\n this.element.submit();\n }, this));\n\n if (!this.isGreaterThanMinimumBalance()) {\n this.getMinimumRewardNoteDOM().show();\n this.disableRewardInput();\n\n }\n },\n\n /**\n *\n * @returns {boolean}\n */\n isGreaterThanMinimumBalance: function () {\n var realBalance = this.options.customerBalance;\n\n if (this.options.usedPoints) {\n realBalance += this.options.usedPoints;\n }\n\n return !this.options.minimumBalance || (realBalance >= this.options.minimumBalance);\n },\n\n /**\n * @return void\n */\n disableRewardInput: function() {\n $(this.options.applyButton).prop(\"disabled\", true);\n $(this.options.rewardAmount).prop(\"disabled\", true);\n },\n\n /**\n *\n * @returns {*|jQuery|HTMLElement}\n */\n getMinimumRewardNoteDOM: function() {\n return $(this.options.minimumNoteSelector);\n }\n });\n\n return $.mage.amrewardPoints;\n});\n","Amasty_Rewards/js/action/cancel-reward.js":"/**\n * Customer store credit(balance) application\n */\ndefine([\n 'jquery',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/url-builder',\n 'Magento_Checkout/js/model/error-processor',\n 'Amasty_Rewards/js/model/payment/reward-messages',\n 'mage/storage',\n 'Magento_Checkout/js/action/get-payment-information',\n 'Magento_Checkout/js/model/totals',\n 'mage/translate',\n 'Magento_Checkout/js/model/full-screen-loader'\n], function ($, quote, urlBuilder, errorProcessor, messageContainer, storage, getPaymentInformationAction, totals, $t,\n fullScreenLoader\n) {\n 'use strict';\n\n return function (isApplied) {\n var url = urlBuilder.createUrl('/carts/mine/points/delete', {}),\n message = $t('You Canceled Reward.');\n\n messageContainer.clear();\n fullScreenLoader.startLoader();\n\n return storage.delete(\n url,\n false\n ).done(function () {\n var deferred = $.Deferred();\n\n totals.isLoading(true);\n getPaymentInformationAction(deferred);\n $.when(deferred).done(function () {\n isApplied(false);\n totals.isLoading(false);\n fullScreenLoader.stopLoader();\n });\n messageContainer.addSuccessMessage({\n 'message': message\n });\n }).fail(function (response) {\n totals.isLoading(false);\n fullScreenLoader.stopLoader();\n errorProcessor.process(response, messageContainer);\n });\n };\n});","Amasty_Rewards/js/action/add-reward.js":"define([\n 'ko',\n 'jquery',\n 'Magento_Checkout/js/model/quote',\n 'Amasty_Rewards/js/model/resource-url-manager',\n 'Magento_Checkout/js/model/error-processor',\n 'Amasty_Rewards/js/model/payment/reward-messages',\n 'mage/storage',\n 'mage/translate',\n 'Magento_Checkout/js/action/get-payment-information',\n 'Magento_Checkout/js/model/totals',\n 'Magento_Checkout/js/model/full-screen-loader'\n ], function (ko, $, quote, urlManager, errorProcessor, messageContainer,\n storage, $t, getPaymentInformationAction, totals, fullScreenLoader\n ) {\n 'use strict';\n return function (points, isApplied, pointsLeftObs, rateForCurrency, noticeMessage) {\n var quoteId = quote.getQuoteId(),\n url = urlManager.getRewardsUrl(points(), quoteId);\n\n messageContainer.clear();\n fullScreenLoader.startLoader();\n\n return storage.put(\n url,\n {},\n false\n ).done(function (response) {\n var deferred,\n pointsUsed = 0;\n\n if (response) {\n pointsUsed = response[1];\n noticeMessage($t(response[0]));\n $('[data-amrewards-js=\"notice-message\"]').show();\n setTimeout(function () {\n $('[data-amrewards-js=\"notice-message\"]').hide('blind', {}, 500);\n }, 5000);\n\n deferred = $.Deferred();\n\n if (pointsUsed > 0) {\n isApplied(true);\n totals.isLoading(true);\n getPaymentInformationAction(deferred);\n\n $.when(deferred).done(function () {\n points((pointsUsed).toFixed(2));\n pointsLeftObs((pointsLeftObs() - points()).toFixed(2));\n $('#amreward_amount').val(points()).change();\n\n fullScreenLoader.stopLoader();\n totals.isLoading(false);\n });\n }\n\n fullScreenLoader.stopLoader();\n }\n }).fail(function (response) {\n fullScreenLoader.stopLoader();\n totals.isLoading(false);\n errorProcessor.process(response, messageContainer);\n });\n };\n }\n);","Amasty_Rewards/js/view/balance.js":"define([\n 'uiComponent',\n 'Magento_Customer/js/customer-data'\n], function (Component, customerData) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n visible: false,\n balance: 0,\n captionText: false\n },\n\n initObservable: function () {\n this._super().observe('visible balance captionText');\n\n return this;\n },\n\n initialize: function () {\n this._super();\n var rewardsData = customerData.get('rewards');\n\n if (rewardsData().balance) {\n this.balance(rewardsData().balance);\n }\n\n rewardsData.subscribe(function (rewardsData) {\n this.balance(rewardsData.balance);\n }.bind(this));\n\n this.visible(true);\n },\n });\n});\n","Amasty_Rewards/js/view/checkout/payment/rewards.js":"define([\n 'jquery',\n 'underscore',\n 'uiComponent',\n 'Magento_Checkout/js/model/quote',\n 'Amasty_Rewards/js/action/add-reward',\n 'Amasty_Rewards/js/action/cancel-reward',\n 'Amasty_Rewards/vendor/tooltipster/js/tooltipster.min',\n 'Magento_Ui/js/model/messageList',\n 'mage/translate'\n], function (\n $,\n _,\n Component,\n quote,\n setRewardPointAction,\n cancelRewardPointAction,\n tooltipster,\n messageList,\n $t\n) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Amasty_Rewards/checkout/payment/rewards',\n isApplied: false,\n pointsUsed: 0,\n pointsLeft: 0,\n noticeMessage: '',\n minimumPointsValue: 0,\n disableElem: false,\n isRewardsTooltipEnabled: false,\n rewardsTooltipContent: '',\n selectors: {\n tooltipElement: '[data-amrewards-js=\"tooltip\"]'\n }\n },\n\n initObservable: function () {\n this._super();\n this.observe(['pointsUsed', 'pointsLeft', 'isApplied', 'noticeMessage', 'disableElem']);\n\n return this;\n },\n\n /**\n * @return {exports}\n */\n initialize: function () {\n this._super();\n this.isApplied(false);\n\n if (this.pointsUsed() > 0) {\n this.isApplied(true);\n }\n\n if (_.isUndefined(Number.parseFloat)) {\n Number.parseFloat = parseFloat;\n }\n\n if (this.getMinimumPointsValue() > this.pointsLeft() + Number.parseFloat(this.pointsUsed())) {\n this.disableElem(true);\n }\n\n this.initTooltip();\n\n return this;\n },\n\n /**\n * @return {*|Boolean}\n */\n isDisplayed: function () {\n return this.customerId;\n },\n\n /**\n * Coupon code application procedure\n */\n apply: function () {\n if (this.validate()) {\n setRewardPointAction(this.pointsUsed, this.isApplied, this.pointsLeft, this.rateForCurrency, this.noticeMessage);\n }\n },\n\n /**\n * Cancel using coupon\n */\n cancel: function () {\n cancelRewardPointAction(this.isApplied);\n this.pointsLeft((Number.parseFloat(this.pointsLeft()) + Number.parseFloat(this.pointsUsed())).toFixed(2));\n },\n\n /**\n *\n * @return {*}\n */\n getRewardsCount: function () {\n return this.pointsLeft();\n },\n\n /**\n *\n * @return {*}\n */\n getPointsRate: function () {\n return this.pointsRate;\n },\n\n /**\n *\n * @return {*}\n */\n getCurrentCurrency: function () {\n return this.currentCurrencyCode;\n },\n\n /**\n *\n * @return {*}\n */\n getRateForCurrency: function () {\n return this.rateForCurrency;\n },\n\n /**\n * @return {*}\n */\n getMinimumPointsValue: function () {\n return Number.parseFloat(this.minimumPointsValue);\n },\n\n /**\n * @return {Boolean}\n */\n canApply: function () {\n return !(this.disableElem() || this.isApplied());\n },\n\n /**\n * Coupon form validation\n *\n * @returns {Boolean}\n */\n validate: function () {\n var form = '#discount-reward-form',\n valueValid = (this.pointsLeft() - this.pointsUsed() >= 0) && this.pointsUsed() > 0;\n\n if ($(form).validation() && $(form).validation('isValid') && valueValid) {\n return true;\n }\n\n messageList.addErrorMessage({\n message: $t('Points \"' + this.pointsUsed() +'\" not valid.')\n });\n\n return false;\n },\n\n initTooltip: function () {\n var tooltipTrigger = this.isTouchDevice() ? 'click' : 'hover';\n\n if (!this.isRewardsTooltipEnabled) {\n return;\n }\n\n $.async(this.selectors.tooltipElement, function () {\n $(this.selectors.tooltipElement).tooltipster({\n position: 'right',\n contentAsHtml: true,\n interactive: true,\n trigger: tooltipTrigger\n });\n }.bind(this));\n },\n\n isTouchDevice: function () {\n return ('ontouchstart' in window)\n || (navigator.maxTouchPoints > 0)\n || (navigator.msMaxTouchPoints > 0);\n }\n });\n});\n","Amasty_Rewards/js/view/checkout/payment/reward-messages.js":"define([\n 'Magento_Ui/js/view/messages',\n 'Amasty_Rewards/js/model/payment/reward-messages'\n], function (Component, messageContainer) {\n 'use strict';\n\n return Component.extend({\n /** @inheritdoc */\n initialize: function (config) {\n return this._super(config, messageContainer);\n }\n });\n});","Amasty_Rewards/js/model/resource-url-manager.js":"define([\n 'Magento_Customer/js/model/customer',\n 'Magento_Checkout/js/model/url-builder',\n 'mageUtils',\n 'mage/url',\n 'mage/translate'\n ], function (customer, urlBuilder, utils, url, $t) {\n 'use strict';\n\n return {\n\n /**\n * @param {String} points\n * @return {*}\n */\n getRewardsUrl: function (points) {\n var params = {},\n url = {\n 'customer': '/carts/mine/points/' + encodeURIComponent(points)\n };\n\n return this.getUrl(url, params);\n },\n\n /**\n * @return {String}\n */\n getCheckoutMethod: function () {\n return 'customer';\n },\n\n /**\n * Get url for service.\n *\n * @param {*} url\n * @param {*} urlParams\n * @return {String|*}\n */\n getUrl: function (url, urlParams) {\n var finalUrl;\n\n if (utils.isEmpty(url)) {\n return $t('Provided service call does not exist.');\n }\n\n if (!utils.isEmpty(url['default'])) {\n finalUrl = url['default'];\n } else {\n finalUrl = url[this.getCheckoutMethod()];\n }\n\n return urlBuilder.createUrl(finalUrl, urlParams);\n }\n };\n }\n);\n","Amasty_Rewards/js/model/totals/highlight.js":"define([\n 'uiComponent',\n 'Magento_Checkout/js/model/totals',\n 'mage/translate',\n], function (Component, totals, $t) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Amasty_Rewards/highlight',\n captionEndText: $t('for completing your purchase!'),\n captionStartText : $t('You can earn'),\n frontend_class: '',\n highlight: []\n },\n\n /**\n * @return {Object}\n */\n initObservable: function () {\n this._super().observe(['highlight']);\n totals.totals.subscribe(this.getHighlightData.bind(this));\n\n return this;\n },\n\n /**\n * @param totals {Object}\n * @return {void}\n */\n getHighlightData: function (totals) {\n let totalsAttributes = totals.extension_attributes;\n\n if (totalsAttributes && totalsAttributes.amasty_rewards_highlight) {\n this.highlight(totalsAttributes.amasty_rewards_highlight);\n } else {\n this.highlight({'visible': false});\n }\n },\n });\n});\n","Amasty_Rewards/js/model/payment/reward-messages.js":"define([\n 'Magento_Ui/js/model/messages'\n], function (Messages) {\n 'use strict';\n\n return new Messages();\n});","Amasty_Rewards/js/model/catalog/highlight-product.js":"define([\n 'jquery',\n 'uiComponent',\n 'mage/translate',\n 'mage/storage',\n], function ($, Component, $t, storage) {\n 'use strict';\n var xhr = null;\n\n return Component.extend({\n defaults: {\n template: 'Amasty_Rewards/highlight',\n captionEndText: $t('for buying this product!'),\n captionStartText : $t('You can earn'),\n productId : 0,\n refreshUrl: false,\n loader: false,\n formSelector: '#product_addtocart_form',\n frontend_class: '',\n highlight: {\n visible: false\n }\n },\n\n initObservable: function () {\n this._super().observe(['highlight', 'loader']);\n this.updateData();\n $(this.formSelector).change(this.updateData.bind(this));\n\n return this;\n },\n\n hide: function () {\n this.highlight({'visible':false});\n\n return this;\n },\n\n updateData: function () {\n if (xhr) {\n xhr.abort();\n }\n this.hide().loader(true);\n\n xhr = storage.post(this.refreshUrl,\n JSON.stringify({\n productId: this.productId,\n attributes: $(this.formSelector).serialize()\n }),\n false\n ).done(function (result) {\n if (result) {\n this.highlight(result);\n }\n }.bind(this)).always(function () {\n this.loader(false);\n xhr = null;\n }.bind(this));\n },\n });\n});\n","Amasty_Rewards/js/model/catalog/highlight-category.js":"define([\n 'jquery',\n 'uiComponent',\n 'mage/translate',\n 'mage/storage',\n], function ($, Component, $t, storage) {\n 'use strict';\n var xhr = {};\n\n return Component.extend({\n defaults: {\n template: 'Amasty_Rewards/highlight-category',\n captionEndText: '',\n captionStartText: $t('Earn'),\n productId: 0,\n refreshUrl: false,\n loader: false,\n formSelector: false,\n frontend_class: '',\n highlight: {\n visible: false\n }\n },\n\n initObservable: function () {\n this._super().observe(['highlight', 'loader']);\n\n if (this.refreshUrl) {\n this.updateData();\n $(this.formSelector).change(this.updateData.bind(this));\n }\n\n return this;\n },\n\n hide: function () {\n this.highlight({'visible': false});\n\n return this;\n },\n\n updateData: function () {\n if (xhr.hasOwnProperty(this.productId)) {\n xhr[this.productId].abort();\n }\n this.hide().loader(true);\n\n xhr[this.productId] = storage.post(this.refreshUrl,\n JSON.stringify({\n productId: this.productId,\n attributes: $(this.formSelector).serialize()\n }),\n false\n ).done(function (result) {\n if (result) {\n this.highlight(result);\n }\n }.bind(this)).always(function () {\n this.loader(false);\n delete xhr[this.productId];\n }.bind(this));\n },\n });\n});\n","Amasty_Rewards/js/model/catalog/guest-highlight-category.js":"define([\n 'jquery',\n 'uiComponent',\n 'mage/translate',\n 'mage/storage',\n], function ($, Component, $t, storage) {\n 'use strict';\n var xhr = {};\n\n return Component.extend({\n defaults: {\n template: 'Amasty_Rewards/guest-highlight',\n captionStartText: $t('You can earn'),\n captionAfterText: '',\n captionRegistrationText: $t('for registration!'),\n captionEndText: '',\n productId: 0,\n refreshUrl: false,\n loader: false,\n formSelector: false,\n frontend_class: '',\n highlight: {\n visible: false\n }\n },\n\n initObservable: function () {\n this._super().observe([ 'highlight', 'loader' ]);\n\n if (this.refreshUrl) {\n this.updateData();\n $(this.formSelector).change(this.updateData.bind(this));\n }\n\n return this;\n },\n\n hide: function () {\n this.highlight({ 'visible': false });\n\n return this;\n },\n\n updateData: function () {\n if (xhr.hasOwnProperty(this.productId)) {\n xhr[this.productId].abort();\n }\n this.hide().loader(true);\n\n xhr[this.productId] = storage.post(this.refreshUrl,\n JSON.stringify({\n page: 3,\n productId: this.productId,\n attributes: $(this.formSelector).serialize()\n }),\n false\n ).done(function (result) {\n if (result) {\n if (result.need_to_change_message === 1) {\n this.captionAfterText = $t('for making a purchase! Available for');\n this.captionRegistrationText = $t('registered');\n this.captionEndText = $t('customers only.');\n }\n this.highlight(result);\n }\n }.bind(this)).always(function () {\n this.loader(false);\n delete xhr[this.productId];\n }.bind(this));\n }\n });\n});\n","Amasty_Rewards/js/model/catalog/guest-highlight-product.js":"define([\n 'jquery',\n 'uiComponent',\n 'mage/translate',\n 'mage/storage',\n], function ($, Component, $t, storage) {\n 'use strict';\n var xhr = null;\n\n return Component.extend({\n defaults: {\n template: 'Amasty_Rewards/guest-highlight',\n captionStartText: $t('You can earn'),\n captionAfterText: '',\n captionRegistrationText: $t('for registration!'),\n captionEndText: '',\n productId: 0,\n refreshUrl: false,\n loader: false,\n formSelector: '#product_addtocart_form',\n frontend_class: '',\n highlight: {\n visible: false\n }\n },\n\n initObservable: function () {\n this._super().observe([ 'highlight', 'loader' ]);\n this.updateData();\n $(this.formSelector).change(this.updateData.bind(this));\n\n return this;\n },\n\n hide: function () {\n this.highlight({ 'visible':false });\n\n return this;\n },\n\n updateData: function () {\n if (xhr) {\n xhr.abort();\n }\n this.hide().loader(true);\n\n xhr = storage.post(this.refreshUrl,\n JSON.stringify({\n page: 0,\n productId: this.productId,\n attributes: $(this.formSelector).serialize()\n }),\n false\n ).done(function (result) {\n if (result) {\n if (result.need_to_change_message === 1) {\n this.captionAfterText = $t('for making a purchase! Available for');\n this.captionRegistrationText = $t('registered');\n this.captionEndText = $t('customers only.');\n }\n this.highlight(result);\n }\n }.bind(this)).always(function () {\n this.loader(false);\n xhr = null;\n }.bind(this));\n }\n });\n});\n","Amasty_Rewards/vendor/tooltipster/js/tooltipster.js":"/**\n * tooltipster http://calebjacob.github.io/tooltipster/\n * A rockin' custom tooltip jQuery plugin\n * Developed by Caleb Jacob and Louis Ameline\n * MIT license\n */\n(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([\"jquery\"], function (a0) {\n return (factory(a0));\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like environments that support module.exports,\n // like Node.\n module.exports = factory(require(\"jquery\"));\n } else {\n factory(jQuery);\n }\n}(this, function ($) {\n\n// This file will be UMDified by a build task.\n\nvar defaults = {\n\t\tanimation: 'fade',\n\t\tanimationDuration: 350,\n\t\tcontent: null,\n\t\tcontentAsHTML: false,\n\t\tcontentCloning: false,\n\t\tdebug: true,\n\t\tdelay: 300,\n\t\tdelayTouch: [300, 500],\n\t\tfunctionInit: null,\n\t\tfunctionBefore: null,\n\t\tfunctionReady: null,\n\t\tfunctionAfter: null,\n\t\tfunctionFormat: null,\n\t\tIEmin: 6,\n\t\tinteractive: false,\n\t\tmultiple: false,\n\t\t// will default to document.body, or must be an element positioned at (0, 0)\n\t\t// in the document, typically like the very top views of an app.\n\t\tparent: null,\n\t\tplugins: ['sideTip'],\n\t\trepositionOnScroll: false,\n\t\trestoration: 'none',\n\t\tselfDestruction: true,\n\t\ttheme: [],\n\t\ttimer: 0,\n\t\ttrackerInterval: 500,\n\t\ttrackOrigin: false,\n\t\ttrackTooltip: false,\n\t\ttrigger: 'hover',\n\t\ttriggerClose: {\n\t\t\tclick: false,\n\t\t\tmouseleave: false,\n\t\t\toriginClick: false,\n\t\t\tscroll: false,\n\t\t\ttap: false,\n\t\t\ttouchleave: false\n\t\t},\n\t\ttriggerOpen: {\n\t\t\tclick: false,\n\t\t\tmouseenter: false,\n\t\t\ttap: false,\n\t\t\ttouchstart: false\n\t\t},\n\t\tupdateAnimation: 'rotate',\n\t\tzIndex: 9999999,\n styles: {\n backgroundColor: '',\n textColor: ''\n }\n\t},\n\t// we'll avoid using the 'window' global as a good practice but npm's\n\t// jquery@<2.1.0 package actually requires a 'window' global, so not sure\n\t// it's useful at all\n\twin = (typeof window != 'undefined') ? window : null,\n\t// env will be proxied by the core for plugins to have access its properties\n\tenv = {\n\t\t// detect if this device can trigger touch events. Better have a false\n\t\t// positive (unused listeners, that's ok) than a false negative.\n\t\t// https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js\n\t\t// http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript\n\t\thasTouchCapability: !!(\n\t\t\twin\n\t\t\t&&\t(\t'ontouchstart' in win\n\t\t\t\t||\t(win.DocumentTouch && win.document instanceof win.DocumentTouch)\n\t\t\t\t||\twin.navigator.maxTouchPoints\n\t\t\t)\n\t\t),\n\t\thasTransitions: transitionSupport(),\n\t\tIE: false,\n\t\t// don't set manually, it will be updated by a build task after the manifest\n\t\tsemVer: '4.2.8',\n\t\twindow: win\n\t},\n\tcore = function() {\n\n\t\t// core variables\n\n\t\t// the core emitters\n\t\tthis.__$emitterPrivate = $({});\n\t\tthis.__$emitterPublic = $({});\n\t\tthis.__instancesLatestArr = [];\n\t\t// collects plugin constructors\n\t\tthis.__plugins = {};\n\t\t// proxy env variables for plugins who might use them\n\t\tthis._env = env;\n\t};\n\n// core methods\ncore.prototype = {\n\n\t/**\n\t * A function to proxy the public methods of an object onto another\n\t *\n\t * @param {object} constructor The constructor to bridge\n\t * @param {object} obj The object that will get new methods (an instance or the core)\n\t * @param {string} pluginName A plugin name for the console log message\n\t * @return {core}\n\t * @private\n\t */\n\t__bridge: function(constructor, obj, pluginName) {\n\n\t\t// if it's not already bridged\n\t\tif (!obj[pluginName]) {\n\n\t\t\tvar fn = function() {};\n\t\t\tfn.prototype = constructor;\n\n\t\t\tvar pluginInstance = new fn();\n\n\t\t\t// the _init method has to exist in instance constructors but might be missing\n\t\t\t// in core constructors\n\t\t\tif (pluginInstance.__init) {\n\t\t\t\tpluginInstance.__init(obj);\n\t\t\t}\n\n\t\t\t$.each(constructor, function(methodName, fn) {\n\n\t\t\t\t// don't proxy \"private\" methods, only \"protected\" and public ones\n\t\t\t\tif (methodName.indexOf('__') != 0) {\n\n\t\t\t\t\t// if the method does not exist yet\n\t\t\t\t\tif (!obj[methodName]) {\n\n\t\t\t\t\t\tobj[methodName] = function() {\n\t\t\t\t\t\t\treturn pluginInstance[methodName].apply(pluginInstance, Array.prototype.slice.apply(arguments));\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// remember to which plugin this method corresponds (several plugins may\n\t\t\t\t\t\t// have methods of the same name, we need to be sure)\n\t\t\t\t\t\tobj[methodName].bridged = pluginInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if (defaults.debug) {\n\n\t\t\t\t\t\tconsole.log('The '+ methodName +' method of the '+ pluginName\n\t\t\t\t\t\t\t+' plugin conflicts with another plugin or native methods');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tobj[pluginName] = pluginInstance;\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * For mockup in Node env if need be, for testing purposes\n\t *\n\t * @return {core}\n\t * @private\n\t */\n\t__setWindow: function(window) {\n\t\tenv.window = window;\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns a ruler, a tool to help measure the size of a tooltip under\n\t * various settings. Meant for plugins\n\t *\n\t * @see Ruler\n\t * @return {object} A Ruler instance\n\t * @protected\n\t */\n\t_getRuler: function($tooltip) {\n\t\treturn new Ruler($tooltip);\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @return {core}\n\t * @protected\n\t */\n\t_off: function() {\n\t\tthis.__$emitterPrivate.off.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @return {core}\n\t * @protected\n\t */\n\t_on: function() {\n\t\tthis.__$emitterPrivate.on.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @return {core}\n\t * @protected\n\t */\n\t_one: function() {\n\t\tthis.__$emitterPrivate.one.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns (getter) or adds (setter) a plugin\n\t *\n\t * @param {string|object} plugin Provide a string (in the full form\n\t * \"namespace.name\") to use as as getter, an object to use as a setter\n\t * @return {object|core}\n\t * @protected\n\t */\n\t_plugin: function(plugin) {\n\n\t\tvar self = this;\n\n\t\t// getter\n\t\tif (typeof plugin == 'string') {\n\n\t\t\tvar pluginName = plugin,\n\t\t\t\tp = null;\n\n\t\t\t// if the namespace is provided, it's easy to search\n\t\t\tif (pluginName.indexOf('.') > 0) {\n\t\t\t\tp = self.__plugins[pluginName];\n\t\t\t}\n\t\t\t// otherwise, return the first name that matches\n\t\t\telse {\n\t\t\t\t$.each(self.__plugins, function(i, plugin) {\n\n\t\t\t\t\tif (plugin.name.substring(plugin.name.length - pluginName.length - 1) == '.'+ pluginName) {\n\t\t\t\t\t\tp = plugin;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn p;\n\t\t}\n\t\t// setter\n\t\telse {\n\n\t\t\t// force namespaces\n\t\t\tif (plugin.name.indexOf('.') < 0) {\n\t\t\t\tthrow new Error('Plugins must be namespaced');\n\t\t\t}\n\n\t\t\tself.__plugins[plugin.name] = plugin;\n\n\t\t\t// if the plugin has core features\n\t\t\tif (plugin.core) {\n\n\t\t\t\t// bridge non-private methods onto the core to allow new core methods\n\t\t\t\tself.__bridge(plugin.core, self, plugin.name);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t},\n\n\t/**\n\t * Trigger events on the core emitters\n\t *\n\t * @returns {core}\n\t * @protected\n\t */\n\t_trigger: function() {\n\n\t\tvar args = Array.prototype.slice.apply(arguments);\n\n\t\tif (typeof args[0] == 'string') {\n\t\t\targs[0] = { type: args[0] };\n\t\t}\n\n\t\t// note: the order of emitters matters\n\t\tthis.__$emitterPrivate.trigger.apply(this.__$emitterPrivate, args);\n\t\tthis.__$emitterPublic.trigger.apply(this.__$emitterPublic, args);\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns instances of all tooltips in the page or an a given element\n\t *\n\t * @param {string|HTML object collection} selector optional Use this\n\t * parameter to restrict the set of objects that will be inspected\n\t * for the retrieval of instances. By default, all instances in the\n\t * page are returned.\n\t * @return {array} An array of instance objects\n\t * @public\n\t */\n\tinstances: function(selector) {\n\n\t\tvar instances = [],\n\t\t\tsel = selector || '.tooltipstered';\n\n\t\t$(sel).each(function() {\n\n\t\t\tvar $this = $(this),\n\t\t\t\tns = $this.data('tooltipster-ns');\n\n\t\t\tif (ns) {\n\n\t\t\t\t$.each(ns, function(i, namespace) {\n\t\t\t\t\tinstances.push($this.data(namespace));\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\treturn instances;\n\t},\n\n\t/**\n\t * Returns the Tooltipster objects generated by the last initializing call\n\t *\n\t * @return {array} An array of instance objects\n\t * @public\n\t */\n\tinstancesLatest: function() {\n\t\treturn this.__instancesLatestArr;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins (use ::_off() instead)\n\t *\n\t * @return {core}\n\t * @public\n\t */\n\toff: function() {\n\t\tthis.__$emitterPublic.off.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins (use ::_on() instead)\n\t *\n\t * @return {core}\n\t * @public\n\t */\n\ton: function() {\n\t\tthis.__$emitterPublic.on.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins (use ::_one() instead)\n\t *\n\t * @return {core}\n\t * @public\n\t */\n\tone: function() {\n\t\tthis.__$emitterPublic.one.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns all HTML elements which have one or more tooltips\n\t *\n\t * @param {string} selector optional Use this to restrict the results\n\t * to the descendants of an element\n\t * @return {array} An array of HTML elements\n\t * @public\n\t */\n\torigins: function(selector) {\n\n\t\tvar sel = selector ?\n\t\t\tselector +' ' :\n\t\t\t'';\n\n\t\treturn $(sel +'.tooltipstered').toArray();\n\t},\n\n\t/**\n\t * Change default options for all future instances\n\t *\n\t * @param {object} d The options that should be made defaults\n\t * @return {core}\n\t * @public\n\t */\n\tsetDefaults: function(d) {\n\t\t$.extend(defaults, d);\n\t\treturn this;\n\t},\n\n\t/**\n\t * For users to trigger their handlers on the public emitter\n\t *\n\t * @returns {core}\n\t * @public\n\t */\n\ttriggerHandler: function() {\n\t\tthis.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t}\n};\n\n// $.tooltipster will be used to call core methods\n$.tooltipster = new core();\n\n// the Tooltipster instance class (mind the capital T)\n$.Tooltipster = function(element, options) {\n\n\t// list of instance variables\n\n\t// stack of custom callbacks provided as parameters to API methods\n\tthis.__callbacks = {\n\t\tclose: [],\n\t\topen: []\n\t};\n\t// the schedule time of DOM removal\n\tthis.__closingTime;\n\t// this will be the user content shown in the tooltip. A capital \"C\" is used\n\t// because there is also a method called content()\n\tthis.__Content;\n\t// for the size tracker\n\tthis.__contentBcr;\n\t// to disable the tooltip after destruction\n\tthis.__destroyed = false;\n\t// we can't emit directly on the instance because if a method with the same\n\t// name as the event exists, it will be called by jQuery. Se we use a plain\n\t// object as emitter. This emitter is for internal use by plugins,\n\t// if needed.\n\tthis.__$emitterPrivate = $({});\n\t// this emitter is for the user to listen to events without risking to mess\n\t// with our internal listeners\n\tthis.__$emitterPublic = $({});\n\tthis.__enabled = true;\n\t// the reference to the gc interval\n\tthis.__garbageCollector;\n\t// various position and size data recomputed before each repositioning\n\tthis.__Geometry;\n\t// the tooltip position, saved after each repositioning by a plugin\n\tthis.__lastPosition;\n\t// a unique namespace per instance\n\tthis.__namespace = 'tooltipster-'+ Math.round(Math.random()*1000000);\n\tthis.__options;\n\t// will be used to support origins in scrollable areas\n\tthis.__$originParents;\n\tthis.__pointerIsOverOrigin = false;\n\t// to remove themes if needed\n\tthis.__previousThemes = [];\n\t// the state can be either: appearing, stable, disappearing, closed\n\tthis.__state = 'closed';\n\t// timeout references\n\tthis.__timeouts = {\n\t\tclose: [],\n\t\topen: null\n\t};\n\t// store touch events to be able to detect emulated mouse events\n\tthis.__touchEvents = [];\n\t// the reference to the tracker interval\n\tthis.__tracker = null;\n\t// the element to which this tooltip is associated\n\tthis._$origin;\n\t// this will be the tooltip element (jQuery wrapped HTML element).\n\t// It's the job of a plugin to create it and append it to the DOM\n\tthis._$tooltip;\n\n\t// launch\n\tthis.__init(element, options);\n};\n\n$.Tooltipster.prototype = {\n\n\t/**\n\t * @param origin\n\t * @param options\n\t * @private\n\t */\n\t__init: function(origin, options) {\n\n\t\tvar self = this;\n\n\t\tself._$origin = $(origin);\n\t\tself.__options = $.extend(true, {}, defaults, options);\n\n\t\t// some options may need to be reformatted\n\t\tself.__optionsFormat();\n\n\t\t// don't run on old IE if asked no to\n\t\tif (\t!env.IE\n\t\t\t||\tenv.IE >= self.__options.IEmin\n\t\t) {\n\n\t\t\t// note: the content is null (empty) by default and can stay that\n\t\t\t// way if the plugin remains initialized but not fed any content. The\n\t\t\t// tooltip will just not appear.\n\n\t\t\t// let's save the initial value of the title attribute for later\n\t\t\t// restoration if need be.\n\t\t\tvar initialTitle = null;\n\n\t\t\t// it will already have been saved in case of multiple tooltips\n\t\t\tif (self._$origin.data('tooltipster-initialTitle') === undefined) {\n\n\t\t\t\tinitialTitle = self._$origin.attr('title');\n\n\t\t\t\t// we do not want initialTitle to be \"undefined\" because\n\t\t\t\t// of how jQuery's .data() method works\n\t\t\t\tif (initialTitle === undefined) initialTitle = null;\n\n\t\t\t\tself._$origin.data('tooltipster-initialTitle', initialTitle);\n\t\t\t}\n\n\t\t\t// If content is provided in the options, it has precedence over the\n\t\t\t// title attribute.\n\t\t\t// Note: an empty string is considered content, only 'null' represents\n\t\t\t// the absence of content.\n\t\t\t// Also, an existing title=\"\" attribute will result in an empty string\n\t\t\t// content\n\t\t\tif (self.__options.content !== null) {\n\t\t\t\tself.__contentSet(self.__options.content);\n\t\t\t}\n\t\t\telse {\n\n\t\t\t\tvar selector = self._$origin.attr('data-tooltip-content'),\n\t\t\t\t\t$el;\n\n\t\t\t\tif (selector){\n\t\t\t\t\t$el = $(selector);\n\t\t\t\t}\n\n\t\t\t\tif ($el && $el[0]) {\n\t\t\t\t\tself.__contentSet($el.first());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tself.__contentSet(initialTitle);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tself._$origin\n\t\t\t\t// strip the title off of the element to prevent the default tooltips\n\t\t\t\t// from popping up\n\t\t\t\t.removeAttr('title')\n\t\t\t\t// to be able to find all instances on the page later (upon window\n\t\t\t\t// events in particular)\n\t\t\t\t.addClass('tooltipstered');\n\n\t\t\t// set listeners on the origin\n\t\t\tself.__prepareOrigin();\n\n\t\t\t// set the garbage collector\n\t\t\tself.__prepareGC();\n\n\t\t\t// init plugins\n\t\t\t$.each(self.__options.plugins, function(i, pluginName) {\n\t\t\t\tself._plug(pluginName);\n\t\t\t});\n\n\t\t\t// to detect swiping\n\t\t\tif (env.hasTouchCapability) {\n\t\t\t\t$(env.window.document.body).on('touchmove.'+ self.__namespace +'-triggerOpen', function(event) {\n\t\t\t\t\tself._touchRecordEvent(event);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tself\n\t\t\t\t// prepare the tooltip when it gets created. This event must\n\t\t\t\t// be fired by a plugin\n\t\t\t\t._on('created', function() {\n\t\t\t\t\tself.__prepareTooltip();\n\t\t\t\t})\n\t\t\t\t// save position information when it's sent by a plugin\n\t\t\t\t._on('repositioned', function(e) {\n\t\t\t\t\tself.__lastPosition = e.position;\n\t\t\t\t});\n\t\t}\n\t\telse {\n\t\t\tself.__options.disabled = true;\n\t\t}\n\t},\n\n\t/**\n\t * Insert the content into the appropriate HTML element of the tooltip\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__contentInsert: function() {\n\n\t\tvar self = this,\n\t\t\t$el = self._$tooltip.find('.tooltipster-content'),\n\t\t\tformattedContent = self.__Content,\n\t\t\tformat = function(content) {\n\t\t\t\tformattedContent = content;\n\t\t\t};\n\n\t\tself._trigger({\n\t\t\ttype: 'format',\n\t\t\tcontent: self.__Content,\n\t\t\tformat: format\n\t\t});\n\n\t\tif (self.__options.functionFormat) {\n\n\t\t\tformattedContent = self.__options.functionFormat.call(\n\t\t\t\tself,\n\t\t\t\tself,\n\t\t\t\t{ origin: self._$origin[0] },\n\t\t\t\tself.__Content\n\t\t\t);\n\t\t}\n\n\t\tif (typeof formattedContent === 'string' && !self.__options.contentAsHTML) {\n\t\t\t$el.text(formattedContent);\n\t\t}\n\t\telse {\n\t\t\t$el\n\t\t\t\t.empty()\n\t\t\t\t.append(formattedContent);\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Save the content, cloning it beforehand if need be\n\t *\n\t * @param content\n\t * @returns {self}\n\t * @private\n\t */\n\t__contentSet: function(content) {\n\n\t\t// clone if asked. Cloning the object makes sure that each instance has its\n\t\t// own version of the content (in case a same object were provided for several\n\t\t// instances)\n\t\t// reminder: typeof null === object\n\t\tif (content instanceof $ && this.__options.contentCloning) {\n\t\t\tcontent = content.clone(true);\n\t\t}\n\n\t\tthis.__Content = content;\n\n\t\tthis._trigger({\n\t\t\ttype: 'updated',\n\t\t\tcontent: content\n\t\t});\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Error message about a method call made after destruction\n\t *\n\t * @private\n\t */\n\t__destroyError: function() {\n\t\tthrow new Error('This tooltip has been destroyed and cannot execute your method call.');\n\t},\n\n\t/**\n\t * Gather all information about dimensions and available space,\n\t * called before every repositioning\n\t *\n\t * @private\n\t * @returns {object}\n\t */\n\t__geometry: function() {\n\n\t\tvar\tself = this,\n\t\t\t$target = self._$origin,\n\t\t\toriginIsArea = self._$origin.is('area');\n\n\t\t// if this._$origin is a map area, the target we'll need\n\t\t// the dimensions of is actually the image using the map,\n\t\t// not the area itself\n\t\tif (originIsArea) {\n\n\t\t\tvar mapName = self._$origin.parent().attr('name');\n\n\t\t\t$target = $('img[usemap=\"#'+ mapName +'\"]');\n\t\t}\n\n\t\tvar bcr = $target[0].getBoundingClientRect(),\n\t\t\t$document = $(env.window.document),\n\t\t\t$window = $(env.window),\n\t\t\t$parent = $target,\n\t\t\t// some useful properties of important elements\n\t\t\tgeo = {\n\t\t\t\t// available space for the tooltip, see down below\n\t\t\t\tavailable: {\n\t\t\t\t\tdocument: null,\n\t\t\t\t\twindow: null\n\t\t\t\t},\n\t\t\t\tdocument: {\n\t\t\t\t\tsize: {\n\t\t\t\t\t\theight: $document.height(),\n\t\t\t\t\t\twidth: $document.width()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\twindow: {\n\t\t\t\t\tscroll: {\n\t\t\t\t\t\t// the second ones are for IE compatibility\n\t\t\t\t\t\tleft: env.window.scrollX || env.window.document.documentElement.scrollLeft,\n\t\t\t\t\t\ttop: env.window.scrollY || env.window.document.documentElement.scrollTop\n\t\t\t\t\t},\n\t\t\t\t\tsize: {\n\t\t\t\t\t\theight: $window.height(),\n\t\t\t\t\t\twidth: $window.width()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\torigin: {\n\t\t\t\t\t// the origin has a fixed lineage if itself or one of its\n\t\t\t\t\t// ancestors has a fixed position\n\t\t\t\t\tfixedLineage: false,\n\t\t\t\t\t// relative to the document\n\t\t\t\t\toffset: {},\n\t\t\t\t\tsize: {\n\t\t\t\t\t\theight: bcr.bottom - bcr.top,\n\t\t\t\t\t\twidth: bcr.right - bcr.left\n\t\t\t\t\t},\n\t\t\t\t\tusemapImage: originIsArea ? $target[0] : null,\n\t\t\t\t\t// relative to the window\n\t\t\t\t\twindowOffset: {\n\t\t\t\t\t\tbottom: bcr.bottom,\n\t\t\t\t\t\tleft: bcr.left,\n\t\t\t\t\t\tright: bcr.right,\n\t\t\t\t\t\ttop: bcr.top\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tgeoFixed = false;\n\n\t\t// if the element is a map area, some properties may need\n\t\t// to be recalculated\n\t\tif (originIsArea) {\n\n\t\t\tvar shape = self._$origin.attr('shape'),\n\t\t\t\tcoords = self._$origin.attr('coords');\n\n\t\t\tif (coords) {\n\n\t\t\t\tcoords = coords.split(',');\n\n\t\t\t\t$.map(coords, function(val, i) {\n\t\t\t\t\tcoords[i] = parseInt(val);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// if the image itself is the area, nothing more to do\n\t\t\tif (shape != 'default') {\n\n\t\t\t\tswitch(shape) {\n\n\t\t\t\t\tcase 'circle':\n\n\t\t\t\t\t\tvar circleCenterLeft = coords[0],\n\t\t\t\t\t\t\tcircleCenterTop = coords[1],\n\t\t\t\t\t\t\tcircleRadius = coords[2],\n\t\t\t\t\t\t\tareaTopOffset = circleCenterTop - circleRadius,\n\t\t\t\t\t\t\tareaLeftOffset = circleCenterLeft - circleRadius;\n\n\t\t\t\t\t\tgeo.origin.size.height = circleRadius * 2;\n\t\t\t\t\t\tgeo.origin.size.width = geo.origin.size.height;\n\n\t\t\t\t\t\tgeo.origin.windowOffset.left += areaLeftOffset;\n\t\t\t\t\t\tgeo.origin.windowOffset.top += areaTopOffset;\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'rect':\n\n\t\t\t\t\t\tvar areaLeft = coords[0],\n\t\t\t\t\t\t\tareaTop = coords[1],\n\t\t\t\t\t\t\tareaRight = coords[2],\n\t\t\t\t\t\t\tareaBottom = coords[3];\n\n\t\t\t\t\t\tgeo.origin.size.height = areaBottom - areaTop;\n\t\t\t\t\t\tgeo.origin.size.width = areaRight - areaLeft;\n\n\t\t\t\t\t\tgeo.origin.windowOffset.left += areaLeft;\n\t\t\t\t\t\tgeo.origin.windowOffset.top += areaTop;\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'poly':\n\n\t\t\t\t\t\tvar areaSmallestX = 0,\n\t\t\t\t\t\t\tareaSmallestY = 0,\n\t\t\t\t\t\t\tareaGreatestX = 0,\n\t\t\t\t\t\t\tareaGreatestY = 0,\n\t\t\t\t\t\t\tarrayAlternate = 'even';\n\n\t\t\t\t\t\tfor (var i = 0; i < coords.length; i++) {\n\n\t\t\t\t\t\t\tvar areaNumber = coords[i];\n\n\t\t\t\t\t\t\tif (arrayAlternate == 'even') {\n\n\t\t\t\t\t\t\t\tif (areaNumber > areaGreatestX) {\n\n\t\t\t\t\t\t\t\t\tareaGreatestX = areaNumber;\n\n\t\t\t\t\t\t\t\t\tif (i === 0) {\n\t\t\t\t\t\t\t\t\t\tareaSmallestX = areaGreatestX;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (areaNumber < areaSmallestX) {\n\t\t\t\t\t\t\t\t\tareaSmallestX = areaNumber;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tarrayAlternate = 'odd';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tif (areaNumber > areaGreatestY) {\n\n\t\t\t\t\t\t\t\t\tareaGreatestY = areaNumber;\n\n\t\t\t\t\t\t\t\t\tif (i == 1) {\n\t\t\t\t\t\t\t\t\t\tareaSmallestY = areaGreatestY;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (areaNumber < areaSmallestY) {\n\t\t\t\t\t\t\t\t\tareaSmallestY = areaNumber;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tarrayAlternate = 'even';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgeo.origin.size.height = areaGreatestY - areaSmallestY;\n\t\t\t\t\t\tgeo.origin.size.width = areaGreatestX - areaSmallestX;\n\n\t\t\t\t\t\tgeo.origin.windowOffset.left += areaSmallestX;\n\t\t\t\t\t\tgeo.origin.windowOffset.top += areaSmallestY;\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// user callback through an event\n\t\tvar edit = function(r) {\n\t\t\tgeo.origin.size.height = r.height,\n\t\t\t\tgeo.origin.windowOffset.left = r.left,\n\t\t\t\tgeo.origin.windowOffset.top = r.top,\n\t\t\t\tgeo.origin.size.width = r.width\n\t\t};\n\n\t\tself._trigger({\n\t\t\ttype: 'geometry',\n\t\t\tedit: edit,\n\t\t\tgeometry: {\n\t\t\t\theight: geo.origin.size.height,\n\t\t\t\tleft: geo.origin.windowOffset.left,\n\t\t\t\ttop: geo.origin.windowOffset.top,\n\t\t\t\twidth: geo.origin.size.width\n\t\t\t}\n\t\t});\n\n\t\t// calculate the remaining properties with what we got\n\n\t\tgeo.origin.windowOffset.right = geo.origin.windowOffset.left + geo.origin.size.width;\n\t\tgeo.origin.windowOffset.bottom = geo.origin.windowOffset.top + geo.origin.size.height;\n\n\t\tgeo.origin.offset.left = geo.origin.windowOffset.left + geo.window.scroll.left;\n\t\tgeo.origin.offset.top = geo.origin.windowOffset.top + geo.window.scroll.top;\n\t\tgeo.origin.offset.bottom = geo.origin.offset.top + geo.origin.size.height;\n\t\tgeo.origin.offset.right = geo.origin.offset.left + geo.origin.size.width;\n\n\t\t// the space that is available to display the tooltip relatively to the document\n\t\tgeo.available.document = {\n\t\t\tbottom: {\n\t\t\t\theight: geo.document.size.height - geo.origin.offset.bottom,\n\t\t\t\twidth: geo.document.size.width\n\t\t\t},\n\t\t\tleft: {\n\t\t\t\theight: geo.document.size.height,\n\t\t\t\twidth: geo.origin.offset.left\n\t\t\t},\n\t\t\tright: {\n\t\t\t\theight: geo.document.size.height,\n\t\t\t\twidth: geo.document.size.width - geo.origin.offset.right\n\t\t\t},\n\t\t\ttop: {\n\t\t\t\theight: geo.origin.offset.top,\n\t\t\t\twidth: geo.document.size.width\n\t\t\t}\n\t\t};\n\n\t\t// the space that is available to display the tooltip relatively to the viewport\n\t\t// (the resulting values may be negative if the origin overflows the viewport)\n\t\tgeo.available.window = {\n\t\t\tbottom: {\n\t\t\t\t// the inner max is here to make sure the available height is no bigger\n\t\t\t\t// than the viewport height (when the origin is off screen at the top).\n\t\t\t\t// The outer max just makes sure that the height is not negative (when\n\t\t\t\t// the origin overflows at the bottom).\n\t\t\t\theight: Math.max(geo.window.size.height - Math.max(geo.origin.windowOffset.bottom, 0), 0),\n\t\t\t\twidth: geo.window.size.width\n\t\t\t},\n\t\t\tleft: {\n\t\t\t\theight: geo.window.size.height,\n\t\t\t\twidth: Math.max(geo.origin.windowOffset.left, 0)\n\t\t\t},\n\t\t\tright: {\n\t\t\t\theight: geo.window.size.height,\n\t\t\t\twidth: Math.max(geo.window.size.width - Math.max(geo.origin.windowOffset.right, 0), 0)\n\t\t\t},\n\t\t\ttop: {\n\t\t\t\theight: Math.max(geo.origin.windowOffset.top, 0),\n\t\t\t\twidth: geo.window.size.width\n\t\t\t}\n\t\t};\n\n\t\twhile ($parent[0].tagName.toLowerCase() != 'html') {\n\n\t\t\tif ($parent.css('position') == 'fixed') {\n\t\t\t\tgeo.origin.fixedLineage = true;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$parent = $parent.parent();\n\t\t}\n\n\t\treturn geo;\n\t},\n\n\t/**\n\t * Some options may need to be formated before being used\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__optionsFormat: function() {\n\n\t\tif (typeof this.__options.animationDuration == 'number') {\n\t\t\tthis.__options.animationDuration = [this.__options.animationDuration, this.__options.animationDuration];\n\t\t}\n\n\t\tif (typeof this.__options.delay == 'number') {\n\t\t\tthis.__options.delay = [this.__options.delay, this.__options.delay];\n\t\t}\n\n\t\tif (typeof this.__options.delayTouch == 'number') {\n\t\t\tthis.__options.delayTouch = [this.__options.delayTouch, this.__options.delayTouch];\n\t\t}\n\n\t\tif (typeof this.__options.theme == 'string') {\n\t\t\tthis.__options.theme = [this.__options.theme];\n\t\t}\n\n\t\t// determine the future parent\n\t\tif (this.__options.parent === null) {\n\t\t\tthis.__options.parent = $(env.window.document.body);\n\t\t}\n\t\telse if (typeof this.__options.parent == 'string') {\n\t\t\tthis.__options.parent = $(this.__options.parent);\n\t\t}\n\n\t\tif (this.__options.trigger == 'hover') {\n\n\t\t\tthis.__options.triggerOpen = {\n\t\t\t\tmouseenter: true,\n\t\t\t\ttouchstart: true\n\t\t\t};\n\n\t\t\tthis.__options.triggerClose = {\n\t\t\t\tmouseleave: true,\n\t\t\t\toriginClick: true,\n\t\t\t\ttouchleave: true\n\t\t\t};\n\t\t}\n\t\telse if (this.__options.trigger == 'click') {\n\n\t\t\tthis.__options.triggerOpen = {\n\t\t\t\tclick: true,\n\t\t\t\ttap: true\n\t\t\t};\n\n\t\t\tthis.__options.triggerClose = {\n\t\t\t\tclick: true,\n\t\t\t\ttap: true\n\t\t\t};\n\t\t}\n\n\t\t// for the plugins\n\t\tthis._trigger('options');\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Schedules or cancels the garbage collector task\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__prepareGC: function() {\n\n\t\tvar self = this;\n\n\t\t// in case the selfDestruction option has been changed by a method call\n\t\tif (self.__options.selfDestruction) {\n\n\t\t\t// the GC task\n\t\t\tself.__garbageCollector = setInterval(function() {\n\n\t\t\t\tvar now = new Date().getTime();\n\n\t\t\t\t// forget the old events\n\t\t\t\tself.__touchEvents = $.grep(self.__touchEvents, function(event, i) {\n\t\t\t\t\t// 1 minute\n\t\t\t\t\treturn now - event.time > 60000;\n\t\t\t\t});\n\n\t\t\t\t// auto-destruct if the origin is gone\n\t\t\t\tif (!bodyContains(self._$origin)) {\n\n\t\t\t\t\tself.close(function(){\n\t\t\t\t\t\tself.destroy();\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}, 20000);\n\t\t}\n\t\telse {\n\t\t\tclearInterval(self.__garbageCollector);\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Sets listeners on the origin if the open triggers require them.\n\t * Unlike the listeners set at opening time, these ones\n\t * remain even when the tooltip is closed. It has been made a\n\t * separate method so it can be called when the triggers are\n\t * changed in the options. Closing is handled in _open()\n\t * because of the bindings that may be needed on the tooltip\n\t * itself\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__prepareOrigin: function() {\n\n\t\tvar self = this;\n\n\t\t// in case we're resetting the triggers\n\t\tself._$origin.off('.'+ self.__namespace +'-triggerOpen');\n\n\t\t// if the device is touch capable, even if only mouse triggers\n\t\t// are asked, we need to listen to touch events to know if the mouse\n\t\t// events are actually emulated (so we can ignore them)\n\t\tif (env.hasTouchCapability) {\n\n\t\t\tself._$origin.on(\n\t\t\t\t'touchstart.'+ self.__namespace +'-triggerOpen ' +\n\t\t\t\t'touchend.'+ self.__namespace +'-triggerOpen ' +\n\t\t\t\t'touchcancel.'+ self.__namespace +'-triggerOpen',\n\t\t\t\tfunction(event){\n\t\t\t\t\tself._touchRecordEvent(event);\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\t// mouse click and touch tap work the same way\n\t\tif (\tself.__options.triggerOpen.click\n\t\t\t||\t(self.__options.triggerOpen.tap && env.hasTouchCapability)\n\t\t) {\n\n\t\t\tvar eventNames = '';\n\t\t\tif (self.__options.triggerOpen.click) {\n\t\t\t\teventNames += 'click.'+ self.__namespace +'-triggerOpen ';\n\t\t\t}\n\t\t\tif (self.__options.triggerOpen.tap && env.hasTouchCapability) {\n\t\t\t\teventNames += 'touchend.'+ self.__namespace +'-triggerOpen';\n\t\t\t}\n\n\t\t\tself._$origin.on(eventNames, function(event) {\n\t\t\t\tif (self._touchIsMeaningfulEvent(event)) {\n\t\t\t\t\tself._open(event);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// mouseenter and touch start work the same way\n\t\tif (\tself.__options.triggerOpen.mouseenter\n\t\t\t||\t(self.__options.triggerOpen.touchstart && env.hasTouchCapability)\n\t\t) {\n\n\t\t\tvar eventNames = '';\n\t\t\tif (self.__options.triggerOpen.mouseenter) {\n\t\t\t\teventNames += 'mouseenter.'+ self.__namespace +'-triggerOpen ';\n\t\t\t}\n\t\t\tif (self.__options.triggerOpen.touchstart && env.hasTouchCapability) {\n\t\t\t\teventNames += 'touchstart.'+ self.__namespace +'-triggerOpen';\n\t\t\t}\n\n\t\t\tself._$origin.on(eventNames, function(event) {\n\t\t\t\tif (\tself._touchIsTouchEvent(event)\n\t\t\t\t\t||\t!self._touchIsEmulatedEvent(event)\n\t\t\t\t) {\n\t\t\t\t\tself.__pointerIsOverOrigin = true;\n\t\t\t\t\tself._openShortly(event);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// info for the mouseleave/touchleave close triggers when they use a delay\n\t\tif (\tself.__options.triggerClose.mouseleave\n\t\t\t||\t(self.__options.triggerClose.touchleave && env.hasTouchCapability)\n\t\t) {\n\n\t\t\tvar eventNames = '';\n\t\t\tif (self.__options.triggerClose.mouseleave) {\n\t\t\t\teventNames += 'mouseleave.'+ self.__namespace +'-triggerOpen ';\n\t\t\t}\n\t\t\tif (self.__options.triggerClose.touchleave && env.hasTouchCapability) {\n\t\t\t\teventNames += 'touchend.'+ self.__namespace +'-triggerOpen touchcancel.'+ self.__namespace +'-triggerOpen';\n\t\t\t}\n\n\t\t\tself._$origin.on(eventNames, function(event) {\n\n\t\t\t\tif (self._touchIsMeaningfulEvent(event)) {\n\t\t\t\t\tself.__pointerIsOverOrigin = false;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Do the things that need to be done only once after the tooltip\n\t * HTML element it has been created. It has been made a separate\n\t * method so it can be called when options are changed. Remember\n\t * that the tooltip may actually exist in the DOM before it is\n\t * opened, and present after it has been closed: it's the display\n\t * plugin that takes care of handling it.\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__prepareTooltip: function() {\n\n\t\tvar self = this,\n\t\t\tp = self.__options.interactive ? 'auto' : '';\n\n\t\t// this will be useful to know quickly if the tooltip is in\n\t\t// the DOM or not\n\t\tself._$tooltip\n\t\t\t.attr('id', self.__namespace)\n\t\t\t.css({\n\t\t\t\t// pointer events\n\t\t\t\t'pointer-events': p,\n\t\t\t\tzIndex: self.__options.zIndex\n\t\t\t});\n\n\t\t// themes\n\t\t// remove the old ones and add the new ones\n\t\t$.each(self.__previousThemes, function(i, theme) {\n\t\t\tself._$tooltip.removeClass(theme);\n\t\t});\n\t\t$.each(self.__options.theme, function(i, theme) {\n\t\t\tself._$tooltip.addClass(theme);\n\t\t});\n\n\t\tself.__previousThemes = $.merge([], self.__options.theme);\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Handles the scroll on any of the parents of the origin (when the\n\t * tooltip is open)\n\t *\n\t * @param {object} event\n\t * @returns {self}\n\t * @private\n\t */\n\t__scrollHandler: function(event) {\n\n\t\tvar self = this;\n\n\t\tif (self.__options.triggerClose.scroll) {\n\t\t\tself._close(event);\n\t\t}\n\t\telse {\n\n\t\t\t// if the origin or tooltip have been removed: do nothing, the tracker will\n\t\t\t// take care of it later\n\t\t\tif (bodyContains(self._$origin) && bodyContains(self._$tooltip)) {\n\n\t\t\t\tvar geo = null;\n\n\t\t\t\t// if the scroll happened on the window\n\t\t\t\tif (event.target === env.window.document) {\n\n\t\t\t\t\t// if the origin has a fixed lineage, window scroll will have no\n\t\t\t\t\t// effect on its position nor on the position of the tooltip\n\t\t\t\t\tif (!self.__Geometry.origin.fixedLineage) {\n\n\t\t\t\t\t\t// we don't need to do anything unless repositionOnScroll is true\n\t\t\t\t\t\t// because the tooltip will already have moved with the window\n\t\t\t\t\t\t// (and of course with the origin)\n\t\t\t\t\t\tif (self.__options.repositionOnScroll) {\n\t\t\t\t\t\t\tself.reposition(event);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// if the scroll happened on another parent of the tooltip, it means\n\t\t\t\t// that it's in a scrollable area and now needs to have its position\n\t\t\t\t// adjusted or recomputed, depending ont the repositionOnScroll\n\t\t\t\t// option. Also, if the origin is partly hidden due to a parent that\n\t\t\t\t// hides its overflow, we'll just hide (not close) the tooltip.\n\t\t\t\telse {\n\n\t\t\t\t\tgeo = self.__geometry();\n\n\t\t\t\t\tvar overflows = false;\n\n\t\t\t\t\t// a fixed position origin is not affected by the overflow hiding\n\t\t\t\t\t// of a parent\n\t\t\t\t\tif (self._$origin.css('position') != 'fixed') {\n\n\t\t\t\t\t\tself.__$originParents.each(function(i, el) {\n\n\t\t\t\t\t\t\tvar $el = $(el),\n\t\t\t\t\t\t\t\toverflowX = $el.css('overflow-x'),\n\t\t\t\t\t\t\t\toverflowY = $el.css('overflow-y');\n\n\t\t\t\t\t\t\tif (overflowX != 'visible' || overflowY != 'visible') {\n\n\t\t\t\t\t\t\t\tvar bcr = el.getBoundingClientRect();\n\n\t\t\t\t\t\t\t\tif (overflowX != 'visible') {\n\n\t\t\t\t\t\t\t\t\tif (\tgeo.origin.windowOffset.left < bcr.left\n\t\t\t\t\t\t\t\t\t\t||\tgeo.origin.windowOffset.right > bcr.right\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\toverflows = true;\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (overflowY != 'visible') {\n\n\t\t\t\t\t\t\t\t\tif (\tgeo.origin.windowOffset.top < bcr.top\n\t\t\t\t\t\t\t\t\t\t||\tgeo.origin.windowOffset.bottom > bcr.bottom\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\toverflows = true;\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// no need to go further if fixed, for the same reason as above\n\t\t\t\t\t\t\tif ($el.css('position') == 'fixed') {\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tif (overflows) {\n\t\t\t\t\t\tself._$tooltip.css('visibility', 'hidden');\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\n\t\t\t\t\t\tself._$tooltip.css('visibility', 'visible');\n\n\t\t\t\t\t\t// reposition\n\t\t\t\t\t\tif (self.__options.repositionOnScroll) {\n\t\t\t\t\t\t\tself.reposition(event);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// or just adjust offset\n\t\t\t\t\t\telse {\n\n\t\t\t\t\t\t\t// we have to use offset and not windowOffset because this way,\n\t\t\t\t\t\t\t// only the scroll distance of the scrollable areas are taken into\n\t\t\t\t\t\t\t// account (the scrolltop value of the main window must be\n\t\t\t\t\t\t\t// ignored since the tooltip already moves with it)\n\t\t\t\t\t\t\tvar offsetLeft = geo.origin.offset.left - self.__Geometry.origin.offset.left,\n\t\t\t\t\t\t\t\toffsetTop = geo.origin.offset.top - self.__Geometry.origin.offset.top;\n\n\t\t\t\t\t\t\t// add the offset to the position initially computed by the display plugin\n\t\t\t\t\t\t\tself._$tooltip.css({\n\t\t\t\t\t\t\t\tleft: self.__lastPosition.coord.left + offsetLeft,\n\t\t\t\t\t\t\t\ttop: self.__lastPosition.coord.top + offsetTop\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tself._trigger({\n\t\t\t\t\ttype: 'scroll',\n\t\t\t\t\tevent: event,\n\t\t\t\t\tgeo: geo\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Changes the state of the tooltip\n\t *\n\t * @param {string} state\n\t * @returns {self}\n\t * @private\n\t */\n\t__stateSet: function(state) {\n\n\t\tthis.__state = state;\n\n\t\tthis._trigger({\n\t\t\ttype: 'state',\n\t\t\tstate: state\n\t\t});\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Clear appearance timeouts\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__timeoutsClear: function() {\n\n\t\t// there is only one possible open timeout: the delayed opening\n\t\t// when the mouseenter/touchstart open triggers are used\n\t\tclearTimeout(this.__timeouts.open);\n\t\tthis.__timeouts.open = null;\n\n\t\t// ... but several close timeouts: the delayed closing when the\n\t\t// mouseleave close trigger is used and the timer option\n\t\t$.each(this.__timeouts.close, function(i, timeout) {\n\t\t\tclearTimeout(timeout);\n\t\t});\n\t\tthis.__timeouts.close = [];\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Start the tracker that will make checks at regular intervals\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__trackerStart: function() {\n\n\t\tvar self = this,\n\t\t\t$content = self._$tooltip.find('.tooltipster-content');\n\n\t\t// get the initial content size\n\t\tif (self.__options.trackTooltip) {\n\t\t\tself.__contentBcr = $content[0].getBoundingClientRect();\n\t\t}\n\n\t\tself.__tracker = setInterval(function() {\n\n\t\t\t// if the origin or tooltip elements have been removed.\n\t\t\t// Note: we could destroy the instance now if the origin has\n\t\t\t// been removed but we'll leave that task to our garbage collector\n\t\t\tif (!bodyContains(self._$origin) || !bodyContains(self._$tooltip)) {\n\t\t\t\tself._close();\n\t\t\t}\n\t\t\t// if everything is alright\n\t\t\telse {\n\n\t\t\t\t// compare the former and current positions of the origin to reposition\n\t\t\t\t// the tooltip if need be\n\t\t\t\tif (self.__options.trackOrigin) {\n\n\t\t\t\t\tvar g = self.__geometry(),\n\t\t\t\t\t\tidentical = false;\n\n\t\t\t\t\t// compare size first (a change requires repositioning too)\n\t\t\t\t\tif (areEqual(g.origin.size, self.__Geometry.origin.size)) {\n\n\t\t\t\t\t\t// for elements that have a fixed lineage (see __geometry()), we track the\n\t\t\t\t\t\t// top and left properties (relative to window)\n\t\t\t\t\t\tif (self.__Geometry.origin.fixedLineage) {\n\t\t\t\t\t\t\tif (areEqual(g.origin.windowOffset, self.__Geometry.origin.windowOffset)) {\n\t\t\t\t\t\t\t\tidentical = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// otherwise, track total offset (relative to document)\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tif (areEqual(g.origin.offset, self.__Geometry.origin.offset)) {\n\t\t\t\t\t\t\t\tidentical = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!identical) {\n\n\t\t\t\t\t\t// close the tooltip when using the mouseleave close trigger\n\t\t\t\t\t\t// (see https://github.com/calebjacob/tooltipster/pull/253)\n\t\t\t\t\t\tif (self.__options.triggerClose.mouseleave) {\n\t\t\t\t\t\t\tself._close();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tself.reposition();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (self.__options.trackTooltip) {\n\n\t\t\t\t\tvar currentBcr = $content[0].getBoundingClientRect();\n\n\t\t\t\t\tif (\tcurrentBcr.height !== self.__contentBcr.height\n\t\t\t\t\t\t||\tcurrentBcr.width !== self.__contentBcr.width\n\t\t\t\t\t) {\n\t\t\t\t\t\tself.reposition();\n\t\t\t\t\t\tself.__contentBcr = currentBcr;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}, self.__options.trackerInterval);\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Closes the tooltip (after the closing delay)\n\t *\n\t * @param event\n\t * @param callback\n\t * @param force Set to true to override a potential refusal of the user's function\n\t * @returns {self}\n\t * @protected\n\t */\n\t_close: function(event, callback, force) {\n\n\t\tvar self = this,\n\t\t\tok = true;\n\n\t\tself._trigger({\n\t\t\ttype: 'close',\n\t\t\tevent: event,\n\t\t\tstop: function() {\n\t\t\t\tok = false;\n\t\t\t}\n\t\t});\n\n\t\t// a destroying tooltip (force == true) may not refuse to close\n\t\tif (ok || force) {\n\n\t\t\t// save the method custom callback and cancel any open method custom callbacks\n\t\t\tif (callback) self.__callbacks.close.push(callback);\n\t\t\tself.__callbacks.open = [];\n\n\t\t\t// clear open/close timeouts\n\t\t\tself.__timeoutsClear();\n\n\t\t\tvar finishCallbacks = function() {\n\n\t\t\t\t// trigger any close method custom callbacks and reset them\n\t\t\t\t$.each(self.__callbacks.close, function(i,c) {\n\t\t\t\t\tc.call(self, self, {\n\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\torigin: self._$origin[0]\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tself.__callbacks.close = [];\n\t\t\t};\n\n\t\t\tif (self.__state != 'closed') {\n\n\t\t\t\tvar necessary = true,\n\t\t\t\t\td = new Date(),\n\t\t\t\t\tnow = d.getTime(),\n\t\t\t\t\tnewClosingTime = now + self.__options.animationDuration[1];\n\n\t\t\t\t// the tooltip may already already be disappearing, but if a new\n\t\t\t\t// call to close() is made after the animationDuration was changed\n\t\t\t\t// to 0 (for example), we ought to actually close it sooner than\n\t\t\t\t// previously scheduled. In that case it should be noted that the\n\t\t\t\t// browser will not adapt the animation duration to the new\n\t\t\t\t// animationDuration that was set after the start of the closing\n\t\t\t\t// animation.\n\t\t\t\t// Note: the same thing could be considered at opening, but is not\n\t\t\t\t// really useful since the tooltip is actually opened immediately\n\t\t\t\t// upon a call to _open(). Since it would not make the opening\n\t\t\t\t// animation finish sooner, its sole impact would be to trigger the\n\t\t\t\t// state event and the open callbacks sooner than the actual end of\n\t\t\t\t// the opening animation, which is not great.\n\t\t\t\tif (self.__state == 'disappearing') {\n\n\t\t\t\t\tif (\tnewClosingTime > self.__closingTime\n\t\t\t\t\t\t// in case closing is actually overdue because the script\n\t\t\t\t\t\t// execution was suspended. See #679\n\t\t\t\t\t\t&&\tself.__options.animationDuration[1] > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tnecessary = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (necessary) {\n\n\t\t\t\t\tself.__closingTime = newClosingTime;\n\n\t\t\t\t\tif (self.__state != 'disappearing') {\n\t\t\t\t\t\tself.__stateSet('disappearing');\n\t\t\t\t\t}\n\n\t\t\t\t\tvar finish = function() {\n\n\t\t\t\t\t\t// stop the tracker\n\t\t\t\t\t\tclearInterval(self.__tracker);\n\n\t\t\t\t\t\t// a \"beforeClose\" option has been asked several times but would\n\t\t\t\t\t\t// probably useless since the content element is still accessible\n\t\t\t\t\t\t// via ::content(), and because people can always use listeners\n\t\t\t\t\t\t// inside their content to track what's going on. For the sake of\n\t\t\t\t\t\t// simplicity, this has been denied. Bur for the rare people who\n\t\t\t\t\t\t// really need the option (for old browsers or for the case where\n\t\t\t\t\t\t// detaching the content is actually destructive, for file or\n\t\t\t\t\t\t// password inputs for example), this event will do the work.\n\t\t\t\t\t\tself._trigger({\n\t\t\t\t\t\t\ttype: 'closing',\n\t\t\t\t\t\t\tevent: event\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// unbind listeners which are no longer needed\n\n\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t.off('.'+ self.__namespace +'-triggerClose')\n\t\t\t\t\t\t\t.removeClass('tooltipster-dying');\n\n\t\t\t\t\t\t// orientationchange, scroll and resize listeners\n\t\t\t\t\t\t$(env.window).off('.'+ self.__namespace +'-triggerClose');\n\n\t\t\t\t\t\t// scroll listeners\n\t\t\t\t\t\tself.__$originParents.each(function(i, el) {\n\t\t\t\t\t\t\t$(el).off('scroll.'+ self.__namespace +'-triggerClose');\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// clear the array to prevent memory leaks\n\t\t\t\t\t\tself.__$originParents = null;\n\n\t\t\t\t\t\t$(env.window.document.body).off('.'+ self.__namespace +'-triggerClose');\n\n\t\t\t\t\t\tself._$origin.off('.'+ self.__namespace +'-triggerClose');\n\n\t\t\t\t\t\tself._off('dismissable');\n\n\t\t\t\t\t\t// a plugin that would like to remove the tooltip from the\n\t\t\t\t\t\t// DOM when closed should bind on this\n\t\t\t\t\t\tself.__stateSet('closed');\n\n\t\t\t\t\t\t// trigger event\n\t\t\t\t\t\tself._trigger({\n\t\t\t\t\t\t\ttype: 'after',\n\t\t\t\t\t\t\tevent: event\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// call our constructor custom callback function\n\t\t\t\t\t\tif (self.__options.functionAfter) {\n\t\t\t\t\t\t\tself.__options.functionAfter.call(self, self, {\n\t\t\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\t\t\torigin: self._$origin[0]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// call our method custom callbacks functions\n\t\t\t\t\t\tfinishCallbacks();\n\t\t\t\t\t};\n\n\t\t\t\t\tif (env.hasTransitions) {\n\n\t\t\t\t\t\tself._$tooltip.css({\n\t\t\t\t\t\t\t'-moz-animation-duration': self.__options.animationDuration[1] + 'ms',\n\t\t\t\t\t\t\t'-ms-animation-duration': self.__options.animationDuration[1] + 'ms',\n\t\t\t\t\t\t\t'-o-animation-duration': self.__options.animationDuration[1] + 'ms',\n\t\t\t\t\t\t\t'-webkit-animation-duration': self.__options.animationDuration[1] + 'ms',\n\t\t\t\t\t\t\t'animation-duration': self.__options.animationDuration[1] + 'ms',\n\t\t\t\t\t\t\t'transition-duration': self.__options.animationDuration[1] + 'ms'\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t// clear both potential open and close tasks\n\t\t\t\t\t\t\t.clearQueue()\n\t\t\t\t\t\t\t.removeClass('tooltipster-show')\n\t\t\t\t\t\t\t// for transitions only\n\t\t\t\t\t\t\t.addClass('tooltipster-dying');\n\n\t\t\t\t\t\tif (self.__options.animationDuration[1] > 0) {\n\t\t\t\t\t\t\tself._$tooltip.delay(self.__options.animationDuration[1]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tself._$tooltip.queue(finish);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\n\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t.stop()\n\t\t\t\t\t\t\t.fadeOut(self.__options.animationDuration[1], finish);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// if the tooltip is already closed, we still need to trigger\n\t\t\t// the method custom callbacks\n\t\t\telse {\n\t\t\t\tfinishCallbacks();\n\t\t\t}\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @returns {self}\n\t * @protected\n\t */\n\t_off: function() {\n\t\tthis.__$emitterPrivate.off.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @returns {self}\n\t * @protected\n\t */\n\t_on: function() {\n\t\tthis.__$emitterPrivate.on.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @returns {self}\n\t * @protected\n\t */\n\t_one: function() {\n\t\tthis.__$emitterPrivate.one.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * Opens the tooltip right away.\n\t *\n\t * @param event\n\t * @param callback Will be called when the opening animation is over\n\t * @returns {self}\n\t * @protected\n\t */\n\t_open: function(event, callback) {\n\n\t\tvar self = this;\n\n\t\t// if the destruction process has not begun and if this was not\n\t\t// triggered by an unwanted emulated click event\n\t\tif (!self.__destroying) {\n\n\t\t\t// check that the origin is still in the DOM\n\t\t\tif (\tbodyContains(self._$origin)\n\t\t\t\t// if the tooltip is enabled\n\t\t\t\t&&\tself.__enabled\n\t\t\t) {\n\n\t\t\t\tvar ok = true;\n\n\t\t\t\t// if the tooltip is not open yet, we need to call functionBefore.\n\t\t\t\t// otherwise we can jst go on\n\t\t\t\tif (self.__state == 'closed') {\n\n\t\t\t\t\t// trigger an event. The event.stop function allows the callback\n\t\t\t\t\t// to prevent the opening of the tooltip\n\t\t\t\t\tself._trigger({\n\t\t\t\t\t\ttype: 'before',\n\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\tstop: function() {\n\t\t\t\t\t\t\tok = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tif (ok && self.__options.functionBefore) {\n\n\t\t\t\t\t\t// call our custom function before continuing\n\t\t\t\t\t\tok = self.__options.functionBefore.call(self, self, {\n\t\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\t\torigin: self._$origin[0]\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (ok !== false) {\n\n\t\t\t\t\t// if there is some content\n\t\t\t\t\tif (self.__Content !== null) {\n\n\t\t\t\t\t\t// save the method callback and cancel close method callbacks\n\t\t\t\t\t\tif (callback) {\n\t\t\t\t\t\t\tself.__callbacks.open.push(callback);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tself.__callbacks.close = [];\n\n\t\t\t\t\t\t// get rid of any appearance timeouts\n\t\t\t\t\t\tself.__timeoutsClear();\n\n\t\t\t\t\t\tvar extraTime,\n\t\t\t\t\t\t\tfinish = function() {\n\n\t\t\t\t\t\t\t\tif (self.__state != 'stable') {\n\t\t\t\t\t\t\t\t\tself.__stateSet('stable');\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// trigger any open method custom callbacks and reset them\n\t\t\t\t\t\t\t\t$.each(self.__callbacks.open, function(i,c) {\n\t\t\t\t\t\t\t\t\tc.call(self, self, {\n\t\t\t\t\t\t\t\t\t\torigin: self._$origin[0],\n\t\t\t\t\t\t\t\t\t\ttooltip: self._$tooltip[0]\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tself.__callbacks.open = [];\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// if the tooltip is already open\n\t\t\t\t\t\tif (self.__state !== 'closed') {\n\n\t\t\t\t\t\t\t// the timer (if any) will start (or restart) right now\n\t\t\t\t\t\t\textraTime = 0;\n\n\t\t\t\t\t\t\t// if it was disappearing, cancel that\n\t\t\t\t\t\t\tif (self.__state === 'disappearing') {\n\n\t\t\t\t\t\t\t\tself.__stateSet('appearing');\n\n\t\t\t\t\t\t\t\tif (env.hasTransitions) {\n\n\t\t\t\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t\t\t\t.clearQueue()\n\t\t\t\t\t\t\t\t\t\t.removeClass('tooltipster-dying')\n\t\t\t\t\t\t\t\t\t\t.addClass('tooltipster-show');\n\n\t\t\t\t\t\t\t\t\tif (self.__options.animationDuration[0] > 0) {\n\t\t\t\t\t\t\t\t\t\tself._$tooltip.delay(self.__options.animationDuration[0]);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tself._$tooltip.queue(finish);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t// in case the tooltip was currently fading out, bring it back\n\t\t\t\t\t\t\t\t\t// to life\n\t\t\t\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t\t\t\t.stop()\n\t\t\t\t\t\t\t\t\t\t.fadeIn(finish);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// if the tooltip is already open, we still need to trigger the method\n\t\t\t\t\t\t\t// custom callback\n\t\t\t\t\t\t\telse if (self.__state == 'stable') {\n\t\t\t\t\t\t\t\tfinish();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// if the tooltip isn't already open, open it\n\t\t\t\t\t\telse {\n\n\t\t\t\t\t\t\t// a plugin must bind on this and store the tooltip in this._$tooltip\n\t\t\t\t\t\t\tself.__stateSet('appearing');\n\n\t\t\t\t\t\t\t// the timer (if any) will start when the tooltip has fully appeared\n\t\t\t\t\t\t\t// after its transition\n\t\t\t\t\t\t\textraTime = self.__options.animationDuration[0];\n\n\t\t\t\t\t\t\t// insert the content inside the tooltip\n\t\t\t\t\t\t\tself.__contentInsert();\n\n\t\t\t\t\t\t\t// reposition the tooltip and attach to the DOM\n\t\t\t\t\t\t\tself.reposition(event, true);\n\n\t\t\t\t\t\t\t// animate in the tooltip. If the display plugin wants no css\n\t\t\t\t\t\t\t// animations, it may override the animation option with a\n\t\t\t\t\t\t\t// dummy value that will produce no effect\n\t\t\t\t\t\t\tif (env.hasTransitions) {\n\n\t\t\t\t\t\t\t\t// note: there seems to be an issue with start animations which\n\t\t\t\t\t\t\t\t// are randomly not played on fast devices in both Chrome and FF,\n\t\t\t\t\t\t\t\t// couldn't find a way to solve it yet. It seems that applying\n\t\t\t\t\t\t\t\t// the classes before appending to the DOM helps a little, but\n\t\t\t\t\t\t\t\t// it messes up some CSS transitions. The issue almost never\n\t\t\t\t\t\t\t\t// happens when delay[0]==0 though\n\t\t\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t\t\t.addClass('tooltipster-'+ self.__options.animation)\n\t\t\t\t\t\t\t\t\t.addClass('tooltipster-initial')\n\t\t\t\t\t\t\t\t\t.css({\n\t\t\t\t\t\t\t\t\t\t'-moz-animation-duration': self.__options.animationDuration[0] + 'ms',\n\t\t\t\t\t\t\t\t\t\t'-ms-animation-duration': self.__options.animationDuration[0] + 'ms',\n\t\t\t\t\t\t\t\t\t\t'-o-animation-duration': self.__options.animationDuration[0] + 'ms',\n\t\t\t\t\t\t\t\t\t\t'-webkit-animation-duration': self.__options.animationDuration[0] + 'ms',\n\t\t\t\t\t\t\t\t\t\t'animation-duration': self.__options.animationDuration[0] + 'ms',\n\t\t\t\t\t\t\t\t\t\t'transition-duration': self.__options.animationDuration[0] + 'ms'\n\t\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t\t\t\t\t// a quick hover may have already triggered a mouseleave\n\t\t\t\t\t\t\t\t\t\tif (self.__state != 'closed') {\n\n\t\t\t\t\t\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t\t\t\t\t\t.addClass('tooltipster-show')\n\t\t\t\t\t\t\t\t\t\t\t\t.removeClass('tooltipster-initial');\n\n\t\t\t\t\t\t\t\t\t\t\tif (self.__options.animationDuration[0] > 0) {\n\t\t\t\t\t\t\t\t\t\t\t\tself._$tooltip.delay(self.__options.animationDuration[0]);\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tself._$tooltip.queue(finish);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t0\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\n\t\t\t\t\t\t\t\t// old browsers will have to live with this\n\t\t\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t\t\t.css('display', 'none')\n\t\t\t\t\t\t\t\t\t.fadeIn(self.__options.animationDuration[0], finish);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// checks if the origin is removed while the tooltip is open\n\t\t\t\t\t\t\tself.__trackerStart();\n\n\t\t\t\t\t\t\t// NOTE: the listeners below have a '-triggerClose' namespace\n\t\t\t\t\t\t\t// because we'll remove them when the tooltip closes (unlike\n\t\t\t\t\t\t\t// the '-triggerOpen' listeners). So some of them are actually\n\t\t\t\t\t\t\t// not about close triggers, rather about positioning.\n\n\t\t\t\t\t\t\t$(env.window)\n\t\t\t\t\t\t\t\t// reposition on resize\n\t\t\t\t\t\t\t\t.on('resize.'+ self.__namespace +'-triggerClose', function(e) {\n\n\t\t\t\t\t\t\t\t\tvar $ae = $(document.activeElement);\n\n\t\t\t\t\t\t\t\t\t// reposition only if the resize event was not triggered upon the opening\n\t\t\t\t\t\t\t\t\t// of a virtual keyboard due to an input field being focused within the tooltip\n\t\t\t\t\t\t\t\t\t// (otherwise the repositioning would lose the focus)\n\t\t\t\t\t\t\t\t\tif (\t(!$ae.is('input') && !$ae.is('textarea'))\n\t\t\t\t\t\t\t\t\t\t||\t!$.contains(self._$tooltip[0], $ae[0])\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\tself.reposition(e);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t// same as below for parents\n\t\t\t\t\t\t\t\t.on('scroll.'+ self.__namespace +'-triggerClose', function(e) {\n\t\t\t\t\t\t\t\t\tself.__scrollHandler(e);\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tself.__$originParents = self._$origin.parents();\n\n\t\t\t\t\t\t\t// scrolling may require the tooltip to be moved or even\n\t\t\t\t\t\t\t// repositioned in some cases\n\t\t\t\t\t\t\tself.__$originParents.each(function(i, parent) {\n\n\t\t\t\t\t\t\t\t$(parent).on('scroll.'+ self.__namespace +'-triggerClose', function(e) {\n\t\t\t\t\t\t\t\t\tself.__scrollHandler(e);\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (\tself.__options.triggerClose.mouseleave\n\t\t\t\t\t\t\t\t||\t(self.__options.triggerClose.touchleave && env.hasTouchCapability)\n\t\t\t\t\t\t\t) {\n\n\t\t\t\t\t\t\t\t// we use an event to allow users/plugins to control when the mouseleave/touchleave\n\t\t\t\t\t\t\t\t// close triggers will come to action. It allows to have more triggering elements\n\t\t\t\t\t\t\t\t// than just the origin and the tooltip for example, or to cancel/delay the closing,\n\t\t\t\t\t\t\t\t// or to make the tooltip interactive even if it wasn't when it was open, etc.\n\t\t\t\t\t\t\t\tself._on('dismissable', function(event) {\n\n\t\t\t\t\t\t\t\t\tif (event.dismissable) {\n\n\t\t\t\t\t\t\t\t\t\tif (event.delay) {\n\n\t\t\t\t\t\t\t\t\t\t\ttimeout = setTimeout(function() {\n\t\t\t\t\t\t\t\t\t\t\t\t// event.event may be undefined\n\t\t\t\t\t\t\t\t\t\t\t\tself._close(event.event);\n\t\t\t\t\t\t\t\t\t\t\t}, event.delay);\n\n\t\t\t\t\t\t\t\t\t\t\tself.__timeouts.close.push(timeout);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\t\tself._close(event);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t// now set the listeners that will trigger 'dismissable' events\n\t\t\t\t\t\t\t\tvar $elements = self._$origin,\n\t\t\t\t\t\t\t\t\teventNamesIn = '',\n\t\t\t\t\t\t\t\t\teventNamesOut = '',\n\t\t\t\t\t\t\t\t\ttimeout = null;\n\n\t\t\t\t\t\t\t\t// if we have to allow interaction, bind on the tooltip too\n\t\t\t\t\t\t\t\tif (self.__options.interactive) {\n\t\t\t\t\t\t\t\t\t$elements = $elements.add(self._$tooltip);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (self.__options.triggerClose.mouseleave) {\n\t\t\t\t\t\t\t\t\teventNamesIn += 'mouseenter.'+ self.__namespace +'-triggerClose ';\n\t\t\t\t\t\t\t\t\teventNamesOut += 'mouseleave.'+ self.__namespace +'-triggerClose ';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (self.__options.triggerClose.touchleave && env.hasTouchCapability) {\n\t\t\t\t\t\t\t\t\teventNamesIn += 'touchstart.'+ self.__namespace +'-triggerClose';\n\t\t\t\t\t\t\t\t\teventNamesOut += 'touchend.'+ self.__namespace +'-triggerClose touchcancel.'+ self.__namespace +'-triggerClose';\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t$elements\n\t\t\t\t\t\t\t\t\t// close after some time spent outside of the elements\n\t\t\t\t\t\t\t\t\t.on(eventNamesOut, function(event) {\n\n\t\t\t\t\t\t\t\t\t\t// it's ok if the touch gesture ended up to be a swipe,\n\t\t\t\t\t\t\t\t\t\t// it's still a \"touch leave\" situation\n\t\t\t\t\t\t\t\t\t\tif (\tself._touchIsTouchEvent(event)\n\t\t\t\t\t\t\t\t\t\t\t||\t!self._touchIsEmulatedEvent(event)\n\t\t\t\t\t\t\t\t\t\t) {\n\n\t\t\t\t\t\t\t\t\t\t\tvar delay = (event.type == 'mouseleave') ?\n\t\t\t\t\t\t\t\t\t\t\t\tself.__options.delay :\n\t\t\t\t\t\t\t\t\t\t\t\tself.__options.delayTouch;\n\n\t\t\t\t\t\t\t\t\t\t\tself._trigger({\n\t\t\t\t\t\t\t\t\t\t\t\tdelay: delay[1],\n\t\t\t\t\t\t\t\t\t\t\t\tdismissable: true,\n\t\t\t\t\t\t\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'dismissable'\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t// suspend the mouseleave timeout when the pointer comes back\n\t\t\t\t\t\t\t\t\t// over the elements\n\t\t\t\t\t\t\t\t\t.on(eventNamesIn, function(event) {\n\n\t\t\t\t\t\t\t\t\t\t// it's also ok if the touch event is a swipe gesture\n\t\t\t\t\t\t\t\t\t\tif (\tself._touchIsTouchEvent(event)\n\t\t\t\t\t\t\t\t\t\t\t||\t!self._touchIsEmulatedEvent(event)\n\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\tself._trigger({\n\t\t\t\t\t\t\t\t\t\t\t\tdismissable: false,\n\t\t\t\t\t\t\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'dismissable'\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// close the tooltip when the origin gets a mouse click (common behavior of\n\t\t\t\t\t\t\t// native tooltips)\n\t\t\t\t\t\t\tif (self.__options.triggerClose.originClick) {\n\n\t\t\t\t\t\t\t\tself._$origin.on('click.'+ self.__namespace + '-triggerClose', function(event) {\n\n\t\t\t\t\t\t\t\t\t// we could actually let a tap trigger this but this feature just\n\t\t\t\t\t\t\t\t\t// does not make sense on touch devices\n\t\t\t\t\t\t\t\t\tif (\t!self._touchIsTouchEvent(event)\n\t\t\t\t\t\t\t\t\t\t&&\t!self._touchIsEmulatedEvent(event)\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\tself._close(event);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// set the same bindings for click and touch on the body to close the tooltip\n\t\t\t\t\t\t\tif (\tself.__options.triggerClose.click\n\t\t\t\t\t\t\t\t||\t(self.__options.triggerClose.tap && env.hasTouchCapability)\n\t\t\t\t\t\t\t) {\n\n\t\t\t\t\t\t\t\t// don't set right away since the click/tap event which triggered this method\n\t\t\t\t\t\t\t\t// (if it was a click/tap) is going to bubble up to the body, we don't want it\n\t\t\t\t\t\t\t\t// to close the tooltip immediately after it opened\n\t\t\t\t\t\t\t\tsetTimeout(function() {\n\n\t\t\t\t\t\t\t\t\tif (self.__state != 'closed') {\n\n\t\t\t\t\t\t\t\t\t\tvar eventNames = '',\n\t\t\t\t\t\t\t\t\t\t\t$body = $(env.window.document.body);\n\n\t\t\t\t\t\t\t\t\t\tif (self.__options.triggerClose.click) {\n\t\t\t\t\t\t\t\t\t\t\teventNames += 'click.'+ self.__namespace +'-triggerClose ';\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tif (self.__options.triggerClose.tap && env.hasTouchCapability) {\n\t\t\t\t\t\t\t\t\t\t\teventNames += 'touchend.'+ self.__namespace +'-triggerClose';\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t$body.on(eventNames, function(event) {\n\n\t\t\t\t\t\t\t\t\t\t\tif (self._touchIsMeaningfulEvent(event)) {\n\n\t\t\t\t\t\t\t\t\t\t\t\tself._touchRecordEvent(event);\n\n\t\t\t\t\t\t\t\t\t\t\t\tif (!self.__options.interactive || !$.contains(self._$tooltip[0], event.target)) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tself._close(event);\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t\t\t// needed to detect and ignore swiping\n\t\t\t\t\t\t\t\t\t\tif (self.__options.triggerClose.tap && env.hasTouchCapability) {\n\n\t\t\t\t\t\t\t\t\t\t\t$body.on('touchstart.'+ self.__namespace +'-triggerClose', function(event) {\n\t\t\t\t\t\t\t\t\t\t\t\tself._touchRecordEvent(event);\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}, 0);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tself._trigger('ready');\n\n\t\t\t\t\t\t\t// call our custom callback\n\t\t\t\t\t\t\tif (self.__options.functionReady) {\n\t\t\t\t\t\t\t\tself.__options.functionReady.call(self, self, {\n\t\t\t\t\t\t\t\t\torigin: self._$origin[0],\n\t\t\t\t\t\t\t\t\ttooltip: self._$tooltip[0]\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// if we have a timer set, let the countdown begin\n\t\t\t\t\t\tif (self.__options.timer > 0) {\n\n\t\t\t\t\t\t\tvar timeout = setTimeout(function() {\n\t\t\t\t\t\t\t\tself._close();\n\t\t\t\t\t\t\t}, self.__options.timer + extraTime);\n\n\t\t\t\t\t\t\tself.__timeouts.close.push(timeout);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * When using the mouseenter/touchstart open triggers, this function will\n\t * schedule the opening of the tooltip after the delay, if there is one\n\t *\n\t * @param event\n\t * @returns {self}\n\t * @protected\n \t */\n\t_openShortly: function(event) {\n\n\t\tvar self = this,\n\t\t\tok = true;\n\n\t\tif (self.__state != 'stable' && self.__state != 'appearing') {\n\n\t\t\t// if a timeout is not already running\n\t\t\tif (!self.__timeouts.open) {\n\n\t\t\t\tself._trigger({\n\t\t\t\t\ttype: 'start',\n\t\t\t\t\tevent: event,\n\t\t\t\t\tstop: function() {\n\t\t\t\t\t\tok = false;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (ok) {\n\n\t\t\t\t\tvar delay = (event.type.indexOf('touch') == 0) ?\n\t\t\t\t\t\tself.__options.delayTouch :\n\t\t\t\t\t\tself.__options.delay;\n\n\t\t\t\t\tif (delay[0]) {\n\n\t\t\t\t\t\tself.__timeouts.open = setTimeout(function() {\n\n\t\t\t\t\t\t\tself.__timeouts.open = null;\n\n\t\t\t\t\t\t\t// open only if the pointer (mouse or touch) is still over the origin.\n\t\t\t\t\t\t\t// The check on the \"meaningful event\" can only be made here, after some\n\t\t\t\t\t\t\t// time has passed (to know if the touch was a swipe or not)\n\t\t\t\t\t\t\tif (self.__pointerIsOverOrigin && self._touchIsMeaningfulEvent(event)) {\n\n\t\t\t\t\t\t\t\t// signal that we go on\n\t\t\t\t\t\t\t\tself._trigger('startend');\n\n\t\t\t\t\t\t\t\tself._open(event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t// signal that we cancel\n\t\t\t\t\t\t\t\tself._trigger('startcancel');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, delay[0]);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// signal that we go on\n\t\t\t\t\t\tself._trigger('startend');\n\n\t\t\t\t\t\tself._open(event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Meant for plugins to get their options\n\t *\n\t * @param {string} pluginName The name of the plugin that asks for its options\n\t * @param {object} defaultOptions The default options of the plugin\n\t * @returns {object} The options\n\t * @protected\n\t */\n\t_optionsExtract: function(pluginName, defaultOptions) {\n\n\t\tvar self = this,\n\t\t\toptions = $.extend(true, {}, defaultOptions);\n\n\t\t// if the plugin options were isolated in a property named after the\n\t\t// plugin, use them (prevents conflicts with other plugins)\n\t\tvar pluginOptions = self.__options[pluginName];\n\n\t\t// if not, try to get them as regular options\n\t\tif (!pluginOptions){\n\n\t\t\tpluginOptions = {};\n\n\t\t\t$.each(defaultOptions, function(optionName, value) {\n\n\t\t\t\tvar o = self.__options[optionName];\n\n\t\t\t\tif (o !== undefined) {\n\t\t\t\t\tpluginOptions[optionName] = o;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// let's merge the default options and the ones that were provided. We'd want\n\t\t// to do a deep copy but not let jQuery merge arrays, so we'll do a shallow\n\t\t// extend on two levels, that will be enough if options are not more than 1\n\t\t// level deep\n\t\t$.each(options, function(optionName, value) {\n\n\t\t\tif (pluginOptions[optionName] !== undefined) {\n\n\t\t\t\tif ((\t\ttypeof value == 'object'\n\t\t\t\t\t\t&&\t!(value instanceof Array)\n\t\t\t\t\t\t&&\tvalue != null\n\t\t\t\t\t)\n\t\t\t\t\t&&\n\t\t\t\t\t(\t\ttypeof pluginOptions[optionName] == 'object'\n\t\t\t\t\t\t&&\t!(pluginOptions[optionName] instanceof Array)\n\t\t\t\t\t\t&&\tpluginOptions[optionName] != null\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\t$.extend(options[optionName], pluginOptions[optionName]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\toptions[optionName] = pluginOptions[optionName];\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn options;\n\t},\n\n\t/**\n\t * Used at instantiation of the plugin, or afterwards by plugins that activate themselves\n\t * on existing instances\n\t *\n\t * @param {object} pluginName\n\t * @returns {self}\n\t * @protected\n\t */\n\t_plug: function(pluginName) {\n\n\t\tvar plugin = $.tooltipster._plugin(pluginName);\n\n\t\tif (plugin) {\n\n\t\t\t// if there is a constructor for instances\n\t\t\tif (plugin.instance) {\n\n\t\t\t\t// proxy non-private methods on the instance to allow new instance methods\n\t\t\t\t$.tooltipster.__bridge(plugin.instance, this, plugin.name);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthrow new Error('The \"'+ pluginName +'\" plugin is not defined');\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * This will return true if the event is a mouse event which was\n\t * emulated by the browser after a touch event. This allows us to\n\t * really dissociate mouse and touch triggers.\n\t *\n\t * There is a margin of error if a real mouse event is fired right\n\t * after (within the delay shown below) a touch event on the same\n\t * element, but hopefully it should not happen often.\n\t *\n\t * @returns {boolean}\n\t * @protected\n\t */\n\t_touchIsEmulatedEvent: function(event) {\n\n\t\tvar isEmulated = false,\n\t\t\tnow = new Date().getTime();\n\n\t\tfor (var i = this.__touchEvents.length - 1; i >= 0; i--) {\n\n\t\t\tvar e = this.__touchEvents[i];\n\n\t\t\t// delay, in milliseconds. It's supposed to be 300ms in\n\t\t\t// most browsers (350ms on iOS) to allow a double tap but\n\t\t\t// can be less (check out FastClick for more info)\n\t\t\tif (now - e.time < 500) {\n\n\t\t\t\tif (e.target === event.target) {\n\t\t\t\t\tisEmulated = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn isEmulated;\n\t},\n\n\t/**\n\t * Returns false if the event was an emulated mouse event or\n\t * a touch event involved in a swipe gesture.\n\t *\n\t * @param {object} event\n\t * @returns {boolean}\n\t * @protected\n\t */\n\t_touchIsMeaningfulEvent: function(event) {\n\t\treturn (\n\t\t\t\t(this._touchIsTouchEvent(event) && !this._touchSwiped(event.target))\n\t\t\t||\t(!this._touchIsTouchEvent(event) && !this._touchIsEmulatedEvent(event))\n\t\t);\n\t},\n\n\t/**\n\t * Checks if an event is a touch event\n\t *\n\t * @param {object} event\n\t * @returns {boolean}\n\t * @protected\n\t */\n\t_touchIsTouchEvent: function(event){\n\t\treturn event.type.indexOf('touch') == 0;\n\t},\n\n\t/**\n\t * Store touch events for a while to detect swiping and emulated mouse events\n\t *\n\t * @param {object} event\n\t * @returns {self}\n\t * @protected\n\t */\n\t_touchRecordEvent: function(event) {\n\n\t\tif (this._touchIsTouchEvent(event)) {\n\t\t\tevent.time = new Date().getTime();\n\t\t\tthis.__touchEvents.push(event);\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns true if a swipe happened after the last touchstart event fired on\n\t * event.target.\n\t *\n\t * We need to differentiate a swipe from a tap before we let the event open\n\t * or close the tooltip. A swipe is when a touchmove (scroll) event happens\n\t * on the body between the touchstart and the touchend events of an element.\n\t *\n\t * @param {object} target The HTML element that may have triggered the swipe\n\t * @returns {boolean}\n\t * @protected\n\t */\n\t_touchSwiped: function(target) {\n\n\t\tvar swiped = false;\n\n\t\tfor (var i = this.__touchEvents.length - 1; i >= 0; i--) {\n\n\t\t\tvar e = this.__touchEvents[i];\n\n\t\t\tif (e.type == 'touchmove') {\n\t\t\t\tswiped = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (\n\t\t\t\te.type == 'touchstart'\n\t\t\t\t&&\ttarget === e.target\n\t\t\t) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn swiped;\n\t},\n\n\t/**\n\t * Triggers an event on the instance emitters\n\t *\n\t * @returns {self}\n\t * @protected\n\t */\n\t_trigger: function() {\n\n\t\tvar args = Array.prototype.slice.apply(arguments);\n\n\t\tif (typeof args[0] == 'string') {\n\t\t\targs[0] = { type: args[0] };\n\t\t}\n\n\t\t// add properties to the event\n\t\targs[0].instance = this;\n\t\targs[0].origin = this._$origin ? this._$origin[0] : null;\n\t\targs[0].tooltip = this._$tooltip ? this._$tooltip[0] : null;\n\n\t\t// note: the order of emitters matters\n\t\tthis.__$emitterPrivate.trigger.apply(this.__$emitterPrivate, args);\n\t\t$.tooltipster._trigger.apply($.tooltipster, args);\n\t\tthis.__$emitterPublic.trigger.apply(this.__$emitterPublic, args);\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Deactivate a plugin on this instance\n\t *\n\t * @returns {self}\n\t * @protected\n\t */\n\t_unplug: function(pluginName) {\n\n\t\tvar self = this;\n\n\t\t// if the plugin has been activated on this instance\n\t\tif (self[pluginName]) {\n\n\t\t\tvar plugin = $.tooltipster._plugin(pluginName);\n\n\t\t\t// if there is a constructor for instances\n\t\t\tif (plugin.instance) {\n\n\t\t\t\t// unbridge\n\t\t\t\t$.each(plugin.instance, function(methodName, fn) {\n\n\t\t\t\t\t// if the method exists (privates methods do not) and comes indeed from\n\t\t\t\t\t// this plugin (may be missing or come from a conflicting plugin).\n\t\t\t\t\tif (\tself[methodName]\n\t\t\t\t\t\t&&\tself[methodName].bridged === self[pluginName]\n\t\t\t\t\t) {\n\t\t\t\t\t\tdelete self[methodName];\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// destroy the plugin\n\t\t\tif (self[pluginName].__destroy) {\n\t\t\t\tself[pluginName].__destroy();\n\t\t\t}\n\n\t\t\t// remove the reference to the plugin instance\n\t\t\tdelete self[pluginName];\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * @see self::_close\n\t * @returns {self}\n\t * @public\n\t */\n\tclose: function(callback) {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis._close(null, callback);\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Sets or gets the content of the tooltip\n\t *\n\t * @returns {mixed|self}\n\t * @public\n\t */\n\tcontent: function(content) {\n\n\t\tvar self = this;\n\n\t\t// getter method\n\t\tif (content === undefined) {\n\t\t\treturn self.__Content;\n\t\t}\n\t\t// setter method\n\t\telse {\n\n\t\t\tif (!self.__destroyed) {\n\n\t\t\t\t// change the content\n\t\t\t\tself.__contentSet(content);\n\n\t\t\t\tif (self.__Content !== null) {\n\n\t\t\t\t\t// update the tooltip if it is open\n\t\t\t\t\tif (self.__state !== 'closed') {\n\n\t\t\t\t\t\t// reset the content in the tooltip\n\t\t\t\t\t\tself.__contentInsert();\n\n\t\t\t\t\t\t// reposition and resize the tooltip\n\t\t\t\t\t\tself.reposition();\n\n\t\t\t\t\t\t// if we want to play a little animation showing the content changed\n\t\t\t\t\t\tif (self.__options.updateAnimation) {\n\n\t\t\t\t\t\t\tif (env.hasTransitions) {\n\n\t\t\t\t\t\t\t\t// keep the reference in the local scope\n\t\t\t\t\t\t\t\tvar animation = self.__options.updateAnimation;\n\n\t\t\t\t\t\t\t\tself._$tooltip.addClass('tooltipster-update-'+ animation);\n\n\t\t\t\t\t\t\t\t// remove the class after a while. The actual duration of the\n\t\t\t\t\t\t\t\t// update animation may be shorter, it's set in the CSS rules\n\t\t\t\t\t\t\t\tsetTimeout(function() {\n\n\t\t\t\t\t\t\t\t\tif (self.__state != 'closed') {\n\n\t\t\t\t\t\t\t\t\t\tself._$tooltip.removeClass('tooltipster-update-'+ animation);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}, 1000);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tself._$tooltip.fadeTo(200, 0.5, function() {\n\t\t\t\t\t\t\t\t\tif (self.__state != 'closed') {\n\t\t\t\t\t\t\t\t\t\tself._$tooltip.fadeTo(200, 1);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tself._close();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tself.__destroyError();\n\t\t\t}\n\n\t\t\treturn self;\n\t\t}\n\t},\n\n\t/**\n\t * Destroys the tooltip\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\tdestroy: function() {\n\n\t\tvar self = this;\n\n\t\tif (!self.__destroyed) {\n\n\t\t\tif(self.__state != 'closed'){\n\n\t\t\t\t// no closing delay\n\t\t\t\tself.option('animationDuration', 0)\n\t\t\t\t\t// force closing\n\t\t\t\t\t._close(null, null, true);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// there might be an open timeout still running\n\t\t\t\tself.__timeoutsClear();\n\t\t\t}\n\n\t\t\t// send event\n\t\t\tself._trigger('destroy');\n\n\t\t\tself.__destroyed = true;\n\n\t\t\tself._$origin\n\t\t\t\t.removeData(self.__namespace)\n\t\t\t\t// remove the open trigger listeners\n\t\t\t\t.off('.'+ self.__namespace +'-triggerOpen');\n\n\t\t\t// remove the touch listener\n\t\t\t$(env.window.document.body).off('.' + self.__namespace +'-triggerOpen');\n\n\t\t\tvar ns = self._$origin.data('tooltipster-ns');\n\n\t\t\t// if the origin has been removed from DOM, its data may\n\t\t\t// well have been destroyed in the process and there would\n\t\t\t// be nothing to clean up or restore\n\t\t\tif (ns) {\n\n\t\t\t\t// if there are no more tooltips on this element\n\t\t\t\tif (ns.length === 1) {\n\n\t\t\t\t\t// optional restoration of a title attribute\n\t\t\t\t\tvar title = null;\n\t\t\t\t\tif (self.__options.restoration == 'previous') {\n\t\t\t\t\t\ttitle = self._$origin.data('tooltipster-initialTitle');\n\t\t\t\t\t}\n\t\t\t\t\telse if (self.__options.restoration == 'current') {\n\n\t\t\t\t\t\t// old school technique to stringify when outerHTML is not supported\n\t\t\t\t\t\ttitle = (typeof self.__Content == 'string') ?\n\t\t\t\t\t\t\tself.__Content :\n\t\t\t\t\t\t\t$('<div></div>').append(self.__Content).html();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (title) {\n\t\t\t\t\t\tself._$origin.attr('title', title);\n\t\t\t\t\t}\n\n\t\t\t\t\t// final cleaning\n\n\t\t\t\t\tself._$origin.removeClass('tooltipstered');\n\n\t\t\t\t\tself._$origin\n\t\t\t\t\t\t.removeData('tooltipster-ns')\n\t\t\t\t\t\t.removeData('tooltipster-initialTitle');\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// remove the instance namespace from the list of namespaces of\n\t\t\t\t\t// tooltips present on the element\n\t\t\t\t\tns = $.grep(ns, function(el, i) {\n\t\t\t\t\t\treturn el !== self.__namespace;\n\t\t\t\t\t});\n\t\t\t\t\tself._$origin.data('tooltipster-ns', ns);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// last event\n\t\t\tself._trigger('destroyed');\n\n\t\t\t// unbind private and public event listeners\n\t\t\tself._off();\n\t\t\tself.off();\n\n\t\t\t// remove external references, just in case\n\t\t\tself.__Content = null;\n\t\t\tself.__$emitterPrivate = null;\n\t\t\tself.__$emitterPublic = null;\n\t\t\tself.__options.parent = null;\n\t\t\tself._$origin = null;\n\t\t\tself._$tooltip = null;\n\n\t\t\t// make sure the object is no longer referenced in there to prevent\n\t\t\t// memory leaks\n\t\t\t$.tooltipster.__instancesLatestArr = $.grep($.tooltipster.__instancesLatestArr, function(el, i) {\n\t\t\t\treturn self !== el;\n\t\t\t});\n\n\t\t\tclearInterval(self.__garbageCollector);\n\t\t}\n\t\telse {\n\t\t\tself.__destroyError();\n\t\t}\n\n\t\t// we return the scope rather than true so that the call to\n\t\t// .tooltipster('destroy') actually returns the matched elements\n\t\t// and applies to all of them\n\t\treturn self;\n\t},\n\n\t/**\n\t * Disables the tooltip\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\tdisable: function() {\n\n\t\tif (!this.__destroyed) {\n\n\t\t\t// close first, in case the tooltip would not disappear on\n\t\t\t// its own (no close trigger)\n\t\t\tthis._close();\n\t\t\tthis.__enabled = false;\n\n\t\t\treturn this;\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns the HTML element of the origin\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\telementOrigin: function() {\n\n\t\tif (!this.__destroyed) {\n\t\t\treturn this._$origin[0];\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\t},\n\n\t/**\n\t * Returns the HTML element of the tooltip\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\telementTooltip: function() {\n\t\treturn this._$tooltip ? this._$tooltip[0] : null;\n\t},\n\n\t/**\n\t * Enables the tooltip\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\tenable: function() {\n\t\tthis.__enabled = true;\n\t\treturn this;\n\t},\n\n\t/**\n\t * Alias, deprecated in 4.0.0\n\t *\n\t * @param {function} callback\n\t * @returns {self}\n\t * @public\n\t */\n\thide: function(callback) {\n\t\treturn this.close(callback);\n\t},\n\n\t/**\n\t * Returns the instance\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\tinstance: function() {\n\t\treturn this;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins (use ::_off() instead)\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\toff: function() {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis.__$emitterPublic.off.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins (use ::_on() instead)\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\ton: function() {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis.__$emitterPublic.on.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\tone: function() {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis.__$emitterPublic.one.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * @see self::_open\n\t * @returns {self}\n\t * @public\n\t */\n\topen: function(callback) {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis._open(null, callback);\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Get or set options. For internal use and advanced users only.\n\t *\n\t * @param {string} o Option name\n\t * @param {mixed} val optional A new value for the option\n\t * @return {mixed|self} If val is omitted, the value of the option\n\t * is returned, otherwise the instance itself is returned\n\t * @public\n\t */\n\toption: function(o, val) {\n\n\t\t// getter\n\t\tif (val === undefined) {\n\t\t\treturn this.__options[o];\n\t\t}\n\t\t// setter\n\t\telse {\n\n\t\t\tif (!this.__destroyed) {\n\n\t\t\t\t// change value\n\t\t\t\tthis.__options[o] = val;\n\n\t\t\t\t// format\n\t\t\t\tthis.__optionsFormat();\n\n\t\t\t\t// re-prepare the triggers if needed\n\t\t\t\tif ($.inArray(o, ['trigger', 'triggerClose', 'triggerOpen']) >= 0) {\n\t\t\t\t\tthis.__prepareOrigin();\n\t\t\t\t}\n\n\t\t\t\tif (o === 'selfDestruction') {\n\t\t\t\t\tthis.__prepareGC();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.__destroyError();\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t},\n\n\t/**\n\t * This method is in charge of setting the position and size properties of the tooltip.\n\t * All the hard work is delegated to the display plugin.\n\t * Note: The tooltip may be detached from the DOM at the moment the method is called\n\t * but must be attached by the end of the method call.\n\t *\n\t * @param {object} event For internal use only. Defined if an event such as\n\t * window resizing triggered the repositioning\n\t * @param {boolean} tooltipIsDetached For internal use only. Set this to true if you\n\t * know that the tooltip not being in the DOM is not an issue (typically when the\n\t * tooltip element has just been created but has not been added to the DOM yet).\n\t * @returns {self}\n\t * @public\n\t */\n\treposition: function(event, tooltipIsDetached) {\n\n\t\tvar self = this;\n\n\t\tif (!self.__destroyed) {\n\n\t\t\t// if the tooltip is still open and the origin is still in the DOM\n\t\t\tif (self.__state != 'closed' && bodyContains(self._$origin)) {\n\n\t\t\t\t// if the tooltip has not been removed from DOM manually (or if it\n\t\t\t\t// has been detached on purpose)\n\t\t\t\tif (tooltipIsDetached || bodyContains(self._$tooltip)) {\n\n\t\t\t\t\tif (!tooltipIsDetached) {\n\t\t\t\t\t\t// detach in case the tooltip overflows the window and adds\n\t\t\t\t\t\t// scrollbars to it, so __geometry can be accurate\n\t\t\t\t\t\tself._$tooltip.detach();\n\t\t\t\t\t}\n\n\t\t\t\t\t// refresh the geometry object before passing it as a helper\n\t\t\t\t\tself.__Geometry = self.__geometry();\n\n\t\t\t\t\t// let a plugin fo the rest\n\t\t\t\t\tself._trigger({\n\t\t\t\t\t\ttype: 'reposition',\n\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\thelper: {\n\t\t\t\t\t\t\tgeo: self.__Geometry\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tself.__destroyError();\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Alias, deprecated in 4.0.0\n\t *\n\t * @param callback\n\t * @returns {self}\n\t * @public\n\t */\n\tshow: function(callback) {\n\t\treturn this.open(callback);\n\t},\n\n\t/**\n\t * Returns some properties about the instance\n\t *\n\t * @returns {object}\n\t * @public\n\t */\n\tstatus: function() {\n\n\t\treturn {\n\t\t\tdestroyed: this.__destroyed,\n\t\t\tenabled: this.__enabled,\n\t\t\topen: this.__state !== 'closed',\n\t\t\tstate: this.__state\n\t\t};\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\ttriggerHandler: function() {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t}\n};\n\n$.fn.tooltipster = function() {\n\n\t// for using in closures\n\tvar args = Array.prototype.slice.apply(arguments),\n\t\t// common mistake: an HTML element can't be in several tooltips at the same time\n\t\tcontentCloningWarning = 'You are using a single HTML element as content for several tooltips. You probably want to set the contentCloning option to TRUE.';\n\n\t// this happens with $(sel).tooltipster(...) when $(sel) does not match anything\n\tif (this.length === 0) {\n\n\t\t// still chainable\n\t\treturn this;\n\t}\n\t// this happens when calling $(sel).tooltipster('methodName or options')\n\t// where $(sel) matches one or more elements\n\telse {\n\n\t\t// method calls\n\t\tif (typeof args[0] === 'string') {\n\n\t\t\tvar v = '#*$~&';\n\n\t\t\tthis.each(function() {\n\n\t\t\t\t// retrieve the namepaces of the tooltip(s) that exist on that element.\n\t\t\t\t// We will interact with the first tooltip only.\n\t\t\t\tvar ns = $(this).data('tooltipster-ns'),\n\t\t\t\t\t// self represents the instance of the first tooltipster plugin\n\t\t\t\t\t// associated to the current HTML object of the loop\n\t\t\t\t\tself = ns ? $(this).data(ns[0]) : null;\n\n\t\t\t\t// if the current element holds a tooltipster instance\n\t\t\t\tif (self) {\n\n\t\t\t\t\tif (typeof self[args[0]] === 'function') {\n\n\t\t\t\t\t\tif (\tthis.length > 1\n\t\t\t\t\t\t\t&&\targs[0] == 'content'\n\t\t\t\t\t\t\t&&\t(\targs[1] instanceof $\n\t\t\t\t\t\t\t\t|| (typeof args[1] == 'object' && args[1] != null && args[1].tagName)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t&&\t!self.__options.contentCloning\n\t\t\t\t\t\t\t&&\tself.__options.debug\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tconsole.log(contentCloningWarning);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// note : args[1] and args[2] may not be defined\n\t\t\t\t\t\tvar resp = self[args[0]](args[1], args[2]);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthrow new Error('Unknown method \"'+ args[0] +'\"');\n\t\t\t\t\t}\n\n\t\t\t\t\t// if the function returned anything other than the instance\n\t\t\t\t\t// itself (which implies chaining, except for the `instance` method)\n\t\t\t\t\tif (resp !== self || args[0] === 'instance') {\n\n\t\t\t\t\t\tv = resp;\n\n\t\t\t\t\t\t// return false to stop .each iteration on the first element\n\t\t\t\t\t\t// matched by the selector\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error('You called Tooltipster\\'s \"'+ args[0] +'\" method on an uninitialized element');\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn (v !== '#*$~&') ? v : this;\n\t\t}\n\t\t// first argument is undefined or an object: the tooltip is initializing\n\t\telse {\n\n\t\t\t// reset the array of last initialized objects\n\t\t\t$.tooltipster.__instancesLatestArr = [];\n\n\t\t\t// is there a defined value for the multiple option in the options object ?\n\t\t\tvar\tmultipleIsSet = args[0] && args[0].multiple !== undefined,\n\t\t\t\t// if the multiple option is set to true, or if it's not defined but\n\t\t\t\t// set to true in the defaults\n\t\t\t\tmultiple = (multipleIsSet && args[0].multiple) || (!multipleIsSet && defaults.multiple),\n\t\t\t\t// same for content\n\t\t\t\tcontentIsSet = args[0] && args[0].content !== undefined,\n\t\t\t\tcontent = (contentIsSet && args[0].content) || (!contentIsSet && defaults.content),\n\t\t\t\t// same for contentCloning\n\t\t\t\tcontentCloningIsSet = args[0] && args[0].contentCloning !== undefined,\n\t\t\t\tcontentCloning =\n\t\t\t\t\t\t(contentCloningIsSet && args[0].contentCloning)\n\t\t\t\t\t||\t(!contentCloningIsSet && defaults.contentCloning),\n\t\t\t\t// same for debug\n\t\t\t\tdebugIsSet = args[0] && args[0].debug !== undefined,\n\t\t\t\tdebug = (debugIsSet && args[0].debug) || (!debugIsSet && defaults.debug);\n\n\t\t\tif (\tthis.length > 1\n\t\t\t\t&&\t(\tcontent instanceof $\n\t\t\t\t\t|| (typeof content == 'object' && content != null && content.tagName)\n\t\t\t\t)\n\t\t\t\t&&\t!contentCloning\n\t\t\t\t&&\tdebug\n\t\t\t) {\n\t\t\t\tconsole.log(contentCloningWarning);\n\t\t\t}\n\n\t\t\t// create a tooltipster instance for each element if it doesn't\n\t\t\t// already have one or if the multiple option is set, and attach the\n\t\t\t// object to it\n\t\t\tthis.each(function() {\n\n\t\t\t\tvar go = false,\n\t\t\t\t\t$this = $(this),\n\t\t\t\t\tns = $this.data('tooltipster-ns'),\n\t\t\t\t\tobj = null;\n\n\t\t\t\tif (!ns) {\n\t\t\t\t\tgo = true;\n\t\t\t\t}\n\t\t\t\telse if (multiple) {\n\t\t\t\t\tgo = true;\n\t\t\t\t}\n\t\t\t\telse if (debug) {\n\t\t\t\t\tconsole.log('Tooltipster: one or more tooltips are already attached to the element below. Ignoring.');\n\t\t\t\t\tconsole.log(this);\n\t\t\t\t}\n\n\t\t\t\tif (go) {\n\t\t\t\t\tobj = new $.Tooltipster(this, args[0]);\n\n\t\t\t\t\t// save the reference of the new instance\n\t\t\t\t\tif (!ns) ns = [];\n\t\t\t\t\tns.push(obj.__namespace);\n\t\t\t\t\t$this.data('tooltipster-ns', ns);\n\n\t\t\t\t\t// save the instance itself\n\t\t\t\t\t$this.data(obj.__namespace, obj);\n\n\t\t\t\t\t// call our constructor custom function.\n\t\t\t\t\t// we do this here and not in ::init() because we wanted\n\t\t\t\t\t// the object to be saved in $this.data before triggering\n\t\t\t\t\t// it\n\t\t\t\t\tif (obj.__options.functionInit) {\n\t\t\t\t\t\tobj.__options.functionInit.call(obj, obj, {\n\t\t\t\t\t\t\torigin: this\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t// and now the event, for the plugins and core emitter\n\t\t\t\t\tobj._trigger('init');\n\t\t\t\t}\n\n\t\t\t\t$.tooltipster.__instancesLatestArr.push(obj);\n\t\t\t});\n\n\t\t\treturn this;\n\t\t}\n\t}\n};\n\n// Utilities\n\n/**\n * A class to check if a tooltip can fit in given dimensions\n *\n * @param {object} $tooltip The jQuery wrapped tooltip element, or a clone of it\n */\nfunction Ruler($tooltip) {\n\n\t// list of instance variables\n\n\tthis.$container;\n\tthis.constraints = null;\n\tthis.__$tooltip;\n\n\tthis.__init($tooltip);\n}\n\nRuler.prototype = {\n\n\t/**\n\t * Move the tooltip into an invisible div that does not allow overflow to make\n\t * size tests. Note: the tooltip may or may not be attached to the DOM at the\n\t * moment this method is called, it does not matter.\n\t *\n\t * @param {object} $tooltip The object to test. May be just a clone of the\n\t * actual tooltip.\n\t * @private\n\t */\n\t__init: function($tooltip) {\n\n\t\tthis.__$tooltip = $tooltip;\n\n\t\tthis.__$tooltip\n\t\t\t.css({\n\t\t\t\t// for some reason we have to specify top and left 0\n\t\t\t\tleft: 0,\n\t\t\t\t// any overflow will be ignored while measuring\n\t\t\t\toverflow: 'hidden',\n\t\t\t\t// positions at (0,0) without the div using 100% of the available width\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: 0\n\t\t\t})\n\t\t\t// overflow must be auto during the test. We re-set this in case\n\t\t\t// it were modified by the user\n\t\t\t.find('.tooltipster-content')\n\t\t\t\t.css('overflow', 'auto');\n\n\t\tthis.$container = $('<div class=\"tooltipster-ruler\"></div>')\n\t\t\t.append(this.__$tooltip)\n\t\t\t.appendTo(env.window.document.body);\n\t},\n\n\t/**\n\t * Force the browser to redraw (re-render) the tooltip immediately. This is required\n\t * when you changed some CSS properties and need to make something with it\n\t * immediately, without waiting for the browser to redraw at the end of instructions.\n\t *\n\t * @see http://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes\n\t * @private\n\t */\n\t__forceRedraw: function() {\n\n\t\t// note: this would work but for Webkit only\n\t\t//this.__$tooltip.close();\n\t\t//this.__$tooltip[0].offsetHeight;\n\t\t//this.__$tooltip.open();\n\n\t\t// works in FF too\n\t\tvar $p = this.__$tooltip.parent();\n\t\tthis.__$tooltip.detach();\n\t\tthis.__$tooltip.appendTo($p);\n\t},\n\n\t/**\n\t * Set maximum dimensions for the tooltip. A call to ::measure afterwards\n\t * will tell us if the content overflows or if it's ok\n\t *\n\t * @param {int} width\n\t * @param {int} height\n\t * @return {Ruler}\n\t * @public\n\t */\n\tconstrain: function(width, height) {\n\n\t\tthis.constraints = {\n\t\t\twidth: width,\n\t\t\theight: height\n\t\t};\n\n\t\tthis.__$tooltip.css({\n\t\t\t// we disable display:flex, otherwise the content would overflow without\n\t\t\t// creating horizontal scrolling (which we need to detect).\n\t\t\tdisplay: 'block',\n\t\t\t// reset any previous height\n\t\t\theight: '',\n\t\t\t// we'll check if horizontal scrolling occurs\n\t\t\toverflow: 'auto',\n\t\t\t// we'll set the width and see what height is generated and if there\n\t\t\t// is horizontal overflow\n\t\t\twidth: width\n\t\t});\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Reset the tooltip content overflow and remove the test container\n\t *\n\t * @returns {Ruler}\n\t * @public\n\t */\n\tdestroy: function() {\n\n\t\t// in case the element was not a clone\n\t\tthis.__$tooltip\n\t\t\t.detach()\n\t\t\t.find('.tooltipster-content')\n\t\t\t\t.css({\n\t\t\t\t\t// reset to CSS value\n\t\t\t\t\tdisplay: '',\n\t\t\t\t\toverflow: ''\n\t\t\t\t});\n\n\t\tthis.$container.remove();\n\t},\n\n\t/**\n\t * Removes any constraints\n\t *\n\t * @returns {Ruler}\n\t * @public\n\t */\n\tfree: function() {\n\n\t\tthis.constraints = null;\n\n\t\t// reset to natural size\n\t\tthis.__$tooltip.css({\n\t\t\tdisplay: '',\n\t\t\theight: '',\n\t\t\toverflow: 'visible',\n\t\t\twidth: ''\n\t\t});\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns the size of the tooltip. When constraints are applied, also returns\n\t * whether the tooltip fits in the provided dimensions.\n\t * The idea is to see if the new height is small enough and if the content does\n\t * not overflow horizontally.\n\t *\n\t * @param {int} width\n\t * @param {int} height\n\t * @returns {object} An object with a bool `fits` property and a `size` property\n\t * @public\n\t */\n\tmeasure: function() {\n\n\t\tthis.__forceRedraw();\n\n\t\tvar tooltipBcr = this.__$tooltip[0].getBoundingClientRect(),\n\t\t\tresult = { size: {\n\t\t\t\t// bcr.width/height are not defined in IE8- but in this\n\t\t\t\t// case, bcr.right/bottom will have the same value\n\t\t\t\t// except in iOS 8+ where tooltipBcr.bottom/right are wrong\n\t\t\t\t// after scrolling for reasons yet to be determined.\n\t\t\t\t// tooltipBcr.top/left might not be 0, see issue #514\n\t\t\t\theight: tooltipBcr.height || (tooltipBcr.bottom - tooltipBcr.top),\n\t\t\t\twidth: tooltipBcr.width || (tooltipBcr.right - tooltipBcr.left)\n\t\t\t}};\n\n\t\tif (this.constraints) {\n\n\t\t\t// note: we used to use offsetWidth instead of boundingRectClient but\n\t\t\t// it returned rounded values, causing issues with sub-pixel layouts.\n\n\t\t\t// note2: noticed that the bcrWidth of text content of a div was once\n\t\t\t// greater than the bcrWidth of its container by 1px, causing the final\n\t\t\t// tooltip box to be too small for its content. However, evaluating\n\t\t\t// their widths one against the other (below) surprisingly returned\n\t\t\t// equality. Happened only once in Chrome 48, was not able to reproduce\n\t\t\t// => just having fun with float position values...\n\n\t\t\tvar $content = this.__$tooltip.find('.tooltipster-content'),\n\t\t\t\theight = this.__$tooltip.outerHeight(),\n\t\t\t\tcontentBcr = $content[0].getBoundingClientRect(),\n\t\t\t\tfits = {\n\t\t\t\t\theight: height <= this.constraints.height,\n\t\t\t\t\twidth: (\n\t\t\t\t\t\t// this condition accounts for min-width property that\n\t\t\t\t\t\t// may apply\n\t\t\t\t\t\ttooltipBcr.width <= this.constraints.width\n\t\t\t\t\t\t\t// the -1 is here because scrollWidth actually returns\n\t\t\t\t\t\t\t// a rounded value, and may be greater than bcr.width if\n\t\t\t\t\t\t\t// it was rounded up. This may cause an issue for contents\n\t\t\t\t\t\t\t// which actually really overflow by 1px or so, but that\n\t\t\t\t\t\t\t// should be rare. Not sure how to solve this efficiently.\n\t\t\t\t\t\t\t// See http://blogs.msdn.com/b/ie/archive/2012/02/17/sub-pixel-rendering-and-the-css-object-model.aspx\n\t\t\t\t\t\t&&\tcontentBcr.width >= $content[0].scrollWidth - 1\n\t\t\t\t\t)\n\t\t\t\t};\n\n\t\t\tresult.fits = fits.height && fits.width;\n\t\t}\n\n\t\t// old versions of IE get the width wrong for some reason and it causes\n\t\t// the text to be broken to a new line, so we round it up. If the width\n\t\t// is the width of the screen though, we can assume it is accurate.\n\t\tif (\tenv.IE\n\t\t\t&&\tenv.IE <= 11\n\t\t\t&&\tresult.size.width !== env.window.document.documentElement.clientWidth\n\t\t) {\n\t\t\tresult.size.width = Math.ceil(result.size.width) + 1;\n\t\t}\n\n\t\treturn result;\n\t}\n};\n\n// quick & dirty compare function, not bijective nor multidimensional\nfunction areEqual(a,b) {\n\tvar same = true;\n\t$.each(a, function(i, _) {\n\t\tif (b[i] === undefined || a[i] !== b[i]) {\n\t\t\tsame = false;\n\t\t\treturn false;\n\t\t}\n\t});\n\treturn same;\n}\n\n/**\n * A fast function to check if an element is still in the DOM. It\n * tries to use an id as ids are indexed by the browser, or falls\n * back to jQuery's `contains` method. May fail if two elements\n * have the same id, but so be it\n *\n * @param {object} $obj A jQuery-wrapped HTML element\n * @return {boolean}\n */\nfunction bodyContains($obj) {\n\tvar id = $obj.attr('id'),\n\t\tel = id ? env.window.document.getElementById(id) : null;\n\t// must also check that the element with the id is the one we want\n\treturn el ? el === $obj[0] : $.contains(env.window.document.body, $obj[0]);\n}\n\n// detect IE versions for dirty fixes\nvar uA = navigator.userAgent.toLowerCase();\nif (uA.indexOf('msie') != -1) env.IE = parseInt(uA.split('msie')[1]);\nelse if (uA.toLowerCase().indexOf('trident') !== -1 && uA.indexOf(' rv:11') !== -1) env.IE = 11;\nelse if (uA.toLowerCase().indexOf('edge/') != -1) env.IE = parseInt(uA.toLowerCase().split('edge/')[1]);\n\n// detecting support for CSS transitions\nfunction transitionSupport() {\n\n\t// env.window is not defined yet when this is called\n\tif (!win) return false;\n\n\tvar b = win.document.body || win.document.documentElement,\n\t\ts = b.style,\n\t\tp = 'transition',\n\t\tv = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'];\n\n\tif (typeof s[p] == 'string') { return true; }\n\n\tp = p.charAt(0).toUpperCase() + p.substr(1);\n\tfor (var i=0; i<v.length; i++) {\n\t\tif (typeof s[v[i] + p] == 'string') { return true; }\n\t}\n\treturn false;\n}\n\n// we'll return jQuery for plugins not to have to declare it as a dependency,\n// but it's done by a build task since it should be included only once at the\n// end when we concatenate the main file with a plugin\n// sideTip is Tooltipster's default plugin.\n// This file will be UMDified by a build task.\n\nvar pluginName = 'tooltipster.sideTip';\n\n$.tooltipster._plugin({\n\tname: pluginName,\n\tinstance: {\n\t\t/**\n\t\t * Defaults are provided as a function for an easy override by inheritance\n\t\t *\n\t\t * @return {object} An object with the defaults options\n\t\t * @private\n\t\t */\n\t\t__defaults: function() {\n\n\t\t\treturn {\n\t\t\t\t// if the tooltip should display an arrow that points to the origin\n\t\t\t\tarrow: true,\n\t\t\t\t// the distance in pixels between the tooltip and the origin\n\t\t\t\tdistance: 6,\n\t\t\t\t// allows to easily change the position of the tooltip\n\t\t\t\tfunctionPosition: null,\n\t\t\t\tmaxWidth: null,\n\t\t\t\t// used to accomodate the arrow of tooltip if there is one.\n\t\t\t\t// First to make sure that the arrow target is not too close\n\t\t\t\t// to the edge of the tooltip, so the arrow does not overflow\n\t\t\t\t// the tooltip. Secondly when we reposition the tooltip to\n\t\t\t\t// make sure that it's positioned in such a way that the arrow is\n\t\t\t\t// still pointing at the target (and not a few pixels beyond it).\n\t\t\t\t// It should be equal to or greater than half the width of\n\t\t\t\t// the arrow (by width we mean the size of the side which touches\n\t\t\t\t// the side of the tooltip).\n\t\t\t\tminIntersection: 16,\n\t\t\t\tminWidth: 0,\n\t\t\t\t// deprecated in 4.0.0. Listed for _optionsExtract to pick it up\n\t\t\t\tposition: null,\n\t\t\t\tside: 'top',\n\t\t\t\t// set to false to position the tooltip relatively to the document rather\n\t\t\t\t// than the window when we open it\n\t\t\t\tviewportAware: true,\n defaultStyles: {\n backgroundColor: '#fff',\n textColor: '#000'\n }\n\t\t\t};\n\t\t},\n\n\t\t/**\n\t\t * Run once: at instantiation of the plugin\n\t\t *\n\t\t * @param {object} instance The tooltipster object that instantiated this plugin\n\t\t * @private\n\t\t */\n\t\t__init: function(instance) {\n\n\t\t\tvar self = this;\n\n\t\t\t// list of instance variables\n\n\t\t\tself.__instance = instance;\n\t\t\tself.__namespace = 'tooltipster-sideTip-'+ Math.round(Math.random()*1000000);\n\t\t\tself.__previousState = 'closed';\n\t\t\tself.__options;\n\n\t\t\t// initial formatting\n\t\t\tself.__optionsFormat();\n\n\t\t\tself.__instance._on('state.'+ self.__namespace, function(event) {\n\n\t\t\t\tif (event.state == 'closed') {\n\t\t\t\t\tself.__close();\n\t\t\t\t}\n\t\t\t\telse if (event.state == 'appearing' && self.__previousState == 'closed') {\n\t\t\t\t\tself.__create();\n\t\t\t\t}\n\n\t\t\t\tself.__previousState = event.state;\n\t\t\t});\n\n\t\t\t// reformat every time the options are changed\n\t\t\tself.__instance._on('options.'+ self.__namespace, function() {\n\t\t\t\tself.__optionsFormat();\n\t\t\t});\n\n\t\t\tself.__instance._on('reposition.'+ self.__namespace, function(e) {\n\t\t\t\tself.__reposition(e.event, e.helper);\n\t\t\t});\n\t\t},\n\n\t\t/**\n\t\t * Called when the tooltip has closed\n\t\t *\n\t\t * @private\n\t\t */\n\t\t__close: function() {\n\n\t\t\t// detach our content object first, so the next jQuery's remove()\n\t\t\t// call does not unbind its event handlers\n\t\t\tif (this.__instance.content() instanceof $) {\n\t\t\t\tthis.__instance.content().detach();\n\t\t\t}\n\n\t\t\t// remove the tooltip from the DOM\n\t\t\tthis.__instance._$tooltip.remove();\n\t\t\tthis.__instance._$tooltip = null;\n\t\t},\n\n\t\t/**\n\t\t * Creates the HTML element of the tooltip.\n\t\t *\n\t\t * @private\n\t\t */\n\t\t__create: function() {\n\t\t var self = this,\n styles = this.__instance.__options.styles;\n\n\t\t\t// note: we wrap with a .tooltipster-box div to be able to set a margin on it\n\t\t\t// (.tooltipster-base must not have one)\n\t\t\tvar $html = $(\n\t\t\t\t'<div class=\"tooltipster-base tooltipster-sidetip\">' +\n\t\t\t\t\t'<div class=\"tooltipster-box\">' +\n\t\t\t\t\t\t'<div class=\"tooltipster-content\"></div>' +\n\t\t\t\t\t'</div>' +\n\t\t\t\t\t'<div class=\"tooltipster-arrow\">' +\n\t\t\t\t\t\t'<div class=\"tooltipster-arrow-uncropped\">' +\n\t\t\t\t\t\t\t'<div class=\"tooltipster-arrow-border\"></div>' +\n\t\t\t\t\t\t\t'<div class=\"tooltipster-arrow-background\"></div>' +\n\t\t\t\t\t\t'</div>' +\n\t\t\t\t\t'</div>' +\n\t\t\t\t'</div>'\n\t\t\t);\n\n $html\n .find('.tooltipster-box')\n .css({\n 'color': styles.textColor ? styles.textColor : self.__options.defaultStyles.textColor,\n 'backgroundColor': styles.backgroundColor\n ? styles.backgroundColor\n : self.__options.defaultStyles.backgroundColor\n });\n\n $html\n .find('.tooltipster-arrow-border')\n .css({\n 'backgroundColor': styles.backgroundColor\n ? styles.backgroundColor\n : self.__options.defaultStyles.backgroundColor\n });\n\n\t\t\t// hide arrow if asked\n\t\t\tif (!this.__options.arrow) {\n\t\t\t\t$html\n\t\t\t\t\t.find('.tooltipster-box')\n\t\t\t\t\t\t.css('margin', 0)\n\t\t\t\t\t\t.end()\n\t\t\t\t\t.find('.tooltipster-arrow')\n\t\t\t\t\t\t.hide();\n\t\t\t}\n\n\t\t\t// apply min/max width if asked\n\t\t\tif (this.__options.minWidth) {\n\t\t\t\t$html.css('min-width', this.__options.minWidth + 'px');\n\t\t\t}\n\t\t\tif (this.__options.maxWidth) {\n\t\t\t\t$html.css('max-width', this.__options.maxWidth + 'px');\n\t\t\t}\n\n\t\t\tthis.__instance._$tooltip = $html;\n\n\t\t\t// tell the instance that the tooltip element has been created\n\t\t\tthis.__instance._trigger('created');\n\t\t},\n\n\t\t/**\n\t\t * Used when the plugin is to be unplugged\n\t\t *\n\t\t * @private\n\t\t */\n\t\t__destroy: function() {\n\t\t\tthis.__instance._off('.'+ self.__namespace);\n\t\t},\n\n\t\t/**\n\t\t * (Re)compute this.__options from the options declared to the instance\n\t\t *\n\t\t * @private\n\t\t */\n\t\t__optionsFormat: function() {\n\n\t\t\tvar self = this;\n\n\t\t\t// get the options\n\t\t\tself.__options = self.__instance._optionsExtract(pluginName, self.__defaults());\n\n\t\t\t// for backward compatibility, deprecated in v4.0.0\n\t\t\tif (self.__options.position) {\n\t\t\t\tself.__options.side = self.__options.position;\n\t\t\t}\n\n\t\t\t// options formatting\n\n\t\t\t// format distance as a four-cell array if it ain't one yet and then make\n\t\t\t// it an object with top/bottom/left/right properties\n\t\t\tif (typeof self.__options.distance != 'object') {\n\t\t\t\tself.__options.distance = [self.__options.distance];\n\t\t\t}\n\t\t\tif (self.__options.distance.length < 4) {\n\t\t\t\tif (self.__options.distance[1] === undefined) self.__options.distance[1] = self.__options.distance[0];\n\t\t\t\tif (self.__options.distance[2] === undefined) self.__options.distance[2] = self.__options.distance[0];\n\t\t\t\tif (self.__options.distance[3] === undefined) self.__options.distance[3] = self.__options.distance[1];\n\t\t\t}\n\n\t\t\tself.__options.distance = {\n\t\t\t\ttop: self.__options.distance[0],\n\t\t\t\tright: self.__options.distance[1],\n\t\t\t\tbottom: self.__options.distance[2],\n\t\t\t\tleft: self.__options.distance[3]\n\t\t\t};\n\n\t\t\t// let's transform:\n\t\t\t// 'top' into ['top', 'bottom', 'right', 'left']\n\t\t\t// 'right' into ['right', 'left', 'top', 'bottom']\n\t\t\t// 'bottom' into ['bottom', 'top', 'right', 'left']\n\t\t\t// 'left' into ['left', 'right', 'top', 'bottom']\n\t\t\tif (typeof self.__options.side == 'string') {\n\n\t\t\t\tvar opposites = {\n\t\t\t\t\t'top': 'bottom',\n\t\t\t\t\t'right': 'left',\n\t\t\t\t\t'bottom': 'top',\n\t\t\t\t\t'left': 'right'\n\t\t\t\t};\n\n\t\t\t\tself.__options.side = [self.__options.side, opposites[self.__options.side]];\n\n\t\t\t\tif (self.__options.side[0] == 'left' || self.__options.side[0] == 'right') {\n\t\t\t\t\tself.__options.side.push('top', 'bottom');\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tself.__options.side.push('right', 'left');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// misc\n\t\t\t// disable the arrow in IE6 unless the arrow option was explicitly set to true\n\t\t\tif (\t$.tooltipster._env.IE === 6\n\t\t\t\t&&\tself.__options.arrow !== true\n\t\t\t) {\n\t\t\t\tself.__options.arrow = false;\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * This method must compute and set the positioning properties of the\n\t\t * tooltip (left, top, width, height, etc.). It must also make sure the\n\t\t * tooltip is eventually appended to its parent (since the element may be\n\t\t * detached from the DOM at the moment the method is called).\n\t\t *\n\t\t * We'll evaluate positioning scenarios to find which side can contain the\n\t\t * tooltip in the best way. We'll consider things relatively to the window\n\t\t * (unless the user asks not to), then to the document (if need be, or if the\n\t\t * user explicitly requires the tests to run on the document). For each\n\t\t * scenario, measures are taken, allowing us to know how well the tooltip\n\t\t * is going to fit. After that, a sorting function will let us know what\n\t\t * the best scenario is (we also allow the user to choose his favorite\n\t\t * scenario by using an event).\n\t\t *\n\t\t * @param {object} helper An object that contains variables that plugin\n\t\t * creators may find useful (see below)\n\t\t * @param {object} helper.geo An object with many layout properties\n\t\t * about objects of interest (window, document, origin). This should help\n\t\t * plugin users compute the optimal position of the tooltip\n\t\t * @private\n\t\t */\n\t\t__reposition: function(event, helper) {\n\n\t\t\tvar self = this,\n\t\t\t\tfinalResult,\n\t\t\t\t// to know where to put the tooltip, we need to know on which point\n\t\t\t\t// of the x or y axis we should center it. That coordinate is the target\n\t\t\t\ttargets = self.__targetFind(helper),\n\t\t\t\ttestResults = [];\n\n\t\t\t// make sure the tooltip is detached while we make tests on a clone\n\t\t\tself.__instance._$tooltip.detach();\n\n\t\t\t// we could actually provide the original element to the Ruler and\n\t\t\t// not a clone, but it just feels right to keep it out of the\n\t\t\t// machinery.\n\t\t\tvar $clone = self.__instance._$tooltip.clone(),\n\t\t\t\t// start position tests session\n\t\t\t\truler = $.tooltipster._getRuler($clone),\n\t\t\t\tsatisfied = false,\n\t\t\t\tanimation = self.__instance.option('animation');\n\n\t\t\t// an animation class could contain properties that distort the size\n\t\t\tif (animation) {\n\t\t\t\t$clone.removeClass('tooltipster-'+ animation);\n\t\t\t}\n\n\t\t\t// start evaluating scenarios\n\t\t\t$.each(['window', 'document'], function(i, container) {\n\n\t\t\t\tvar takeTest = null;\n\n\t\t\t\t// let the user decide to keep on testing or not\n\t\t\t\tself.__instance._trigger({\n\t\t\t\t\tcontainer: container,\n\t\t\t\t\thelper: helper,\n\t\t\t\t\tsatisfied: satisfied,\n\t\t\t\t\ttakeTest: function(bool) {\n\t\t\t\t\t\ttakeTest = bool;\n\t\t\t\t\t},\n\t\t\t\t\tresults: testResults,\n\t\t\t\t\ttype: 'positionTest'\n\t\t\t\t});\n\n\t\t\t\tif (\ttakeTest == true\n\t\t\t\t\t||\t(\ttakeTest != false\n\t\t\t\t\t\t&&\tsatisfied == false\n\t\t\t\t\t\t\t// skip the window scenarios if asked. If they are reintegrated by\n\t\t\t\t\t\t\t// the callback of the positionTest event, they will have to be\n\t\t\t\t\t\t\t// excluded using the callback of positionTested\n\t\t\t\t\t\t&&\t(container != 'window' || self.__options.viewportAware)\n\t\t\t\t\t)\n\t\t\t\t) {\n\n\t\t\t\t\t// for each allowed side\n\t\t\t\t\tfor (var i=0; i < self.__options.side.length; i++) {\n\n\t\t\t\t\t\tvar distance = {\n\t\t\t\t\t\t\t\thorizontal: 0,\n\t\t\t\t\t\t\t\tvertical: 0\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tside = self.__options.side[i];\n\n\t\t\t\t\t\tif (side == 'top' || side == 'bottom') {\n\t\t\t\t\t\t\tdistance.vertical = self.__options.distance[side];\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tdistance.horizontal = self.__options.distance[side];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// this may have an effect on the size of the tooltip if there are css\n\t\t\t\t\t\t// rules for the arrow or something else\n\t\t\t\t\t\tself.__sideChange($clone, side);\n\n\t\t\t\t\t\t$.each(['natural', 'constrained'], function(i, mode) {\n\n\t\t\t\t\t\t\ttakeTest = null;\n\n\t\t\t\t\t\t\t// emit an event on the instance\n\t\t\t\t\t\t\tself.__instance._trigger({\n\t\t\t\t\t\t\t\tcontainer: container,\n\t\t\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\t\t\thelper: helper,\n\t\t\t\t\t\t\t\tmode: mode,\n\t\t\t\t\t\t\t\tresults: testResults,\n\t\t\t\t\t\t\t\tsatisfied: satisfied,\n\t\t\t\t\t\t\t\tside: side,\n\t\t\t\t\t\t\t\ttakeTest: function(bool) {\n\t\t\t\t\t\t\t\t\ttakeTest = bool;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\ttype: 'positionTest'\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (\ttakeTest == true\n\t\t\t\t\t\t\t\t||\t(\ttakeTest != false\n\t\t\t\t\t\t\t\t\t&&\tsatisfied == false\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t) {\n\n\t\t\t\t\t\t\t\tvar testResult = {\n\t\t\t\t\t\t\t\t\tcontainer: container,\n\t\t\t\t\t\t\t\t\t// we let the distance as an object here, it can make things a little easier\n\t\t\t\t\t\t\t\t\t// during the user's calculations at positionTest/positionTested\n\t\t\t\t\t\t\t\t\tdistance: distance,\n\t\t\t\t\t\t\t\t\t// whether the tooltip can fit in the size of the viewport (does not mean\n\t\t\t\t\t\t\t\t\t// that we'll be able to make it initially entirely visible, see 'whole')\n\t\t\t\t\t\t\t\t\tfits: null,\n\t\t\t\t\t\t\t\t\tmode: mode,\n\t\t\t\t\t\t\t\t\touterSize: null,\n\t\t\t\t\t\t\t\t\tside: side,\n\t\t\t\t\t\t\t\t\tsize: null,\n\t\t\t\t\t\t\t\t\ttarget: targets[side],\n\t\t\t\t\t\t\t\t\t// check if the origin has enough surface on screen for the tooltip to\n\t\t\t\t\t\t\t\t\t// aim at it without overflowing the viewport (this is due to the thickness\n\t\t\t\t\t\t\t\t\t// of the arrow represented by the minIntersection length).\n\t\t\t\t\t\t\t\t\t// If not, the tooltip will have to be partly or entirely off screen in\n\t\t\t\t\t\t\t\t\t// order to stay docked to the origin. This value will stay null when the\n\t\t\t\t\t\t\t\t\t// container is the document, as it is not relevant\n\t\t\t\t\t\t\t\t\twhole: null\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t// get the size of the tooltip with or without size constraints\n\t\t\t\t\t\t\t\tvar rulerConfigured = (mode == 'natural') ?\n\t\t\t\t\t\t\t\t\t\truler.free() :\n\t\t\t\t\t\t\t\t\t\truler.constrain(\n\t\t\t\t\t\t\t\t\t\t\thelper.geo.available[container][side].width - distance.horizontal,\n\t\t\t\t\t\t\t\t\t\t\thelper.geo.available[container][side].height - distance.vertical\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\trulerResults = rulerConfigured.measure();\n\n\t\t\t\t\t\t\t\ttestResult.size = rulerResults.size;\n\t\t\t\t\t\t\t\ttestResult.outerSize = {\n\t\t\t\t\t\t\t\t\theight: rulerResults.size.height + distance.vertical,\n\t\t\t\t\t\t\t\t\twidth: rulerResults.size.width + distance.horizontal\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tif (mode == 'natural') {\n\n\t\t\t\t\t\t\t\t\tif(\t\thelper.geo.available[container][side].width >= testResult.outerSize.width\n\t\t\t\t\t\t\t\t\t\t&&\thelper.geo.available[container][side].height >= testResult.outerSize.height\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\ttestResult.fits = true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\ttestResult.fits = false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\ttestResult.fits = rulerResults.fits;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (container == 'window') {\n\n\t\t\t\t\t\t\t\t\tif (!testResult.fits) {\n\t\t\t\t\t\t\t\t\t\ttestResult.whole = false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tif (side == 'top' || side == 'bottom') {\n\n\t\t\t\t\t\t\t\t\t\t\ttestResult.whole = (\n\t\t\t\t\t\t\t\t\t\t\t\t\thelper.geo.origin.windowOffset.right >= self.__options.minIntersection\n\t\t\t\t\t\t\t\t\t\t\t\t&&\thelper.geo.window.size.width - helper.geo.origin.windowOffset.left >= self.__options.minIntersection\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\t\ttestResult.whole = (\n\t\t\t\t\t\t\t\t\t\t\t\t\thelper.geo.origin.windowOffset.bottom >= self.__options.minIntersection\n\t\t\t\t\t\t\t\t\t\t\t\t&&\thelper.geo.window.size.height - helper.geo.origin.windowOffset.top >= self.__options.minIntersection\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ttestResults.push(testResult);\n\n\t\t\t\t\t\t\t\t// we don't need to compute more positions if we have one fully on screen\n\t\t\t\t\t\t\t\tif (testResult.whole) {\n\t\t\t\t\t\t\t\t\tsatisfied = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t// don't run the constrained test unless the natural width was greater\n\t\t\t\t\t\t\t\t\t// than the available width, otherwise it's pointless as we know it\n\t\t\t\t\t\t\t\t\t// wouldn't fit either\n\t\t\t\t\t\t\t\t\tif (\ttestResult.mode == 'natural'\n\t\t\t\t\t\t\t\t\t\t&&\t(\ttestResult.fits\n\t\t\t\t\t\t\t\t\t\t\t||\ttestResult.size.width <= helper.geo.available[container][side].width\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// the user may eliminate the unwanted scenarios from testResults, but he's\n\t\t\t// not supposed to alter them at this point. functionPosition and the\n\t\t\t// position event serve that purpose.\n\t\t\tself.__instance._trigger({\n\t\t\t\tedit: function(r) {\n\t\t\t\t\ttestResults = r;\n\t\t\t\t},\n\t\t\t\tevent: event,\n\t\t\t\thelper: helper,\n\t\t\t\tresults: testResults,\n\t\t\t\ttype: 'positionTested'\n\t\t\t});\n\n\t\t\t/**\n\t\t\t * Sort the scenarios to find the favorite one.\n\t\t\t *\n\t\t\t * The favorite scenario is when we can fully display the tooltip on screen,\n\t\t\t * even if it means that the middle of the tooltip is no longer centered on\n\t\t\t * the middle of the origin (when the origin is near the edge of the screen\n\t\t\t * or even partly off screen). We want the tooltip on the preferred side,\n\t\t\t * even if it means that we have to use a constrained size rather than a\n\t\t\t * natural one (as long as it fits). When the origin is off screen at the top\n\t\t\t * the tooltip will be positioned at the bottom (if allowed), if the origin\n\t\t\t * is off screen on the right, it will be positioned on the left, etc.\n\t\t\t * If there are no scenarios where the tooltip can fit on screen, or if the\n\t\t\t * user does not want the tooltip to fit on screen (viewportAware == false),\n\t\t\t * we fall back to the scenarios relative to the document.\n\t\t\t *\n\t\t\t * When the tooltip is bigger than the viewport in either dimension, we stop\n\t\t\t * looking at the window scenarios and consider the document scenarios only,\n\t\t\t * with the same logic to find on which side it would fit best.\n\t\t\t *\n\t\t\t * If the tooltip cannot fit the document on any side, we force it at the\n\t\t\t * bottom, so at least the user can scroll to see it.\n \t\t\t */\n\t\t\ttestResults.sort(function(a, b) {\n\n\t\t\t\t// best if it's whole (the tooltip fits and adapts to the viewport)\n\t\t\t\tif (a.whole && !b.whole) {\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\telse if (!a.whole && b.whole) {\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\telse if (a.whole && b.whole) {\n\n\t\t\t\t\tvar ai = self.__options.side.indexOf(a.side),\n\t\t\t\t\t\tbi = self.__options.side.indexOf(b.side);\n\n\t\t\t\t\t// use the user's sides fallback array\n\t\t\t\t\tif (ai < bi) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (ai > bi) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// will be used if the user forced the tests to continue\n\t\t\t\t\t\treturn a.mode == 'natural' ? -1 : 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\n\t\t\t\t\t// better if it fits\n\t\t\t\t\tif (a.fits && !b.fits) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!a.fits && b.fits) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (a.fits && b.fits) {\n\n\t\t\t\t\t\tvar ai = self.__options.side.indexOf(a.side),\n\t\t\t\t\t\t\tbi = self.__options.side.indexOf(b.side);\n\n\t\t\t\t\t\t// use the user's sides fallback array\n\t\t\t\t\t\tif (ai < bi) {\n\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (ai > bi) {\n\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// will be used if the user forced the tests to continue\n\t\t\t\t\t\t\treturn a.mode == 'natural' ? -1 : 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\n\t\t\t\t\t\t// if everything failed, this will give a preference to the case where\n\t\t\t\t\t\t// the tooltip overflows the document at the bottom\n\t\t\t\t\t\tif (\ta.container == 'document'\n\t\t\t\t\t\t\t&&\ta.side == 'bottom'\n\t\t\t\t\t\t\t&&\ta.mode == 'natural'\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tfinalResult = testResults[0];\n\n\n\t\t\t// now let's find the coordinates of the tooltip relatively to the window\n\t\t\tfinalResult.coord = {};\n\n\t\t\tswitch (finalResult.side) {\n\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'right':\n\t\t\t\t\tfinalResult.coord.top = Math.floor(finalResult.target - finalResult.size.height / 2);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'bottom':\n\t\t\t\tcase 'top':\n\t\t\t\t\tfinalResult.coord.left = Math.floor(finalResult.target - finalResult.size.width / 2);\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tswitch (finalResult.side) {\n\n\t\t\t\tcase 'left':\n\t\t\t\t\tfinalResult.coord.left = helper.geo.origin.windowOffset.left - finalResult.outerSize.width;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'right':\n\t\t\t\t\tfinalResult.coord.left = helper.geo.origin.windowOffset.right + finalResult.distance.horizontal;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'top':\n\t\t\t\t\tfinalResult.coord.top = helper.geo.origin.windowOffset.top - finalResult.outerSize.height;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'bottom':\n\t\t\t\t\tfinalResult.coord.top = helper.geo.origin.windowOffset.bottom + finalResult.distance.vertical;\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// if the tooltip can potentially be contained within the viewport dimensions\n\t\t\t// and that we are asked to make it fit on screen\n\t\t\tif (finalResult.container == 'window') {\n\n\t\t\t\t// if the tooltip overflows the viewport, we'll move it accordingly (then it will\n\t\t\t\t// not be centered on the middle of the origin anymore). We only move horizontally\n\t\t\t\t// for top and bottom tooltips and vice versa.\n\t\t\t\tif (finalResult.side == 'top' || finalResult.side == 'bottom') {\n\n\t\t\t\t\t// if there is an overflow on the left\n\t\t\t\t\tif (finalResult.coord.left < 0) {\n\n\t\t\t\t\t\t// prevent the overflow unless the origin itself gets off screen (minus the\n\t\t\t\t\t\t// margin needed to keep the arrow pointing at the target)\n\t\t\t\t\t\tif (helper.geo.origin.windowOffset.right - this.__options.minIntersection >= 0) {\n\t\t\t\t\t\t\tfinalResult.coord.left = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tfinalResult.coord.left = helper.geo.origin.windowOffset.right - this.__options.minIntersection - 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// or an overflow on the right\n\t\t\t\t\telse if (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) {\n\n\t\t\t\t\t\tif (helper.geo.origin.windowOffset.left + this.__options.minIntersection <= helper.geo.window.size.width) {\n\t\t\t\t\t\t\tfinalResult.coord.left = helper.geo.window.size.width - finalResult.size.width;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tfinalResult.coord.left = helper.geo.origin.windowOffset.left + this.__options.minIntersection + 1 - finalResult.size.width;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\n\t\t\t\t\t// overflow at the top\n\t\t\t\t\tif (finalResult.coord.top < 0) {\n\n\t\t\t\t\t\tif (helper.geo.origin.windowOffset.bottom - this.__options.minIntersection >= 0) {\n\t\t\t\t\t\t\tfinalResult.coord.top = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tfinalResult.coord.top = helper.geo.origin.windowOffset.bottom - this.__options.minIntersection - 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// or at the bottom\n\t\t\t\t\telse if (finalResult.coord.top > helper.geo.window.size.height - finalResult.size.height) {\n\n\t\t\t\t\t\tif (helper.geo.origin.windowOffset.top + this.__options.minIntersection <= helper.geo.window.size.height) {\n\t\t\t\t\t\t\tfinalResult.coord.top = helper.geo.window.size.height - finalResult.size.height;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tfinalResult.coord.top = helper.geo.origin.windowOffset.top + this.__options.minIntersection + 1 - finalResult.size.height;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\n\t\t\t\t// there might be overflow here too but it's easier to handle. If there has\n\t\t\t\t// to be an overflow, we'll make sure it's on the right side of the screen\n\t\t\t\t// (because the browser will extend the document size if there is an overflow\n\t\t\t\t// on the right, but not on the left). The sort function above has already\n\t\t\t\t// made sure that a bottom document overflow is preferred to a top overflow,\n\t\t\t\t// so we don't have to care about it.\n\n\t\t\t\t// if there is an overflow on the right\n\t\t\t\tif (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) {\n\n\t\t\t\t\t// this may actually create on overflow on the left but we'll fix it in a sec\n\t\t\t\t\tfinalResult.coord.left = helper.geo.window.size.width - finalResult.size.width;\n\t\t\t\t}\n\n\t\t\t\t// if there is an overflow on the left\n\t\t\t\tif (finalResult.coord.left < 0) {\n\n\t\t\t\t\t// don't care if it overflows the right after that, we made our best\n\t\t\t\t\tfinalResult.coord.left = 0;\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\t// submit the positioning proposal to the user function which may choose to change\n\t\t\t// the side, size and/or the coordinates\n\n\t\t\t// first, set the rules that corresponds to the proposed side: it may change\n\t\t\t// the size of the tooltip, and the custom functionPosition may want to detect the\n\t\t\t// size of something before making a decision. So let's make things easier for the\n\t\t\t// implementor\n\t\t\tself.__sideChange($clone, finalResult.side);\n\n\t\t\t// add some variables to the helper\n\t\t\thelper.tooltipClone = $clone[0];\n\t\t\thelper.tooltipParent = self.__instance.option('parent').parent[0];\n\t\t\t// move informative values to the helper\n\t\t\thelper.mode = finalResult.mode;\n\t\t\thelper.whole = finalResult.whole;\n\t\t\t// add some variables to the helper for the functionPosition callback (these\n\t\t\t// will also be added to the event fired by self.__instance._trigger but that's\n\t\t\t// ok, we're just being consistent)\n\t\t\thelper.origin = self.__instance._$origin[0];\n\t\t\thelper.tooltip = self.__instance._$tooltip[0];\n\n\t\t\t// leave only the actionable values in there for functionPosition\n\t\t\tdelete finalResult.container;\n\t\t\tdelete finalResult.fits;\n\t\t\tdelete finalResult.mode;\n\t\t\tdelete finalResult.outerSize;\n\t\t\tdelete finalResult.whole;\n\n\t\t\t// keep only the distance on the relevant side, for clarity\n\t\t\tfinalResult.distance = finalResult.distance.horizontal || finalResult.distance.vertical;\n\n\t\t\t// beginners may not be comfortable with the concept of editing the object\n\t\t\t// passed by reference, so we provide an edit function and pass a clone\n\t\t\tvar finalResultClone = $.extend(true, {}, finalResult);\n\n\t\t\t// emit an event on the instance\n\t\t\tself.__instance._trigger({\n\t\t\t\tedit: function(result) {\n\t\t\t\t\tfinalResult = result;\n\t\t\t\t},\n\t\t\t\tevent: event,\n\t\t\t\thelper: helper,\n\t\t\t\tposition: finalResultClone,\n\t\t\t\ttype: 'position'\n\t\t\t});\n\n\t\t\tif (self.__options.functionPosition) {\n\n\t\t\t\tvar result = self.__options.functionPosition.call(self, self.__instance, helper, finalResultClone);\n\n\t\t\t\tif (result) finalResult = result;\n\t\t\t}\n\n\t\t\t// end the positioning tests session (the user might have had a\n\t\t\t// use for it during the position event, now it's over)\n\t\t\truler.destroy();\n\n\t\t\t// compute the position of the target relatively to the tooltip root\n\t\t\t// element so we can place the arrow and make the needed adjustments\n\t\t\tvar arrowCoord,\n\t\t\t\tmaxVal;\n\n\t\t\tif (finalResult.side == 'top' || finalResult.side == 'bottom') {\n\n\t\t\t\tarrowCoord = {\n\t\t\t\t\tprop: 'left',\n\t\t\t\t\tval: finalResult.target - finalResult.coord.left\n\t\t\t\t};\n\t\t\t\tmaxVal = finalResult.size.width - this.__options.minIntersection;\n\t\t\t}\n\t\t\telse {\n\n\t\t\t\tarrowCoord = {\n\t\t\t\t\tprop: 'top',\n\t\t\t\t\tval: finalResult.target - finalResult.coord.top\n\t\t\t\t};\n\t\t\t\tmaxVal = finalResult.size.height - this.__options.minIntersection;\n\t\t\t}\n\n\t\t\t// cannot lie beyond the boundaries of the tooltip, minus the\n\t\t\t// arrow margin\n\t\t\tif (arrowCoord.val < this.__options.minIntersection) {\n\t\t\t\tarrowCoord.val = this.__options.minIntersection;\n\t\t\t}\n\t\t\telse if (arrowCoord.val > maxVal) {\n\t\t\t\tarrowCoord.val = maxVal;\n\t\t\t}\n\n\t\t\tvar originParentOffset;\n\n\t\t\t// let's convert the window-relative coordinates into coordinates relative to the\n\t\t\t// future positioned parent that the tooltip will be appended to\n\t\t\tif (helper.geo.origin.fixedLineage) {\n\n\t\t\t\t// same as windowOffset when the position is fixed\n\t\t\t\toriginParentOffset = helper.geo.origin.windowOffset;\n\t\t\t}\n\t\t\telse {\n\n\t\t\t\t// this assumes that the parent of the tooltip is located at\n\t\t\t\t// (0, 0) in the document, typically like when the parent is\n\t\t\t\t// <body>.\n\t\t\t\t// If we ever allow other types of parent, .tooltipster-ruler\n\t\t\t\t// will have to be appended to the parent to inherit css style\n\t\t\t\t// values that affect the display of the text and such.\n\t\t\t\toriginParentOffset = {\n\t\t\t\t\tleft: helper.geo.origin.windowOffset.left + helper.geo.window.scroll.left,\n\t\t\t\t\ttop: helper.geo.origin.windowOffset.top + helper.geo.window.scroll.top\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tfinalResult.coord = {\n\t\t\t\tleft: originParentOffset.left + (finalResult.coord.left - helper.geo.origin.windowOffset.left),\n\t\t\t\ttop: originParentOffset.top + (finalResult.coord.top - helper.geo.origin.windowOffset.top)\n\t\t\t};\n\n\t\t\t// set position values on the original tooltip element\n\n\t\t\tself.__sideChange(self.__instance._$tooltip, finalResult.side);\n\n\t\t\tif (helper.geo.origin.fixedLineage) {\n\t\t\t\tself.__instance._$tooltip\n\t\t\t\t\t.css('position', 'fixed');\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// CSS default\n\t\t\t\tself.__instance._$tooltip\n\t\t\t\t\t.css('position', '');\n\t\t\t}\n\n\t\t\tself.__instance._$tooltip\n\t\t\t\t.css({\n\t\t\t\t\tleft: finalResult.coord.left,\n\t\t\t\t\ttop: finalResult.coord.top,\n\t\t\t\t\t// we need to set a size even if the tooltip is in its natural size\n\t\t\t\t\t// because when the tooltip is positioned beyond the width of the body\n\t\t\t\t\t// (which is by default the width of the window; it will happen when\n\t\t\t\t\t// you scroll the window horizontally to get to the origin), its text\n\t\t\t\t\t// content will otherwise break lines at each word to keep up with the\n\t\t\t\t\t// body overflow strategy.\n\t\t\t\t\theight: finalResult.size.height,\n\t\t\t\t\twidth: finalResult.size.width\n\t\t\t\t})\n\t\t\t\t.find('.tooltipster-arrow')\n\t\t\t\t\t.css({\n\t\t\t\t\t\t'left': '',\n\t\t\t\t\t\t'top': ''\n\t\t\t\t\t})\n\t\t\t\t\t.css(arrowCoord.prop, arrowCoord.val);\n\n\t\t\t// append the tooltip HTML element to its parent\n\t\t\tself.__instance._$tooltip.appendTo(self.__instance.option('parent'));\n\n\t\t\tself.__instance._trigger({\n\t\t\t\ttype: 'repositioned',\n\t\t\t\tevent: event,\n\t\t\t\tposition: finalResult\n\t\t\t});\n\t\t},\n\n\t\t/**\n\t\t * Make whatever modifications are needed when the side is changed. This has\n\t\t * been made an independant method for easy inheritance in custom plugins based\n\t\t * on this default plugin.\n\t\t *\n\t\t * @param {object} $obj\n\t\t * @param {string} side\n\t\t * @private\n\t\t */\n\t\t__sideChange: function($obj, side) {\n\n\t\t\t$obj\n\t\t\t\t.removeClass('tooltipster-bottom')\n\t\t\t\t.removeClass('tooltipster-left')\n\t\t\t\t.removeClass('tooltipster-right')\n\t\t\t\t.removeClass('tooltipster-top')\n\t\t\t\t.addClass('tooltipster-'+ side);\n\t\t},\n\n\t\t/**\n\t\t * Returns the target that the tooltip should aim at for a given side.\n\t\t * The calculated value is a distance from the edge of the window\n\t\t * (left edge for top/bottom sides, top edge for left/right side). The\n\t\t * tooltip will be centered on that position and the arrow will be\n\t\t * positioned there (as much as possible).\n\t\t *\n\t\t * @param {object} helper\n\t\t * @return {integer}\n\t\t * @private\n\t\t */\n\t\t__targetFind: function(helper) {\n\n\t\t\tvar target = {},\n\t\t\t\trects = this.__instance._$origin[0].getClientRects();\n\n\t\t\t// these lines fix a Chrome bug (issue #491)\n\t\t\tif (rects.length > 1) {\n\t\t\t\tvar opacity = this.__instance._$origin.css('opacity');\n\t\t\t\tif(opacity == 1) {\n\t\t\t\t\tthis.__instance._$origin.css('opacity', 0.99);\n\t\t\t\t\trects = this.__instance._$origin[0].getClientRects();\n\t\t\t\t\tthis.__instance._$origin.css('opacity', 1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// by default, the target will be the middle of the origin\n\t\t\tif (rects.length < 2) {\n\n\t\t\t\ttarget.top = Math.floor(helper.geo.origin.windowOffset.left + (helper.geo.origin.size.width / 2));\n\t\t\t\ttarget.bottom = target.top;\n\n\t\t\t\ttarget.left = Math.floor(helper.geo.origin.windowOffset.top + (helper.geo.origin.size.height / 2));\n\t\t\t\ttarget.right = target.left;\n\t\t\t}\n\t\t\t// if multiple client rects exist, the element may be text split\n\t\t\t// up into multiple lines and the middle of the origin may not be\n\t\t\t// best option anymore. We need to choose the best target client rect\n\t\t\telse {\n\n\t\t\t\t// top: the first\n\t\t\t\tvar targetRect = rects[0];\n\t\t\t\ttarget.top = Math.floor(targetRect.left + (targetRect.right - targetRect.left) / 2);\n\n\t\t\t\t// right: the middle line, rounded down in case there is an even\n\t\t\t\t// number of lines (looks more centered => check out the\n\t\t\t\t// demo with 4 split lines)\n\t\t\t\tif (rects.length > 2) {\n\t\t\t\t\ttargetRect = rects[Math.ceil(rects.length / 2) - 1];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttargetRect = rects[0];\n\t\t\t\t}\n\t\t\t\ttarget.right = Math.floor(targetRect.top + (targetRect.bottom - targetRect.top) / 2);\n\n\t\t\t\t// bottom: the last\n\t\t\t\ttargetRect = rects[rects.length - 1];\n\t\t\t\ttarget.bottom = Math.floor(targetRect.left + (targetRect.right - targetRect.left) / 2);\n\n\t\t\t\t// left: the middle line, rounded up\n\t\t\t\tif (rects.length > 2) {\n\t\t\t\t\ttargetRect = rects[Math.ceil((rects.length + 1) / 2) - 1];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttargetRect = rects[rects.length - 1];\n\t\t\t\t}\n\n\t\t\t\ttarget.left = Math.floor(targetRect.top + (targetRect.bottom - targetRect.top) / 2);\n\t\t\t}\n\n\t\t\treturn target;\n\t\t}\n\t}\n});\n\n/* a build task will add \"return $;\" here */\nreturn $;\n\n}));\n","Amasty_Rewards/vendor/tooltipster/js/tooltipster.min.js":"!function(t,i){\"function\"==typeof define&&define.amd?define([\"jquery\"],function(t){return i(t)}):\"object\"==typeof exports?module.exports=i(require(\"jquery\")):i(jQuery)}(0,function(t){var i={animation:\"fade\",animationDuration:350,content:null,contentAsHTML:!1,contentCloning:!1,debug:!0,delay:300,delayTouch:[300,500],functionInit:null,functionBefore:null,functionReady:null,functionAfter:null,functionFormat:null,IEmin:6,interactive:!1,multiple:!1,parent:null,plugins:[\"sideTip\"],repositionOnScroll:!1,restoration:\"none\",selfDestruction:!0,theme:[],timer:0,trackerInterval:500,trackOrigin:!1,trackTooltip:!1,trigger:\"hover\",triggerClose:{click:!1,mouseleave:!1,originClick:!1,scroll:!1,tap:!1,touchleave:!1},triggerOpen:{click:!1,mouseenter:!1,tap:!1,touchstart:!1},updateAnimation:\"rotate\",zIndex:9999999,styles:{backgroundColor:\"\",textColor:\"\"}},o=\"undefined\"!=typeof window?window:null,e={hasTouchCapability:!(!o||!(\"ontouchstart\"in o||o.DocumentTouch&&o.document instanceof o.DocumentTouch||o.navigator.maxTouchPoints)),hasTransitions:function(){if(!o)return!1;var t=(o.document.body||o.document.documentElement).style,i=\"transition\",e=[\"Moz\",\"Webkit\",\"Khtml\",\"O\",\"ms\"];if(\"string\"==typeof t[i])return!0;i=i.charAt(0).toUpperCase()+i.substr(1);for(var n=0;n<e.length;n++)if(\"string\"==typeof t[e[n]+i])return!0;return!1}(),IE:!1,semVer:\"4.2.8\",window:o},n=function(){this.__$emitterPrivate=t({}),this.__$emitterPublic=t({}),this.__instancesLatestArr=[],this.__plugins={},this._env=e};function s(t){this.$container,this.constraints=null,this.__$tooltip,this.__init(t)}function r(i,o){var e=!0;return t.each(i,function(t,n){if(void 0===o[t]||i[t]!==o[t])return e=!1,!1}),e}function _(i){var o=i.attr(\"id\"),n=o?e.window.document.getElementById(o):null;return n?n===i[0]:t.contains(e.window.document.body,i[0])}n.prototype={__bridge:function(o,e,n){if(!e[n]){var s=function(){};s.prototype=o;var r=new s;r.__init&&r.__init(e),t.each(o,function(t,o){0!=t.indexOf(\"__\")&&(e[t]?i.debug&&console.log(\"The \"+t+\" method of the \"+n+\" plugin conflicts with another plugin or native methods\"):(e[t]=function(){return r[t].apply(r,Array.prototype.slice.apply(arguments))},e[t].bridged=r))}),e[n]=r}return this},__setWindow:function(t){return e.window=t,this},_getRuler:function(t){return new s(t)},_off:function(){return this.__$emitterPrivate.off.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_on:function(){return this.__$emitterPrivate.on.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_one:function(){return this.__$emitterPrivate.one.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_plugin:function(i){if(\"string\"==typeof i){var o=i,e=null;return o.indexOf(\".\")>0?e=this.__plugins[o]:t.each(this.__plugins,function(t,i){if(i.name.substring(i.name.length-o.length-1)==\".\"+o)return e=i,!1}),e}if(i.name.indexOf(\".\")<0)throw new Error(\"Plugins must be namespaced\");return this.__plugins[i.name]=i,i.core&&this.__bridge(i.core,this,i.name),this},_trigger:function(){var t=Array.prototype.slice.apply(arguments);return\"string\"==typeof t[0]&&(t[0]={type:t[0]}),this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate,t),this.__$emitterPublic.trigger.apply(this.__$emitterPublic,t),this},instances:function(i){var o=[];return t(i||\".tooltipstered\").each(function(){var i=t(this),e=i.data(\"tooltipster-ns\");e&&t.each(e,function(t,e){o.push(i.data(e))})}),o},instancesLatest:function(){return this.__instancesLatestArr},off:function(){return this.__$emitterPublic.off.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},on:function(){return this.__$emitterPublic.on.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},one:function(){return this.__$emitterPublic.one.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},origins:function(i){return t((i?i+\" \":\"\")+\".tooltipstered\").toArray()},setDefaults:function(o){return t.extend(i,o),this},triggerHandler:function(){return this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this}},t.tooltipster=new n,t.Tooltipster=function(i,o){this.__callbacks={close:[],open:[]},this.__closingTime,this.__Content,this.__contentBcr,this.__destroyed=!1,this.__$emitterPrivate=t({}),this.__$emitterPublic=t({}),this.__enabled=!0,this.__garbageCollector,this.__Geometry,this.__lastPosition,this.__namespace=\"tooltipster-\"+Math.round(1e6*Math.random()),this.__options,this.__$originParents,this.__pointerIsOverOrigin=!1,this.__previousThemes=[],this.__state=\"closed\",this.__timeouts={close:[],open:null},this.__touchEvents=[],this.__tracker=null,this._$origin,this._$tooltip,this.__init(i,o)},t.Tooltipster.prototype={__init:function(o,n){var s=this;if(s._$origin=t(o),s.__options=t.extend(!0,{},i,n),s.__optionsFormat(),!e.IE||e.IE>=s.__options.IEmin){var r=null;if(void 0===s._$origin.data(\"tooltipster-initialTitle\")&&(void 0===(r=s._$origin.attr(\"title\"))&&(r=null),s._$origin.data(\"tooltipster-initialTitle\",r)),null!==s.__options.content)s.__contentSet(s.__options.content);else{var _,a=s._$origin.attr(\"data-tooltip-content\");a&&(_=t(a)),_&&_[0]?s.__contentSet(_.first()):s.__contentSet(r)}s._$origin.removeAttr(\"title\").addClass(\"tooltipstered\"),s.__prepareOrigin(),s.__prepareGC(),t.each(s.__options.plugins,function(t,i){s._plug(i)}),e.hasTouchCapability&&t(e.window.document.body).on(\"touchmove.\"+s.__namespace+\"-triggerOpen\",function(t){s._touchRecordEvent(t)}),s._on(\"created\",function(){s.__prepareTooltip()})._on(\"repositioned\",function(t){s.__lastPosition=t.position})}else s.__options.disabled=!0},__contentInsert:function(){var t=this._$tooltip.find(\".tooltipster-content\"),i=this.__Content;return this._trigger({type:\"format\",content:this.__Content,format:function(t){i=t}}),this.__options.functionFormat&&(i=this.__options.functionFormat.call(this,this,{origin:this._$origin[0]},this.__Content)),\"string\"!=typeof i||this.__options.contentAsHTML?t.empty().append(i):t.text(i),this},__contentSet:function(i){return i instanceof t&&this.__options.contentCloning&&(i=i.clone(!0)),this.__Content=i,this._trigger({type:\"updated\",content:i}),this},__destroyError:function(){throw new Error(\"This tooltip has been destroyed and cannot execute your method call.\")},__geometry:function(){var i=this._$origin,o=this._$origin.is(\"area\");if(o){var n=this._$origin.parent().attr(\"name\");i=t('img[usemap=\"#'+n+'\"]')}var s=i[0].getBoundingClientRect(),r=t(e.window.document),_=t(e.window),a=i,l={available:{document:null,window:null},document:{size:{height:r.height(),width:r.width()}},window:{scroll:{left:e.window.scrollX||e.window.document.documentElement.scrollLeft,top:e.window.scrollY||e.window.document.documentElement.scrollTop},size:{height:_.height(),width:_.width()}},origin:{fixedLineage:!1,offset:{},size:{height:s.bottom-s.top,width:s.right-s.left},usemapImage:o?i[0]:null,windowOffset:{bottom:s.bottom,left:s.left,right:s.right,top:s.top}}};if(o){var p=this._$origin.attr(\"shape\"),c=this._$origin.attr(\"coords\");if(c&&(c=c.split(\",\"),t.map(c,function(t,i){c[i]=parseInt(t)})),\"default\"!=p)switch(p){case\"circle\":var h=c[0],d=c[1],u=c[2],g=d-u,f=h-u;l.origin.size.height=2*u,l.origin.size.width=l.origin.size.height,l.origin.windowOffset.left+=f,l.origin.windowOffset.top+=g;break;case\"rect\":var m=c[0],w=c[1],v=c[2],y=c[3];l.origin.size.height=y-w,l.origin.size.width=v-m,l.origin.windowOffset.left+=m,l.origin.windowOffset.top+=w;break;case\"poly\":for(var b=0,$=0,C=0,O=0,T=\"even\",z=0;z<c.length;z++){var E=c[z];\"even\"==T?(E>C&&(C=E,0===z&&(b=C)),E<b&&(b=E),T=\"odd\"):(E>O&&(O=E,1==z&&($=O)),E<$&&($=E),T=\"even\")}l.origin.size.height=O-$,l.origin.size.width=C-b,l.origin.windowOffset.left+=b,l.origin.windowOffset.top+=$}}for(this._trigger({type:\"geometry\",edit:function(t){l.origin.size.height=t.height,l.origin.windowOffset.left=t.left,l.origin.windowOffset.top=t.top,l.origin.size.width=t.width},geometry:{height:l.origin.size.height,left:l.origin.windowOffset.left,top:l.origin.windowOffset.top,width:l.origin.size.width}}),l.origin.windowOffset.right=l.origin.windowOffset.left+l.origin.size.width,l.origin.windowOffset.bottom=l.origin.windowOffset.top+l.origin.size.height,l.origin.offset.left=l.origin.windowOffset.left+l.window.scroll.left,l.origin.offset.top=l.origin.windowOffset.top+l.window.scroll.top,l.origin.offset.bottom=l.origin.offset.top+l.origin.size.height,l.origin.offset.right=l.origin.offset.left+l.origin.size.width,l.available.document={bottom:{height:l.document.size.height-l.origin.offset.bottom,width:l.document.size.width},left:{height:l.document.size.height,width:l.origin.offset.left},right:{height:l.document.size.height,width:l.document.size.width-l.origin.offset.right},top:{height:l.origin.offset.top,width:l.document.size.width}},l.available.window={bottom:{height:Math.max(l.window.size.height-Math.max(l.origin.windowOffset.bottom,0),0),width:l.window.size.width},left:{height:l.window.size.height,width:Math.max(l.origin.windowOffset.left,0)},right:{height:l.window.size.height,width:Math.max(l.window.size.width-Math.max(l.origin.windowOffset.right,0),0)},top:{height:Math.max(l.origin.windowOffset.top,0),width:l.window.size.width}};\"html\"!=a[0].tagName.toLowerCase();){if(\"fixed\"==a.css(\"position\")){l.origin.fixedLineage=!0;break}a=a.parent()}return l},__optionsFormat:function(){return\"number\"==typeof this.__options.animationDuration&&(this.__options.animationDuration=[this.__options.animationDuration,this.__options.animationDuration]),\"number\"==typeof this.__options.delay&&(this.__options.delay=[this.__options.delay,this.__options.delay]),\"number\"==typeof this.__options.delayTouch&&(this.__options.delayTouch=[this.__options.delayTouch,this.__options.delayTouch]),\"string\"==typeof this.__options.theme&&(this.__options.theme=[this.__options.theme]),null===this.__options.parent?this.__options.parent=t(e.window.document.body):\"string\"==typeof this.__options.parent&&(this.__options.parent=t(this.__options.parent)),\"hover\"==this.__options.trigger?(this.__options.triggerOpen={mouseenter:!0,touchstart:!0},this.__options.triggerClose={mouseleave:!0,originClick:!0,touchleave:!0}):\"click\"==this.__options.trigger&&(this.__options.triggerOpen={click:!0,tap:!0},this.__options.triggerClose={click:!0,tap:!0}),this._trigger(\"options\"),this},__prepareGC:function(){var i=this;return i.__options.selfDestruction?i.__garbageCollector=setInterval(function(){var o=(new Date).getTime();i.__touchEvents=t.grep(i.__touchEvents,function(t,i){return o-t.time>6e4}),_(i._$origin)||i.close(function(){i.destroy()})},2e4):clearInterval(i.__garbageCollector),i},__prepareOrigin:function(){var t=this;if(t._$origin.off(\".\"+t.__namespace+\"-triggerOpen\"),e.hasTouchCapability&&t._$origin.on(\"touchstart.\"+t.__namespace+\"-triggerOpen touchend.\"+t.__namespace+\"-triggerOpen touchcancel.\"+t.__namespace+\"-triggerOpen\",function(i){t._touchRecordEvent(i)}),t.__options.triggerOpen.click||t.__options.triggerOpen.tap&&e.hasTouchCapability){var i=\"\";t.__options.triggerOpen.click&&(i+=\"click.\"+t.__namespace+\"-triggerOpen \"),t.__options.triggerOpen.tap&&e.hasTouchCapability&&(i+=\"touchend.\"+t.__namespace+\"-triggerOpen\"),t._$origin.on(i,function(i){t._touchIsMeaningfulEvent(i)&&t._open(i)})}if(t.__options.triggerOpen.mouseenter||t.__options.triggerOpen.touchstart&&e.hasTouchCapability){i=\"\";t.__options.triggerOpen.mouseenter&&(i+=\"mouseenter.\"+t.__namespace+\"-triggerOpen \"),t.__options.triggerOpen.touchstart&&e.hasTouchCapability&&(i+=\"touchstart.\"+t.__namespace+\"-triggerOpen\"),t._$origin.on(i,function(i){!t._touchIsTouchEvent(i)&&t._touchIsEmulatedEvent(i)||(t.__pointerIsOverOrigin=!0,t._openShortly(i))})}if(t.__options.triggerClose.mouseleave||t.__options.triggerClose.touchleave&&e.hasTouchCapability){i=\"\";t.__options.triggerClose.mouseleave&&(i+=\"mouseleave.\"+t.__namespace+\"-triggerOpen \"),t.__options.triggerClose.touchleave&&e.hasTouchCapability&&(i+=\"touchend.\"+t.__namespace+\"-triggerOpen touchcancel.\"+t.__namespace+\"-triggerOpen\"),t._$origin.on(i,function(i){t._touchIsMeaningfulEvent(i)&&(t.__pointerIsOverOrigin=!1)})}return t},__prepareTooltip:function(){var i=this,o=i.__options.interactive?\"auto\":\"\";return i._$tooltip.attr(\"id\",i.__namespace).css({\"pointer-events\":o,zIndex:i.__options.zIndex}),t.each(i.__previousThemes,function(t,o){i._$tooltip.removeClass(o)}),t.each(i.__options.theme,function(t,o){i._$tooltip.addClass(o)}),i.__previousThemes=t.merge([],i.__options.theme),i},__scrollHandler:function(i){if(this.__options.triggerClose.scroll)this._close(i);else if(_(this._$origin)&&_(this._$tooltip)){var o=null;if(i.target===e.window.document)this.__Geometry.origin.fixedLineage||this.__options.repositionOnScroll&&this.reposition(i);else{o=this.__geometry();var n=!1;if(\"fixed\"!=this._$origin.css(\"position\")&&this.__$originParents.each(function(i,e){var s=t(e),r=s.css(\"overflow-x\"),_=s.css(\"overflow-y\");if(\"visible\"!=r||\"visible\"!=_){var a=e.getBoundingClientRect();if(\"visible\"!=r&&(o.origin.windowOffset.left<a.left||o.origin.windowOffset.right>a.right))return n=!0,!1;if(\"visible\"!=_&&(o.origin.windowOffset.top<a.top||o.origin.windowOffset.bottom>a.bottom))return n=!0,!1}if(\"fixed\"==s.css(\"position\"))return!1}),n)this._$tooltip.css(\"visibility\",\"hidden\");else if(this._$tooltip.css(\"visibility\",\"visible\"),this.__options.repositionOnScroll)this.reposition(i);else{var s=o.origin.offset.left-this.__Geometry.origin.offset.left,r=o.origin.offset.top-this.__Geometry.origin.offset.top;this._$tooltip.css({left:this.__lastPosition.coord.left+s,top:this.__lastPosition.coord.top+r})}}this._trigger({type:\"scroll\",event:i,geo:o})}return this},__stateSet:function(t){return this.__state=t,this._trigger({type:\"state\",state:t}),this},__timeoutsClear:function(){return clearTimeout(this.__timeouts.open),this.__timeouts.open=null,t.each(this.__timeouts.close,function(t,i){clearTimeout(i)}),this.__timeouts.close=[],this},__trackerStart:function(){var t=this,i=t._$tooltip.find(\".tooltipster-content\");return t.__options.trackTooltip&&(t.__contentBcr=i[0].getBoundingClientRect()),t.__tracker=setInterval(function(){if(_(t._$origin)&&_(t._$tooltip)){if(t.__options.trackOrigin){var o=t.__geometry(),e=!1;r(o.origin.size,t.__Geometry.origin.size)&&(t.__Geometry.origin.fixedLineage?r(o.origin.windowOffset,t.__Geometry.origin.windowOffset)&&(e=!0):r(o.origin.offset,t.__Geometry.origin.offset)&&(e=!0)),e||(t.__options.triggerClose.mouseleave?t._close():t.reposition())}if(t.__options.trackTooltip){var n=i[0].getBoundingClientRect();n.height===t.__contentBcr.height&&n.width===t.__contentBcr.width||(t.reposition(),t.__contentBcr=n)}}else t._close()},t.__options.trackerInterval),t},_close:function(i,o,n){var s=this,r=!0;if(s._trigger({type:\"close\",event:i,stop:function(){r=!1}}),r||n){o&&s.__callbacks.close.push(o),s.__callbacks.open=[],s.__timeoutsClear();var _=function(){t.each(s.__callbacks.close,function(t,o){o.call(s,s,{event:i,origin:s._$origin[0]})}),s.__callbacks.close=[]};if(\"closed\"!=s.__state){var a=!0,l=(new Date).getTime()+s.__options.animationDuration[1];if(\"disappearing\"==s.__state&&l>s.__closingTime&&s.__options.animationDuration[1]>0&&(a=!1),a){s.__closingTime=l,\"disappearing\"!=s.__state&&s.__stateSet(\"disappearing\");var p=function(){clearInterval(s.__tracker),s._trigger({type:\"closing\",event:i}),s._$tooltip.off(\".\"+s.__namespace+\"-triggerClose\").removeClass(\"tooltipster-dying\"),t(e.window).off(\".\"+s.__namespace+\"-triggerClose\"),s.__$originParents.each(function(i,o){t(o).off(\"scroll.\"+s.__namespace+\"-triggerClose\")}),s.__$originParents=null,t(e.window.document.body).off(\".\"+s.__namespace+\"-triggerClose\"),s._$origin.off(\".\"+s.__namespace+\"-triggerClose\"),s._off(\"dismissable\"),s.__stateSet(\"closed\"),s._trigger({type:\"after\",event:i}),s.__options.functionAfter&&s.__options.functionAfter.call(s,s,{event:i,origin:s._$origin[0]}),_()};e.hasTransitions?(s._$tooltip.css({\"-moz-animation-duration\":s.__options.animationDuration[1]+\"ms\",\"-ms-animation-duration\":s.__options.animationDuration[1]+\"ms\",\"-o-animation-duration\":s.__options.animationDuration[1]+\"ms\",\"-webkit-animation-duration\":s.__options.animationDuration[1]+\"ms\",\"animation-duration\":s.__options.animationDuration[1]+\"ms\",\"transition-duration\":s.__options.animationDuration[1]+\"ms\"}),s._$tooltip.clearQueue().removeClass(\"tooltipster-show\").addClass(\"tooltipster-dying\"),s.__options.animationDuration[1]>0&&s._$tooltip.delay(s.__options.animationDuration[1]),s._$tooltip.queue(p)):s._$tooltip.stop().fadeOut(s.__options.animationDuration[1],p)}}else _()}return s},_off:function(){return this.__$emitterPrivate.off.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_on:function(){return this.__$emitterPrivate.on.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_one:function(){return this.__$emitterPrivate.one.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_open:function(i,o){var n=this;if(!n.__destroying&&_(n._$origin)&&n.__enabled){var s=!0;if(\"closed\"==n.__state&&(n._trigger({type:\"before\",event:i,stop:function(){s=!1}}),s&&n.__options.functionBefore&&(s=n.__options.functionBefore.call(n,n,{event:i,origin:n._$origin[0]}))),!1!==s&&null!==n.__Content){o&&n.__callbacks.open.push(o),n.__callbacks.close=[],n.__timeoutsClear();var r,a=function(){\"stable\"!=n.__state&&n.__stateSet(\"stable\"),t.each(n.__callbacks.open,function(t,i){i.call(n,n,{origin:n._$origin[0],tooltip:n._$tooltip[0]})}),n.__callbacks.open=[]};if(\"closed\"!==n.__state)r=0,\"disappearing\"===n.__state?(n.__stateSet(\"appearing\"),e.hasTransitions?(n._$tooltip.clearQueue().removeClass(\"tooltipster-dying\").addClass(\"tooltipster-show\"),n.__options.animationDuration[0]>0&&n._$tooltip.delay(n.__options.animationDuration[0]),n._$tooltip.queue(a)):n._$tooltip.stop().fadeIn(a)):\"stable\"==n.__state&&a();else{if(n.__stateSet(\"appearing\"),r=n.__options.animationDuration[0],n.__contentInsert(),n.reposition(i,!0),e.hasTransitions?(n._$tooltip.addClass(\"tooltipster-\"+n.__options.animation).addClass(\"tooltipster-initial\").css({\"-moz-animation-duration\":n.__options.animationDuration[0]+\"ms\",\"-ms-animation-duration\":n.__options.animationDuration[0]+\"ms\",\"-o-animation-duration\":n.__options.animationDuration[0]+\"ms\",\"-webkit-animation-duration\":n.__options.animationDuration[0]+\"ms\",\"animation-duration\":n.__options.animationDuration[0]+\"ms\",\"transition-duration\":n.__options.animationDuration[0]+\"ms\"}),setTimeout(function(){\"closed\"!=n.__state&&(n._$tooltip.addClass(\"tooltipster-show\").removeClass(\"tooltipster-initial\"),n.__options.animationDuration[0]>0&&n._$tooltip.delay(n.__options.animationDuration[0]),n._$tooltip.queue(a))},0)):n._$tooltip.css(\"display\",\"none\").fadeIn(n.__options.animationDuration[0],a),n.__trackerStart(),t(e.window).on(\"resize.\"+n.__namespace+\"-triggerClose\",function(i){var o=t(document.activeElement);(o.is(\"input\")||o.is(\"textarea\"))&&t.contains(n._$tooltip[0],o[0])||n.reposition(i)}).on(\"scroll.\"+n.__namespace+\"-triggerClose\",function(t){n.__scrollHandler(t)}),n.__$originParents=n._$origin.parents(),n.__$originParents.each(function(i,o){t(o).on(\"scroll.\"+n.__namespace+\"-triggerClose\",function(t){n.__scrollHandler(t)})}),n.__options.triggerClose.mouseleave||n.__options.triggerClose.touchleave&&e.hasTouchCapability){n._on(\"dismissable\",function(t){t.dismissable?t.delay?(h=setTimeout(function(){n._close(t.event)},t.delay),n.__timeouts.close.push(h)):n._close(t):clearTimeout(h)});var l=n._$origin,p=\"\",c=\"\",h=null;n.__options.interactive&&(l=l.add(n._$tooltip)),n.__options.triggerClose.mouseleave&&(p+=\"mouseenter.\"+n.__namespace+\"-triggerClose \",c+=\"mouseleave.\"+n.__namespace+\"-triggerClose \"),n.__options.triggerClose.touchleave&&e.hasTouchCapability&&(p+=\"touchstart.\"+n.__namespace+\"-triggerClose\",c+=\"touchend.\"+n.__namespace+\"-triggerClose touchcancel.\"+n.__namespace+\"-triggerClose\"),l.on(c,function(t){if(n._touchIsTouchEvent(t)||!n._touchIsEmulatedEvent(t)){var i=\"mouseleave\"==t.type?n.__options.delay:n.__options.delayTouch;n._trigger({delay:i[1],dismissable:!0,event:t,type:\"dismissable\"})}}).on(p,function(t){!n._touchIsTouchEvent(t)&&n._touchIsEmulatedEvent(t)||n._trigger({dismissable:!1,event:t,type:\"dismissable\"})})}n.__options.triggerClose.originClick&&n._$origin.on(\"click.\"+n.__namespace+\"-triggerClose\",function(t){n._touchIsTouchEvent(t)||n._touchIsEmulatedEvent(t)||n._close(t)}),(n.__options.triggerClose.click||n.__options.triggerClose.tap&&e.hasTouchCapability)&&setTimeout(function(){if(\"closed\"!=n.__state){var i=\"\",o=t(e.window.document.body);n.__options.triggerClose.click&&(i+=\"click.\"+n.__namespace+\"-triggerClose \"),n.__options.triggerClose.tap&&e.hasTouchCapability&&(i+=\"touchend.\"+n.__namespace+\"-triggerClose\"),o.on(i,function(i){n._touchIsMeaningfulEvent(i)&&(n._touchRecordEvent(i),n.__options.interactive&&t.contains(n._$tooltip[0],i.target)||n._close(i))}),n.__options.triggerClose.tap&&e.hasTouchCapability&&o.on(\"touchstart.\"+n.__namespace+\"-triggerClose\",function(t){n._touchRecordEvent(t)})}},0),n._trigger(\"ready\"),n.__options.functionReady&&n.__options.functionReady.call(n,n,{origin:n._$origin[0],tooltip:n._$tooltip[0]})}if(n.__options.timer>0){h=setTimeout(function(){n._close()},n.__options.timer+r);n.__timeouts.close.push(h)}}}return n},_openShortly:function(t){var i=this,o=!0;if(\"stable\"!=i.__state&&\"appearing\"!=i.__state&&!i.__timeouts.open&&(i._trigger({type:\"start\",event:t,stop:function(){o=!1}}),o)){var e=0==t.type.indexOf(\"touch\")?i.__options.delayTouch:i.__options.delay;e[0]?i.__timeouts.open=setTimeout(function(){i.__timeouts.open=null,i.__pointerIsOverOrigin&&i._touchIsMeaningfulEvent(t)?(i._trigger(\"startend\"),i._open(t)):i._trigger(\"startcancel\")},e[0]):(i._trigger(\"startend\"),i._open(t))}return i},_optionsExtract:function(i,o){var e=this,n=t.extend(!0,{},o),s=e.__options[i];return s||(s={},t.each(o,function(t,i){var o=e.__options[t];void 0!==o&&(s[t]=o)})),t.each(n,function(i,o){void 0!==s[i]&&(\"object\"!=typeof o||o instanceof Array||null==o||\"object\"!=typeof s[i]||s[i]instanceof Array||null==s[i]?n[i]=s[i]:t.extend(n[i],s[i]))}),n},_plug:function(i){var o=t.tooltipster._plugin(i);if(!o)throw new Error('The \"'+i+'\" plugin is not defined');return o.instance&&t.tooltipster.__bridge(o.instance,this,o.name),this},_touchIsEmulatedEvent:function(t){for(var i=!1,o=(new Date).getTime(),e=this.__touchEvents.length-1;e>=0;e--){var n=this.__touchEvents[e];if(!(o-n.time<500))break;n.target===t.target&&(i=!0)}return i},_touchIsMeaningfulEvent:function(t){return this._touchIsTouchEvent(t)&&!this._touchSwiped(t.target)||!this._touchIsTouchEvent(t)&&!this._touchIsEmulatedEvent(t)},_touchIsTouchEvent:function(t){return 0==t.type.indexOf(\"touch\")},_touchRecordEvent:function(t){return this._touchIsTouchEvent(t)&&(t.time=(new Date).getTime(),this.__touchEvents.push(t)),this},_touchSwiped:function(t){for(var i=!1,o=this.__touchEvents.length-1;o>=0;o--){var e=this.__touchEvents[o];if(\"touchmove\"==e.type){i=!0;break}if(\"touchstart\"==e.type&&t===e.target)break}return i},_trigger:function(){var i=Array.prototype.slice.apply(arguments);return\"string\"==typeof i[0]&&(i[0]={type:i[0]}),i[0].instance=this,i[0].origin=this._$origin?this._$origin[0]:null,i[0].tooltip=this._$tooltip?this._$tooltip[0]:null,this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate,i),t.tooltipster._trigger.apply(t.tooltipster,i),this.__$emitterPublic.trigger.apply(this.__$emitterPublic,i),this},_unplug:function(i){var o=this;if(o[i]){var e=t.tooltipster._plugin(i);e.instance&&t.each(e.instance,function(t,e){o[t]&&o[t].bridged===o[i]&&delete o[t]}),o[i].__destroy&&o[i].__destroy(),delete o[i]}return o},close:function(t){return this.__destroyed?this.__destroyError():this._close(null,t),this},content:function(t){var i=this;if(void 0===t)return i.__Content;if(i.__destroyed)i.__destroyError();else if(i.__contentSet(t),null!==i.__Content){if(\"closed\"!==i.__state&&(i.__contentInsert(),i.reposition(),i.__options.updateAnimation))if(e.hasTransitions){var o=i.__options.updateAnimation;i._$tooltip.addClass(\"tooltipster-update-\"+o),setTimeout(function(){\"closed\"!=i.__state&&i._$tooltip.removeClass(\"tooltipster-update-\"+o)},1e3)}else i._$tooltip.fadeTo(200,.5,function(){\"closed\"!=i.__state&&i._$tooltip.fadeTo(200,1)})}else i._close();return i},destroy:function(){var i=this;if(i.__destroyed)i.__destroyError();else{\"closed\"!=i.__state?i.option(\"animationDuration\",0)._close(null,null,!0):i.__timeoutsClear(),i._trigger(\"destroy\"),i.__destroyed=!0,i._$origin.removeData(i.__namespace).off(\".\"+i.__namespace+\"-triggerOpen\"),t(e.window.document.body).off(\".\"+i.__namespace+\"-triggerOpen\");var o=i._$origin.data(\"tooltipster-ns\");if(o)if(1===o.length){var n=null;\"previous\"==i.__options.restoration?n=i._$origin.data(\"tooltipster-initialTitle\"):\"current\"==i.__options.restoration&&(n=\"string\"==typeof i.__Content?i.__Content:t(\"<div></div>\").append(i.__Content).html()),n&&i._$origin.attr(\"title\",n),i._$origin.removeClass(\"tooltipstered\"),i._$origin.removeData(\"tooltipster-ns\").removeData(\"tooltipster-initialTitle\")}else o=t.grep(o,function(t,o){return t!==i.__namespace}),i._$origin.data(\"tooltipster-ns\",o);i._trigger(\"destroyed\"),i._off(),i.off(),i.__Content=null,i.__$emitterPrivate=null,i.__$emitterPublic=null,i.__options.parent=null,i._$origin=null,i._$tooltip=null,t.tooltipster.__instancesLatestArr=t.grep(t.tooltipster.__instancesLatestArr,function(t,o){return i!==t}),clearInterval(i.__garbageCollector)}return i},disable:function(){return this.__destroyed?(this.__destroyError(),this):(this._close(),this.__enabled=!1,this)},elementOrigin:function(){if(!this.__destroyed)return this._$origin[0];this.__destroyError()},elementTooltip:function(){return this._$tooltip?this._$tooltip[0]:null},enable:function(){return this.__enabled=!0,this},hide:function(t){return this.close(t)},instance:function(){return this},off:function(){return this.__destroyed||this.__$emitterPublic.off.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},on:function(){return this.__destroyed?this.__destroyError():this.__$emitterPublic.on.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},one:function(){return this.__destroyed?this.__destroyError():this.__$emitterPublic.one.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},open:function(t){return this.__destroyed?this.__destroyError():this._open(null,t),this},option:function(i,o){return void 0===o?this.__options[i]:(this.__destroyed?this.__destroyError():(this.__options[i]=o,this.__optionsFormat(),t.inArray(i,[\"trigger\",\"triggerClose\",\"triggerOpen\"])>=0&&this.__prepareOrigin(),\"selfDestruction\"===i&&this.__prepareGC()),this)},reposition:function(t,i){return this.__destroyed?this.__destroyError():\"closed\"!=this.__state&&_(this._$origin)&&(i||_(this._$tooltip))&&(i||this._$tooltip.detach(),this.__Geometry=this.__geometry(),this._trigger({type:\"reposition\",event:t,helper:{geo:this.__Geometry}})),this},show:function(t){return this.open(t)},status:function(){return{destroyed:this.__destroyed,enabled:this.__enabled,open:\"closed\"!==this.__state,state:this.__state}},triggerHandler:function(){return this.__destroyed?this.__destroyError():this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this}},t.fn.tooltipster=function(){var o=Array.prototype.slice.apply(arguments),e=\"You are using a single HTML element as content for several tooltips. You probably want to set the contentCloning option to TRUE.\";if(0===this.length)return this;if(\"string\"==typeof o[0]){var n=\"#*$~&\";return this.each(function(){var i=t(this).data(\"tooltipster-ns\"),s=i?t(this).data(i[0]):null;if(!s)throw new Error(\"You called Tooltipster's \\\"\"+o[0]+'\" method on an uninitialized element');if(\"function\"!=typeof s[o[0]])throw new Error('Unknown method \"'+o[0]+'\"');this.length>1&&\"content\"==o[0]&&(o[1]instanceof t||\"object\"==typeof o[1]&&null!=o[1]&&o[1].tagName)&&!s.__options.contentCloning&&s.__options.debug&&console.log(e);var r=s[o[0]](o[1],o[2]);if(r!==s||\"instance\"===o[0])return n=r,!1}),\"#*$~&\"!==n?n:this}t.tooltipster.__instancesLatestArr=[];var s=o[0]&&void 0!==o[0].multiple,r=s&&o[0].multiple||!s&&i.multiple,_=o[0]&&void 0!==o[0].content,a=_&&o[0].content||!_&&i.content,l=o[0]&&void 0!==o[0].contentCloning,p=l&&o[0].contentCloning||!l&&i.contentCloning,c=o[0]&&void 0!==o[0].debug,h=c&&o[0].debug||!c&&i.debug;return this.length>1&&(a instanceof t||\"object\"==typeof a&&null!=a&&a.tagName)&&!p&&h&&console.log(e),this.each(function(){var i=!1,e=t(this),n=e.data(\"tooltipster-ns\"),s=null;n?r?i=!0:h&&(console.log(\"Tooltipster: one or more tooltips are already attached to the element below. Ignoring.\"),console.log(this)):i=!0,i&&(s=new t.Tooltipster(this,o[0]),n||(n=[]),n.push(s.__namespace),e.data(\"tooltipster-ns\",n),e.data(s.__namespace,s),s.__options.functionInit&&s.__options.functionInit.call(s,s,{origin:this}),s._trigger(\"init\")),t.tooltipster.__instancesLatestArr.push(s)}),this},s.prototype={__init:function(i){this.__$tooltip=i,this.__$tooltip.css({left:0,overflow:\"hidden\",position:\"absolute\",top:0}).find(\".tooltipster-content\").css(\"overflow\",\"auto\"),this.$container=t('<div class=\"tooltipster-ruler\"></div>').append(this.__$tooltip).appendTo(e.window.document.body)},__forceRedraw:function(){var t=this.__$tooltip.parent();this.__$tooltip.detach(),this.__$tooltip.appendTo(t)},constrain:function(t,i){return this.constraints={width:t,height:i},this.__$tooltip.css({display:\"block\",height:\"\",overflow:\"auto\",width:t}),this},destroy:function(){this.__$tooltip.detach().find(\".tooltipster-content\").css({display:\"\",overflow:\"\"}),this.$container.remove()},free:function(){return this.constraints=null,this.__$tooltip.css({display:\"\",height:\"\",overflow:\"visible\",width:\"\"}),this},measure:function(){this.__forceRedraw();var t=this.__$tooltip[0].getBoundingClientRect(),i={size:{height:t.height||t.bottom-t.top,width:t.width||t.right-t.left}};if(this.constraints){var o=this.__$tooltip.find(\".tooltipster-content\"),n=this.__$tooltip.outerHeight(),s=o[0].getBoundingClientRect(),r={height:n<=this.constraints.height,width:t.width<=this.constraints.width&&s.width>=o[0].scrollWidth-1};i.fits=r.height&&r.width}return e.IE&&e.IE<=11&&i.size.width!==e.window.document.documentElement.clientWidth&&(i.size.width=Math.ceil(i.size.width)+1),i}};var a=navigator.userAgent.toLowerCase();-1!=a.indexOf(\"msie\")?e.IE=parseInt(a.split(\"msie\")[1]):-1!==a.toLowerCase().indexOf(\"trident\")&&-1!==a.indexOf(\" rv:11\")?e.IE=11:-1!=a.toLowerCase().indexOf(\"edge/\")&&(e.IE=parseInt(a.toLowerCase().split(\"edge/\")[1]));return t.tooltipster._plugin({name:\"tooltipster.sideTip\",instance:{__defaults:function(){return{arrow:!0,distance:6,functionPosition:null,maxWidth:null,minIntersection:16,minWidth:0,position:null,side:\"top\",viewportAware:!0,defaultStyles:{backgroundColor:\"#fff\",textColor:\"#000\"}}},__init:function(t){var i=this;i.__instance=t,i.__namespace=\"tooltipster-sideTip-\"+Math.round(1e6*Math.random()),i.__previousState=\"closed\",i.__options,i.__optionsFormat(),i.__instance._on(\"state.\"+i.__namespace,function(t){\"closed\"==t.state?i.__close():\"appearing\"==t.state&&\"closed\"==i.__previousState&&i.__create(),i.__previousState=t.state}),i.__instance._on(\"options.\"+i.__namespace,function(){i.__optionsFormat()}),i.__instance._on(\"reposition.\"+i.__namespace,function(t){i.__reposition(t.event,t.helper)})},__close:function(){this.__instance.content()instanceof t&&this.__instance.content().detach(),this.__instance._$tooltip.remove(),this.__instance._$tooltip=null},__create:function(){var i=this.__instance.__options.styles,o=t('<div class=\"tooltipster-base tooltipster-sidetip\"><div class=\"tooltipster-box\"><div class=\"tooltipster-content\"></div></div><div class=\"tooltipster-arrow\"><div class=\"tooltipster-arrow-uncropped\"><div class=\"tooltipster-arrow-border\"></div><div class=\"tooltipster-arrow-background\"></div></div></div></div>');o.find(\".tooltipster-box\").css({color:i.textColor?i.textColor:this.__options.defaultStyles.textColor,backgroundColor:i.backgroundColor?i.backgroundColor:this.__options.defaultStyles.backgroundColor}),o.find(\".tooltipster-arrow-border\").css({backgroundColor:i.backgroundColor?i.backgroundColor:this.__options.defaultStyles.backgroundColor}),this.__options.arrow||o.find(\".tooltipster-box\").css(\"margin\",0).end().find(\".tooltipster-arrow\").hide(),this.__options.minWidth&&o.css(\"min-width\",this.__options.minWidth+\"px\"),this.__options.maxWidth&&o.css(\"max-width\",this.__options.maxWidth+\"px\"),this.__instance._$tooltip=o,this.__instance._trigger(\"created\")},__destroy:function(){this.__instance._off(\".\"+self.__namespace)},__optionsFormat:function(){if(this.__options=this.__instance._optionsExtract(\"tooltipster.sideTip\",this.__defaults()),this.__options.position&&(this.__options.side=this.__options.position),\"object\"!=typeof this.__options.distance&&(this.__options.distance=[this.__options.distance]),this.__options.distance.length<4&&(void 0===this.__options.distance[1]&&(this.__options.distance[1]=this.__options.distance[0]),void 0===this.__options.distance[2]&&(this.__options.distance[2]=this.__options.distance[0]),void 0===this.__options.distance[3]&&(this.__options.distance[3]=this.__options.distance[1])),this.__options.distance={top:this.__options.distance[0],right:this.__options.distance[1],bottom:this.__options.distance[2],left:this.__options.distance[3]},\"string\"==typeof this.__options.side){this.__options.side=[this.__options.side,{top:\"bottom\",right:\"left\",bottom:\"top\",left:\"right\"}[this.__options.side]],\"left\"==this.__options.side[0]||\"right\"==this.__options.side[0]?this.__options.side.push(\"top\",\"bottom\"):this.__options.side.push(\"right\",\"left\")}6===t.tooltipster._env.IE&&!0!==this.__options.arrow&&(this.__options.arrow=!1)},__reposition:function(i,o){var e,n=this,s=n.__targetFind(o),r=[];n.__instance._$tooltip.detach();var _=n.__instance._$tooltip.clone(),a=t.tooltipster._getRuler(_),l=!1,p=n.__instance.option(\"animation\");switch(p&&_.removeClass(\"tooltipster-\"+p),t.each([\"window\",\"document\"],function(e,p){var c=null;if(n.__instance._trigger({container:p,helper:o,satisfied:l,takeTest:function(t){c=t},results:r,type:\"positionTest\"}),1==c||0!=c&&0==l&&(\"window\"!=p||n.__options.viewportAware))for(e=0;e<n.__options.side.length;e++){var h={horizontal:0,vertical:0},d=n.__options.side[e];\"top\"==d||\"bottom\"==d?h.vertical=n.__options.distance[d]:h.horizontal=n.__options.distance[d],n.__sideChange(_,d),t.each([\"natural\",\"constrained\"],function(t,e){if(c=null,n.__instance._trigger({container:p,event:i,helper:o,mode:e,results:r,satisfied:l,side:d,takeTest:function(t){c=t},type:\"positionTest\"}),1==c||0!=c&&0==l){var _={container:p,distance:h,fits:null,mode:e,outerSize:null,side:d,size:null,target:s[d],whole:null},u=(\"natural\"==e?a.free():a.constrain(o.geo.available[p][d].width-h.horizontal,o.geo.available[p][d].height-h.vertical)).measure();if(_.size=u.size,_.outerSize={height:u.size.height+h.vertical,width:u.size.width+h.horizontal},\"natural\"==e?o.geo.available[p][d].width>=_.outerSize.width&&o.geo.available[p][d].height>=_.outerSize.height?_.fits=!0:_.fits=!1:_.fits=u.fits,\"window\"==p&&(_.fits?_.whole=\"top\"==d||\"bottom\"==d?o.geo.origin.windowOffset.right>=n.__options.minIntersection&&o.geo.window.size.width-o.geo.origin.windowOffset.left>=n.__options.minIntersection:o.geo.origin.windowOffset.bottom>=n.__options.minIntersection&&o.geo.window.size.height-o.geo.origin.windowOffset.top>=n.__options.minIntersection:_.whole=!1),r.push(_),_.whole)l=!0;else if(\"natural\"==_.mode&&(_.fits||_.size.width<=o.geo.available[p][d].width))return!1}})}}),n.__instance._trigger({edit:function(t){r=t},event:i,helper:o,results:r,type:\"positionTested\"}),r.sort(function(t,i){return t.whole&&!i.whole?-1:!t.whole&&i.whole?1:t.whole&&i.whole?(o=n.__options.side.indexOf(t.side))<(e=n.__options.side.indexOf(i.side))?-1:o>e?1:\"natural\"==t.mode?-1:1:t.fits&&!i.fits?-1:!t.fits&&i.fits?1:t.fits&&i.fits?(o=n.__options.side.indexOf(t.side))<(e=n.__options.side.indexOf(i.side))?-1:o>e?1:\"natural\"==t.mode?-1:1:\"document\"==t.container&&\"bottom\"==t.side&&\"natural\"==t.mode?-1:1;var o,e}),(e=r[0]).coord={},e.side){case\"left\":case\"right\":e.coord.top=Math.floor(e.target-e.size.height/2);break;case\"bottom\":case\"top\":e.coord.left=Math.floor(e.target-e.size.width/2)}switch(e.side){case\"left\":e.coord.left=o.geo.origin.windowOffset.left-e.outerSize.width;break;case\"right\":e.coord.left=o.geo.origin.windowOffset.right+e.distance.horizontal;break;case\"top\":e.coord.top=o.geo.origin.windowOffset.top-e.outerSize.height;break;case\"bottom\":e.coord.top=o.geo.origin.windowOffset.bottom+e.distance.vertical}\"window\"==e.container?\"top\"==e.side||\"bottom\"==e.side?e.coord.left<0?o.geo.origin.windowOffset.right-this.__options.minIntersection>=0?e.coord.left=0:e.coord.left=o.geo.origin.windowOffset.right-this.__options.minIntersection-1:e.coord.left>o.geo.window.size.width-e.size.width&&(o.geo.origin.windowOffset.left+this.__options.minIntersection<=o.geo.window.size.width?e.coord.left=o.geo.window.size.width-e.size.width:e.coord.left=o.geo.origin.windowOffset.left+this.__options.minIntersection+1-e.size.width):e.coord.top<0?o.geo.origin.windowOffset.bottom-this.__options.minIntersection>=0?e.coord.top=0:e.coord.top=o.geo.origin.windowOffset.bottom-this.__options.minIntersection-1:e.coord.top>o.geo.window.size.height-e.size.height&&(o.geo.origin.windowOffset.top+this.__options.minIntersection<=o.geo.window.size.height?e.coord.top=o.geo.window.size.height-e.size.height:e.coord.top=o.geo.origin.windowOffset.top+this.__options.minIntersection+1-e.size.height):(e.coord.left>o.geo.window.size.width-e.size.width&&(e.coord.left=o.geo.window.size.width-e.size.width),e.coord.left<0&&(e.coord.left=0)),n.__sideChange(_,e.side),o.tooltipClone=_[0],o.tooltipParent=n.__instance.option(\"parent\").parent[0],o.mode=e.mode,o.whole=e.whole,o.origin=n.__instance._$origin[0],o.tooltip=n.__instance._$tooltip[0],delete e.container,delete e.fits,delete e.mode,delete e.outerSize,delete e.whole,e.distance=e.distance.horizontal||e.distance.vertical;var c,h,d,u=t.extend(!0,{},e);if(n.__instance._trigger({edit:function(t){e=t},event:i,helper:o,position:u,type:\"position\"}),n.__options.functionPosition){var g=n.__options.functionPosition.call(n,n.__instance,o,u);g&&(e=g)}a.destroy(),\"top\"==e.side||\"bottom\"==e.side?(c={prop:\"left\",val:e.target-e.coord.left},h=e.size.width-this.__options.minIntersection):(c={prop:\"top\",val:e.target-e.coord.top},h=e.size.height-this.__options.minIntersection),c.val<this.__options.minIntersection?c.val=this.__options.minIntersection:c.val>h&&(c.val=h),d=o.geo.origin.fixedLineage?o.geo.origin.windowOffset:{left:o.geo.origin.windowOffset.left+o.geo.window.scroll.left,top:o.geo.origin.windowOffset.top+o.geo.window.scroll.top},e.coord={left:d.left+(e.coord.left-o.geo.origin.windowOffset.left),top:d.top+(e.coord.top-o.geo.origin.windowOffset.top)},n.__sideChange(n.__instance._$tooltip,e.side),o.geo.origin.fixedLineage?n.__instance._$tooltip.css(\"position\",\"fixed\"):n.__instance._$tooltip.css(\"position\",\"\"),n.__instance._$tooltip.css({left:e.coord.left,top:e.coord.top,height:e.size.height,width:e.size.width}).find(\".tooltipster-arrow\").css({left:\"\",top:\"\"}).css(c.prop,c.val),n.__instance._$tooltip.appendTo(n.__instance.option(\"parent\")),n.__instance._trigger({type:\"repositioned\",event:i,position:e})},__sideChange:function(t,i){t.removeClass(\"tooltipster-bottom\").removeClass(\"tooltipster-left\").removeClass(\"tooltipster-right\").removeClass(\"tooltipster-top\").addClass(\"tooltipster-\"+i)},__targetFind:function(t){var i={},o=this.__instance._$origin[0].getClientRects();o.length>1&&(1==this.__instance._$origin.css(\"opacity\")&&(this.__instance._$origin.css(\"opacity\",.99),o=this.__instance._$origin[0].getClientRects(),this.__instance._$origin.css(\"opacity\",1)));if(o.length<2)i.top=Math.floor(t.geo.origin.windowOffset.left+t.geo.origin.size.width/2),i.bottom=i.top,i.left=Math.floor(t.geo.origin.windowOffset.top+t.geo.origin.size.height/2),i.right=i.left;else{var e=o[0];i.top=Math.floor(e.left+(e.right-e.left)/2),e=o.length>2?o[Math.ceil(o.length/2)-1]:o[0],i.right=Math.floor(e.top+(e.bottom-e.top)/2),e=o[o.length-1],i.bottom=Math.floor(e.left+(e.right-e.left)/2),e=o.length>2?o[Math.ceil((o.length+1)/2)-1]:o[o.length-1],i.left=Math.floor(e.top+(e.bottom-e.top)/2)}return i}}}),t});\n","Magento_ConfigurableProduct/js/catalog-add-to-cart-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'underscore',\n 'jquery',\n 'Magento_ConfigurableProduct/js/product/view/product-info-resolver'\n], function (_, $, productInfoResolver) {\n 'use strict';\n\n return function (widget) {\n\n $.widget('mage.catalogAddToCart', widget, {\n /**\n * @param {jQuery} form\n */\n ajaxSubmit: function (form) {\n var isConfigurable = !!_.find(form.serializeArray(), function (item) {\n return item.name.indexOf('super_attribute') !== -1;\n });\n\n if (isConfigurable) {\n this.options.productInfoResolver = productInfoResolver;\n }\n\n return this._super(form);\n }\n });\n\n return $.mage.catalogAddToCart;\n };\n});\n","Magento_ConfigurableProduct/js/configurable-customer-data.js":"require([\n 'jquery',\n 'Magento_ConfigurableProduct/js/options-updater'\n], function ($, Updater) {\n 'use strict';\n\n var selectors = {\n formSelector: '#product_addtocart_form'\n },\n configurableWidgetName = 'mageConfigurable',\n widgetInitEvent = 'configurable.initialized',\n\n /**\n * Sets all configurable attribute's selected values\n */\n updateConfigurableOptions = function () {\n var configurableWidget = $(selectors.formSelector).data(configurableWidgetName);\n\n if (!configurableWidget) {\n return;\n }\n configurableWidget.options.values = this.productOptions || {};\n configurableWidget._configureForValues();\n },\n updater = new Updater(widgetInitEvent, updateConfigurableOptions);\n\n updater.listen();\n});\n","Magento_ConfigurableProduct/js/options-updater.js":"define([\n 'jquery',\n 'underscore',\n 'Magento_Customer/js/customer-data',\n 'domReady!'\n], function ($, _, customerData) {\n 'use strict';\n\n var selectors = {\n formSelector: '#product_addtocart_form',\n productIdSelector: '#product_addtocart_form [name=\"product\"]',\n itemIdSelector: '#product_addtocart_form [name=\"item\"]'\n },\n cartData = customerData.get('cart'),\n productId = $(selectors.productIdSelector).val(),\n itemId = $(selectors.itemIdSelector).val(),\n\n /**\n * set productOptions according to cart data from customer-data\n *\n * @param {Object} data - cart data from customer-data\n * @returns {Boolean} - whether the new options differ from previous\n */\n setProductOptions = function (data) {\n var changedProductOptions;\n\n if (!(data && data.items && data.items.length && productId)) {\n return false;\n }\n changedProductOptions = _.find(data.items, function (item) {\n if (item['item_id'] === itemId) {\n return item['product_id'] === productId;\n }\n });\n changedProductOptions = changedProductOptions && changedProductOptions.options &&\n changedProductOptions.options.reduce(function (obj, val) {\n obj[val['option_id']] = val['option_value'];\n\n return obj;\n }, {});\n\n if (JSON.stringify(this.productOptions || {}) === JSON.stringify(changedProductOptions || {})) {\n return false;\n }\n\n this.productOptions = changedProductOptions;\n\n return true;\n },\n\n /**\n * Listens to update of cart data or options initialization and update selected option according to customer data\n *\n */\n listen = function () {\n cartData.subscribe(function (updateCartData) {\n if (this.setProductOptions(updateCartData)) {\n this.updateOptions();\n }\n }.bind(this));\n $(selectors.formSelector).on(this.eventName, function () {\n this.setProductOptions(cartData());\n this.updateOptions();\n }.bind(this));\n },\n\n /**\n * Updater constructor function\n *\n */\n Updater = function (eventName, updateOptionsCallback) {\n if (this instanceof Updater) {\n this.eventName = eventName;\n this.updateOptions = updateOptionsCallback;\n this.productOptions = {};\n }\n };\n\n Updater.prototype.setProductOptions = setProductOptions;\n Updater.prototype.listen = listen;\n\n return Updater;\n});\n","Magento_ConfigurableProduct/js/configurable.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n 'mage/template',\n 'mage/translate',\n 'priceUtils',\n 'priceBox',\n 'jquery-ui-modules/widget',\n 'jquery/jquery.parsequery',\n 'fotoramaVideoEvents'\n], function ($, _, mageTemplate, $t, priceUtils) {\n 'use strict';\n\n $.widget('mage.configurable', {\n options: {\n superSelector: '.super-attribute-select',\n selectSimpleProduct: '[name=\"selected_configurable_option\"]',\n priceHolderSelector: '.price-box',\n spConfig: {},\n state: {},\n priceFormat: {},\n optionTemplate: '<%- data.label %>' +\n '<% if (typeof data.finalPrice.value !== \"undefined\") { %>' +\n ' <%- data.finalPrice.formatted %>' +\n '<% } %>',\n mediaGallerySelector: '[data-gallery-role=gallery-placeholder]',\n mediaGalleryInitial: null,\n slyOldPriceSelector: '.sly-old-price',\n normalPriceLabelSelector: '.product-info-main .normal-price .price-label',\n\n /**\n * Defines the mechanism of how images of a gallery should be\n * updated when user switches between configurations of a product.\n *\n * As for now value of this option can be either 'replace' or 'prepend'.\n *\n * @type {String}\n */\n gallerySwitchStrategy: 'replace',\n tierPriceTemplateSelector: '#tier-prices-template',\n tierPriceBlockSelector: '[data-role=\"tier-price-block\"]',\n tierPriceTemplate: '',\n selectorProduct: '.product-info-main',\n selectorProductPrice: '[data-role=priceBox]',\n qtyInfo: '#qty'\n },\n\n /**\n * Creates widget\n * @private\n */\n _create: function () {\n // Initial setting of various option values\n this._initializeOptions();\n\n // Override defaults with URL query parameters and/or inputs values\n this._overrideDefaults();\n\n // Change events to check select reloads\n this._setupChangeEvents();\n\n // Fill state\n this._fillState();\n\n // Setup child and prev/next settings\n this._setChildSettings();\n\n // Setup/configure values to inputs\n this._configureForValues();\n\n $(this.element).trigger('configurable.initialized');\n $(this.options.qtyInfo).on('input', this._reloadPrice.bind(this));\n },\n\n /**\n * Initialize tax configuration, initial settings, and options values.\n * @private\n */\n _initializeOptions: function () {\n var options = this.options,\n gallery = $(options.mediaGallerySelector),\n priceBoxOptions = $(this.options.priceHolderSelector).priceBox('option').priceConfig || null;\n\n if (priceBoxOptions && priceBoxOptions.optionTemplate) {\n options.optionTemplate = priceBoxOptions.optionTemplate;\n }\n\n if (priceBoxOptions && priceBoxOptions.priceFormat) {\n options.priceFormat = priceBoxOptions.priceFormat;\n }\n options.optionTemplate = mageTemplate(options.optionTemplate);\n options.tierPriceTemplate = $(this.options.tierPriceTemplateSelector).html();\n\n options.settings = options.spConfig.containerId ?\n $(options.spConfig.containerId).find(options.superSelector) :\n $(options.superSelector);\n\n options.values = options.spConfig.defaultValues || {};\n options.parentImage = $('[data-role=base-image-container] img').attr('src');\n\n this.inputSimpleProduct = this.element.find(options.selectSimpleProduct);\n\n gallery.data('gallery') ?\n this._onGalleryLoaded(gallery) :\n gallery.on('gallery:loaded', this._onGalleryLoaded.bind(this, gallery));\n\n },\n\n /**\n * Override default options values settings with either URL query parameters or\n * initialized inputs values.\n * @private\n */\n _overrideDefaults: function () {\n var hashIndex = window.location.href.indexOf('#');\n\n if (hashIndex !== -1) {\n this._parseQueryParams(window.location.href.substr(hashIndex + 1));\n }\n\n if (this.options.spConfig.inputsInitialized) {\n this._setValuesByAttribute();\n }\n\n this._setInitialOptionsLabels();\n },\n\n /**\n * Parse query parameters from a query string and set options values based on the\n * key value pairs of the parameters.\n * @param {*} queryString - URL query string containing query parameters.\n * @private\n */\n _parseQueryParams: function (queryString) {\n var queryParams = $.parseQuery({\n query: queryString\n });\n\n $.each(queryParams, $.proxy(function (key, value) {\n if (this.options.spConfig.attributes[key] !== undefined &&\n _.find(this.options.spConfig.attributes[key].options, function (element) {\n return element.id === value;\n })) {\n this.options.values[key] = value;\n }\n }, this));\n },\n\n /**\n * Override default options values with values based on each element's attribute\n * identifier.\n * @private\n */\n _setValuesByAttribute: function () {\n this.options.values = {};\n $.each(this.options.settings, $.proxy(function (index, element) {\n var attributeId;\n\n if (element.value) {\n attributeId = element.id.replace(/[a-z]*/, '');\n\n if (this.options.spConfig.attributes[attributeId] !== undefined &&\n _.find(this.options.spConfig.attributes[attributeId].options, function (optionElement) {\n return optionElement.id === element.value;\n })) {\n this.options.values[attributeId] = element.value;\n }\n }\n }, this));\n },\n\n /**\n * Set additional field with initial label to be used when switching between options with different prices.\n * @private\n */\n _setInitialOptionsLabels: function () {\n $.each(this.options.spConfig.attributes, $.proxy(function (index, element) {\n $.each(element.options, $.proxy(function (optIndex, optElement) {\n this.options.spConfig.attributes[index].options[optIndex].initialLabel = optElement.label;\n }, this));\n }, this));\n },\n\n /**\n * Set up .on('change') events for each option element to configure the option.\n * @private\n */\n _setupChangeEvents: function () {\n $.each(this.options.settings, $.proxy(function (index, element) {\n $(element).on('change', this, this._configure);\n }, this));\n },\n\n /**\n * Iterate through the option settings and set each option's element configuration,\n * attribute identifier. Set the state based on the attribute identifier.\n * @private\n */\n _fillState: function () {\n $.each(this.options.settings, $.proxy(function (index, element) {\n var attributeId = element.id.replace(/[a-z]*/, '');\n\n if (attributeId && this.options.spConfig.attributes[attributeId]) {\n element.config = this.options.spConfig.attributes[attributeId];\n element.attributeId = attributeId;\n this.options.state[attributeId] = false;\n }\n }, this));\n },\n\n /**\n * Set each option's child settings, and next/prev option setting. Fill (initialize)\n * an option's list of selections as needed or disable an option's setting.\n * @private\n */\n _setChildSettings: function () {\n var childSettings = [],\n settings = this.options.settings,\n index = settings.length,\n option;\n\n while (index--) {\n option = settings[index];\n\n if (index) {\n option.disabled = true;\n } else {\n this._fillSelect(option);\n }\n\n _.extend(option, {\n childSettings: childSettings.slice(),\n prevSetting: settings[index - 1],\n nextSetting: settings[index + 1]\n });\n\n childSettings.push(option);\n }\n },\n\n /**\n * Setup for all configurable option settings. Set the value of the option and configure\n * the option, which sets its state, and initializes the option's choices, etc.\n * @private\n */\n _configureForValues: function () {\n if (this.options.values) {\n this.options.settings.each($.proxy(function (index, element) {\n var attributeId = element.attributeId;\n\n element.value = this.options.values[attributeId] || '';\n this._configureElement(element);\n }, this));\n }\n },\n\n /**\n * Event handler for configuring an option.\n * @private\n * @param {Object} event - Event triggered to configure an option.\n */\n _configure: function (event) {\n event.data._configureElement(this);\n },\n\n /**\n * Configure an option, initializing it's state and enabling related options, which\n * populates the related option's selection and resets child option selections.\n * @private\n * @param {*} element - The element associated with a configurable option.\n */\n _configureElement: function (element) {\n this.simpleProduct = this._getSimpleProductId(element);\n\n if (element.value) {\n this.options.state[element.config.id] = element.value;\n\n if (element.nextSetting) {\n element.nextSetting.disabled = false;\n this._fillSelect(element.nextSetting);\n this._resetChildren(element.nextSetting);\n } else {\n if (!!document.documentMode) { //eslint-disable-line\n this.inputSimpleProduct.val(element.options[element.selectedIndex].config.allowedProducts[0]);\n } else {\n this.inputSimpleProduct.val(element.selectedOptions[0].config.allowedProducts[0]);\n }\n }\n } else {\n this._resetChildren(element);\n }\n\n this._reloadPrice();\n this._displayRegularPriceBlock(this.simpleProduct);\n this._displayTierPriceBlock(this.simpleProduct);\n this._displayNormalPriceLabel();\n this._changeProductImage();\n },\n\n /**\n * Change displayed product image according to chosen options of configurable product\n *\n * @private\n */\n _changeProductImage: function () {\n var images,\n initialImages = this.options.mediaGalleryInitial,\n gallery = $(this.options.mediaGallerySelector).data('gallery');\n\n if (_.isUndefined(gallery)) {\n $(this.options.mediaGallerySelector).on('gallery:loaded', function () {\n this._changeProductImage();\n }.bind(this));\n\n return;\n }\n\n images = this.options.spConfig.images[this.simpleProduct];\n\n if (images) {\n images = this._sortImages(images);\n\n if (this.options.gallerySwitchStrategy === 'prepend') {\n images = images.concat(initialImages);\n }\n\n images = $.extend(true, [], images);\n images = this._setImageIndex(images);\n\n gallery.updateData(images);\n this._addFotoramaVideoEvents(false);\n } else {\n gallery.updateData(initialImages);\n this._addFotoramaVideoEvents(true);\n }\n },\n\n /**\n * Add video events\n *\n * @param {Boolean} isInitial\n * @private\n */\n _addFotoramaVideoEvents: function (isInitial) {\n if (_.isUndefined($.mage.AddFotoramaVideoEvents)) {\n return;\n }\n\n if (isInitial) {\n $(this.options.mediaGallerySelector).AddFotoramaVideoEvents();\n\n return;\n }\n\n $(this.options.mediaGallerySelector).AddFotoramaVideoEvents({\n selectedOption: this.simpleProduct,\n dataMergeStrategy: this.options.gallerySwitchStrategy\n });\n },\n\n /**\n * Sorting images array\n *\n * @private\n */\n _sortImages: function (images) {\n return _.sortBy(images, function (image) {\n return image.position;\n });\n },\n\n /**\n * Set correct indexes for image set.\n *\n * @param {Array} images\n * @private\n */\n _setImageIndex: function (images) {\n var length = images.length,\n i;\n\n for (i = 0; length > i; i++) {\n images[i].i = i + 1;\n }\n\n return images;\n },\n\n /**\n * For a given option element, reset all of its selectable options. Clear any selected\n * index, disable the option choice, and reset the option's state if necessary.\n * @private\n * @param {*} element - The element associated with a configurable option.\n */\n _resetChildren: function (element) {\n if (element.childSettings) {\n _.each(element.childSettings, function (set) {\n set.selectedIndex = 0;\n set.disabled = true;\n });\n\n if (element.config) {\n this.options.state[element.config.id] = false;\n }\n }\n },\n\n /**\n * Populates an option's selectable choices.\n * @private\n * @param {*} element - Element associated with a configurable option.\n */\n _fillSelect: function (element) {\n var attributeId = element.id.replace(/[a-z]*/, ''),\n options = this._getAttributeOptions(attributeId),\n prevConfig,\n index = 1,\n allowedProducts,\n allowedProductsByOption,\n allowedProductsAll,\n i,\n j,\n finalPrice = parseFloat(this.options.spConfig.prices.finalPrice.amount),\n optionFinalPrice,\n optionPriceDiff,\n optionPrices = this.options.spConfig.optionPrices,\n allowedOptions = [],\n indexKey,\n allowedProductMinPrice,\n allowedProductsAllMinPrice,\n canDisplayOutOfStockProducts = false,\n filteredSalableProducts;\n\n this._clearSelect(element);\n element.options[0] = new Option('', '');\n element.options[0].innerHTML = this.options.spConfig.chooseText;\n prevConfig = false;\n\n if (element.prevSetting) {\n prevConfig = element.prevSetting.options[element.prevSetting.selectedIndex];\n }\n\n if (options) {\n for (indexKey in this.options.spConfig.index) {\n /* eslint-disable max-depth */\n if (this.options.spConfig.index.hasOwnProperty(indexKey)) {\n allowedOptions = allowedOptions.concat(_.values(this.options.spConfig.index[indexKey]));\n }\n }\n\n if (prevConfig) {\n allowedProductsByOption = {};\n allowedProductsAll = [];\n\n for (i = 0; i < options.length; i++) {\n /* eslint-disable max-depth */\n for (j = 0; j < options[i].products.length; j++) {\n // prevConfig.config can be undefined\n if (prevConfig.config &&\n prevConfig.config.allowedProducts &&\n prevConfig.config.allowedProducts.indexOf(options[i].products[j]) > -1) {\n if (!allowedProductsByOption[i]) {\n allowedProductsByOption[i] = [];\n }\n allowedProductsByOption[i].push(options[i].products[j]);\n allowedProductsAll.push(options[i].products[j]);\n }\n }\n }\n\n if (typeof allowedProductsAll[0] !== 'undefined' &&\n typeof optionPrices[allowedProductsAll[0]] !== 'undefined') {\n allowedProductsAllMinPrice = this._getAllowedProductWithMinPrice(allowedProductsAll);\n finalPrice = parseFloat(optionPrices[allowedProductsAllMinPrice].finalPrice.amount);\n }\n }\n\n for (i = 0; i < options.length; i++) {\n if (prevConfig && typeof allowedProductsByOption[i] === 'undefined') {\n continue; //jscs:ignore disallowKeywords\n }\n\n allowedProducts = prevConfig ? allowedProductsByOption[i] : options[i].products.slice(0);\n optionPriceDiff = 0;\n\n if (typeof allowedProducts[0] !== 'undefined' &&\n typeof optionPrices[allowedProducts[0]] !== 'undefined') {\n allowedProductMinPrice = this._getAllowedProductWithMinPrice(allowedProducts);\n optionFinalPrice = parseFloat(optionPrices[allowedProductMinPrice].finalPrice.amount);\n optionPriceDiff = optionFinalPrice - finalPrice;\n options[i].label = options[i].initialLabel;\n\n if (optionPriceDiff !== 0) {\n options[i].label += ' ' + priceUtils.formatPriceLocale(\n optionPriceDiff,\n this.options.priceFormat,\n true\n );\n }\n }\n\n if (allowedProducts.length > 0 || _.include(allowedOptions, options[i].id)) {\n options[i].allowedProducts = allowedProducts;\n element.options[index] = new Option(this._getOptionLabel(options[i]), options[i].id);\n\n if (this.options.spConfig.canDisplayShowOutOfStockStatus) {\n filteredSalableProducts = $(this.options.spConfig.salable[attributeId][options[i].id]).\n filter(options[i].allowedProducts);\n canDisplayOutOfStockProducts = filteredSalableProducts.length === 0;\n }\n\n if (typeof options[i].price !== 'undefined') {\n element.options[index].setAttribute('price', options[i].price);\n }\n\n if (allowedProducts.length === 0 || canDisplayOutOfStockProducts) {\n element.options[index].disabled = true;\n }\n\n element.options[index].config = options[i];\n index++;\n }\n\n /* eslint-enable max-depth */\n }\n }\n },\n\n /**\n * Generate the label associated with a configurable option. This includes the option's\n * label or value and the option's price.\n * @private\n * @param {*} option - A single choice among a group of choices for a configurable option.\n * @return {String} The option label with option value and price (e.g. Black +1.99)\n */\n _getOptionLabel: function (option) {\n return option.label;\n },\n\n /**\n * Removes an option's selections.\n * @private\n * @param {*} element - The element associated with a configurable option.\n */\n _clearSelect: function (element) {\n var i;\n\n for (i = element.options.length - 1; i >= 0; i--) {\n element.remove(i);\n }\n },\n\n /**\n * Retrieve the attribute options associated with a specific attribute Id.\n * @private\n * @param {Number} attributeId - The id of the attribute whose configurable options are sought.\n * @return {Object} Object containing the attribute options.\n */\n _getAttributeOptions: function (attributeId) {\n if (this.options.spConfig.attributes[attributeId]) {\n return this.options.spConfig.attributes[attributeId].options;\n }\n },\n\n /**\n * Reload the price of the configurable product incorporating the prices of all of the\n * configurable product's option selections.\n */\n _reloadPrice: function () {\n $(this.options.priceHolderSelector).trigger('updatePrice', this._getPrices());\n },\n\n /**\n * Get product various prices\n * @returns {{}}\n * @private\n */\n _getPrices: function () {\n var prices = {},\n elements = _.toArray(this.options.settings),\n allowedProduct;\n\n _.each(elements, function (element) {\n var selected = element.options[element.selectedIndex],\n config = selected && selected.config,\n priceValue = this._calculatePrice({});\n\n if (config && config.allowedProducts.length === 1) {\n priceValue = this._calculatePrice(config);\n } else if (element.value) {\n allowedProduct = this._getAllowedProductWithMinPrice(config.allowedProducts);\n priceValue = this._calculatePrice({\n 'allowedProducts': [\n allowedProduct\n ]\n });\n }\n\n if (!_.isEmpty(priceValue)) {\n prices.prices = priceValue;\n }\n }, this);\n\n return prices;\n },\n\n /**\n * Get product with minimum price from selected options.\n *\n * @param {Array} allowedProducts\n * @returns {String}\n * @private\n */\n _getAllowedProductWithMinPrice: function (allowedProducts) {\n var optionPrices = this.options.spConfig.optionPrices,\n product = {},\n optionMinPrice, optionFinalPrice;\n\n _.each(allowedProducts, function (allowedProduct) {\n optionFinalPrice = parseFloat(optionPrices[allowedProduct].finalPrice.amount);\n\n if (_.isEmpty(product) || optionFinalPrice < optionMinPrice) {\n optionMinPrice = optionFinalPrice;\n product = allowedProduct;\n }\n }, this);\n\n return product;\n },\n\n /**\n * Returns prices for configured products\n *\n * @param {*} config - Products configuration\n * @returns {*}\n * @private\n */\n _calculatePrice: function (config) {\n var displayPrices = $(this.options.priceHolderSelector).priceBox('option').prices,\n newPrices = this.options.spConfig.optionPrices[_.first(config.allowedProducts)] || {};\n\n _.each(displayPrices, function (price, code) {\n displayPrices[code].amount = newPrices[code] ? newPrices[code].amount - displayPrices[code].amount : 0;\n });\n\n return displayPrices;\n },\n\n /**\n * Returns Simple product Id\n * depending on current selected option.\n *\n * @private\n * @param {HTMLElement} element\n * @returns {String|undefined}\n */\n _getSimpleProductId: function (element) {\n // TODO: Rewrite algorithm. It should return ID of\n // simple product based on selected options.\n var allOptions = element.config.options,\n value = element.value,\n config;\n\n config = _.filter(allOptions, function (option) {\n return option.id === value;\n });\n config = _.first(config);\n\n return _.isEmpty(config) ?\n undefined :\n _.first(config.allowedProducts);\n\n },\n\n /**\n * Show or hide regular price block\n *\n * @param {*} optionId\n * @private\n */\n _displayRegularPriceBlock: function (optionId) {\n var shouldBeShown = true,\n $priceBox = this.element.parents(this.options.selectorProduct)\n .find(this.options.selectorProductPrice);\n\n _.each(this.options.settings, function (element) {\n if (element.value === '') {\n shouldBeShown = false;\n }\n });\n\n if (shouldBeShown &&\n this.options.spConfig.optionPrices[optionId].oldPrice.amount !==\n this.options.spConfig.optionPrices[optionId].finalPrice.amount\n ) {\n $(this.options.slyOldPriceSelector).show();\n } else {\n $(this.options.slyOldPriceSelector).hide();\n }\n\n $(document).trigger('updateMsrpPriceBlock',\n [\n optionId,\n this.options.spConfig.optionPrices,\n $priceBox\n ]\n );\n },\n\n /**\n * Show or hide normal price label\n *\n * @private\n */\n _displayNormalPriceLabel: function () {\n var shouldBeShown = false;\n\n _.each(this.options.settings, function (element) {\n if (element.value === '') {\n shouldBeShown = true;\n }\n });\n\n if (shouldBeShown) {\n $(this.options.normalPriceLabelSelector).show();\n } else {\n $(this.options.normalPriceLabelSelector).hide();\n }\n },\n\n /**\n * Callback which fired after gallery gets initialized.\n *\n * @param {HTMLElement} element - DOM element associated with gallery.\n */\n _onGalleryLoaded: function (element) {\n var galleryObject = element.data('gallery');\n\n this.options.mediaGalleryInitial = galleryObject.returnCurrentImages();\n },\n\n /**\n * Show or hide tier price block\n *\n * @param {*} optionId\n * @private\n */\n _displayTierPriceBlock: function (optionId) {\n var tierPrices = typeof optionId != 'undefined' && this.options.spConfig.optionPrices[optionId].tierPrices;\n\n if (_.isArray(tierPrices) && tierPrices.length > 0) {\n\n if (this.options.tierPriceTemplate) {\n $(this.options.tierPriceBlockSelector).html(\n mageTemplate(this.options.tierPriceTemplate, {\n 'tierPrices': tierPrices,\n '$t': $t,\n 'currencyFormat': this.options.spConfig.currencyFormat,\n 'priceUtils': priceUtils\n })\n ).show();\n }\n } else {\n $(this.options.tierPriceBlockSelector).hide();\n }\n }\n });\n\n return $.mage.configurable;\n});\n","Magento_ConfigurableProduct/js/catalog-add-to-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\nrequire([\n 'jquery'\n], function ($) {\n 'use strict';\n\n /**\n * Add selected configurable attributes to redirect url\n *\n * @see Magento_Catalog/js/catalog-add-to-cart\n */\n $('body').on('catalogCategoryAddToCartRedirect', function (event, data) {\n $(data.form).find('select[name*=\"super\"]').each(function (index, item) {\n data.redirectParameters.push(item.config.id + '=' + $(item).val());\n });\n });\n});\n","Magento_ConfigurableProduct/js/product/view/product-info-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'underscore',\n 'Magento_Catalog/js/product/view/product-info'\n], function (_, productInfo) {\n 'use strict';\n\n /**\n * Returns info about configurable products in form.\n *\n * @param {jQuery} $form\n * @return {Array}\n */\n return function ($form) {\n var optionValues = [],\n product = _.findWhere($form.serializeArray(), {\n name: 'product'\n }),\n productId;\n\n if (!_.isUndefined(product)) {\n productId = product.value;\n _.each($form.serializeArray(), function (item) {\n if (item.name.indexOf('super_attribute') !== -1) {\n optionValues.push(item.value);\n }\n });\n optionValues.sort();\n productInfo().push(\n {\n 'id': productId,\n 'optionValues': optionValues\n }\n );\n }\n\n return _.uniq(productInfo(), function (item) {\n var optionValuesStr = item.optionValues ? item.optionValues.join() : '';\n\n return item.id + optionValuesStr;\n });\n };\n});\n\n","Magento_ReCaptchaCheckoutSalesRule/js/checkout-sales-rule.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* global grecaptcha */\ndefine(\n [\n 'Magento_ReCaptchaWebapiUi/js/webapiReCaptcha',\n 'Magento_ReCaptchaWebapiUi/js/webapiReCaptchaRegistry',\n 'jquery',\n 'Magento_SalesRule/js/action/set-coupon-code',\n 'Magento_SalesRule/js/action/cancel-coupon',\n 'Magento_Checkout/js/model/quote',\n 'ko'\n ], function (Component, recaptchaRegistry, $, setCouponCodeAction, cancelCouponAction, quote, ko) {\n 'use strict';\n\n var totals = quote.getTotals(),\n couponCode = ko.observable(null),\n isApplied;\n\n if (totals()) {\n couponCode(totals()['coupon_code']);\n }\n //Captcha can only be required for adding a coupon so we need to know if one was added already.\n isApplied = ko.observable(couponCode() != null);\n\n return Component.extend({\n\n /**\n * Initialize parent form.\n *\n * @param {Object} parentForm\n * @param {String} widgetId\n */\n initParentForm: function (parentForm, widgetId) {\n var self = this,\n xRecaptchaValue,\n captchaId = this.getReCaptchaId();\n\n this._super();\n\n if (couponCode() != null) {\n if (isApplied) {\n self.validateReCaptcha(true);\n $('#' + captchaId).hide();\n }\n }\n\n if (recaptchaRegistry.triggers.hasOwnProperty('recaptcha-checkout-coupon-apply')) {\n recaptchaRegistry.addListener('recaptcha-checkout-coupon-apply', function (token) {\n //Add reCaptcha value to coupon request\n xRecaptchaValue = token;\n });\n }\n\n setCouponCodeAction.registerDataModifier(function (headers) {\n headers['X-ReCaptcha'] = xRecaptchaValue;\n });\n\n if (self.getIsInvisibleRecaptcha()) {\n grecaptcha.execute(widgetId);\n self.validateReCaptcha(true);\n }\n //Refresh reCaptcha after failed request.\n setCouponCodeAction.registerFailCallback(function () {\n if (self.getIsInvisibleRecaptcha()) {\n grecaptcha.execute(widgetId);\n self.validateReCaptcha(true);\n } else {\n self.validateReCaptcha(false);\n grecaptcha.reset(widgetId);\n $('#' + captchaId).show();\n }\n });\n //Hide captcha when a coupon has been applied.\n setCouponCodeAction.registerSuccessCallback(function () {\n self.validateReCaptcha(true);\n $('#' + captchaId).hide();\n });\n //Show captcha again if it was canceled.\n cancelCouponAction.registerSuccessCallback(function () {\n self.validateReCaptcha(false);\n grecaptcha.reset(widgetId);\n $('#' + captchaId).show();\n });\n }\n });\n });\n","Magento_Bundle/js/price-bundle.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n 'mage/template',\n 'priceUtils',\n 'priceBox'\n], function ($, _, mageTemplate, utils) {\n 'use strict';\n\n var globalOptions = {\n optionConfig: null,\n productBundleSelector: 'input.bundle.option, select.bundle.option, textarea.bundle.option',\n qtyFieldSelector: 'input.qty',\n priceBoxSelector: '.price-box',\n optionHandlers: {},\n optionTemplate: '<%- data.label %>' +\n '<% if (data.finalPrice.value) { %>' +\n ' +<%- data.finalPrice.formatted %>' +\n '<% } %>',\n controlContainer: 'dd', // should be eliminated\n priceFormat: {},\n isFixedPrice: false,\n optionTierPricesBlocksSelector: '#option-tier-prices-{1} [data-role=\"selection-tier-prices\"]',\n isOptionsInitialized: false\n };\n\n $.widget('mage.priceBundle', {\n options: globalOptions,\n\n /**\n * @private\n */\n _init: function initPriceBundle() {\n var form = this.element,\n options = $(this.options.productBundleSelector, form);\n\n options.trigger('change');\n },\n\n /**\n * @private\n */\n _create: function createPriceBundle() {\n var form = this.element,\n options = $(this.options.productBundleSelector, form),\n priceBox = $(this.options.priceBoxSelector, form),\n qty = $(this.options.qtyFieldSelector, form);\n\n this._updatePriceBox();\n priceBox.on('price-box-initialized', this._updatePriceBox.bind(this));\n options.on('change', this._onBundleOptionChanged.bind(this));\n qty.on('change', this._onQtyFieldChanged.bind(this));\n },\n\n /**\n * Update price box config with bundle option prices\n * @private\n */\n _updatePriceBox: function () {\n var form = this.element,\n options = $(this.options.productBundleSelector, form),\n priceBox = $(this.options.priceBoxSelector, form);\n\n if (!this.options.isOptionsInitialized) {\n if (priceBox.data('magePriceBox') &&\n priceBox.priceBox('option') &&\n priceBox.priceBox('option').priceConfig\n ) {\n if (priceBox.priceBox('option').priceConfig.optionTemplate) { //eslint-disable-line max-depth\n this._setOption('optionTemplate', priceBox.priceBox('option').priceConfig.optionTemplate);\n }\n this._setOption('priceFormat', priceBox.priceBox('option').priceConfig.priceFormat);\n priceBox.priceBox('setDefault', this.options.optionConfig.prices);\n this.options.isOptionsInitialized = true;\n }\n this._applyOptionNodeFix(options);\n }\n\n return this;\n },\n\n /**\n * Handle change on bundle option inputs\n * @param {jQuery.Event} event\n * @private\n */\n _onBundleOptionChanged: function onBundleOptionChanged(event) {\n var changes,\n bundleOption = $(event.target),\n priceBox = $(this.options.priceBoxSelector, this.element),\n handler = this.options.optionHandlers[bundleOption.data('role')];\n\n bundleOption.data('optionContainer', bundleOption.closest(this.options.controlContainer));\n bundleOption.data('qtyField', bundleOption.data('optionContainer').find(this.options.qtyFieldSelector));\n\n if (handler && handler instanceof Function) {\n changes = handler(bundleOption, this.options.optionConfig, this);\n } else {\n changes = defaultGetOptionValue(bundleOption, this.options.optionConfig);//eslint-disable-line\n }\n\n // eslint-disable-next-line no-use-before-define\n if (isValidQty(bundleOption)) {\n if (changes) {\n priceBox.trigger('updatePrice', changes);\n }\n\n this._displayTierPriceBlock(bundleOption);\n this.updateProductSummary();\n }\n },\n\n /**\n * Handle change on qty inputs near bundle option\n * @param {jQuery.Event} event\n * @private\n */\n _onQtyFieldChanged: function onQtyFieldChanged(event) {\n var field = $(event.target),\n optionInstance,\n optionConfig;\n\n if (field.data('optionId') && field.data('optionValueId')) {\n optionInstance = field.data('option');\n optionConfig = this.options.optionConfig\n .options[field.data('optionId')]\n .selections[field.data('optionValueId')];\n optionConfig.qty = field.val();\n\n // eslint-disable-next-line no-use-before-define\n if (isValidQty(optionInstance)) {\n optionInstance.trigger('change');\n }\n }\n },\n\n /**\n * Helper to fix backend behavior:\n * - if default qty large than 1 then backend multiply price in config\n *\n * @deprecated\n * @private\n */\n _applyQtyFix: function applyQtyFix() {\n var config = this.options.optionConfig;\n\n if (config.isFixedPrice) {\n _.each(config.options, function (option) {\n _.each(option.selections, function (item) {\n if (item.qty && item.qty !== 1) {\n _.each(item.prices, function (price) {\n price.amount /= item.qty;\n });\n }\n });\n });\n }\n },\n\n /**\n * Helper to fix issue with option nodes:\n * - you can't place any html in option ->\n * so you can't style it via CSS\n * @param {jQuery} options\n * @private\n */\n _applyOptionNodeFix: function applyOptionNodeFix(options) {\n var config = this.options,\n format = config.priceFormat,\n template = config.optionTemplate;\n\n template = mageTemplate(template);\n options.filter('select').each(function (index, element) {\n var $element = $(element),\n optionId = utils.findOptionId($element),\n optionConfig = config.optionConfig && config.optionConfig.options[optionId].selections,\n value;\n\n $element.find('option').each(function (idx, option) {\n var $option,\n optionValue,\n toTemplate,\n prices;\n\n $option = $(option);\n optionValue = $option.val();\n\n if (!optionValue && optionValue !== 0) {\n return;\n }\n\n toTemplate = {\n data: {\n label: optionConfig[optionValue] && optionConfig[optionValue].name\n }\n };\n prices = optionConfig[optionValue].prices;\n\n _.each(prices, function (price, type) {\n value = +price.amount;\n value += _.reduce(price.adjustments, function (sum, x) {//eslint-disable-line\n return sum + x;\n }, 0);\n toTemplate.data[type] = {\n value: value,\n formatted: utils.formatPriceLocale(value, format)\n };\n });\n\n $option.html(template(toTemplate));\n });\n });\n },\n\n /**\n * Custom behavior on getting options:\n * now widget able to deep merge accepted configuration with instance options.\n * @param {Object} options\n * @return {$.Widget}\n */\n _setOptions: function setOptions(options) {\n $.extend(true, this.options, options);\n\n this._super(options);\n\n return this;\n },\n\n /**\n * Show or hide option tier prices block\n *\n * @param {Object} optionElement\n * @private\n */\n _displayTierPriceBlock: function (optionElement) {\n var optionType = optionElement.prop('type'),\n optionId,\n optionValue,\n optionTierPricesElements;\n\n if (optionType === 'select-one') {\n optionId = utils.findOptionId(optionElement[0]);\n optionValue = optionElement.val() || null;\n optionTierPricesElements = $(this.options.optionTierPricesBlocksSelector.replace('{1}', optionId));\n\n _.each(optionTierPricesElements, function (tierPriceElement) {\n var selectionId = $(tierPriceElement).data('selection-id') + '';\n\n if (selectionId === optionValue) {\n $(tierPriceElement).show();\n } else {\n $(tierPriceElement).hide();\n }\n });\n }\n },\n\n /**\n * Handler to update productSummary box\n */\n updateProductSummary: function updateProductSummary() {\n this.element.trigger('updateProductSummary', {\n config: this.options.optionConfig\n });\n }\n });\n\n return $.mage.priceBundle;\n\n /**\n * Converts option value to priceBox object\n *\n * @param {jQuery} element\n * @param {Object} config\n * @returns {Object|null} - priceBox object with additional prices\n */\n function defaultGetOptionValue(element, config) {\n var changes = {},\n optionHash,\n tempChanges,\n qtyField,\n optionId = utils.findOptionId(element[0]),\n optionValue = element.val() || null,\n optionName = element.prop('name'),\n optionType = element.prop('type'),\n optionConfig = config.options[optionId].selections,\n optionQty = 0,\n canQtyCustomize = false,\n selectedIds = config.selected;\n\n switch (optionType) {\n case 'radio':\n case 'select-one':\n\n if (optionType === 'radio' && !element.is(':checked')) {\n return null;\n }\n\n qtyField = element.data('qtyField');\n qtyField.data('option', element);\n\n if (optionValue) {\n optionQty = optionConfig[optionValue].qty || 0;\n canQtyCustomize = optionConfig[optionValue].customQty === '1';\n toggleQtyField(qtyField, optionQty, optionId, optionValue, canQtyCustomize);//eslint-disable-line\n tempChanges = utils.deepClone(optionConfig[optionValue].prices);\n tempChanges = applyTierPrice(//eslint-disable-line\n tempChanges,\n optionQty,\n optionConfig[optionValue]\n );\n tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n } else {\n tempChanges = {};\n toggleQtyField(qtyField, '0', optionId, optionValue, false);//eslint-disable-line\n }\n optionHash = 'bundle-option-' + optionName;\n changes[optionHash] = tempChanges;\n selectedIds[optionId] = [optionValue];\n break;\n\n case 'select-multiple':\n optionValue = _.compact(optionValue);\n\n _.each(optionConfig, function (row, optionValueCode) {\n optionHash = 'bundle-option-' + optionName + '##' + optionValueCode;\n optionQty = row.qty || 0;\n tempChanges = utils.deepClone(row.prices);\n tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig);//eslint-disable-line\n tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n changes[optionHash] = _.contains(optionValue, optionValueCode) ? tempChanges : {};\n });\n\n selectedIds[optionId] = optionValue || [];\n break;\n\n case 'checkbox':\n optionHash = 'bundle-option-' + optionName + '##' + optionValue;\n optionQty = optionConfig[optionValue].qty || 0;\n tempChanges = utils.deepClone(optionConfig[optionValue].prices);\n tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig);//eslint-disable-line\n tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n changes[optionHash] = element.is(':checked') ? tempChanges : {};\n\n selectedIds[optionId] = selectedIds[optionId] || [];\n\n if (!_.contains(selectedIds[optionId], optionValue) && element.is(':checked')) {\n selectedIds[optionId].push(optionValue);\n } else if (!element.is(':checked')) {\n selectedIds[optionId] = _.without(selectedIds[optionId], optionValue);\n }\n break;\n\n case 'hidden':\n optionHash = 'bundle-option-' + optionName + '##' + optionValue;\n optionQty = optionConfig[optionValue].qty || 0;\n canQtyCustomize = optionConfig[optionValue].customQty === '1';\n qtyField = element.data('qtyField');\n qtyField.data('option', element);\n toggleQtyField(qtyField, optionQty, optionId, optionValue, canQtyCustomize);//eslint-disable-line\n tempChanges = utils.deepClone(optionConfig[optionValue].prices);\n tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig);//eslint-disable-line\n tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n\n optionHash = 'bundle-option-' + optionName;\n changes[optionHash] = tempChanges;\n selectedIds[optionId] = [optionValue];\n break;\n }\n\n return changes;\n }\n\n /**\n * Check the quantity field if negative value occurs.\n *\n * @param {Object} bundleOption\n */\n function isValidQty(bundleOption) {\n var isValid = true,\n qtyElem = bundleOption.data('qtyField'),\n bundleOptionType = bundleOption.prop('type');\n\n if (['radio', 'select-one'].includes(bundleOptionType) && qtyElem.val() < 0) {\n isValid = false;\n }\n\n return isValid;\n }\n\n /**\n * Helper to toggle qty field\n * @param {jQuery} element\n * @param {String|Number} value\n * @param {String|Number} optionId\n * @param {String|Number} optionValueId\n * @param {Boolean} canEdit\n */\n function toggleQtyField(element, value, optionId, optionValueId, canEdit) {\n element\n .val(value)\n .data('optionId', optionId)\n .data('optionValueId', optionValueId)\n .attr('disabled', !canEdit);\n\n if (canEdit) {\n element.removeClass('qty-disabled');\n } else {\n element.addClass('qty-disabled');\n }\n }\n\n /**\n * Helper to multiply on qty\n *\n * @param {Object} prices\n * @param {Number} qty\n * @returns {Object}\n */\n function applyQty(prices, qty) {\n _.each(prices, function (everyPrice) {\n everyPrice.amount *= qty;\n _.each(everyPrice.adjustments, function (el, index) {\n everyPrice.adjustments[index] *= qty;\n });\n });\n\n return prices;\n }\n\n /**\n * Helper to limit price with tier price\n *\n * @param {Object} oneItemPrice\n * @param {Number} qty\n * @param {Object} optionConfig\n * @returns {Object}\n */\n function applyTierPrice(oneItemPrice, qty, optionConfig) {\n var tiers = optionConfig.tierPrice,\n magicKey = _.keys(oneItemPrice)[0],\n tiersFirstKey = _.keys(optionConfig)[0],\n lowest = false;\n\n if (!tiers) {//tiers is undefined when options has only one option\n tiers = optionConfig[tiersFirstKey].tierPrice;\n }\n\n tiers.sort(function (a, b) {//sorting based on \"price_qty\"\n return a['price_qty'] - b['price_qty'];\n });\n\n _.each(tiers, function (tier, index) {\n if (tier['price_qty'] > qty) {\n return;\n }\n\n if (tier.prices[magicKey].amount < oneItemPrice[magicKey].amount) {\n lowest = index;\n }\n });\n\n if (lowest !== false) {\n oneItemPrice = utils.deepClone(tiers[lowest].prices);\n }\n\n return oneItemPrice;\n }\n});\n","Magento_Bundle/js/product-summary.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'mage/template',\n 'jquery-ui-modules/widget',\n 'Magento_Bundle/js/price-bundle'\n], function ($, mageTemplate) {\n 'use strict';\n\n /**\n * Widget product Summary:\n * Handles rendering of Bundle options and displays them in the Summary box\n */\n $.widget('mage.productSummary', {\n options: {\n mainContainer: '#product_addtocart_form',\n templates: {\n summaryBlock: '[data-template=\"bundle-summary\"]',\n optionBlock: '[data-template=\"bundle-option\"]'\n },\n optionSelector: '[data-container=\"options\"]',\n summaryContainer: '[data-container=\"product-summary\"]',\n bundleSummaryContainer: '.bundle-summary'\n },\n cache: {},\n\n /**\n * Method attaches event observer to the product form\n * @private\n */\n _create: function () {\n this.element\n .closest(this.options.mainContainer)\n .on('updateProductSummary', $.proxy(this._renderSummaryBox, this))\n .priceBundle({})\n ;\n },\n\n /**\n * Method extracts data from the event and renders Summary box\n * using jQuery template mechanism\n * @param {Event} event\n * @param {Object} data\n * @private\n */\n _renderSummaryBox: function (event, data) {\n this.cache.currentElement = data.config;\n this.cache.currentElementCount = 0;\n\n // Clear Summary box\n this.element.html('');\n this.cache.currentElement.positions.forEach(function (optionId) {\n this._renderOption(optionId, this.cache.currentElement.selected[optionId]);\n }, this);\n this.element\n .parents(this.options.bundleSummaryContainer)\n .toggleClass('empty', !this.cache.currentElementCount); // Zero elements equal '.empty' container\n },\n\n /**\n * @param {String} key\n * @param {String} row\n * @private\n */\n _renderOption: function (key, row) {\n var template;\n\n if (row && row.length > 0 && row[0] !== null) {\n template = this.element\n .closest(this.options.summaryContainer)\n .find(this.options.templates.summaryBlock)\n .html();\n template = mageTemplate(template.trim(), {\n data: {\n _label_: this.cache.currentElement.options[key].title\n }\n });\n\n this.cache.currentKey = key;\n this.cache.summaryContainer = $(template);\n this.element.append(this.cache.summaryContainer);\n\n $.each(row, this._renderOptionRow.bind(this));\n this.cache.currentElementCount += row.length;\n\n //Reset Cache\n this.cache.currentKey = null;\n }\n },\n\n /**\n * @param {String} key\n * @param {String} optionIndex\n * @private\n */\n _renderOptionRow: function (key, optionIndex) {\n var template;\n\n template = this.element\n .closest(this.options.summaryContainer)\n .find(this.options.templates.optionBlock)\n .html();\n template = mageTemplate(template.trim(), {\n data: {\n _quantity_: this.cache.currentElement.options[this.cache.currentKey].selections[optionIndex].qty,\n _label_: this.cache.currentElement.options[this.cache.currentKey].selections[optionIndex].name\n }\n });\n this.cache.summaryContainer\n .find(this.options.optionSelector)\n .append(template);\n }\n });\n\n return $.mage.productSummary;\n});\n","Magento_Bundle/js/slide.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget'\n], function ($) {\n 'use strict';\n\n $.widget('mage.slide', {\n options: {\n slideSpeed: 1500,\n slideSelector: '#bundle-slide',\n slideBackSelector: '.bundle-slide-back',\n bundleProductSelector: '#bundleProduct',\n bundleOptionsContainer: '#options-container',\n productViewContainer: '#productView',\n slidedown: true\n\n },\n\n /** @inheritdoc */\n _create: function () {\n if (this.options.slidedown === true) {\n $(this.options.slideSelector).on('click', $.proxy(this._show, this));\n $(this.options.slideBackSelector).on('click', $.proxy(this._hide, this));\n this.options.autostart && this._show();\n } else {\n $(this.options.slideSelector).on('click', $.proxy(this._slide, this));\n $(this.options.slideBackSelector).on('click', $.proxy(this._slideBack, this));\n this.options.autostart && this._slide();\n }\n },\n\n /**\n * slide bundleOptionsContainer over to the main view area\n * @private\n */\n _slide: function () {\n $(this.options.bundleProductSelector).css('top', '0px');\n $(this.options.bundleOptionsContainer).show();\n this.element.css('height', $(this.options.productViewContainer).height() + 'px');\n $(this.options.bundleProductSelector).css('left', '0px').animate(\n {\n 'left': '-' + this.element.width() + 'px'\n },\n this.options.slideSpeed,\n $.proxy(function () {\n this.element.css('height', 'auto');\n $(this.options.productViewContainer).hide();\n }, this)\n );\n },\n\n /**\n * slideback productViewContainer to main view area\n * @private\n */\n _slideBack: function () {\n $(this.options.bundleProductSelector).css('top', '0px');\n $(this.options.productViewContainer).show();\n this.element.css('height', $(this.options.bundleOptionsContainer).height() + 'px');\n $(this.options.bundleProductSelector).animate(\n {\n 'left': '0px'\n },\n this.options.slideSpeed,\n $.proxy(function () {\n $(this.options.bundleOptionsContainer).hide();\n this.element.css('height', 'auto');\n }, this)\n );\n },\n\n /**\n * @private\n */\n _show: function () {\n $(this.options.bundleOptionsContainer).slideDown(800);\n $('html, body').animate({\n scrollTop: $(this.options.bundleOptionsContainer).offset().top\n }, 600);\n $('#product-options-wrapper > fieldset').trigger('focus');\n },\n\n /**\n * @private\n */\n _hide: function () {\n $('html, body').animate({\n scrollTop: 0\n }, 600);\n $(this.options.bundleOptionsContainer).slideUp(800);\n }\n });\n\n return $.mage.slide;\n});\n","Magento_Newsletter/js/subscription-status-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mage/url'\n], function ($, urlBuilder) {\n 'use strict';\n\n return function (email, deferred) {\n return $.getJSON(\n urlBuilder.build('newsletter/ajax/status'),\n {\n email: email\n }\n ).done(function (response) {\n if (response.errors) {\n deferred.reject();\n } else {\n deferred.resolve(response.subscribed);\n }\n }).fail(function () {\n deferred.reject();\n });\n };\n});\n","Magento_Newsletter/js/newsletter-sign-up.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'uiElement',\n 'mage/url',\n 'subscriptionStatusResolver',\n 'mage/validation'\n], function ($, Component, urlBuilder, subscriptionStatusResolver) {\n 'use strict';\n\n return Component.extend({\n\n defaults: {\n signUpElement: '',\n submitButton: '',\n element: null\n },\n\n /** @inheritdoc */\n initialize: function (config, element) {\n this._super();\n this.element = element;\n $(element).on('change', $.proxy(this.updateSignUpStatus, this));\n this.updateSignUpStatus();\n },\n\n /**\n * Send status request and update subscription element according to result.\n */\n updateSignUpStatus: function () {\n var element = $(this.element),\n email = element.val(),\n self = this,\n newsletterSubscription;\n\n if ($(self.signUpElement).is(':checked')) {\n return;\n }\n\n if (!email || !$.validator.methods['validate-email'].call(this, email, element)) {\n return;\n }\n\n newsletterSubscription = $.Deferred();\n\n $(self.submitButton).prop('disabled', true);\n\n subscriptionStatusResolver(email, newsletterSubscription);\n\n $.when(newsletterSubscription).done(function (isSubscribed) {\n if (isSubscribed) {\n $(self.signUpElement).prop('checked', true);\n }\n }).always(function () {\n $(self.submitButton).prop('disabled', false);\n });\n }\n });\n});\n","Magento_Ui/js/block-loader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'jquery',\n 'Magento_Ui/js/lib/knockout/template/loader',\n 'mage/template'\n], function (ko, $, templateLoader, template) {\n 'use strict';\n\n var blockLoaderTemplatePath = 'ui/block-loader',\n blockContentLoadingClass = '_block-content-loading',\n blockLoader,\n blockLoaderClass,\n blockLoaderElement = $.Deferred(),\n loaderImageHref = $.Deferred();\n\n templateLoader.loadTemplate(blockLoaderTemplatePath).done(function (blockLoaderTemplate) {\n loaderImageHref.done(function (loaderHref) {\n blockLoader = template(blockLoaderTemplate.trim(), {\n loaderImageHref: loaderHref\n });\n blockLoader = $(blockLoader);\n blockLoaderClass = '.' + blockLoader.attr('class');\n blockLoaderElement.resolve();\n });\n });\n\n /**\n * Helper function to check if blockContentLoading class should be applied.\n * @param {Object} element\n * @returns {Boolean}\n */\n function isLoadingClassRequired(element) {\n var position = element.css('position');\n\n if (position === 'absolute' || position === 'fixed') {\n return false;\n }\n\n return true;\n }\n\n /**\n * Add loader to block.\n * @param {Object} element\n */\n function addBlockLoader(element) {\n element.find(':focus').trigger('blur');\n element.find('input:disabled, select:disabled').addClass('_disabled');\n element.find('input, select').prop('disabled', true);\n\n if (isLoadingClassRequired(element)) {\n element.addClass(blockContentLoadingClass);\n }\n element.append(blockLoader.clone());\n }\n\n /**\n * Remove loader from block.\n * @param {Object} element\n */\n function removeBlockLoader(element) {\n if (!element.has(blockLoaderClass).length) {\n return;\n }\n element.find(blockLoaderClass).remove();\n element.find('input:not(\"._disabled\"), select:not(\"._disabled\")').prop('disabled', false);\n element.find('input:disabled, select:disabled').removeClass('_disabled');\n element.removeClass(blockContentLoadingClass);\n }\n\n return function (loaderHref) {\n loaderImageHref.resolve(loaderHref);\n ko.bindingHandlers.blockLoader = {\n /**\n * Process loader for block\n * @param {String} element\n * @param {Boolean} displayBlockLoader\n */\n update: function (element, displayBlockLoader) {\n element = $(element);\n\n if (ko.unwrap(displayBlockLoader())) {\n blockLoaderElement.done(addBlockLoader(element));\n } else {\n blockLoaderElement.done(removeBlockLoader(element));\n }\n }\n };\n };\n});\n","Magento_Ui/js/form/button-adapter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'uiClass',\n 'jquery',\n 'underscore',\n 'uiRegistry'\n], function (Class, $, _, registry) {\n 'use strict';\n\n return Class.extend({\n\n /**\n * Initialize actions and adapter.\n *\n * @param {Object} config\n * @param {Element} elem\n * @returns {Object}\n */\n initialize: function (config, elem) {\n return this._super()\n .initActions()\n .initAdapter(elem);\n },\n\n /**\n * Creates callback from declared actions.\n *\n * @returns {Object}\n */\n initActions: function () {\n var callbacks = [];\n\n _.each(this.actions, function (action) {\n callbacks.push({\n action: registry.async(action.targetName),\n args: _.union([action.actionName], action.params)\n });\n });\n\n /**\n * Callback function.\n */\n this.callback = function () {\n _.each(callbacks, function (callback) {\n callback.action.apply(callback.action, callback.args);\n });\n };\n\n return this;\n },\n\n /**\n * Attach callback handler on button.\n *\n * @param {Element} elem\n */\n initAdapter: function (elem) {\n $(elem).on('click', this.callback);\n\n return this;\n }\n });\n});\n","Magento_Ui/js/form/switcher.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'uiRegistry',\n 'uiClass'\n], function (_, registry, Class) {\n 'use strict';\n\n return Class.extend({\n defaults: {\n rules: []\n },\n\n /**\n * Initializes instance of a DataSwitcher.\n *\n * @returns {DataSwitcher} Chainable.\n */\n initialize: function () {\n this._super()\n .initRules();\n\n return this;\n },\n\n /**\n *\n * @returns {DataSwitcher} Chainable.\n */\n initRules: function () {\n this.rules.forEach(this.initRule, this);\n\n return this;\n },\n\n /**\n *\n * @param {Object} rule - Rule definition.\n * @returns {DataSwitcher} Chainable.\n */\n initRule: function (rule) {\n var handler = this.onValueChange.bind(this, rule);\n\n if (!rule.target) {\n rule.target = this.target;\n }\n\n if (!rule.property) {\n rule.property = this.property;\n }\n\n registry.get(rule.target, function (target) {\n this.applyRule(rule, target.get(rule.property));\n target.on(rule.property, handler);\n }.bind(this));\n\n return this;\n },\n\n /**\n *\n * @param {Object} rule - Rule definition.\n * @returns {DataSwitcher} Chainable.\n */\n addRule: function (rule) {\n this.rules.push(rule);\n this.initRule(rule);\n\n return this;\n },\n\n /**\n *\n * @param {Object} rule - Rule object.\n * @param {*} value - Current value associated with a rule.\n */\n applyRule: function (rule, value) {\n var actions = rule.actions;\n\n //TODO Refactor this logic in scope of MAGETWO-48585\n /* eslint-disable eqeqeq */\n if (rule.value != value) {\n return;\n } else if (rule.strict) {\n return;\n }\n\n /* eslint-enable eqeqeq */\n actions.forEach(this.applyAction, this);\n },\n\n /**\n *\n * @param {Object} action - Action object.\n */\n applyAction: function (action) {\n registry.get(action.target, function (target) {\n var callback = target[action.callback];\n\n callback.apply(target, action.params || []);\n });\n },\n\n /**\n *\n * @param {Object} rule - Rules object.\n * @param {*} value - Current value associated with a rule.\n */\n onValueChange: function (rule, value) {\n this.applyRule(rule, value);\n }\n });\n});\n","Magento_Ui/js/form/form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'Magento_Ui/js/lib/spinner',\n 'rjsResolver',\n './adapter',\n 'uiCollection',\n 'mageUtils',\n 'jquery',\n 'Magento_Ui/js/core/app',\n 'mage/validation'\n], function (_, loader, resolver, adapter, Collection, utils, $, app) {\n 'use strict';\n\n /**\n * Format params\n *\n * @param {Object} params\n * @returns {Array}\n */\n function prepareParams(params) {\n var result = '?';\n\n _.each(params, function (value, key) {\n result += key + '=' + value + '&';\n });\n\n return result.slice(0, -1);\n }\n\n /**\n * Collect form data.\n *\n * @param {Array} items\n * @returns {Object}\n */\n function collectData(items) {\n var result = {},\n name;\n\n items = Array.prototype.slice.call(items);\n\n items.forEach(function (item) {\n switch (item.type) {\n case 'checkbox':\n result[item.name] = +!!item.checked;\n break;\n\n case 'radio':\n if (item.checked) {\n result[item.name] = item.value;\n }\n break;\n\n case 'select-multiple':\n name = item.name.substring(0, item.name.length - 2); //remove [] from the name ending\n result[name] = _.pluck(item.selectedOptions, 'value');\n break;\n\n default:\n result[item.name] = item.value;\n }\n });\n\n return result;\n }\n\n /**\n * Makes ajax request\n *\n * @param {Object} params\n * @param {Object} data\n * @param {String} url\n * @returns {*}\n */\n function makeRequest(params, data, url) {\n var save = $.Deferred();\n\n data = utils.serialize(data);\n data['form_key'] = window.FORM_KEY;\n\n if (!url) {\n save.resolve();\n }\n\n $('body').trigger('processStart');\n\n $.ajax({\n url: url + prepareParams(params),\n data: data,\n dataType: 'json',\n\n /**\n * Success callback.\n * @param {Object} resp\n * @returns {Boolean}\n */\n success: function (resp) {\n if (resp.ajaxExpired) {\n window.location.href = resp.ajaxRedirect;\n }\n\n if (!resp.error) {\n save.resolve(resp);\n\n return true;\n }\n\n $('body').notification('clear');\n $.each(resp.messages, function (key, message) {\n $('body').notification('add', {\n error: resp.error,\n message: message,\n\n /**\n * Inserts message on page\n * @param {String} msg\n */\n insertMethod: function (msg) {\n $('.page-main-actions').after(msg);\n }\n });\n });\n },\n\n /**\n * Complete callback.\n */\n complete: function () {\n $('body').trigger('processStop');\n }\n });\n\n return save.promise();\n }\n\n /**\n * Check if fields is valid.\n *\n * @param {Array}items\n * @returns {Boolean}\n */\n function isValidFields(items) {\n var result = true;\n\n _.each(items, function (item) {\n if (!$.validator.validateSingleElement(item)) {\n result = false;\n }\n });\n\n return result;\n }\n\n return Collection.extend({\n defaults: {\n additionalFields: [],\n additionalInvalid: false,\n selectorPrefix: '.page-content',\n messagesClass: 'messages',\n errorClass: '.admin__field._error',\n eventPrefix: '.${ $.index }',\n ajaxSave: false,\n ajaxSaveType: 'default',\n imports: {\n reloadUrl: '${ $.provider}:reloadUrl'\n },\n listens: {\n selectorPrefix: 'destroyAdapter initAdapter',\n '${ $.name }.${ $.reloadItem }': 'params.set reload'\n },\n exports: {\n selectorPrefix: '${ $.provider }:client.selectorPrefix',\n messagesClass: '${ $.provider }:client.messagesClass'\n }\n },\n\n /** @inheritdoc */\n initialize: function () {\n this._super()\n .initAdapter();\n\n resolver(this.hideLoader, this);\n\n return this;\n },\n\n /** @inheritdoc */\n initObservable: function () {\n return this._super()\n .observe([\n 'responseData',\n 'responseStatus'\n ]);\n },\n\n /** @inheritdoc */\n initConfig: function () {\n this._super();\n\n this.selector = '[data-form-part=' + this.namespace + ']';\n\n return this;\n },\n\n /**\n * Initialize adapter handlers.\n *\n * @returns {Object}\n */\n initAdapter: function () {\n adapter.on({\n 'reset': this.reset.bind(this),\n 'save': this.save.bind(this, true, {}),\n 'saveAndContinue': this.save.bind(this, false, {})\n }, this.selectorPrefix, this.eventPrefix);\n\n return this;\n },\n\n /**\n * Destroy adapter handlers.\n *\n * @returns {Object}\n */\n destroyAdapter: function () {\n adapter.off([\n 'reset',\n 'save',\n 'saveAndContinue'\n ], this.eventPrefix);\n\n return this;\n },\n\n /**\n * Hide loader.\n *\n * @returns {Object}\n */\n hideLoader: function () {\n loader.get(this.name).hide();\n\n return this;\n },\n\n /**\n * Validate and save form.\n *\n * @param {String} redirect\n * @param {Object} data\n */\n save: function (redirect, data) {\n this.validate();\n\n if (!this.additionalInvalid && !this.source.get('params.invalid')) {\n this.setAdditionalData(data)\n .submit(redirect);\n } else {\n this.focusInvalid();\n }\n },\n\n /**\n * Tries to set focus on first invalid form field.\n *\n * @returns {Object}\n */\n focusInvalid: function () {\n var invalidField = _.find(this.delegate('checkInvalid'));\n\n if (!_.isUndefined(invalidField) && _.isFunction(invalidField.focused)) {\n invalidField.focused(true);\n }\n\n return this;\n },\n\n /**\n * Set additional data to source before form submit and after validation.\n *\n * @param {Object} data\n * @returns {Object}\n */\n setAdditionalData: function (data) {\n _.each(data, function (value, name) {\n this.source.set('data.' + name, value);\n }, this);\n\n return this;\n },\n\n /**\n * Submits form\n *\n * @param {String} redirect\n */\n submit: function (redirect) {\n var additional = collectData(this.additionalFields),\n source = this.source;\n\n _.each(additional, function (value, name) {\n source.set('data.' + name, value);\n });\n\n source.save({\n redirect: redirect,\n ajaxSave: this.ajaxSave,\n ajaxSaveType: this.ajaxSaveType,\n response: {\n data: this.responseData,\n status: this.responseStatus\n },\n attributes: {\n id: this.namespace\n }\n });\n },\n\n /**\n * Validates each element and returns true, if all elements are valid.\n */\n validate: function () {\n this.additionalFields = document.querySelectorAll(this.selector);\n this.source.set('params.invalid', false);\n this.source.trigger('data.validate');\n this.set('additionalInvalid', !isValidFields(this.additionalFields));\n },\n\n /**\n * Trigger reset form data.\n */\n reset: function () {\n this.source.trigger('data.reset');\n $('[data-bind*=datepicker]').val('');\n },\n\n /**\n * Trigger overload form data.\n */\n overload: function () {\n this.source.trigger('data.overload');\n },\n\n /**\n * Updates data from server.\n */\n reload: function () {\n makeRequest(this.params, this.data, this.reloadUrl).then(function (data) {\n app(data, true);\n });\n }\n });\n});\n","Magento_Ui/js/form/client.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'underscore',\n 'mageUtils',\n 'uiClass'\n], function ($, _, utils, Class) {\n 'use strict';\n\n /**\n * Before save validate request.\n *\n * @param {Object} data\n * @param {String} url\n * @param {String} selectorPrefix\n * @param {String} messagesClass\n * @returns {*}\n */\n function beforeSave(data, url, selectorPrefix, messagesClass) {\n var save = $.Deferred();\n\n data = utils.serialize(utils.filterFormData(data));\n data['form_key'] = window.FORM_KEY;\n\n if (!url || url === 'undefined') {\n return save.resolve();\n }\n\n $('body').trigger('processStart');\n\n $.ajax({\n url: url,\n data: data,\n\n /**\n * Success callback.\n * @param {Object} resp\n * @returns {Boolean}\n */\n success: function (resp) {\n if (!resp.error) {\n save.resolve();\n\n return true;\n }\n\n $('body').notification('clear');\n $.each(resp.messages || [resp.message] || [], function (key, message) {\n $('body').notification('add', {\n error: resp.error,\n message: message,\n\n /**\n * Insert method.\n *\n * @param {String} msg\n */\n insertMethod: function (msg) {\n var $wrapper = $('<div></div>').addClass(messagesClass).html(msg);\n\n $('.page-main-actions', selectorPrefix).after($wrapper);\n $('html, body').animate({\n scrollTop: $('.page-main-actions', selectorPrefix).offset().top\n });\n }\n });\n });\n },\n\n /**\n * Complete callback.\n */\n complete: function () {\n $('body').trigger('processStop');\n }\n });\n\n return save.promise();\n }\n\n return Class.extend({\n\n /**\n * Assembles data and submits it using 'utils.submit' method\n */\n save: function (data, options) {\n var url = this.urls.beforeSave,\n save = this._save.bind(this, data, options);\n\n beforeSave(data, url, this.selectorPrefix, this.messagesClass).then(save);\n\n return this;\n },\n\n /**\n * Save data.\n *\n * @param {Object} data\n * @param {Object} options\n * @returns {Object}\n * @private\n */\n _save: function (data, options) {\n var url = this.urls.save;\n\n $('body').trigger('processStart');\n options = options || {};\n\n if (!options.redirect) {\n url += 'back/edit';\n }\n\n if (options.ajaxSave) {\n utils.ajaxSubmit({\n url: url,\n data: data\n }, options);\n\n $('body').trigger('processStop');\n\n return this;\n }\n\n utils.submit({\n url: url,\n data: data\n }, options.attributes);\n\n return this;\n }\n });\n});\n","Magento_Ui/js/form/adapter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n 'Magento_Ui/js/form/adapter/buttons'\n], function ($, _, buttons) {\n 'use strict';\n\n var selectorPrefix = '',\n eventPrefix;\n\n /**\n * Initialize listener.\n *\n * @param {Function} callback\n * @param {String} action\n */\n function initListener(callback, action) {\n var selector = selectorPrefix ? selectorPrefix + ' ' + buttons[action] : buttons[action],\n elem = $(selector)[0];\n\n if (!elem) {\n return;\n }\n\n if (elem.onclick) {\n elem.onclick = null;\n }\n\n $(elem).on('click' + eventPrefix, callback);\n }\n\n /**\n * Destroy listener.\n *\n * @param {String} action\n */\n function destroyListener(action) {\n var selector = selectorPrefix ? selectorPrefix + ' ' + buttons[action] : buttons[action],\n elem = $(selector)[0];\n\n if (!elem) {\n return;\n }\n\n if (elem.onclick) {\n elem.onclick = null;\n }\n\n $(elem).off('click' + eventPrefix);\n }\n\n return {\n\n /**\n * Attaches events handlers.\n *\n * @param {Object} handlers\n * @param {String} selectorPref\n * @param {String} eventPref\n */\n on: function (handlers, selectorPref, eventPref) {\n selectorPrefix = selectorPrefix || selectorPref;\n eventPrefix = eventPref;\n _.each(handlers, initListener);\n selectorPrefix = '';\n },\n\n /**\n * Removes events handlers.\n *\n * @param {Object} handlers\n * @param {String} eventPref\n */\n off: function (handlers, eventPref) {\n eventPrefix = eventPref;\n _.each(handlers, destroyListener);\n }\n };\n});\n","Magento_Ui/js/form/provider.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'uiElement',\n './client',\n 'mageUtils'\n], function (_, Element, Client, utils) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n clientConfig: {\n urls: {\n save: '${ $.submit_url }',\n beforeSave: '${ $.validate_url }'\n }\n },\n ignoreTmpls: {\n data: true\n }\n },\n\n /**\n * Initializes provider component.\n *\n * @returns {Provider} Chainable.\n */\n initialize: function () {\n this._super()\n .initClient();\n\n return this;\n },\n\n /**\n * Initializes client component.\n *\n * @returns {Provider} Chainable.\n */\n initClient: function () {\n this.client = new Client(this.clientConfig);\n\n return this;\n },\n\n /**\n * Saves currently available data.\n *\n * @param {Object} [options] - Addtitional request options.\n * @returns {Provider} Chainable.\n */\n save: function (options) {\n var data = this.get('data');\n\n this.client.save(data, options);\n\n return this;\n },\n\n /**\n * Update data that stored in provider.\n *\n * @param {Boolean} isProvider\n * @param {Object} newData\n * @param {Object} oldData\n *\n * @returns {Provider}\n */\n updateConfig: function (isProvider, newData, oldData) {\n if (isProvider === true) {\n this.setData(oldData, newData, this);\n }\n\n return this;\n },\n\n /**\n * Set data to provider based on current data.\n *\n * @param {Object} oldData\n * @param {Object} newData\n * @param {Provider} current\n * @param {String} parentPath\n */\n setData: function (oldData, newData, current, parentPath) {\n _.each(newData, function (val, key) {\n if (_.isObject(val) || _.isArray(val)) {\n this.setData(oldData[key], val, current[key], utils.fullPath(parentPath, key));\n } else if (val != oldData[key] && oldData[key] == current[key]) {//eslint-disable-line eqeqeq\n this.set(utils.fullPath(parentPath, key), val);\n }\n }, this);\n }\n });\n});\n","Magento_Ui/js/form/adapter/buttons.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine(function () {\n 'use strict';\n\n return {\n 'reset': '#reset',\n 'save': '#save',\n 'saveAndContinue': '#save_and_continue'\n };\n});\n","Magento_Ui/js/form/components/fieldset.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'Magento_Ui/js/lib/collapsible',\n 'underscore'\n], function (Collapsible, _) {\n 'use strict';\n\n return Collapsible.extend({\n defaults: {\n template: 'ui/form/fieldset',\n collapsible: false,\n changed: false,\n loading: false,\n error: false,\n opened: false,\n level: 0,\n visible: true,\n initializeFieldsetDataByDefault: false, /* Data in some fieldsets should be initialized before open */\n disabled: false,\n listens: {\n 'opened': 'onVisibilityChange'\n },\n additionalClasses: {}\n },\n\n /**\n * Extends instance with defaults. Invokes parent initialize method.\n * Calls initListeners and pushParams methods.\n */\n initialize: function () {\n _.bindAll(this, 'onChildrenUpdate', 'onChildrenError', 'onContentLoading');\n\n return this._super()\n ._setClasses();\n },\n\n /**\n * Initializes components' configuration.\n *\n * @returns {Fieldset} Chainable.\n */\n initConfig: function () {\n this._super();\n this._wasOpened = this.opened || !this.collapsible;\n\n return this;\n },\n\n /**\n * Calls initObservable of parent class.\n * Defines observable properties of instance.\n *\n * @returns {Object} Reference to instance\n */\n initObservable: function () {\n this._super()\n .observe('changed loading error visible');\n\n return this;\n },\n\n /**\n * Calls parent's initElement method.\n * Assigns callbacks on various events of incoming element.\n *\n * @param {Object} elem\n * @return {Object} - reference to instance\n */\n initElement: function (elem) {\n elem.initContainer(this);\n\n elem.on({\n 'update': this.onChildrenUpdate,\n 'loading': this.onContentLoading,\n 'error': this.onChildrenError\n });\n\n if (this.disabled) {\n try {\n elem.disabled(true);\n }\n catch (e) {\n\n }\n }\n\n return this;\n },\n\n /**\n * Is being invoked on children update.\n * Sets changed property to one incoming.\n *\n * @param {Boolean} hasChanged\n */\n onChildrenUpdate: function (hasChanged) {\n if (!hasChanged) {\n hasChanged = _.some(this.delegate('hasChanged'));\n }\n\n this.bubble('update', hasChanged);\n this.changed(hasChanged);\n },\n\n /**\n * Extends 'additionalClasses' object.\n *\n * @returns {Group} Chainable.\n */\n _setClasses: function () {\n var additional = this.additionalClasses,\n classes;\n\n if (_.isString(additional)) {\n additional = this.additionalClasses.split(' ');\n classes = this.additionalClasses = {};\n\n additional.forEach(function (name) {\n classes[name] = true;\n }, this);\n }\n\n _.extend(this.additionalClasses, {\n 'admin__collapsible-block-wrapper': this.collapsible,\n _show: this.opened,\n _hide: !this.opened,\n _disabled: this.disabled\n });\n\n return this;\n },\n\n /**\n * Handler of the \"opened\" property changes.\n *\n * @param {Boolean} isOpened\n */\n onVisibilityChange: function (isOpened) {\n if (!this._wasOpened) {\n this._wasOpened = isOpened;\n }\n },\n\n /**\n * Is being invoked on children validation error.\n * Sets error property to one incoming.\n *\n * @param {String} message - error message.\n */\n onChildrenError: function (message) {\n var hasErrors = false;\n\n if (!message) {\n hasErrors = this._isChildrenHasErrors(hasErrors, this);\n }\n\n this.error(hasErrors || message);\n\n if (hasErrors || message) {\n this.open();\n }\n },\n\n /**\n * Returns errors of children if exist\n *\n * @param {Boolean} hasErrors\n * @param {*} container\n * @return {Boolean}\n * @private\n */\n _isChildrenHasErrors: function (hasErrors, container) {\n var self = this;\n\n if (hasErrors === false && container.hasOwnProperty('elems')) {\n hasErrors = container.elems.some('error');\n\n if (hasErrors === false && container.hasOwnProperty('_elems')) {\n container._elems.forEach(function (child) {\n\n if (hasErrors === false) {\n hasErrors = self._isChildrenHasErrors(hasErrors, child);\n }\n });\n }\n }\n\n return hasErrors;\n },\n\n /**\n * Callback that sets loading property to true.\n */\n onContentLoading: function (isLoading) {\n this.loading(isLoading);\n }\n });\n});\n","Magento_Ui/js/form/components/button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'uiElement',\n 'uiRegistry',\n 'uiLayout',\n 'mageUtils',\n 'underscore'\n], function (Element, registry, layout, utils, _) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n buttonClasses: {},\n additionalClasses: {},\n displayArea: 'outsideGroup',\n displayAsLink: false,\n elementTmpl: 'ui/form/element/button',\n template: 'ui/form/components/button/simple',\n visible: true,\n disabled: false,\n title: '',\n buttonTextId: '',\n ariLabelledby: ''\n },\n\n /**\n * Initializes component.\n *\n * @returns {Object} Chainable.\n */\n initialize: function () {\n return this._super()\n ._setClasses()\n ._setButtonClasses();\n },\n\n /** @inheritdoc */\n initObservable: function () {\n return this._super()\n .observe([\n 'visible',\n 'disabled',\n 'title',\n 'childError'\n ]);\n },\n\n /**\n * Performs configured actions\n */\n action: function () {\n this.actions.forEach(this.applyAction, this);\n },\n\n /**\n * Apply action on target component,\n * but previously create this component from template if it is not existed\n *\n * @param {Object} action - action configuration\n */\n applyAction: function (action) {\n var targetName = action.targetName,\n params = utils.copy(action.params) || [],\n actionName = action.actionName,\n target;\n\n if (!registry.has(targetName)) {\n this.getFromTemplate(targetName);\n }\n target = registry.async(targetName);\n\n if (target && typeof target === 'function' && actionName) {\n params.unshift(actionName);\n target.apply(target, params);\n }\n },\n\n /**\n * Create target component from template\n *\n * @param {Object} targetName - name of component,\n * that supposed to be a template and need to be initialized\n */\n getFromTemplate: function (targetName) {\n var parentName = targetName.split('.'),\n index = parentName.pop(),\n child;\n\n parentName = parentName.join('.');\n child = utils.template({\n parent: parentName,\n name: index,\n nodeTemplate: targetName\n });\n layout([child]);\n },\n\n /**\n * Extends 'additionalClasses' object.\n *\n * @returns {Object} Chainable.\n */\n _setClasses: function () {\n if (typeof this.additionalClasses === 'string') {\n if (this.additionalClasses === '') {\n this.additionalClasses = {};\n\n return this;\n }\n\n this.additionalClasses = this.additionalClasses\n .trim()\n .split(' ')\n .reduce(function (classes, name) {\n classes[name] = true;\n\n return classes;\n }, {}\n );\n }\n\n return this;\n },\n\n /**\n * Extends 'buttonClasses' object.\n *\n * @returns {Object} Chainable.\n */\n _setButtonClasses: function () {\n var additional = this.buttonClasses;\n\n if (_.isString(additional)) {\n this.buttonClasses = {};\n\n if (additional.trim().length) {\n additional = additional.trim().split(' ');\n\n additional.forEach(function (name) {\n if (name.length) {\n this.buttonClasses[name] = true;\n }\n }, this);\n }\n }\n\n _.extend(this.buttonClasses, {\n 'action-basic': !this.displayAsLink,\n 'action-additional': this.displayAsLink\n });\n\n return this;\n }\n });\n});\n","Magento_Ui/js/form/components/tab.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'uiCollection'\n], function (Collection) {\n 'use strict';\n\n return Collection.extend({\n defaults: {\n uniqueProp: 'active',\n active: false,\n wasActivated: false\n },\n\n /**\n * Extends instance with defaults. Invokes parent initialize method.\n * Calls initListeners and pushParams methods.\n */\n initialize: function () {\n this._super()\n .setUnique();\n },\n\n /**\n * Calls initObservable of parent class.\n * Defines observable properties of instance.\n * @return {Object} - reference to instance\n */\n initObservable: function () {\n this._super()\n .observe('active wasActivated');\n\n return this;\n },\n\n /**\n * Sets active property to true, then invokes pushParams method.\n */\n activate: function () {\n this.active(true);\n this.wasActivated(true);\n\n this.setUnique();\n\n return true;\n }\n });\n});\n","Magento_Ui/js/form/components/html.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n 'uiComponent'\n], function ($, _, Component) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n content: '',\n showSpinner: false,\n loading: false,\n visible: true,\n template: 'ui/content/content',\n additionalClasses: {},\n ignoreTmpls: {\n content: true\n }\n },\n\n /**\n * Extends instance with default config, calls 'initialize' method of\n * parent, calls 'initAjaxConfig'\n */\n initialize: function () {\n _.bindAll(this, 'onContainerToggle', 'onDataLoaded');\n\n this._super()\n ._setClasses()\n .initAjaxConfig();\n\n return this;\n },\n\n /**\n * Calls 'initObservable' method of parent, initializes observable\n * properties of instance\n *\n * @return {Object} - reference to instance\n */\n initObservable: function () {\n this._super()\n .observe('content loading visible');\n\n return this;\n },\n\n /**\n * Extends 'additionalClasses' object.\n *\n * @returns {Group} Chainable.\n */\n _setClasses: function () {\n var additional = this.additionalClasses,\n classes;\n\n if (_.isString(additional)) {\n additional = this.additionalClasses.split(' ');\n classes = this.additionalClasses = {};\n\n additional.forEach(function (name) {\n classes[name] = true;\n }, this);\n }\n\n _.extend(this.additionalClasses, {\n 'admin__scope-old': !!additional\n });\n\n return this;\n },\n\n /** @inheritdoc */\n initContainer: function (parent) {\n this._super();\n\n parent.on('active', this.onContainerToggle);\n\n return this;\n },\n\n /**\n * Initializes default ajax config on instance\n *\n * @return {Object} - reference to instance\n */\n initAjaxConfig: function () {\n this.ajaxConfig = {\n url: this.url,\n data: {\n FORM_KEY: window.FORM_KEY\n },\n success: this.onDataLoaded\n };\n\n return this;\n },\n\n /**\n * Calls 'loadData' if both 'active' variable and 'shouldLoad'\n * property are truthy\n *\n * @param {Boolean} active\n */\n onContainerToggle: function (active) {\n if (active && this.shouldLoad()) {\n this.loadData();\n }\n },\n\n /**\n * Defines if instance has 'content' property defined.\n *\n * @return {Boolean} [description]\n */\n hasData: function () {\n return !!this.content();\n },\n\n /**\n * Defines if instance should load external data\n *\n * @return {Boolean}\n */\n shouldLoad: function () {\n return this.url && !this.hasData() && !this.loading();\n },\n\n /**\n * Sets loading property to true, makes ajax call\n *\n * @return {Object} - reference to instance\n */\n loadData: function () {\n this.loading(true);\n\n $.ajax(this.ajaxConfig);\n\n return this;\n },\n\n /**\n * Ajax's request success handler. Calls 'updateContent' passing 'data'\n * to it, then sets 'loading' property to false.\n *\n * @param {String} data\n */\n onDataLoaded: function (data) {\n this.updateContent(data)\n .loading(false);\n },\n\n /**\n * Sets incoming data 'content' property's value\n *\n * @param {String} content\n * @return {Object} - reference to instance\n */\n updateContent: function (content) {\n this.content(content);\n\n return this;\n },\n\n /**\n * Content getter\n *\n * @returns {String}\n */\n getContentUnsanitizedHtml: function () {\n return this.content();\n }\n });\n});\n","Magento_Ui/js/form/components/multiline.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n './group'\n], function (Group) {\n 'use strict';\n\n return Group.extend({\n defaults: {\n links: {\n value: '${ $.provider }:${ $.dataScope }'\n }\n },\n\n /**\n * Initialize Multiline component.\n *\n * @returns {Object}\n */\n initialize: function () {\n return this._super()\n ._prepareValue();\n },\n\n /**\n * {@inheritdoc}\n */\n initObservable: function () {\n this._super()\n .observe('value');\n\n return this;\n },\n\n /**\n * Prepare value for Multiline options.\n *\n * @returns {Object} Chainable.\n * @private\n */\n _prepareValue: function () {\n var value = this.value();\n\n if (typeof value === 'string') {\n this.value(value.split('\\n'));\n }\n\n return this;\n }\n });\n});\n","Magento_Ui/js/form/components/collection.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'mageUtils',\n 'uiRegistry',\n 'uiComponent',\n 'uiLayout',\n 'Magento_Ui/js/modal/confirm'\n], function (_, utils, registry, Component, layout, confirm) {\n 'use strict';\n\n var childTemplate = {\n parent: '${ $.$data.name }',\n name: '${ $.$data.childIndex }',\n dataScope: '${ $.name }',\n nodeTemplate: '${ $.$data.name }.${ $.$data.itemTemplate }'\n };\n\n return Component.extend({\n defaults: {\n lastIndex: 0,\n template: 'ui/form/components/collection'\n },\n\n /**\n * Extends instance with default config, calls initialize of parent\n * class, calls initChildren method.\n */\n initialize: function () {\n this._super()\n .initChildren();\n\n return this;\n },\n\n /**\n * Activates the incoming child and triggers the update event.\n *\n * @param {Object} elem - Incoming child.\n */\n initElement: function (elem) {\n this._super();\n\n elem.activate();\n\n this.bubble('update');\n\n return this;\n },\n\n /**\n * Loops over corresponding data in data storage,\n * creates child for each and pushes it's identifier to initialItems array.\n *\n * @returns {Collection} Chainable.\n */\n initChildren: function () {\n var children = this.source.get(this.dataScope),\n initial = this.initialItems = [];\n\n _.each(children, function (item, index) {\n initial.push(index);\n this.addChild(index);\n }, this);\n\n return this;\n },\n\n /**\n * Creates new item of collection, based on incoming 'index'.\n * If not passed creates one with 'new_' prefix.\n *\n * @param {String|Object} [index] - Index of a child.\n * @returns {Collection} Chainable.\n */\n addChild: function (index) {\n this.childIndex = !_.isString(index) ?\n 'new_' + this.lastIndex++ :\n index;\n\n layout([utils.template(childTemplate, this)]);\n\n return this;\n },\n\n /**\n * Returns true if current set of items differ from initial one,\n * or if some child has been changed.\n *\n * @returns {Boolean}\n */\n hasChanged: function () {\n var initial = this.initialItems,\n current = this.elems.pluck('index'),\n changed = !utils.equalArrays(initial, current);\n\n return changed || this.elems.some(function (elem) {\n return _.some(elem.delegate('hasChanged'));\n });\n },\n\n /**\n * Initiates validation of its' children components.\n *\n * @returns {Array} An array of validation results.\n */\n validate: function () {\n var elems;\n\n this.allValid = true;\n\n elems = this.elems.sortBy(function (elem) {\n return !elem.active();\n });\n\n elems = elems.map(this._validate, this);\n\n return _.flatten(elems);\n },\n\n /**\n * Iterator function for components validation.\n * Activates first invalid child component.\n *\n * @param {Object} elem - Element to run validation on.\n * @returns {Array} An array of validation results.\n */\n _validate: function (elem) {\n var result = elem.delegate('validate'),\n invalid;\n\n invalid = _.some(result, function (item) {\n return !item.valid;\n });\n\n if (this.allValid && invalid) {\n this.allValid = false;\n\n elem.activate();\n }\n\n return result;\n },\n\n /**\n * Creates function that removes element\n * from collection using '_removeChild' method.\n * @param {Object} elem - Element that should be removed.\n * @deprecated Not used anymore\n */\n removeAddress: function (elem) {\n var self = this;\n\n confirm({\n content: this.removeMessage,\n actions: {\n /** @inheritdoc */\n confirm: function () {\n self._removeAddress(elem);\n }\n }\n });\n },\n\n /**\n * Removes element from both collection and data storage,\n * activates first element if removed one was active,\n * triggers 'update' event.\n *\n * @param {Object} elem - Element to remove.\n */\n _removeAddress: function (elem) {\n var isActive = elem.active(),\n first;\n\n elem.destroy();\n\n first = this.elems.first();\n\n if (first && isActive) {\n first.activate();\n }\n\n this.bubble('update');\n }\n });\n});\n","Magento_Ui/js/form/components/area.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n './tab'\n], function (_, Tab) {\n 'use strict';\n\n return Tab.extend({\n defaults: {\n uniqueNs: 'params.activeArea',\n template: 'ui/area',\n changed: false,\n loading: false\n },\n\n /**\n * Extends instance with defaults. Invokes parent initialize method.\n * Calls initListeners and pushParams methods.\n */\n initialize: function () {\n _.bindAll(this, 'onChildrenUpdate', 'onContentLoading');\n\n return this._super();\n },\n\n /**\n * Calls initObservable of parent class.\n * Defines observable properties of instance.\n * @return {Object} - reference to instance\n */\n initObservable: function () {\n this._super()\n .observe('changed loading');\n\n return this;\n },\n\n /**\n * Calls parent's initElement method.\n * Assigns callbacks on various events of incoming element.\n * @param {Object} elem\n * @return {Object} - reference to instance\n */\n initElement: function (elem) {\n this._super();\n\n elem.on({\n 'update': this.onChildrenUpdate,\n 'loading': this.onContentLoading\n });\n\n return this;\n },\n\n /**\n * Is being invoked on children update.\n * Sets changed property to one incoming.\n * Invokes setActive method if settings\n * contain makeVisible property set to true.\n *\n * @param {Boolean} hasChanged\n */\n onChildrenUpdate: function (hasChanged) {\n if (!hasChanged) {\n hasChanged = _.some(this.delegate('hasChanged'));\n }\n\n this.changed(hasChanged);\n },\n\n /**\n * Callback that sets loading property to true.\n */\n onContentLoading: function (isLoading) {\n this.loading(isLoading);\n }\n });\n});\n","Magento_Ui/js/form/components/insert-form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n './insert',\n 'mageUtils',\n 'jquery'\n], function (Insert, utils, $) {\n 'use strict';\n\n /**\n * Get page actions element.\n *\n * @param {String} elem\n * @param {String} actionsClass\n * @returns {String}\n */\n function getPageActions(elem, actionsClass) {\n var el = document.createElement('div');\n\n el.innerHTML = elem;\n\n return el.getElementsByClassName(actionsClass)[0];\n }\n\n /**\n * Return element without page actions toolbar\n *\n * @param {String} elem\n * @param {String} actionsClass\n * @returns {String}\n */\n function removePageActions(elem, actionsClass) {\n var el = document.createElement('div'),\n actions;\n\n el.innerHTML = elem;\n actions = el.getElementsByClassName(actionsClass)[0];\n\n if (actions) {\n el.removeChild(actions);\n }\n\n return el.innerHTML;\n }\n\n return Insert.extend({\n defaults: {\n externalFormName: '${ $.ns }.${ $.ns }',\n pageActionsClass: 'page-actions',\n actionsContainerClass: 'page-main-actions',\n exports: {\n prefix: '${ $.externalFormName }:selectorPrefix'\n },\n imports: {\n toolbarSection: '${ $.toolbarContainer }:toolbarSection',\n prefix: '${ $.toolbarContainer }:rootSelector',\n messagesClass: '${ $.externalFormName }:messagesClass'\n },\n settings: {\n ajax: {\n ajaxSave: true,\n exports: {\n ajaxSave: '${ $.externalFormName }:ajaxSave'\n },\n imports: {\n responseStatus: '${ $.externalFormName }:responseStatus',\n responseData: '${ $.externalFormName }:responseData'\n }\n }\n },\n modules: {\n externalForm: '${ $.externalFormName }'\n }\n },\n\n /** @inheritdoc */\n initObservable: function () {\n return this._super()\n .observe('responseStatus');\n },\n\n /** @inheritdoc */\n initConfig: function (config) {\n var defaults = this.constructor.defaults;\n\n utils.extend(defaults, defaults.settings[config.formSubmitType] || {});\n\n return this._super();\n },\n\n /** @inheritdoc*/\n destroyInserted: function () {\n if (this.isRendered && this.externalForm()) {\n this.externalForm().delegate('destroy');\n this.removeActions();\n this.responseStatus(undefined);\n this.responseData = {};\n }\n\n return this._super();\n },\n\n /** @inheritdoc */\n onRender: function (data) {\n var actions = getPageActions(data, this.pageActionsClass);\n\n if (!data.length) {\n return this;\n }\n data = removePageActions(data, this.pageActionsClass);\n this.renderActions(actions);\n this._super(data);\n },\n\n /**\n * Insert actions in toolbar.\n *\n * @param {String} actions\n */\n renderActions: function (actions) {\n var $container = $('<div></div>');\n\n $container\n .addClass(this.actionsContainerClass)\n .append(actions);\n\n this.formHeader = $container;\n\n $(this.toolbarSection).append(this.formHeader);\n },\n\n /**\n * Remove actions toolbar.\n */\n removeActions: function () {\n $(this.formHeader).siblings('.' + this.messagesClass).remove();\n $(this.formHeader).remove();\n this.formHeader = $();\n },\n\n /**\n * Reset external form data.\n */\n resetForm: function () {\n if (this.externalSource()) {\n this.externalSource().trigger('data.reset');\n this.responseStatus(undefined);\n }\n }\n });\n});\n","Magento_Ui/js/form/components/tab_group.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'Magento_Ui/js/lib/collapsible'\n], function (_, Collapsible) {\n 'use strict';\n\n return Collapsible.extend({\n defaults: {\n listens: {\n '${ $.provider }:data.validate': 'onValidate'\n },\n collapsible: false,\n opened: true\n },\n\n /**\n * Invokes initElement method of parent class, calls 'initActivation' method\n * passing element to it.\n * @param {Object} elem\n * @returns {Object} - reference to instance\n */\n initElement: function (elem) {\n this._super()\n .initActivation(elem);\n\n return this;\n },\n\n /**\n * Activates element if one is first or if one has 'active' propert\n * set to true.\n *\n * @param {Object} elem\n * @returns {Object} - reference to instance\n */\n initActivation: function (elem) {\n var elems = this.elems(),\n isFirst = !elems.indexOf(elem);\n\n if (isFirst || elem.active()) {\n elem.activate();\n }\n\n return this;\n },\n\n /**\n * Delegates 'validate' method on element, then reads 'invalid' property\n * of params storage, and if defined, activates element, sets\n * 'allValid' property of instance to false and sets invalid's\n * 'focused' property to true.\n *\n * @param {Object} elem\n */\n validate: function (elem) {\n var result = elem.delegate('validate'),\n invalid;\n\n invalid = _.find(result, function (item) {\n return typeof item !== 'undefined' && !item.valid;\n });\n\n if (invalid) {\n elem.activate();\n invalid.target.focused(true);\n }\n\n return invalid;\n },\n\n /**\n * Sets 'allValid' property of instance to true, then calls 'validate' method\n * of instance for each element.\n */\n onValidate: function () {\n this.elems.sortBy(function (elem) {\n return !elem.active();\n }).some(this.validate, this);\n }\n });\n});\n","Magento_Ui/js/form/components/group.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'uiCollection'\n], function (_, Collection) {\n 'use strict';\n\n return Collection.extend({\n defaults: {\n visible: true,\n label: '',\n showLabel: true,\n required: false,\n template: 'ui/group/group',\n fieldTemplate: 'ui/form/field',\n breakLine: true,\n validateWholeGroup: false,\n additionalClasses: {}\n },\n\n /**\n * Extends this with defaults and config.\n * Then calls initObservable, iniListenes and extractData methods.\n */\n initialize: function () {\n this._super()\n ._setClasses();\n\n return this;\n },\n\n /**\n * Calls initObservable of parent class.\n * Defines observable properties of instance.\n *\n * @return {Object} - reference to instance\n */\n initObservable: function () {\n this._super()\n .observe('visible')\n .observe({\n required: !!+this.required\n });\n\n return this;\n },\n\n /**\n * Extends 'additionalClasses' object.\n *\n * @returns {Group} Chainable.\n */\n _setClasses: function () {\n var additional = this.additionalClasses,\n classes;\n\n if (_.isString(additional)) {\n additional = this.additionalClasses.split(' ');\n classes = this.additionalClasses = {};\n\n additional.forEach(function (name) {\n classes[name] = true;\n }, this);\n }\n\n _.extend(this.additionalClasses, {\n 'admin__control-grouped': !this.breakLine,\n 'admin__control-fields': this.breakLine,\n required: this.required,\n _error: this.error,\n _disabled: this.disabled\n });\n\n return this;\n },\n\n /**\n * Defines if group has only one element.\n * @return {Boolean}\n */\n isSingle: function () {\n return this.elems.getLength() === 1;\n },\n\n /**\n * Defines if group has multiple elements.\n * @return {Boolean}\n */\n isMultiple: function () {\n return this.elems.getLength() > 1;\n },\n\n /**\n * Returns an array of child components previews.\n *\n * @returns {Array}\n */\n getPreview: function () {\n return this.elems.map('getPreview');\n }\n });\n});\n","Magento_Ui/js/form/components/collection/item.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'mageUtils',\n '../tab'\n], function (_, utils, Tab) {\n 'use strict';\n\n var previewConfig = {\n separator: ' ',\n prefix: ''\n };\n\n /**\n * Parses incoming data and returns result merged with default preview config\n *\n * @param {Object|String} data\n * @return {Object}\n */\n function parsePreview(data) {\n if (typeof data == 'string') {\n data = {\n items: data\n };\n }\n\n data.items = utils.stringToArray(data.items);\n\n return _.defaults(data, previewConfig);\n }\n\n return Tab.extend({\n defaults: {\n label: '',\n uniqueNs: 'activeCollectionItem',\n previewTpl: 'ui/form/components/collection/preview'\n },\n\n /**\n * Extends instance with default config, calls initializes of parent class\n */\n initialize: function () {\n _.bindAll(this, 'buildPreview', 'hasPreview');\n\n return this._super();\n },\n\n /**\n * Calls initProperties of parent class, initializes properties\n * of instance.\n *\n * @return {Object} - reference to instance\n */\n initConfig: function () {\n this._super();\n\n this.displayed = [];\n\n return this;\n },\n\n /**\n * Calls initObservable of parent class, initializes observable\n * properties of instance.\n *\n * @return {Object} - reference to instance\n */\n initObservable: function () {\n this._super()\n .observe({\n noPreview: true,\n indexed: {}\n });\n\n return this;\n },\n\n /**\n * Is being called when child element has been initialized,\n * calls initElement of parent class, binds to element's update event,\n * calls insertToArea and insertToIndexed methods passing element to it\n *\n * @param {Object} elem\n */\n initElement: function (elem) {\n this._super()\n .insertToIndexed(elem);\n\n return this;\n },\n\n /**\n * Adds element to observable indexed object of instance\n *\n * @param {Object} elem\n * @return {Object} - reference to instance\n */\n insertToIndexed: function (elem) {\n var indexed = this.indexed();\n\n indexed[elem.index] = elem;\n\n this.indexed(indexed);\n\n return this;\n },\n\n /**\n * Destroys current instance along with all of its' children.\n * Overrides base method to clear data when this method is called.\n */\n destroy: function () {\n this._super();\n this._clearData();\n },\n\n /**\n * Clears all data associated with component.\n * @private\n *\n * @returns {Item} Chainable.\n */\n _clearData: function () {\n this.source.remove(this.dataScope);\n\n return this;\n },\n\n /**\n * Formats incoming previews array via parsePreview function.\n *\n * @param {Array} previews\n * @return {Array} - formatted previews\n */\n formatPreviews: function (previews) {\n return previews.map(parsePreview);\n },\n\n /**\n * Creates string view of previews\n *\n * @param {Object} data\n * @return {Strict} - formatted preview string\n */\n buildPreview: function (data) {\n var preview = this.getPreview(data.items),\n prefix = data.prefix;\n\n return prefix + preview.join(data.separator);\n },\n\n /**\n * Defines if instance has preview for incoming data\n *\n * @param {Object} data\n * @return {Boolean}\n */\n hasPreview: function (data) {\n return !!this.getPreview(data.items).length;\n },\n\n /**\n * Creates an array of previews for elements specified in incoming\n * items array, calls updatePreview afterwards.\n *\n * @param {Array} items - An array of element's indexes.\n * @returns {Array} An array of previews.\n */\n getPreview: function (items) {\n var elems = this.indexed(),\n displayed = this.displayed,\n preview;\n\n items = items.map(function (index) {\n var elem = elems[index];\n\n preview = elem && elem.visible() ? elem.getPreview() : '';\n\n preview = Array.isArray(preview) ?\n _.compact(preview).join(', ') :\n preview;\n\n utils.toggle(displayed, index, !!preview);\n\n return preview;\n });\n\n this.noPreview(!displayed.length);\n\n return _.compact(items);\n }\n });\n});\n","Magento_Ui/js/form/element/multiselect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'mageUtils',\n './select'\n], function (_, utils, Select) {\n 'use strict';\n\n return Select.extend({\n defaults: {\n size: 5,\n elementTmpl: 'ui/form/element/multiselect',\n listens: {\n value: 'setDifferedFromDefault setPrepareToSendData'\n }\n },\n\n /**\n * @inheritdoc\n */\n setInitialValue: function () {\n this._super();\n\n this.initialValue = utils.copy(this.initialValue);\n\n return this;\n },\n\n /**\n * @inheritdoc\n */\n normalizeData: function (value) {\n if (utils.isEmpty(value)) {\n value = [];\n }\n\n return _.isString(value) ? value.split(',') : value;\n },\n\n /**\n * Sets the prepared data to dataSource\n * by path, where key is component link to dataSource with\n * suffix \"-prepared-for-send\"\n *\n * @param {Array} data - current component value\n */\n setPrepareToSendData: function (data) {\n if (_.isUndefined(data) || !data.length) {\n data = '';\n }\n\n this.source.set(this.dataScope + '-prepared-for-send', data);\n },\n\n /**\n * @inheritdoc\n */\n getInitialValue: function () {\n var values = [\n this.normalizeData(this.source.get(this.dataScope)),\n this.normalizeData(this.default)\n ],\n value;\n\n values.some(function (v) {\n return _.isArray(v) && (value = utils.copy(v)) && !_.isEmpty(v);\n });\n\n return value;\n },\n\n /**\n * @inheritdoc\n */\n hasChanged: function () {\n var value = this.value(),\n initial = this.initialValue;\n\n return !utils.equalArrays(value, initial);\n },\n\n /**\n * @inheritdoc\n */\n reset: function () {\n this.value(utils.copy(this.initialValue));\n this.error(false);\n\n return this;\n },\n\n /**\n * @inheritdoc\n */\n clear: function () {\n this.value([]);\n this.error(false);\n\n return this;\n }\n });\n});\n","Magento_Ui/js/form/element/url-input.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'uiLayout',\n 'mage/translate',\n 'Magento_Ui/js/form/element/abstract'\n], function (_, layout, $t, Abstract) {\n 'use strict';\n\n return Abstract.extend({\n defaults: {\n linkedElement: {},\n settingTemplate: 'ui/form/element/urlInput/setting',\n typeSelectorTemplate: 'ui/form/element/urlInput/typeSelector',\n options: [],\n linkedElementInstances: {},\n //checkbox\n isDisplayAdditionalSettings: true,\n settingValue: false,\n settingLabel: $t('Open in new tab'),\n tracks: {\n linkedElement: true\n },\n baseLinkSetting: {\n namePrefix: '${$.name}.',\n dataScopePrefix: '${$.dataScope}.',\n provider: '${$.provider}'\n },\n urlTypes: {},\n listens: {\n settingValue: 'checked',\n disabled: 'hideLinkedElement',\n linkType: 'createChildUrlInputComponent'\n },\n links: {\n linkType: '${$.provider}:${$.dataScope}.type',\n settingValue: '${$.provider}:${$.dataScope}.setting'\n }\n },\n\n /** @inheritdoc */\n initConfig: function (config) {\n var processedLinkTypes = {},\n baseLinkType = this.constructor.defaults.baseLinkSetting;\n\n _.each(config.urlTypes, function (linkSettingsArray, linkName) {\n //add link name by link type\n linkSettingsArray.name = baseLinkType.namePrefix + linkName;\n linkSettingsArray.dataScope = baseLinkType.dataScopePrefix + linkName;\n linkSettingsArray.type = linkName;\n linkSettingsArray.disabled = config.disabled;\n linkSettingsArray.visible = config.visible;\n processedLinkTypes[linkName] = {};\n _.extend(processedLinkTypes[linkName], baseLinkType, linkSettingsArray);\n });\n _.extend(this.constructor.defaults.urlTypes, processedLinkTypes);\n\n this._super();\n },\n\n /**\n * Initializes observable properties of instance\n *\n * @returns {Abstract} Chainable.\n */\n initObservable: function () {\n this._super()\n .observe('componentTemplate options value linkType settingValue checked isDisplayAdditionalSettings')\n .setOptions();\n\n return this;\n },\n\n /**\n * Set options to select based on link types configuration\n *\n * @return {Object}\n */\n setOptions: function () {\n var result = [];\n\n _.each(this.urlTypes, function (option, key) {\n result.push({\n value: key,\n label: option.label,\n sortOrder: option.sortOrder || 0\n });\n });\n\n //sort options by sortOrder\n result.sort(function (a, b) {\n return a.sortOrder > b.sortOrder ? 1 : -1;\n });\n\n this.options(result);\n\n return this;\n },\n\n /** @inheritdoc */\n setPreview: function (visible) {\n this.linkedElement().visible(visible);\n },\n\n /**\n * Initializes observable properties of instance\n *\n * @param {Boolean} disabled\n */\n hideLinkedElement: function (disabled) {\n this.linkedElement().disabled(disabled);\n },\n\n /** @inheritdoc */\n destroy: function () {\n _.each(this.linkedElementInstances, function (value) {\n value().destroy();\n });\n this._super();\n },\n\n /**\n * Create child component by value\n *\n * @param {String} value\n * @return void\n */\n createChildUrlInputComponent: function (value) {\n var elementConfig;\n\n if (!_.isEmpty(value) && _.isUndefined(this.linkedElementInstances[value])) {\n elementConfig = this.urlTypes[value];\n layout([elementConfig]);\n this.linkedElementInstances[value] = this.requestModule(elementConfig.name);\n }\n this.linkedElement = this.linkedElementInstances[value];\n\n },\n\n /**\n * Returns linked element to display related field in template\n * @return String\n */\n getLinkedElementName: function () {\n return this.linkedElement;\n },\n\n /**\n * Add ability to choose check box by clicking on label\n */\n checkboxClick: function () {\n if (!this.disabled()) {\n this.settingValue(!this.settingValue());\n }\n }\n });\n});\n","Magento_Ui/js/form/element/media.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'mageUtils',\n './abstract'\n], function (utils, Abstract) {\n 'use strict';\n\n return Abstract.extend({\n defaults: {\n links: {\n value: ''\n }\n },\n\n /**\n * Initializes file component.\n *\n * @returns {Media} Chainable.\n */\n initialize: function () {\n this._super()\n .initFormId();\n\n return this;\n },\n\n /**\n * Defines form ID with which file input will be associated.\n *\n * @returns {Media} Chainable.\n */\n initFormId: function () {\n var namespace;\n\n if (this.formId) {\n return this;\n }\n\n namespace = this.name.split('.');\n this.formId = namespace[0];\n\n return this;\n }\n });\n});\n","Magento_Ui/js/form/element/abstract.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'mageUtils',\n 'uiLayout',\n 'uiElement',\n 'Magento_Ui/js/lib/validation/validator'\n], function (_, utils, layout, Element, validator) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n visible: true,\n preview: '',\n focused: false,\n required: false,\n disabled: false,\n valueChangedByUser: false,\n elementTmpl: 'ui/form/element/input',\n tooltipTpl: 'ui/form/element/helper/tooltip',\n fallbackResetTpl: 'ui/form/element/helper/fallback-reset',\n 'input_type': 'input',\n placeholder: false,\n description: '',\n labelVisible: true,\n label: '',\n error: '',\n warn: '',\n notice: '',\n customScope: '',\n default: '',\n isDifferedFromDefault: false,\n showFallbackReset: false,\n additionalClasses: {},\n isUseDefault: '',\n serviceDisabled: false,\n valueUpdate: false, // ko binding valueUpdate\n\n switcherConfig: {\n component: 'Magento_Ui/js/form/switcher',\n name: '${ $.name }_switcher',\n target: '${ $.name }',\n property: 'value'\n },\n listens: {\n visible: 'setPreview',\n value: 'setDifferedFromDefault',\n '${ $.provider }:data.reset': 'reset',\n '${ $.provider }:data.overload': 'overload',\n '${ $.provider }:${ $.customScope ? $.customScope + \".\" : \"\"}data.validate': 'validate',\n 'isUseDefault': 'toggleUseDefault'\n },\n ignoreTmpls: {\n value: true\n },\n\n links: {\n value: '${ $.provider }:${ $.dataScope }'\n }\n },\n\n /**\n * Invokes initialize method of parent class,\n * contains initialization logic\n */\n initialize: function () {\n _.bindAll(this, 'reset');\n\n this._super()\n .setInitialValue()\n ._setClasses()\n .initSwitcher();\n\n return this;\n },\n\n /**\n * Checks if component has error.\n *\n * @returns {Object}\n */\n checkInvalid: function () {\n return this.error() && this.error().length ? this : null;\n },\n\n /**\n * Initializes observable properties of instance\n *\n * @returns {Abstract} Chainable.\n */\n initObservable: function () {\n var rules = this.validation = this.validation || {};\n\n this._super();\n\n this.observe('error disabled focused preview visible value warn notice isDifferedFromDefault')\n .observe('isUseDefault serviceDisabled')\n .observe({\n 'required': !!rules['required-entry']\n });\n\n return this;\n },\n\n /**\n * Initializes regular properties of instance.\n *\n * @returns {Abstract} Chainable.\n */\n initConfig: function () {\n var uid = utils.uniqueid(),\n name,\n valueUpdate,\n scope;\n\n this._super();\n\n scope = this.dataScope.split('.');\n name = scope.length > 1 ? scope.slice(1) : scope;\n\n valueUpdate = this.showFallbackReset ? 'afterkeydown' : this.valueUpdate;\n\n _.extend(this, {\n uid: uid,\n noticeId: 'notice-' + uid,\n errorId: 'error-' + uid,\n tooltipId: 'tooltip-' + uid,\n inputName: utils.serializeName(name.join('.')),\n valueUpdate: valueUpdate\n });\n\n return this;\n },\n\n /**\n * Initializes switcher element instance.\n *\n * @returns {Abstract} Chainable.\n */\n initSwitcher: function () {\n if (this.switcherConfig.enabled) {\n layout([this.switcherConfig]);\n }\n\n return this;\n },\n\n /**\n * Sets initial value of the element and subscribes to it's changes.\n *\n * @returns {Abstract} Chainable.\n */\n setInitialValue: function () {\n this.initialValue = this.getInitialValue();\n\n if (this.value.peek() !== this.initialValue) {\n this.value(this.initialValue);\n }\n\n this.on('value', this.onUpdate.bind(this));\n this.isUseDefault(this.disabled());\n\n return this;\n },\n\n /**\n * Extends 'additionalClasses' object.\n *\n * @returns {Abstract} Chainable.\n */\n _setClasses: function () {\n var additional = this.additionalClasses;\n\n if (_.isString(additional)) {\n this.additionalClasses = {};\n\n if (additional.trim().length) {\n additional = additional.trim().split(' ');\n\n additional.forEach(function (name) {\n if (name.length) {\n this.additionalClasses[name] = true;\n }\n }, this);\n }\n }\n\n _.extend(this.additionalClasses, {\n _required: this.required,\n _error: this.error,\n _warn: this.warn,\n _disabled: this.disabled\n });\n\n return this;\n },\n\n /**\n * Gets initial value of element\n *\n * @returns {*} Elements' value.\n */\n getInitialValue: function () {\n var values = [this.value(), this.default],\n value;\n\n values.some(function (v) {\n if (v !== null && v !== undefined) {\n value = v;\n\n return true;\n }\n\n return false;\n });\n\n return this.normalizeData(value);\n },\n\n /**\n * Sets 'value' as 'hidden' property's value, triggers 'toggle' event,\n * sets instance's hidden identifier in params storage based on\n * 'value'.\n *\n * @returns {Abstract} Chainable.\n */\n setVisible: function (isVisible) {\n this.visible(isVisible);\n\n return this;\n },\n\n /**\n * Show element.\n *\n * @returns {Abstract} Chainable.\n */\n show: function () {\n this.visible(true);\n\n return this;\n },\n\n /**\n * Hide element.\n *\n * @returns {Abstract} Chainable.\n */\n hide: function () {\n this.visible(false);\n\n return this;\n },\n\n /**\n * Disable element.\n *\n * @returns {Abstract} Chainable.\n */\n disable: function () {\n this.disabled(true);\n\n return this;\n },\n\n /**\n * Enable element.\n *\n * @returns {Abstract} Chainable.\n */\n enable: function () {\n this.disabled(false);\n\n return this;\n },\n\n /**\n *\n * @param {(String|Object)} rule\n * @param {(Object|Boolean)} [options]\n * @returns {Abstract} Chainable.\n */\n setValidation: function (rule, options) {\n var rules = utils.copy(this.validation),\n changed;\n\n if (_.isObject(rule)) {\n _.extend(this.validation, rule);\n } else {\n this.validation[rule] = options;\n }\n\n changed = !utils.compare(rules, this.validation).equal;\n\n if (changed) {\n this.required(!!rules['required-entry']);\n this.validate();\n }\n\n return this;\n },\n\n /**\n * Returns unwrapped preview observable.\n *\n * @returns {String} Value of the preview observable.\n */\n getPreview: function () {\n return this.value();\n },\n\n /**\n * Checks if element has addons\n *\n * @returns {Boolean}\n */\n hasAddons: function () {\n return this.addbefore || this.addafter;\n },\n\n /**\n * Checks if element has service setting\n *\n * @returns {Boolean}\n */\n hasService: function () {\n return this.service && this.service.template;\n },\n\n /**\n * Defines if value has changed.\n *\n * @returns {Boolean}\n */\n hasChanged: function () {\n var notEqual = this.value() !== this.initialValue;\n\n return !this.visible() ? false : notEqual;\n },\n\n /**\n * Checks if 'value' is not empty.\n *\n * @returns {Boolean}\n */\n hasData: function () {\n return !utils.isEmpty(this.value());\n },\n\n /**\n * Sets value observable to initialValue property.\n *\n * @returns {Abstract} Chainable.\n */\n reset: function () {\n this.value(this.initialValue);\n this.error(false);\n\n return this;\n },\n\n /**\n * Sets current state as initial.\n */\n overload: function () {\n this.setInitialValue();\n this.bubble('update', this.hasChanged());\n },\n\n /**\n * Clears 'value' property.\n *\n * @returns {Abstract} Chainable.\n */\n clear: function () {\n this.value('');\n\n return this;\n },\n\n /**\n * Converts values like 'null' or 'undefined' to an empty string.\n *\n * @param {*} value - Value to be processed.\n * @returns {*}\n */\n normalizeData: function (value) {\n return utils.isEmpty(value) ? '' : value;\n },\n\n /**\n * Validates itself by it's validation rules using validator object.\n * If validation of a rule did not pass, writes it's message to\n * 'error' observable property.\n *\n * @returns {Object} Validate information.\n */\n validate: function () {\n var value = this.value(),\n result = validator(this.validation, value, this.validationParams),\n message = !this.disabled() && this.visible() ? result.message : '',\n isValid = this.disabled() || !this.visible() || result.passed;\n\n this.error(message);\n this.error.valueHasMutated();\n this.bubble('error', message);\n\n //TODO: Implement proper result propagation for form\n if (this.source && !isValid) {\n this.source.set('params.invalid', true);\n }\n\n return {\n valid: isValid,\n target: this\n };\n },\n\n /**\n * Callback that fires when 'value' property is updated.\n */\n onUpdate: function () {\n this.bubble('update', this.hasChanged());\n\n this.validate();\n },\n\n /**\n * Restore value to default\n */\n restoreToDefault: function () {\n this.value(this.default);\n this.focused(true);\n },\n\n /**\n * Update whether value differs from default value\n */\n setDifferedFromDefault: function () {\n var value = typeof this.value() != 'undefined' && this.value() !== null ? this.value() : '',\n defaultValue = typeof this.default != 'undefined' && this.default !== null ? this.default : '';\n\n this.isDifferedFromDefault(value !== defaultValue);\n },\n\n /**\n * @param {Boolean} state\n */\n toggleUseDefault: function (state) {\n this.disabled(state);\n\n if (this.source && this.hasService()) {\n this.source.set('data.use_default.' + this.index, Number(state));\n }\n },\n\n /**\n * Callback when value is changed by user\n */\n userChanges: function () {\n this.valueChangedByUser = true;\n },\n\n /**\n * Returns correct id for 'aria-describedby' accessibility attribute\n *\n * @returns {Boolean|String}\n */\n getDescriptionId: function () {\n var id = false;\n\n if (this.error()) {\n id = this.errorId;\n } else if (this.notice()) {\n id = this.noticeId;\n }\n\n return id;\n }\n });\n});\n","Magento_Ui/js/form/element/boolean.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n './abstract'\n], function (Abstract) {\n 'use strict';\n\n return Abstract.extend({\n defaults: {\n checked: false,\n links: {\n checked: 'value'\n }\n },\n\n /**\n * @returns {*|void|Element}\n */\n initObservable: function () {\n return this._super()\n .observe('checked');\n },\n\n /**\n * Converts provided value to boolean.\n *\n * @returns {Boolean}\n */\n normalizeData: function () {\n return !!+this._super();\n },\n\n /**\n * Calls 'onUpdate' method of parent, if value is defined and instance's\n * 'unique' property set to true, calls 'setUnique' method\n *\n * @return {Object} - reference to instance\n */\n onUpdate: function () {\n if (this.hasUnique) {\n this.setUnique();\n }\n\n return this._super();\n }\n });\n});\n","Magento_Ui/js/form/element/select.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'mageUtils',\n 'uiRegistry',\n './abstract',\n 'uiLayout'\n], function (_, utils, registry, Abstract, layout) {\n 'use strict';\n\n var inputNode = {\n parent: '${ $.$data.parentName }',\n component: 'Magento_Ui/js/form/element/abstract',\n template: '${ $.$data.template }',\n provider: '${ $.$data.provider }',\n name: '${ $.$data.index }_input',\n dataScope: '${ $.$data.customEntry }',\n customScope: '${ $.$data.customScope }',\n sortOrder: {\n after: '${ $.$data.name }'\n },\n displayArea: 'body',\n label: '${ $.$data.label }'\n };\n\n /**\n * Parses incoming options, considers options with undefined value property\n * as caption\n *\n * @param {Array} nodes\n * @return {Object}\n */\n function parseOptions(nodes, captionValue) {\n var caption,\n value;\n\n nodes = _.map(nodes, function (node) {\n value = node.value;\n\n if (value === null || value === captionValue) {\n if (_.isUndefined(caption)) {\n caption = node.label;\n }\n } else {\n return node;\n }\n });\n\n return {\n options: _.compact(nodes),\n caption: _.isString(caption) ? caption : false\n };\n }\n\n /**\n * Recursively loops over data to find non-undefined, non-array value\n *\n * @param {Array} data\n * @return {*} - first non-undefined value in array\n */\n function findFirst(data) {\n var value;\n\n data.some(function (node) {\n value = node.value;\n\n if (Array.isArray(value)) {\n value = findFirst(value);\n }\n\n return !_.isUndefined(value);\n });\n\n return value;\n }\n\n /**\n * Recursively set to object item like value and item.value like key.\n *\n * @param {Array} data\n * @param {Object} result\n * @returns {Object}\n */\n function indexOptions(data, result) {\n var value;\n\n result = result || {};\n\n data.forEach(function (item) {\n value = item.value;\n\n if (Array.isArray(value)) {\n indexOptions(value, result);\n } else {\n result[value] = item;\n }\n });\n\n return result;\n }\n\n return Abstract.extend({\n defaults: {\n customName: '${ $.parentName }.${ $.index }_input',\n elementTmpl: 'ui/form/element/select',\n caption: '',\n options: []\n },\n\n /**\n * Extends instance with defaults, extends config with formatted values\n * and options, and invokes initialize method of AbstractElement class.\n * If instance's 'customEntry' property is set to true, calls 'initInput'\n */\n initialize: function () {\n this._super();\n\n if (this.customEntry) {\n registry.get(this.name, this.initInput.bind(this));\n }\n\n if (this.filterBy) {\n this.initFilter();\n }\n\n return this;\n },\n\n /**\n * Calls 'initObservable' of parent, initializes 'options' and 'initialOptions'\n * properties, calls 'setOptions' passing options to it\n *\n * @returns {Object} Chainable.\n */\n initObservable: function () {\n this._super();\n\n this.initialOptions = this.options;\n\n this.observe('options caption')\n .setOptions(this.options());\n\n return this;\n },\n\n /**\n * Set link for filter.\n *\n * @returns {Object} Chainable\n */\n initFilter: function () {\n var filter = this.filterBy;\n\n this.filter(this.default, filter.field);\n this.setLinks({\n filter: filter.target\n }, 'imports');\n\n return this;\n },\n\n /**\n * Creates input from template, renders it via renderer.\n *\n * @returns {Object} Chainable.\n */\n initInput: function () {\n layout([utils.template(inputNode, this)]);\n\n return this;\n },\n\n /**\n * Matches specified value with existing options\n * or, if value is not specified, returns value of the first option.\n *\n * @returns {*}\n */\n normalizeData: function () {\n var value = this._super(),\n option;\n\n if (value !== '') {\n option = this.getOption(value);\n\n return option && option.value;\n }\n\n if (!this.caption()) {\n return findFirst(this.options);\n }\n },\n\n /**\n * Filters 'initialOptions' property by 'field' and 'value' passed,\n * calls 'setOptions' passing the result to it\n *\n * @param {*} value\n * @param {String} field\n */\n filter: function (value, field) {\n var source = this.initialOptions,\n result;\n\n field = field || this.filterBy.field;\n\n result = _.filter(source, function (item) {\n return item[field] === value || item.value === '';\n });\n\n this.setOptions(result);\n },\n\n /**\n * Change visibility for input.\n *\n * @param {Boolean} isVisible\n */\n toggleInput: function (isVisible) {\n registry.get(this.customName, function (input) {\n input.setVisible(isVisible);\n });\n },\n\n /**\n * Sets 'data' to 'options' observable array, if instance has\n * 'customEntry' property set to true, calls 'setHidden' method\n * passing !options.length as a parameter\n *\n * @param {Array} data\n * @returns {Object} Chainable\n */\n setOptions: function (data) {\n var captionValue = this.captionValue || '',\n result = parseOptions(data, captionValue),\n isVisible;\n\n this.indexedOptions = indexOptions(result.options);\n\n this.options(result.options);\n\n if (!this.caption()) {\n this.caption(result.caption);\n }\n\n if (this.customEntry) {\n isVisible = !!result.options.length;\n\n this.setVisible(isVisible);\n this.toggleInput(!isVisible);\n }\n\n return this;\n },\n\n /**\n * Processes preview for option by it's value, and sets the result\n * to 'preview' observable\n *\n * @returns {Object} Chainable.\n */\n getPreview: function () {\n var value = this.value(),\n option = this.indexedOptions[value],\n preview = option ? option.label : '';\n\n this.preview(preview);\n\n return preview;\n },\n\n /**\n * Get option from indexedOptions list.\n *\n * @param {Number} value\n * @returns {Object} Chainable\n */\n getOption: function (value) {\n return this.indexedOptions[value];\n },\n\n /**\n * Select first available option\n *\n * @returns {Object} Chainable.\n */\n clear: function () {\n var value = this.caption() ? '' : findFirst(this.options);\n\n this.value(value);\n\n return this;\n },\n\n /**\n * Initializes observable properties of instance\n *\n * @returns {Object} Chainable.\n */\n setInitialValue: function () {\n if (_.isUndefined(this.value()) && !this.default) {\n this.clear();\n }\n\n return this._super();\n }\n });\n});\n","Magento_Ui/js/form/element/single-checkbox.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'Magento_Ui/js/form/element/abstract',\n 'underscore',\n 'mage/translate'\n], function (AbstractField, _, $t) {\n 'use strict';\n\n return AbstractField.extend({\n defaults: {\n template: 'ui/form/components/single/field',\n checked: false,\n initialChecked: false,\n multiple: false,\n prefer: 'checkbox', // 'radio' | 'checkbox' | 'toggle'\n valueMap: {},\n\n templates: {\n radio: 'ui/form/components/single/radio',\n checkbox: 'ui/form/components/single/checkbox',\n toggle: 'ui/form/components/single/switcher'\n },\n\n listens: {\n 'checked': 'onCheckedChanged',\n 'value': 'onExtendedValueChanged'\n }\n },\n\n /**\n * @inheritdoc\n */\n initConfig: function (config) {\n this._super();\n\n if (!config.elementTmpl) {\n if (!this.prefer && !this.multiple) {\n this.elementTmpl = this.templates.radio;\n } else if (this.prefer === 'radio') {\n this.elementTmpl = this.templates.radio;\n } else if (this.prefer === 'checkbox') {\n this.elementTmpl = this.templates.checkbox;\n } else if (this.prefer === 'toggle') {\n this.elementTmpl = this.templates.toggle;\n } else {\n this.elementTmpl = this.templates.checkbox;\n }\n }\n\n if (this.prefer === 'toggle' && _.isEmpty(this.toggleLabels)) {\n this.toggleLabels = {\n 'on': $t('Yes'),\n 'off': $t('No')\n };\n }\n\n if (typeof this.default === 'undefined' || this.default === null) {\n this.default = '';\n }\n\n if (typeof this.value === 'undefined' || this.value === null) {\n this.value = _.isEmpty(this.valueMap) || this.default !== '' ? this.default : this.valueMap.false;\n this.initialValue = this.value;\n } else {\n this.initialValue = this.value;\n }\n\n if (this.multiple && !_.isArray(this.value)) {\n this.value = []; // needed for correct observable assignment\n }\n\n this.initialChecked = this.checked;\n\n return this;\n },\n\n /**\n * @inheritdoc\n */\n initObservable: function () {\n return this\n ._super()\n .observe('checked');\n },\n\n /**\n * Get true/false key from valueMap by value.\n *\n * @param {*} value\n * @returns {Boolean|undefined}\n */\n getReverseValueMap: function getReverseValueMap(value) {\n var bool = false;\n\n _.some(this.valueMap, function (iValue, iBool) {\n if (iValue === value) {\n bool = iBool === 'true';\n\n return true;\n }\n });\n\n return bool;\n },\n\n /**\n * @inheritdoc\n */\n setInitialValue: function () {\n if (_.isEmpty(this.valueMap)) {\n this.on('value', this.onUpdate.bind(this));\n } else {\n this._super();\n this.checked(this.getReverseValueMap(this.value()));\n }\n\n return this;\n },\n\n /**\n * Handle dataScope changes for checkbox / radio button.\n *\n * @param {*} newExportedValue\n */\n onExtendedValueChanged: function (newExportedValue) {\n var isMappedUsed = !_.isEmpty(this.valueMap),\n oldChecked = this.checked.peek(),\n oldValue = this.initialValue,\n newChecked;\n\n if (this.multiple) {\n newChecked = newExportedValue.indexOf(oldValue) !== -1;\n } else if (isMappedUsed) {\n newChecked = this.getReverseValueMap(newExportedValue);\n } else if (typeof newExportedValue === 'boolean') {\n newChecked = newExportedValue;\n } else {\n newChecked = newExportedValue === oldValue;\n }\n\n if (newChecked !== oldChecked) {\n this.checked(newChecked);\n }\n },\n\n /**\n * Handle checked state changes for checkbox / radio button.\n *\n * @param {Boolean} newChecked\n */\n onCheckedChanged: function (newChecked) {\n var isMappedUsed = !_.isEmpty(this.valueMap),\n oldValue = this.initialValue,\n newValue;\n\n if (isMappedUsed) {\n newValue = this.valueMap[newChecked];\n } else {\n newValue = oldValue;\n }\n\n if (!this.multiple && newChecked) {\n this.value(newValue);\n } else if (!this.multiple && !newChecked) {\n if (typeof newValue === 'boolean') {\n this.value(newChecked);\n } else if (newValue === this.value.peek()) {\n this.value('');\n }\n\n if (isMappedUsed) {\n this.value(newValue);\n }\n } else if (this.multiple && newChecked && this.value.indexOf(newValue) === -1) {\n this.value.push(newValue);\n } else if (this.multiple && !newChecked && this.value.indexOf(newValue) !== -1) {\n this.value.splice(this.value.indexOf(newValue), 1);\n }\n },\n\n /**\n * @inheritdoc\n */\n onUpdate: function () {\n if (this.hasUnique) {\n this.setUnique();\n }\n\n return this._super();\n },\n\n /**\n * @inheritdoc\n */\n reset: function () {\n if (this.multiple && this.initialChecked) {\n this.value.push(this.initialValue);\n } else if (this.multiple && !this.initialChecked) {\n this.value.splice(this.value.indexOf(this.initialValue), 1);\n } else {\n this.value(this.initialValue);\n }\n\n this.error(false);\n\n return this;\n },\n\n /**\n * @inheritdoc\n */\n clear: function () {\n if (this.multiple) {\n this.value([]);\n } else {\n this.value('');\n }\n\n this.error(false);\n\n return this;\n }\n });\n});\n","Magento_Ui/js/form/element/website.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'uiRegistry',\n './select'\n], function (_, registry, Select) {\n 'use strict';\n\n return Select.extend({\n defaults: {\n customerId: null,\n isGlobalScope: 0\n },\n\n /**\n * Website component constructor.\n * @returns {exports}\n */\n initialize: function () {\n this._super();\n\n return this;\n }\n });\n});\n","Magento_Ui/js/form/element/wysiwyg.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'wysiwygAdapter',\n 'Magento_Ui/js/lib/view/utils/async',\n 'underscore',\n 'ko',\n './abstract',\n 'mage/adminhtml/events',\n 'Magento_Variable/variables'\n], function (wysiwyg, $, _, ko, Abstract, varienGlobalEvents) {\n 'use strict';\n\n return Abstract.extend({\n currentWysiwyg: undefined,\n defaults: {\n elementSelector: 'textarea',\n suffixRegExpPattern: '${ $.wysiwygUniqueSuffix }',\n $wysiwygEditorButton: '',\n links: {\n value: '${ $.provider }:${ $.dataScope }'\n },\n template: 'ui/form/field',\n elementTmpl: 'ui/form/element/wysiwyg',\n content: '',\n showSpinner: false,\n loading: false,\n listens: {\n disabled: 'setDisabled'\n }\n },\n\n /**\n *\n * @returns {} Chainable.\n */\n initialize: function () {\n this._super()\n .initNodeListener();\n\n $.async({\n component: this,\n selector: 'button'\n }, function (element) {\n this.$wysiwygEditorButton = this.$wysiwygEditorButton ?\n this.$wysiwygEditorButton.add($(element)) : $(element);\n }.bind(this));\n\n // disable editor completely after initialization is field is disabled\n varienGlobalEvents.attachEventHandler('wysiwygEditorInitialized', function () {\n if (!_.isUndefined(window.tinyMceEditors)) {\n this.currentWysiwyg = window.tinyMceEditors[this.wysiwygId];\n }\n\n if (this.disabled()) {\n this.setDisabled(true);\n }\n }.bind(this));\n\n return this;\n },\n\n /** @inheritdoc */\n initConfig: function (config) {\n var pattern = config.suffixRegExpPattern || this.constructor.defaults.suffixRegExpPattern;\n\n pattern = pattern.replace(/\\$/g, '\\\\$&');\n config.content = config.content.replace(new RegExp(pattern, 'g'), this.getUniqueSuffix(config));\n this._super();\n\n return this;\n },\n\n /**\n * Build unique id based on name, underscore separated.\n *\n * @param {Object} config\n */\n getUniqueSuffix: function (config) {\n return config.name.replace(/(\\.|-)/g, '_');\n },\n\n /**\n * @inheritdoc\n */\n destroy: function () {\n this._super();\n wysiwyg.removeEvents(this.wysiwygId);\n },\n\n /**\n *\n * @returns {exports}\n */\n initObservable: function () {\n this._super()\n .observe(['value', 'content']);\n\n return this;\n },\n\n /**\n *\n * @returns {} Chainable.\n */\n initNodeListener: function () {\n $.async({\n component: this,\n selector: this.elementSelector\n }, this.setElementNode.bind(this));\n\n return this;\n },\n\n /**\n *\n * @param {HTMLElement} node\n */\n setElementNode: function (node) {\n $(node).bindings({\n value: this.value\n });\n },\n\n /**\n * Set disabled property to wysiwyg component\n *\n * @param {Boolean} disabled\n */\n setDisabled: function (disabled) {\n if (this.$wysiwygEditorButton && disabled) {\n this.$wysiwygEditorButton.prop('disabled', 'disabled');\n } else if (this.$wysiwygEditorButton) {\n this.$wysiwygEditorButton.prop('disabled', false);\n }\n\n /* eslint-disable no-undef */\n if (!_.isUndefined(this.currentWysiwyg) && this.currentWysiwyg.activeEditor()) {\n this.currentWysiwyg.setEnabledStatus(!disabled);\n this.currentWysiwyg.getPluginButtons().prop('disabled', disabled);\n }\n },\n\n /**\n * Content getter\n *\n * @returns {String}\n */\n getContentUnsanitizedHtml: function () {\n return this.content();\n }\n });\n});\n","Magento_Ui/js/form/element/single-checkbox-use-config.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'Magento_Ui/js/form/element/single-checkbox'\n], function (Component) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n isUseDefault: false,\n isUseConfig: false,\n listens: {\n 'isUseConfig': 'toggleElement',\n 'isUseDefault': 'toggleElement'\n }\n },\n\n /**\n * @inheritdoc\n */\n initObservable: function () {\n\n return this\n ._super()\n .observe('isUseConfig');\n },\n\n /**\n * Toggle element\n */\n toggleElement: function () {\n this.disabled(this.isUseDefault() || this.isUseConfig());\n\n if (this.source) {\n this.source.set('data.use_default.' + this.index, Number(this.isUseDefault()));\n }\n }\n });\n});\n","Magento_Ui/js/form/element/region.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'uiRegistry',\n './select',\n 'Magento_Checkout/js/model/default-post-code-resolver'\n], function (_, registry, Select, defaultPostCodeResolver) {\n 'use strict';\n\n return Select.extend({\n defaults: {\n skipValidation: false,\n imports: {\n countryOptions: '${ $.parentName }.country_id:indexedOptions',\n update: '${ $.parentName }.country_id:value'\n }\n },\n\n /**\n * {@inheritdoc}\n */\n initialize: function () {\n var option;\n\n this._super();\n\n option = _.find(this.countryOptions, function (row) {\n return row['is_default'] === true;\n });\n this.hideRegion(option);\n\n return this;\n },\n\n /**\n * Method called every time country selector's value gets changed.\n * Updates all validations and requirements for certain country.\n * @param {String} value - Selected country ID.\n */\n update: function (value) {\n var isRegionRequired,\n option;\n\n if (!value) {\n return;\n }\n\n option = _.isObject(this.countryOptions) && this.countryOptions[value];\n\n if (!option) {\n return;\n }\n\n this.hideRegion(option);\n\n defaultPostCodeResolver.setUseDefaultPostCode(!option['is_zipcode_optional']);\n\n isRegionRequired = !this.skipValidation && !!option['is_region_required'];\n\n if (!isRegionRequired) {\n this.error(false);\n }\n\n this.required(isRegionRequired);\n this.validation['required-entry'] = isRegionRequired;\n\n registry.get(this.customName, function (input) {\n input.required(isRegionRequired);\n input.validation['required-entry'] = isRegionRequired;\n input.validation['validate-not-number-first'] = !this.options().length;\n }.bind(this));\n },\n\n /**\n * Hide select and corresponding text input field if region must not be shown for selected country.\n *\n * @private\n * @param {Object}option\n */\n hideRegion: function (option) {\n if (!option || option['is_region_visible'] !== false) {\n return;\n }\n\n this.setVisible(false);\n\n if (this.customEntry) {\n this.toggleInput(false);\n }\n }\n });\n});\n","Magento_Ui/js/form/element/single-checkbox-toggle-notice.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'Magento_Ui/js/form/element/single-checkbox'\n], function (SingleCheckbox) {\n 'use strict';\n\n return SingleCheckbox.extend({\n defaults: {\n notices: [],\n tracks: {\n notice: true\n }\n },\n\n /**\n * Choose notice on initialization\n *\n * @returns {*|void|Element}\n */\n initialize: function () {\n this._super()\n .chooseNotice();\n\n return this;\n },\n\n /**\n * Choose notice function\n *\n * @returns void\n */\n chooseNotice: function () {\n var checkedNoticeNumber = Number(this.checked());\n\n this.notice = this.notices[checkedNoticeNumber];\n },\n\n /**\n * Choose notice on update\n *\n * @returns void\n */\n onUpdate: function () {\n this._super();\n this.chooseNotice();\n }\n });\n});\n","Magento_Ui/js/form/element/text.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'uiElement',\n 'mageUtils'\n], function (Element, utils) {\n 'use strict';\n\n return Element.extend({\n defaults: {\n visible: true,\n label: '',\n error: '',\n uid: utils.uniqueid(),\n disabled: false,\n links: {\n value: '${ $.provider }:${ $.dataScope }'\n }\n },\n\n /**\n * Has service\n *\n * @returns {Boolean} false.\n */\n hasService: function () {\n return false;\n },\n\n /**\n * Has addons\n *\n * @returns {Boolean} false.\n */\n hasAddons: function () {\n return false;\n },\n\n /**\n * Calls 'initObservable' of parent\n *\n * @returns {Object} Chainable.\n */\n initObservable: function () {\n this._super()\n .observe('disabled visible value');\n\n return this;\n }\n });\n});\n","Magento_Ui/js/form/element/date.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'moment',\n 'mageUtils',\n './abstract',\n 'moment-timezone-with-data'\n], function (moment, utils, Abstract) {\n 'use strict';\n\n return Abstract.extend({\n defaults: {\n options: {},\n\n storeTimeZone: 'UTC',\n\n validationParams: {\n dateFormat: '${ $.outputDateFormat }'\n },\n\n /**\n * Format of date that comes from the\n * server (ICU Date Format).\n *\n * Used only in date picker mode\n * (this.options.showsTime == false).\n *\n * @type {String}\n */\n inputDateFormat: 'y-MM-dd',\n\n /**\n * Format of date that should be sent to the\n * server (ICU Date Format).\n *\n * Used only in date picker mode\n * (this.options.showsTime == false).\n *\n * @type {String}\n */\n outputDateFormat: 'MM/dd/y',\n\n /**\n * Date/time format that is used to display date in\n * the input field.\n *\n * @type {String}\n */\n pickerDateTimeFormat: '',\n\n pickerDefaultDateFormat: 'MM/dd/y', // ICU Date Format\n pickerDefaultTimeFormat: 'h:mm a', // ICU Time Format\n\n elementTmpl: 'ui/form/element/date',\n\n /**\n * Format needed by moment timezone for conversion\n */\n timezoneFormat: 'YYYY-MM-DD HH:mm',\n\n listens: {\n 'value': 'onValueChange',\n 'shiftedValue': 'onShiftedValueChange'\n },\n\n /**\n * Date/time value shifted to corresponding timezone\n * according to this.storeTimeZone property. This value\n * will be sent to the server.\n *\n * @type {String}\n */\n shiftedValue: ''\n },\n\n /**\n * Initializes regular properties of instance.\n *\n * @returns {Object} Chainable.\n */\n initConfig: function () {\n this._super();\n\n if (!this.options.dateFormat) {\n this.options.dateFormat = this.pickerDefaultDateFormat;\n }\n\n if (!this.options.timeFormat) {\n this.options.timeFormat = this.pickerDefaultTimeFormat;\n }\n\n this.prepareDateTimeFormats();\n\n return this;\n },\n\n /**\n * @inheritdoc\n */\n initObservable: function () {\n return this._super().observe(['shiftedValue']);\n },\n\n /**\n * @inheritdoc\n */\n getPreview: function () {\n return this.shiftedValue();\n },\n\n /**\n * Prepares and sets date/time value that will be displayed\n * in the input field.\n *\n * @param {String} value\n */\n onValueChange: function (value) {\n var shiftedValue;\n\n if (value) {\n if (this.options.showsTime && !this.options.timeOnly) {\n shiftedValue = moment.tz(value, 'UTC').tz(this.storeTimeZone);\n } else {\n shiftedValue = moment(value, this.outputDateFormat, true);\n }\n\n if (!shiftedValue.isValid()) {\n shiftedValue = moment(value, this.inputDateFormat);\n }\n shiftedValue = shiftedValue.format(this.pickerDateTimeFormat);\n } else {\n shiftedValue = '';\n }\n\n if (shiftedValue !== this.shiftedValue()) {\n this.shiftedValue(shiftedValue);\n }\n },\n\n /**\n * Prepares and sets date/time value that will be sent\n * to the server.\n *\n * @param {String} shiftedValue\n */\n onShiftedValueChange: function (shiftedValue) {\n var value,\n formattedValue,\n momentValue;\n\n if (shiftedValue) {\n momentValue = moment(shiftedValue, this.pickerDateTimeFormat);\n\n if (this.options.showsTime && !this.options.timeOnly) {\n formattedValue = moment(momentValue).format(this.timezoneFormat);\n value = moment.tz(formattedValue, this.storeTimeZone).tz('UTC').toISOString();\n } else {\n value = momentValue.format(this.outputDateFormat);\n }\n } else {\n value = '';\n }\n\n if (value !== this.value()) {\n this.value(value);\n }\n },\n\n /**\n * Prepares and converts all date/time formats to be compatible\n * with moment.js library.\n */\n prepareDateTimeFormats: function () {\n if (this.options.timeOnly) {\n this.pickerDateTimeFormat = this.options.timeFormat;\n } else {\n this.pickerDateTimeFormat = this.options.dateFormat;\n\n if (this.options.showsTime) {\n this.pickerDateTimeFormat += ' ' + this.options.timeFormat;\n }\n }\n\n this.pickerDateTimeFormat = utils.convertToMomentFormat(this.pickerDateTimeFormat);\n\n if (this.options.dateFormat) {\n this.outputDateFormat = this.options.dateFormat;\n }\n\n this.inputDateFormat = this.options.timeOnly ?\n utils.convertToMomentFormat(this.pickerDefaultTimeFormat) :\n utils.convertToMomentFormat(this.inputDateFormat);\n this.outputDateFormat = this.options.timeOnly ?\n utils.convertToMomentFormat(this.options.timeFormat) :\n utils.convertToMomentFormat(this.outputDateFormat);\n\n this.validationParams.dateFormat = this.outputDateFormat;\n }\n });\n});\n","Magento_Ui/js/form/element/color-picker.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'mage/translate',\n 'Magento_Ui/js/form/element/abstract',\n 'Magento_Ui/js/form/element/color-picker-palette'\n], function ($t, Abstract, palette) {\n 'use strict';\n\n return Abstract.extend({\n\n defaults: {\n colorPickerConfig: {\n chooseText: $t('Apply'),\n cancelText: $t('Cancel'),\n maxSelectionSize: 8,\n clickoutFiresChange: true,\n allowEmpty: true,\n localStorageKey: 'magento.spectrum',\n palette: palette\n }\n },\n\n /**\n * Invokes initialize method of parent class,\n * contains initialization logic\n */\n initialize: function () {\n this._super();\n\n this.colorPickerConfig.value = this.value;\n\n return this;\n }\n });\n});\n","Magento_Ui/js/form/element/image-uploader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global Base64 */\ndefine([\n 'jquery',\n 'underscore',\n 'mageUtils',\n 'Magento_Ui/js/modal/alert',\n 'Magento_Ui/js/lib/validation/validator',\n 'Magento_Ui/js/form/element/file-uploader',\n 'mage/adminhtml/browser'\n], function ($, _, utils, uiAlert, validator, Element, browser) {\n 'use strict';\n\n return Element.extend({\n /**\n * {@inheritDoc}\n */\n initialize: function () {\n this._super();\n\n // Listen for file deletions from the media browser\n $(window).on('fileDeleted.mediabrowser', this.onDeleteFile.bind(this));\n },\n\n /**\n * Assign uid for media gallery\n *\n * @return {ImageUploader} Chainable.\n */\n initConfig: function () {\n var mediaGalleryUid = utils.uniqueid();\n\n this._super();\n\n _.extend(this, {\n mediaGalleryUid: mediaGalleryUid\n });\n\n return this;\n },\n\n /**\n * Add file event callback triggered from media gallery\n *\n * @param {ImageUploader} imageUploader - UI Class\n * @param {Event} e\n */\n addFileFromMediaGallery: function (imageUploader, e) {\n var $buttonEl = $(e.target),\n fileSize = $buttonEl.data('size'),\n fileMimeType = $buttonEl.data('mime-type'),\n filePathname = $buttonEl.val(),\n fileBasename = filePathname.split('/').pop();\n\n this.addFile({\n type: fileMimeType,\n name: fileBasename,\n size: fileSize,\n url: filePathname\n });\n },\n\n /**\n * Open the media browser dialog\n *\n * @param {ImageUploader} imageUploader - UI Class\n * @param {Event} e\n */\n openMediaBrowserDialog: function (imageUploader, e) {\n var $buttonEl = $(e.target),\n openDialogUrl = this.mediaGallery.openDialogUrl +\n 'target_element_id/' + $buttonEl.attr('id') +\n '/store/' + this.mediaGallery.storeId +\n '/type/image/?isAjax=true';\n\n if (this.mediaGallery.initialOpenSubpath) {\n openDialogUrl += '¤t_tree_path=' + Base64.idEncode(this.mediaGallery.initialOpenSubpath);\n }\n\n browser.openDialog(\n openDialogUrl,\n null,\n null,\n this.mediaGallery.openDialogTitle,\n {\n targetElementId: $buttonEl.attr('id')\n }\n );\n },\n\n /**\n * @param {jQuery.event} e\n * @param {Object} data\n * @returns {Object} Chainables\n */\n onDeleteFile: function (e, data) {\n var fileId = this.getFileId(),\n deletedFileIds = data.ids;\n\n if (fileId && $.inArray(fileId, deletedFileIds) > -1) {\n this.clear();\n }\n\n return this;\n },\n\n /**\n * {@inheritDoc}\n */\n clear: function () {\n this.value([]);\n\n return this;\n },\n\n /**\n * Gets the ID of the file used if set\n *\n * @return {String|Null} ID\n */\n getFileId: function () {\n return this.hasData() ? this.value()[0].id : null;\n },\n\n /**\n * Trigger native browser file upload UI via clicking on 'Upload' button\n *\n * @param {ImageUploader} imageUploader - UI Class\n * @param {Event} e\n */\n triggerImageUpload: function (imageUploader, e) {\n $(e.target).closest('.file-uploader').find('input[type=\"file\"]').trigger('click');\n },\n\n /**\n * Get list of file extensions allowed in comma delimited format\n *\n * @return {String}\n */\n getAllowedFileExtensionsInCommaDelimitedFormat: function () {\n var allowedExtensions = this.allowedExtensions.toUpperCase().split(' ');\n\n // if jpg and jpeg in allowed extensions, remove jpeg from list\n if (allowedExtensions.indexOf('JPG') !== -1 && allowedExtensions.indexOf('JPEG') !== -1) {\n allowedExtensions.splice(allowedExtensions.indexOf('JPEG'), 1);\n }\n\n return allowedExtensions.join(', ');\n }\n });\n});\n","Magento_Ui/js/form/element/textarea.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n './abstract'\n], function (Abstract) {\n 'use strict';\n\n return Abstract.extend({\n defaults: {\n cols: 15,\n rows: 2,\n elementTmpl: 'ui/form/element/textarea'\n }\n });\n});\n","Magento_Ui/js/form/element/post-code.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n './abstract'\n], function (_, Abstract) {\n 'use strict';\n\n return Abstract.extend({\n defaults: {\n imports: {\n countryOptions: '${ $.parentName }.country_id:indexedOptions',\n update: '${ $.parentName }.country_id:value'\n }\n },\n\n /**\n * Initializes observable properties of instance\n *\n * @returns {Abstract} Chainable.\n */\n initObservable: function () {\n this._super();\n\n /**\n * equalityComparer function\n *\n * @returns boolean.\n */\n this.value.equalityComparer = function (oldValue, newValue) {\n return !oldValue && !newValue || oldValue === newValue;\n };\n\n return this;\n },\n\n /**\n * Method called every time country selector's value gets changed.\n * Updates all validations and requirements for certain country.\n * @param {String} value - Selected country ID.\n */\n update: function (value) {\n var isZipCodeOptional,\n option;\n\n if (!value) {\n return;\n }\n\n option = _.isObject(this.countryOptions) && this.countryOptions[value];\n\n if (!option) {\n return;\n }\n\n isZipCodeOptional = !!option['is_zipcode_optional'];\n\n if (isZipCodeOptional) {\n this.error(false);\n }\n\n this.validation['required-entry'] = !isZipCodeOptional;\n this.required(!isZipCodeOptional);\n }\n });\n});\n","Magento_Ui/js/form/element/checkbox-set.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'mageUtils',\n './abstract'\n], function (_, utils, Abstract) {\n 'use strict';\n\n return Abstract.extend({\n defaults: {\n template: 'ui/form/element/checkbox-set',\n multiple: false,\n multipleScopeValue: null\n },\n\n /**\n * @inheritdoc\n */\n initConfig: function () {\n this._super();\n\n this.value = this.normalizeData(this.value);\n\n return this;\n },\n\n /**\n * @inheritdoc\n */\n initLinks: function () {\n var scope = this.source.get(this.dataScope);\n\n this.multipleScopeValue = this.multiple && _.isArray(scope) ? utils.copy(scope) : undefined;\n\n return this._super();\n },\n\n /**\n * @inheritdoc\n */\n reset: function () {\n this.value(utils.copy(this.initialValue));\n this.error(false);\n\n return this;\n },\n\n /**\n * @inheritdoc\n */\n clear: function () {\n var value = this.multiple ? [] : '';\n\n this.value(value);\n this.error(false);\n\n return this;\n },\n\n /**\n * @inheritdoc\n */\n normalizeData: function (value) {\n if (!this.multiple) {\n return this._super();\n }\n\n return _.isArray(value) ? utils.copy(value) : [];\n },\n\n /**\n * @inheritdoc\n */\n setInitialValue: function () {\n this._super();\n\n this.initialValue = utils.copy(this.initialValue);\n\n return this;\n },\n\n /**\n * @inheritdoc\n */\n getInitialValue: function () {\n var values = [this.multipleScopeValue, this.default, this.value.peek(), []],\n value;\n\n if (!this.multiple) {\n return this._super();\n }\n\n values.some(function (v) {\n return _.isArray(v) && (value = utils.copy(v));\n });\n\n return value;\n },\n\n /**\n * Returns labels which matches current value.\n *\n * @returns {String|Array}\n */\n getPreview: function () {\n var option;\n\n if (!this.multiple) {\n option = this.getOption(this.value());\n\n return option ? option.label : '';\n }\n\n return this.value.map(function (value) {\n return this.getOption(value).label;\n }, this);\n },\n\n /**\n * Returns option object associated with provided value.\n *\n * @param {String} value\n * @returns {Object}\n */\n getOption: function (value) {\n return _.findWhere(this.options, {\n value: value\n });\n },\n\n /**\n * @inheritdoc\n */\n hasChanged: function () {\n var value = this.value(),\n initial = this.initialValue;\n\n return this.multiple ?\n !utils.equalArrays(value, initial) :\n this._super();\n }\n });\n});\n","Magento_Ui/js/form/element/country.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'uiRegistry',\n './select'\n], function (_, registry, Select) {\n 'use strict';\n\n return Select.extend({\n defaults: {\n imports: {\n update: '${ $.parentName }.website_id:value'\n }\n },\n\n /**\n * Filters 'initialOptions' property by 'field' and 'value' passed,\n * calls 'setOptions' passing the result to it\n *\n * @param {*} value\n * @param {String} field\n */\n filter: function (value, field) {\n var result, defaultCountry, defaultValue;\n\n if (!field) { //validate field, if we are on update\n field = this.filterBy.field;\n }\n\n this._super(value, field);\n result = _.filter(this.initialOptions, function (item) {\n\n if (item[field]) {\n return ~item[field].indexOf(value);\n }\n\n return false;\n });\n\n this.setOptions(result);\n this.reset();\n\n if (!this.value()) {\n defaultCountry = _.filter(result, function (item) {\n return item['is_default'] && _.contains(item['is_default'], value);\n });\n\n if (defaultCountry.length) {\n defaultValue = defaultCountry.shift();\n this.value(defaultValue.value);\n }\n }\n }\n });\n});\n\n","Magento_Ui/js/form/element/color-picker-palette.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([], function () {\n 'use strict';\n\n return [\n [\n 'rgb(0,0,0)', 'rgb(52,52,52)', 'rgb(83,83,83)', 'rgb(135,135,135)', 'rgb(193,193,193)',\n 'rgb(234,234,234)', 'rgb(240,240,240)', 'rgb(255,255,255)'\n ],\n [\n 'rgb(252,0,9)', 'rgb(253,135,10)', 'rgb(255,255,13)', 'rgb(35,255,9)', 'rgb(33,255,255)',\n 'rgb(0,0,254)', 'rgb(132,0,254)', 'rgb(251,0,255)'\n ],\n [\n 'rgb(240,192,194)', 'rgb(251,223,194)', 'rgb(255,241,193)', 'rgb(210,230,201)',\n 'rgb(199,217,220)', 'rgb(197,219,240)', 'rgb(208,200,227)', 'rgb(229,199,212)'\n ],\n [\n 'rgb(228,133,135)', 'rgb(246,193,139)', 'rgb(254,225,136)', 'rgb(168,208,152)',\n 'rgb(146,184,190)', 'rgb(143,184,227)', 'rgb(165,148,204)', 'rgb(202,147,175)'\n ],\n [\n 'rgb(214,78,83)', 'rgb(243,163,88)', 'rgb(254,211,83)', 'rgb(130,187,106)',\n 'rgb(99,149,159)', 'rgb(93,150,211)', 'rgb(123,100,182)', 'rgb(180,100,142)'\n ],\n [\n 'rgb(190,0,5)', 'rgb(222,126,44)', 'rgb(236,183,39)', 'rgb(89,155,61)', 'rgb(55,110,123)',\n 'rgb(49,112,185)', 'rgb(83,55,150)', 'rgb(147,55,101)'\n ],\n [\n 'rgb(133,0,3)', 'rgb(163,74,10)', 'rgb(177,127,7)', 'rgb(45,101,23)', 'rgb(18,62,74)',\n 'rgb(14,62,129)', 'rgb(40,15,97)', 'rgb(95,16,55)'\n ],\n [\n 'rgb(81,0,1)', 'rgb(100,48,7)', 'rgb(107,78,3)', 'rgb(31,63,16)',\n 'rgb(13,39,46)', 'rgb(10,40,79)', 'rgb(24,12,59)', 'rgb(59,10,36)'\n ]\n ];\n});\n","Magento_Ui/js/view/messages.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'ko',\n 'jquery',\n 'uiComponent',\n '../model/messageList',\n 'jquery-ui-modules/effect-blind'\n], function (ko, $, Component, globalMessages) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Magento_Ui/messages',\n selector: '[data-role=checkout-messages]',\n isHidden: false,\n hideTimeout: 5000,\n hideSpeed: 500,\n listens: {\n isHidden: 'onHiddenChange'\n }\n },\n\n /** @inheritdoc */\n initialize: function (config, messageContainer) {\n this._super()\n .initObservable();\n\n this.messageContainer = messageContainer || config.messageContainer || globalMessages;\n\n return this;\n },\n\n /** @inheritdoc */\n initObservable: function () {\n this._super()\n .observe('isHidden');\n\n return this;\n },\n\n /**\n * Checks visibility.\n *\n * @return {Boolean}\n */\n isVisible: function () {\n return this.isHidden(this.messageContainer.hasMessages());\n },\n\n /**\n * Remove all messages.\n */\n removeAll: function () {\n this.messageContainer.clear();\n },\n\n /**\n * @param {Boolean} isHidden\n */\n onHiddenChange: function (isHidden) {\n // Hide message block if needed\n if (isHidden) {\n setTimeout(function () {\n $(this.selector).hide('slow');\n\n //commented because effect-blind.js(1.13.1) is having show & hide issue\n // $(this.selector).hide('blind', {}, this.hideSpeed);\n }.bind(this), this.hideTimeout);\n }\n }\n });\n});\n","Magento_Ui/js/core/app.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n './renderer/types',\n './renderer/layout',\n '../lib/knockout/bootstrap'\n], function (types, layout) {\n 'use strict';\n\n return function (data, merge) {\n types.set(data.types);\n layout(data.components, undefined, true, merge);\n };\n});\n","Magento_Ui/js/core/renderer/types.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'mageUtils'\n], function (_, utils) {\n 'use strict';\n\n var store = {};\n\n /**\n * Flatten a nested data.\n *\n * @param {Object} data\n * @returns {Object}\n */\n function flatten(data) {\n var extender = data.extends || [],\n result = {};\n\n extender = utils.stringToArray(extender);\n\n extender.push(data);\n\n extender.forEach(function (item) {\n if (_.isString(item)) {\n item = store[item] || {};\n }\n\n utils.extend(result, item);\n });\n\n delete result.extends;\n\n return result;\n }\n\n return {\n /**\n * Set types to store object.\n *\n * @param {Object} types\n */\n set: function (types) {\n types = types || {};\n\n utils.extend(store, types);\n\n _.each(types, function (data, type) {\n store[type] = flatten(data);\n });\n },\n\n /**\n * Get type from store object.\n *\n * @param {String} type\n * @returns {*|{}}\n */\n get: function (type) {\n return store[type] || {};\n }\n };\n});\n","Magento_Ui/js/core/renderer/layout.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'jquery',\n 'mageUtils',\n 'uiRegistry',\n './types',\n '../../lib/logger/console-logger'\n], function (_, $, utils, registry, types, consoleLogger) {\n 'use strict';\n\n var templates = registry.create(),\n layout = {},\n cachedConfig = {};\n\n /**\n * Build name from parent name and node name\n *\n * @param {Object} parent\n * @param {Object} node\n * @param {String} [name]\n * @returns {String}\n */\n function getNodeName(parent, node, name) {\n var parentName = parent && parent.name;\n\n if (typeof name !== 'string') {\n name = node.name || name;\n }\n\n return utils.fullPath(parentName, name);\n }\n\n /**\n * Get node type from node or parent.\n *\n * @param {Object} parent\n * @param {Object} node\n * @returns {String}\n */\n function getNodeType(parent, node) {\n return node.type || parent && parent.childType;\n }\n\n /**\n * Get data scope based on parent data scope and node data scope.\n *\n * @param {Object} parent\n * @param {Object} node\n * @returns {String}\n */\n function getDataScope(parent, node) {\n var dataScope = node.dataScope,\n parentScope = parent && parent.dataScope;\n\n return !utils.isEmpty(parentScope) ?\n !utils.isEmpty(dataScope) ?\n parentScope + '.' + dataScope :\n parentScope :\n dataScope || '';\n }\n\n /**\n * Load node dependencies on other instances.\n *\n * @param {Object} node\n * @returns {jQueryPromise}\n */\n function loadDeps(node) {\n var loaded = $.Deferred(),\n loggerUtils = consoleLogger.utils;\n\n if (node.deps) {\n consoleLogger.utils.asyncLog(\n loaded,\n {\n data: {\n component: node.name,\n deps: node.deps\n },\n messages: loggerUtils.createMessages(\n 'depsStartRequesting',\n 'depsFinishRequesting',\n 'depsLoadingFail'\n )\n }\n );\n }\n\n registry.get(node.deps, function (deps) {\n node.provider = node.extendProvider ? deps && deps.name : node.provider;\n loaded.resolve(node);\n });\n\n return loaded.promise();\n }\n\n /**\n * Load node component file via requirejs.\n *\n * @param {Object} node\n * @returns {jQueryPromise}\n */\n function loadSource(node) {\n var loaded = $.Deferred(),\n source = node.component;\n\n consoleLogger.info('componentStartLoading', {\n component: node.component\n });\n\n require([source], function (constr) {\n consoleLogger.info('componentFinishLoading', {\n component: node.component\n });\n loaded.resolve(node, constr);\n }, function () {\n consoleLogger.error('componentLoadingFail', {\n component: node.component\n });\n });\n\n return loaded.promise();\n }\n\n /**\n * Create a new component instance and set it to the registry.\n *\n * @param {Object} node\n * @param {Function} Constr\n */\n function initComponent(node, Constr) {\n var component = new Constr(_.omit(node, 'children'));\n\n consoleLogger.info('componentStartInitialization', {\n component: node.component,\n componentName: node.name\n });\n\n registry.set(node.name, component);\n }\n\n /**\n * Application entry point.\n *\n * @param {Object} nodes\n * @param {Object} parent\n * @param {Boolean} cached\n * @param {Boolean} merge\n * @returns {Boolean|undefined}\n */\n function run(nodes, parent, cached, merge) {\n if (_.isBoolean(merge) && merge) {\n layout.merge(nodes);\n\n return false;\n }\n\n if (cached) {\n cachedConfig[_.keys(nodes)[0]] = JSON.parse(JSON.stringify(nodes));\n }\n\n _.each(nodes || [], layout.iterator.bind(layout, parent));\n }\n\n _.extend(layout, {\n /**\n * Determines if node ready to be added or process it.\n *\n * @param {Object} parent\n * @param {Object|String} node\n */\n iterator: function (parent, node) {\n var action = _.isString(node) ?\n this.addChild :\n this.process;\n\n action.apply(this, arguments);\n },\n\n /**\n * Prepare component.\n *\n * @param {Object} parent\n * @param {Object} node\n * @param {String} name\n * @returns {Object}\n */\n process: function (parent, node, name) {\n if (!parent && node.parent) {\n return this.waitParent(node, name);\n }\n\n if (node.nodeTemplate) {\n return this.waitTemplate.apply(this, arguments);\n }\n\n node = this.build.apply(this, arguments);\n\n if (!registry.has(node.name)) {\n this.addChild(parent, node)\n .manipulate(node)\n .initComponent(node);\n }\n\n if (node) {\n run(node.children, node);\n }\n\n return this;\n },\n\n /**\n * Detailed processing of component config.\n *\n * @param {Object} parent\n * @param {Object} node\n * @param {String} name\n * @returns {Boolean|Object}\n */\n build: function (parent, node, name) {\n var defaults = parent && parent.childDefaults || {},\n children = this.filterDisabledChildren(node.children),\n type = getNodeType(parent, node),\n dataScope = getDataScope(parent, node),\n component,\n extendDeps = true,\n nodeName;\n\n node.children = false;\n node.extendProvider = true;\n\n if (node.config && node.config.provider || node.provider) {\n node.extendProvider = false;\n }\n\n if (node.config && node.config.deps || node.deps) {\n extendDeps = false;\n }\n\n node = utils.extend({\n }, types.get(type), defaults, node);\n\n nodeName = getNodeName(parent, node, name);\n\n if (registry.has(nodeName)) {\n component = registry.get(nodeName);\n component.children = children;\n\n return component;\n }\n\n if (extendDeps && parent && parent.deps && type) {\n node.deps = parent.deps;\n }\n\n _.extend(node, node.config || {}, {\n index: node.name || name,\n name: nodeName,\n dataScope: dataScope,\n parentName: utils.getPart(nodeName, -2),\n parentScope: utils.getPart(dataScope, -2)\n });\n\n node.children = children;\n node.componentType = node.type;\n\n delete node.type;\n delete node.config;\n\n if (children) {\n node.initChildCount = _.size(children);\n }\n\n if (node.isTemplate) {\n node.isTemplate = false;\n\n templates.set(node.name, node);\n registry.get(node.parentName, function (parentComp) {\n parentComp.childTemplate = node;\n });\n\n return false;\n }\n\n if (node.componentDisabled === true) {\n return false;\n }\n\n return node;\n },\n\n /**\n * Filter out all disabled components.\n *\n * @param {Object} children\n * @returns {*}\n */\n filterDisabledChildren: function (children) {\n var cIds;\n\n //cleanup children config.componentDisabled = true\n if (children && typeof children === 'object') {\n cIds = Object.keys(children);\n\n if (cIds) {\n _.each(cIds, function (cId) {\n if (typeof children[cId] === 'object' &&\n children[cId].hasOwnProperty('config') &&\n typeof children[cId].config === 'object' &&\n children[cId].config.hasOwnProperty('componentDisabled') &&\n children[cId].config.componentDisabled === true) {\n delete children[cId];\n }\n });\n }\n }\n\n return children;\n },\n\n /**\n * Init component.\n *\n * @param {Object} node\n * @returns {Object}\n */\n initComponent: function (node) {\n if (!node.component) {\n return this;\n }\n\n loadDeps(node)\n .then(loadSource)\n .done(initComponent);\n\n return this;\n }\n });\n\n _.extend(layout, {\n /**\n * Loading component marked as isTemplate.\n *\n * @param {Object} parent\n * @param {Object} node\n * @returns {Object}\n */\n waitTemplate: function (parent, node) {\n var args = _.toArray(arguments);\n\n templates.get(node.nodeTemplate, function () {\n this.applyTemplate.apply(this, args);\n }.bind(this));\n\n return this;\n },\n\n /**\n * Waiting for parent component and process provided component.\n *\n * @param {Object} node\n * @param {String} name\n * @returns {Object}\n */\n waitParent: function (node, name) {\n var process = this.process.bind(this);\n\n registry.get(node.parent, function (parent) {\n process(parent, node, name);\n });\n\n return this;\n },\n\n /**\n * Processing component marked as isTemplate.\n *\n * @param {Object} parent\n * @param {Object} node\n * @param {String} name\n */\n applyTemplate: function (parent, node, name) {\n var template = templates.get(node.nodeTemplate);\n\n node = utils.extend({}, template, node);\n\n delete node.nodeTemplate;\n\n this.process(parent, node, name);\n }\n });\n\n _.extend(layout, {\n /**\n * Determines inserting strategy.\n *\n * @param {Object} node\n * @returns {Object}\n */\n manipulate: function (node) {\n var name = node.name;\n\n if (node.appendTo) {\n this.insert(name, node.appendTo, -1);\n }\n\n if (node.prependTo) {\n this.insert(name, node.prependTo, 0);\n }\n\n if (node.insertTo) {\n this.insertTo(name, node.insertTo);\n }\n\n return this;\n },\n\n /**\n * Insert component to provide target and position.\n *\n * @param {Object|String} item\n * @param {Object} target\n * @param {Number} position\n * @returns {Object}\n */\n insert: function (item, target, position) {\n registry.get(target, function (container) {\n container.insertChild(item, position);\n });\n\n return this;\n },\n\n /**\n * Insert component into multiple targets.\n *\n * @param {Object} item\n * @param {Array} targets\n * @returns {Object}\n */\n insertTo: function (item, targets) {\n _.each(targets, function (info, target) {\n this.insert(item, target, info.position);\n }, this);\n\n return this;\n },\n\n /**\n * Add provided child to parent.\n *\n * @param {Object} parent\n * @param {Object|String} child\n * @returns {Object}\n */\n addChild: function (parent, child) {\n var name;\n\n if (parent && parent.component) {\n name = child.name || child;\n\n this.insert(name, parent.name, child.sortOrder);\n }\n\n return this;\n },\n\n /**\n * Merge components configuration with cached configuration.\n *\n * @param {Array} components\n */\n merge: function (components) {\n var cachedKey = _.keys(components)[0],\n compared = utils.compare(cachedConfig[cachedKey], components),\n remove = this.filterComponents(this.getByProperty(compared.changes, 'type', 'remove'), true),\n update = this.getByProperty(compared.changes, 'type', 'update'),\n dataSources = this.getDataSources(components),\n names, index, name, component;\n\n _.each(dataSources, function (val, key) {\n name = key.replace(/\\.children|\\.config/g, '');\n component = registry.get(name);\n\n component.cacheData();\n component.updateConfig(\n true,\n this.getFullConfig(key, components),\n this.getFullConfig(key, cachedConfig[cachedKey])\n );\n }, this);\n\n _.each(remove, function (val) {\n component = registry.get(val.path);\n\n if (component) {\n component.destroy();\n }\n });\n\n update = _.compact(_.filter(update, function (val) {\n return !_.isEqual(val.oldValue, val.value);\n }));\n\n _.each(update, function (val) {\n names = val.path.split('.');\n index = Math.max(_.lastIndexOf(names, 'config'), _.lastIndexOf(names, 'children') + 2);\n name = _.without(names.splice(0, index), 'children', 'config').join('.');\n component = registry.get(name);\n\n if (val.name === 'sortOrder' && component) {\n registry.get(component.parentName).insertChild(component, val.value);\n } else if (component) {\n component.updateConfig(\n val.oldValue,\n val.value,\n val.path\n );\n }\n }, this);\n\n run(components, undefined, true);\n },\n\n /**\n * Recursive dataSource assignment.\n *\n * @param {Object} config\n * @param {String} parentPath\n * @returns {Object}\n */\n getDataSources: function (config, parentPath) {\n var dataSources = {},\n key, obj;\n\n /* eslint-disable no-loop-func, max-depth */\n for (key in config) {\n if (config.hasOwnProperty(key)) {\n if (\n key === 'type' &&\n config[key] === 'dataSource' &&\n config.hasOwnProperty('config')\n ) {\n dataSources[parentPath + '.config'] = config.config;\n } else if (_.isObject(config[key])) {\n obj = this.getDataSources(config[key], utils.fullPath(parentPath, key));\n\n _.each(obj, function (value, path) {\n dataSources[path] = value;\n });\n }\n }\n }\n\n /* eslint-enable no-loop-func, max-depth */\n\n return dataSources;\n },\n\n /**\n * Configuration getter.\n *\n * @param {String} path\n * @param {Object} config\n * @returns {Boolean|Object}\n */\n getFullConfig: function (path, config) {\n var index;\n\n path = path.split('.');\n index = _.lastIndexOf(path, 'config');\n\n if (!~index) {\n return false;\n }\n path = path.splice(0, index);\n\n _.each(path, function (val) {\n config = config[val];\n });\n\n return config.config;\n },\n\n /**\n * Filter data by property and value.\n *\n * @param {Object} data\n * @param {String} prop\n * @param {*} propValue\n */\n getByProperty: function (data, prop, propValue) {\n return _.filter(data, function (value) {\n return value[prop] === propValue;\n });\n },\n\n /**\n * Filter components.\n *\n * @param {Array} data\n * @param {Boolean} splitPath\n * @param {Number} index\n * @param {String} separator\n * @param {String} keyName\n * @returns {Array}\n */\n filterComponents: function (data, splitPath, index, separator, keyName) {\n var result = [],\n names, length;\n\n index = -2;\n separator = '.' || separator;\n keyName = 'children' || keyName;\n\n _.each(data, function (val) {\n names = val.path.split(separator);\n length = names.length;\n\n if (names[length + index] === keyName) {\n val.path = splitPath ? _.without(names, keyName).join(separator) : val.path;\n result.push(val);\n }\n });\n\n return result;\n }\n });\n\n return run;\n});\n","Magento_Ui/js/model/messageList.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n './messages'\n], function (Messages) {\n 'use strict';\n\n return new Messages();\n});\n","Magento_Ui/js/model/messages.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'ko',\n 'uiClass'\n], function (ko, Class) {\n 'use strict';\n\n return Class.extend({\n /** @inheritdoc */\n initialize: function () {\n this._super()\n .initObservable();\n\n return this;\n },\n\n /** @inheritdoc */\n initObservable: function () {\n this.errorMessages = ko.observableArray([]);\n this.successMessages = ko.observableArray([]);\n\n return this;\n },\n\n /**\n * Add message to list.\n * @param {Object} messageObj\n * @param {Object} type\n * @returns {Boolean}\n */\n add: function (messageObj, type) {\n var expr = /([%])\\w+/g,\n message;\n\n if (!messageObj.hasOwnProperty('parameters')) {\n this.clear();\n type.push(messageObj.message);\n\n return true;\n }\n message = messageObj.message.replace(expr, function (varName) {\n varName = varName.substr(1);\n\n if (!isNaN(varName)) {\n varName--;\n }\n\n if (messageObj.parameters.hasOwnProperty(varName)) {\n return messageObj.parameters[varName];\n }\n\n return messageObj.parameters.shift();\n });\n this.clear();\n type.push(message);\n\n return true;\n },\n\n /**\n * Add success message.\n *\n * @param {Object} message\n * @return {*|Boolean}\n */\n addSuccessMessage: function (message) {\n return this.add(message, this.successMessages);\n },\n\n /**\n * Add error message.\n *\n * @param {Object} message\n * @return {*|Boolean}\n */\n addErrorMessage: function (message) {\n return this.add(message, this.errorMessages);\n },\n\n /**\n * Get error messages.\n *\n * @return {Array}\n */\n getErrorMessages: function () {\n return this.errorMessages;\n },\n\n /**\n * Get success messages.\n *\n * @return {Array}\n */\n getSuccessMessages: function () {\n return this.successMessages;\n },\n\n /**\n * Checks if an instance has stored messages.\n *\n * @return {Boolean}\n */\n hasMessages: function () {\n return this.errorMessages().length > 0 || this.successMessages().length > 0;\n },\n\n /**\n * Removes stored messages.\n */\n clear: function () {\n this.errorMessages.removeAll();\n this.successMessages.removeAll();\n }\n });\n});\n","Magento_Ui/js/lib/key-codes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([], function () {\n 'use strict';\n\n return {\n 13: 'enterKey',\n 27: 'escapeKey',\n 40: 'pageDownKey',\n 38: 'pageUpKey',\n 32: 'spaceKey',\n 9: 'tabKey',\n 37: 'pageLeftKey',\n 39: 'pageRightKey',\n 17: 'ctrlKey',\n 18: 'altKey',\n 16: 'shiftKey',\n 191: 'forwardSlashKey',\n 66: 'bKey',\n 73: 'iKey',\n 85: 'uKey'\n };\n});\n","Magento_Ui/js/lib/spinner.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery'\n], function ($) {\n 'use strict';\n\n var selector = '[data-role=\"spinner\"]',\n spinner = $(selector);\n\n return {\n /**\n * Show spinner.\n */\n show: function () {\n spinner.show();\n },\n\n /**\n * Hide spinner.\n */\n hide: function () {\n spinner.hide();\n },\n\n /**\n * Get spinner by selector.\n *\n * @param {String} id\n * @return {jQuery}\n */\n get: function (id) {\n return $(selector + '[data-component=\"' + id + '\"]');\n }\n };\n});\n","Magento_Ui/js/lib/collapsible.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'uiComponent'\n], function (Component) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n opened: false,\n collapsible: true\n },\n\n /**\n * Initializes observable properties.\n *\n * @returns {Collapsible} Chainable.\n */\n initObservable: function () {\n this._super()\n .observe('opened');\n\n return this;\n },\n\n /**\n * Toggles value of the 'opened' property.\n *\n * @returns {Collapsible} Chainable.\n */\n toggleOpened: function () {\n this.opened() ?\n this.close() :\n this.open();\n\n return this;\n },\n\n /**\n * Sets 'opened' flag to false.\n *\n * @returns {Collapsible} Chainable.\n */\n close: function () {\n if (this.collapsible) {\n this.opened(false);\n }\n\n return this;\n },\n\n /**\n * Sets 'opened' flag to true.\n *\n * @returns {Collapsible} Chainable.\n */\n open: function () {\n if (this.collapsible) {\n this.opened(true);\n }\n\n return this;\n }\n });\n});\n","Magento_Ui/js/lib/knockout/bootstrap.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/** Loads all available knockout bindings, sets custom template engine, initializes knockout on page */\n\ndefine([\n 'ko',\n './template/engine',\n 'knockoutjs/knockout-es5',\n './bindings/bootstrap',\n './extender/observable_array',\n './extender/bound-nodes',\n 'domReady!'\n], function (ko, templateEngine) {\n 'use strict';\n\n ko.uid = 0;\n\n ko.setTemplateEngine(templateEngine);\n ko.applyBindings();\n});\n","Magento_Ui/js/lib/knockout/extender/observable_array.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'underscore'\n], function (ko, _) {\n 'use strict';\n\n /**\n * Iterator function.\n *\n * @param {String} callback\n * @param {Array} args\n * @param {Object} elem\n * @returns {*}\n */\n function iterator(callback, args, elem) {\n callback = elem[callback];\n\n if (_.isFunction(callback)) {\n return callback.apply(elem, args);\n }\n\n return callback;\n }\n\n /**\n * Wrapper function.\n *\n * @param {String} method\n * @returns {Function}\n */\n function wrapper(method) {\n return function (iteratee) {\n var callback = iteratee,\n elems = this(),\n args = _.toArray(arguments);\n\n if (_.isString(iteratee)) {\n callback = iterator.bind(null, iteratee, args.slice(1));\n\n args.unshift(callback);\n }\n\n args.unshift(elems);\n\n return _[method].apply(_, args);\n };\n }\n\n _.extend(ko.observableArray.fn, {\n each: wrapper('each'),\n\n map: wrapper('map'),\n\n filter: wrapper('filter'),\n\n some: wrapper('some'),\n\n every: wrapper('every'),\n\n groupBy: wrapper('groupBy'),\n\n sortBy: wrapper('sortBy'),\n\n /**\n * Wrapper for underscore findWhere function.\n *\n * @param {Object} properties\n * @return {Object}\n */\n findWhere: function (properties) {\n return _.findWhere(this(), properties);\n },\n\n /**\n * Wrapper for underscore contains function.\n *\n * @param {*} value\n * @return {Boolean}\n */\n contains: function (value) {\n return _.contains(this(), value);\n },\n\n /**\n * Inverse contains call.\n *\n * @return {Boolean}\n */\n hasNo: function () {\n return !this.contains.apply(this, arguments);\n },\n\n /**\n * Getter for length property.\n *\n * @return {Number}\n */\n getLength: function () {\n return this().length;\n },\n\n /**\n * Create object with keys that gets from each object property.\n *\n * @return {Object}\n */\n indexBy: function (key) {\n return _.indexBy(this(), key);\n },\n\n /**\n * Returns a copy of the array with all instances of the values removed.\n *\n * @return {Array}\n */\n without: function () {\n var args = Array.prototype.slice.call(arguments);\n\n args.unshift(this());\n\n return _.without.apply(_, args);\n },\n\n /**\n * Returns the first element of an array.\n *\n * @return {*}\n */\n first: function () {\n return _.first(this());\n },\n\n /**\n * Returns the last element of an array\n *\n * @return {*}\n */\n last: function () {\n return _.last(this());\n },\n\n /**\n * Iterate and pick provided properties.\n *\n * @return {Array}\n */\n pluck: function () {\n var args = Array.prototype.slice.call(arguments);\n\n args.unshift(this());\n\n return _.pluck.apply(_, args);\n }\n });\n});\n","Magento_Ui/js/lib/knockout/extender/bound-nodes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'underscore',\n 'mage/utils/wrapper',\n 'uiEvents'\n], function (ko, _, wrapper, Events) {\n 'use strict';\n\n var nodesMap = new WeakMap();\n\n /**\n * Returns a array of nodes associated with a specified model.\n *\n * @param {Object} model\n * @returns {Undefined|Array}\n */\n function getBounded(model) {\n return nodesMap.get(model);\n }\n\n /**\n * Removes specified node to models' associations list, if it's\n * a root node (node is not a descendant of any previously added nodes).\n * Triggers 'addNode' event.\n *\n * @param {Object} model\n * @param {HTMLElement} node\n */\n function addBounded(model, node) {\n var nodes = getBounded(model),\n isRoot;\n\n if (!nodes) {\n nodesMap.set(model, [node]);\n\n Events.trigger.call(model, 'addNode', node);\n\n return;\n }\n\n isRoot = nodes.every(function (bounded) {\n return !bounded.contains(node);\n });\n\n if (isRoot) {\n nodes.push(node);\n\n Events.trigger.call(model, 'addNode', node);\n }\n }\n\n /**\n * Removes specified node from models' associations list.\n * Triggers 'removeNode' event.\n *\n * @param {Object} model\n * @param {HTMLElement} node\n */\n function removeBounded(model, node) {\n var nodes = getBounded(model),\n index;\n\n if (!nodes) {\n return;\n }\n\n index = nodes.indexOf(node);\n\n if (~index) {\n nodes.splice(index, 0);\n\n Events.trigger.call(model, 'removeNode', node);\n }\n\n if (!nodes.length) {\n nodesMap.delete(model);\n }\n }\n\n /**\n * Returns node's first sibling of 'element' type within the common component scope\n *\n * @param {HTMLElement} node\n * @param {*} data\n * @returns {HTMLElement}\n */\n function getElement(node, data) {\n var elem;\n\n while (node.nextElementSibling) {\n node = node.nextElementSibling;\n\n if (node.nodeType === 1 && ko.dataFor(node) === data) {\n elem = node;\n break;\n }\n }\n\n return elem;\n }\n\n wrapper.extend(ko, {\n\n /**\n * Extends knockouts' 'applyBindings'\n * to track nodes associated with model.\n *\n * @param {Function} orig - Original 'applyBindings' method.\n * @param {Object} ctx\n * @param {HTMLElement} node - Original 'applyBindings' method.\n */\n applyBindings: function (orig, ctx, node) {\n var result = orig(),\n data = ctx && (ctx.$data || ctx);\n\n if (node && node.nodeType === 8) {\n node = getElement(node, data);\n }\n\n if (!node || node.nodeType !== 1) {\n return result;\n }\n\n if (data && data.registerNodes) {\n addBounded(data, node);\n }\n\n return result;\n },\n\n /**\n * Extends knockouts' cleanNode\n * to track nodes associated with model.\n *\n * @param {Function} orig - Original 'cleanNode' method.\n * @param {HTMLElement} node - Original 'cleanNode' method.\n */\n cleanNode: function (orig, node) {\n var result = orig(),\n data;\n\n if (node.nodeType !== 1) {\n return result;\n }\n\n data = ko.dataFor(node);\n\n if (data && data.registerNodes) {\n removeBounded(data, node);\n }\n\n return result;\n }\n });\n\n return {\n\n /**\n * Returns root nodes associated with a model. If callback is provided,\n * will iterate through all of the present nodes triggering callback\n * for each of it. Also it will subscribe to the 'addNode' event.\n *\n * @param {Object} model\n * @param {Function} [callback]\n * @returns {Array|Undefined}\n */\n get: function (model, callback) {\n var nodes = getBounded(model) || [];\n\n if (!_.isFunction(callback)) {\n return nodes;\n }\n\n nodes.forEach(function (node) {\n callback(node);\n });\n\n this.add.apply(this, arguments);\n },\n\n /**\n * Subscribes to adding of nodes associated with a model.\n *\n * @param {Object} model\n */\n add: function (model) {\n var args = _.toArray(arguments).slice(1);\n\n args.unshift('addNode');\n\n Events.on.apply(model, args);\n },\n\n /**\n * Subscribes to removal of nodes associated with a model.\n *\n * @param {Object} model\n */\n remove: function (model) {\n var args = _.toArray(arguments).slice(1);\n\n args.unshift('removeNode');\n\n Events.on.apply(model, args);\n },\n\n /**\n * Removes subscriptions from the model.\n *\n * @param {Object} model\n */\n off: function (model) {\n var args = _.toArray(arguments).slice(1);\n\n Events.off.apply(model, args);\n }\n };\n});\n","Magento_Ui/js/lib/knockout/template/observable_source.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * Is being used by knockout template engine to store template to.\n */\ndefine([\n 'ko',\n 'uiClass'\n], function (ko, Class) {\n 'use strict';\n\n return Class.extend({\n\n /**\n * Initializes templateName, _data, nodes properties.\n *\n * @param {template} template - identifier of template\n */\n initialize: function (template) {\n this.templateName = template;\n this._data = {};\n this.nodes = ko.observable([]);\n },\n\n /**\n * Data setter. If only one arguments passed, returns corresponding value.\n * Else, writes into it.\n * @param {String} key - key to write to or to read from\n * @param {*} value\n * @return {*} - if 1 arg provided, Returns _data[key] property\n */\n data: function (key, value) {\n if (arguments.length === 1) {\n return this._data[key];\n }\n\n this._data[key] = value;\n }\n });\n});\n","Magento_Ui/js/lib/knockout/template/renderer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'underscore',\n './loader'\n], function ($, _, loader) {\n 'use strict';\n\n var colonReg = /\\\\:/g,\n renderedTemplatePromises = {},\n attributes = {},\n elements = {},\n globals = [],\n renderer,\n preset;\n\n renderer = {\n\n /**\n * Loads template by provided path and\n * than converts it's content to html.\n *\n * @param {String} tmplPath - Path to the template.\n * @returns {jQueryPromise}\n * @alias getRendered\n */\n render: function (tmplPath) {\n var cachedPromise = renderedTemplatePromises[tmplPath];\n\n if (!cachedPromise) {\n cachedPromise = renderedTemplatePromises[tmplPath] = loader\n .loadTemplate(tmplPath)\n .then(renderer.parseTemplate);\n }\n\n return cachedPromise;\n },\n\n /**\n * @ignore\n */\n getRendered: function (tmplPath) {\n return renderer.render(tmplPath);\n },\n\n /**\n * Parses provided string as html content\n * and returns an array of DOM elements.\n *\n * @param {String} html - String to be processed.\n * @returns {Array}\n */\n parseTemplate: function (html) {\n var fragment = document.createDocumentFragment();\n\n $(fragment).append(html);\n\n return renderer.normalize(fragment);\n },\n\n /**\n * Processes custom attributes and nodes of provided DOM element.\n *\n * @param {HTMLElement} content - Element to be processed.\n * @returns {Array} An array of content's child nodes.\n */\n normalize: function (content) {\n globals.forEach(function (handler) {\n handler(content);\n });\n\n return _.toArray(content.childNodes);\n },\n\n /**\n * Adds new global content handler.\n *\n * @param {Function} handler - Function which will be invoked for\n * an every content passed to 'normalize' method.\n * @returns {Renderer} Chainable.\n */\n addGlobal: function (handler) {\n if (!_.contains(globals, handler)) {\n globals.push(handler);\n }\n\n return this;\n },\n\n /**\n * Removes specified global content handler.\n *\n * @param {Function} handler - Handler to be removed.\n * @returns {Renderer} Chainable.\n */\n removeGlobal: function (handler) {\n var index = globals.indexOf(handler);\n\n if (~index) {\n globals.splice(index, 1);\n }\n\n return this;\n },\n\n /**\n * Adds new custom attribute handler.\n *\n * @param {String} id - Attribute identifier.\n * @param {(Object|Function)} [config={}]\n * @returns {Renderer} Chainable.\n */\n addAttribute: function (id, config) {\n var data = {\n name: id,\n binding: id,\n handler: renderer.handlers.attribute\n };\n\n if (_.isFunction(config)) {\n data.handler = config;\n } else if (_.isObject(config)) {\n _.extend(data, config);\n }\n\n data.id = id;\n attributes[id] = data;\n\n return this;\n },\n\n /**\n * Removes specified attribute handler.\n *\n * @param {String} id - Attribute identifier.\n * @returns {Renderer} Chainable.\n */\n removeAttribute: function (id) {\n delete attributes[id];\n\n return this;\n },\n\n /**\n * Adds new custom node handler.\n *\n * @param {String} id - Node identifier.\n * @param {(Object|Function)} [config={}]\n * @returns {Renderer} Chainable.\n */\n addNode: function (id, config) {\n var data = {\n name: id,\n binding: id,\n handler: renderer.handlers.node\n };\n\n if (_.isFunction(config)) {\n data.handler = config;\n } else if (_.isObject(config)) {\n _.extend(data, config);\n }\n\n data.id = id;\n elements[id] = data;\n\n return this;\n },\n\n /**\n * Removes specified custom node handler.\n *\n * @param {String} id - Node identifier.\n * @returns {Renderer} Chainable.\n */\n removeNode: function (id) {\n delete elements[id];\n\n return this;\n },\n\n /**\n * Checks if provided DOM element is a custom node.\n *\n * @param {HTMLElement} node - Node to be checked.\n * @returns {Boolean}\n */\n isCustomNode: function (node) {\n return _.some(elements, function (elem) {\n return elem.name.toUpperCase() === node.tagName;\n });\n },\n\n /**\n * Processes custom attributes of a content's child nodes.\n *\n * @param {HTMLElement} content - DOM element to be processed.\n */\n processAttributes: function (content) {\n var repeat;\n\n repeat = _.some(attributes, function (attr) {\n var attrName = attr.name,\n nodes = content.querySelectorAll('[' + attrName + ']'),\n handler = attr.handler;\n\n return _.toArray(nodes).some(function (node) {\n var data = node.getAttribute(attrName);\n\n return handler(node, data, attr) === true;\n });\n });\n\n if (repeat) {\n renderer.processAttributes(content);\n }\n },\n\n /**\n * Processes custom nodes of a provided content.\n *\n * @param {HTMLElement} content - DOM element to be processed.\n */\n processNodes: function (content) {\n var repeat;\n\n repeat = _.some(elements, function (element) {\n var nodes = content.querySelectorAll(element.name),\n handler = element.handler;\n\n return _.toArray(nodes).some(function (node) {\n var data = node.getAttribute('args');\n\n return handler(node, data, element) === true;\n });\n });\n\n if (repeat) {\n renderer.processNodes(content);\n }\n },\n\n /**\n * Wraps provided string in curly braces if it's necessary.\n *\n * @param {String} args - String to be wrapped.\n * @returns {String} Wrapped string.\n */\n wrapArgs: function (args) {\n if (~args.indexOf('\\\\:')) {\n args = args.replace(colonReg, ':');\n } else if (~args.indexOf(':') && !~args.indexOf('}')) {\n args = '{' + args + '}';\n }\n\n return args;\n },\n\n /**\n * Wraps child nodes of provided DOM element\n * with knockout's comment tag.\n *\n * @param {HTMLElement} node - Node whose children should be wrapped.\n * @param {String} binding - Name of the binding for the opener comment tag.\n * @param {String} data - Data associated with a binding.\n *\n * @example\n * <div id=\"example\"><span/></div>\n * wrapChildren(document.getElementById('example'), 'foreach', 'data');\n * =>\n * <div id=\"example\">\n * <!-- ko foreach: data -->\n * <span></span>\n * <!-- /ko -->\n * </div>\n */\n wrapChildren: function (node, binding, data) {\n var tag = this.createComment(binding, data),\n $node = $(node);\n\n $node.prepend(tag.open);\n $node.append(tag.close);\n },\n\n /**\n * Wraps specified node with knockout's comment tag.\n *\n * @param {HTMLElement} node - Node to be wrapped.\n * @param {String} binding - Name of the binding for the opener comment tag.\n * @param {String} data - Data associated with a binding.\n *\n * @example\n * <div id=\"example\"></div>\n * wrapNode(document.getElementById('example'), 'foreach', 'data');\n * =>\n * <!-- ko foreach: data -->\n * <div id=\"example\"></div>\n * <!-- /ko -->\n */\n wrapNode: function (node, binding, data) {\n var tag = this.createComment(binding, data),\n $node = $(node);\n\n $node.before(tag.open);\n $node.after(tag.close);\n },\n\n /**\n * Creates knockouts' comment tag for the provided binding.\n *\n * @param {String} binding - Name of the binding.\n * @param {String} data - Data associated with a binding.\n * @returns {Object} Object with an open and close comment elements.\n */\n createComment: function (binding, data) {\n return {\n open: document.createComment(' ko ' + binding + ': ' + data + ' '),\n close: document.createComment(' /ko ')\n };\n }\n };\n\n renderer.handlers = {\n\n /**\n * Basic node handler. Replaces custom nodes\n * with a corresponding knockout's comment tag.\n *\n * @param {HTMLElement} node - Node to be processed.\n * @param {String} data\n * @param {Object} element\n * @returns {Boolean} True\n *\n * @example Sample syntaxes conversions.\n * <with args=\"model\">\n * <span/>\n * </with>\n * =>\n * <!-- ko with: model-->\n * <span/>\n * <!-- /ko -->\n */\n node: function (node, data, element) {\n data = renderer.wrapArgs(data);\n\n renderer.wrapNode(node, element.binding, data);\n $(node).replaceWith(node.childNodes);\n\n return true;\n },\n\n /**\n * Base attribute handler. Replaces custom attributes with\n * a corresponding knockouts' data binding.\n *\n * @param {HTMLElement} node - Node to be processed.\n * @param {String} data - Data associated with a binding.\n * @param {Object} attr - Attribute definition.\n *\n * @example Sample syntaxes conversions.\n * <div text=\"label\"></div>\n * =>\n * <div data-bind=\"text: label\"></div>\n */\n attribute: function (node, data, attr) {\n data = renderer.wrapArgs(data);\n\n renderer.bindings.add(node, attr.binding, data);\n node.removeAttribute(attr.name);\n },\n\n /**\n * Wraps provided node with a knockouts' comment tag.\n *\n * @param {HTMLElement} node - Node that will be wrapped.\n * @param {String} data - Data associated with a binding.\n * @param {Object} attr - Attribute definition.\n *\n * @example\n * <div outereach=\"data\" class=\"test\"></div>\n * =>\n * <!-- ko foreach: data -->\n * <div class=\"test\"></div>\n * <!-- /ko -->\n */\n wrapAttribute: function (node, data, attr) {\n data = renderer.wrapArgs(data);\n\n renderer.wrapNode(node, attr.binding, data);\n node.removeAttribute(attr.name);\n }\n };\n\n renderer.bindings = {\n\n /**\n * Appends binding string to the current\n * 'data-bind' attribute of provided node.\n *\n * @param {HTMLElement} node - DOM element whose 'data-bind' attribute will be extended.\n * @param {String} name - Name of a binding.\n * @param {String} data - Data associated with the binding.\n */\n add: function (node, name, data) {\n var bindings = this.get(node);\n\n if (bindings) {\n bindings += ', ';\n }\n\n bindings += name;\n\n if (data) {\n bindings += ': ' + data;\n }\n\n this.set(node, bindings);\n },\n\n /**\n * Extracts value of a 'data-bind' attribute from provided node.\n *\n * @param {HTMLElement} node - Node whose attribute to be extracted.\n * @returns {String}\n */\n get: function (node) {\n return node.getAttribute('data-bind') || '';\n },\n\n /**\n * Sets 'data-bind' attribute of the specified node\n * to the provided value.\n *\n * @param {HTMLElement} node - Node whose attribute will be altered.\n * @param {String} bindings - New value of 'data-bind' attribute.\n */\n set: function (node, bindings) {\n node.setAttribute('data-bind', bindings);\n }\n };\n\n renderer\n .addGlobal(renderer.processAttributes)\n .addGlobal(renderer.processNodes);\n\n /**\n * Collection of default binding conversions.\n */\n preset = {\n nodes: _.object([\n 'if',\n 'text',\n 'with',\n 'scope',\n 'ifnot',\n 'foreach',\n 'component'\n ], Array.prototype),\n attributes: _.object([\n 'css',\n 'attr',\n 'html',\n 'with',\n 'text',\n 'click',\n 'event',\n 'submit',\n 'enable',\n 'disable',\n 'options',\n 'visible',\n 'template',\n 'hasFocus',\n 'textInput',\n 'component',\n 'uniqueName',\n 'optionsText',\n 'optionsValue',\n 'checkedValue',\n 'selectedOptions'\n ], Array.prototype)\n };\n\n _.extend(preset.attributes, {\n if: renderer.handlers.wrapAttribute,\n ifnot: renderer.handlers.wrapAttribute,\n innerif: {\n binding: 'if'\n },\n innerifnot: {\n binding: 'ifnot'\n },\n outereach: {\n binding: 'foreach',\n handler: renderer.handlers.wrapAttribute\n },\n foreach: {\n name: 'each'\n },\n value: {\n name: 'ko-value'\n },\n style: {\n name: 'ko-style'\n },\n checked: {\n name: 'ko-checked'\n },\n disabled: {\n name: 'ko-disabled',\n binding: 'disable'\n },\n focused: {\n name: 'ko-focused',\n binding: 'hasFocus'\n },\n\n /**\n * Custom 'render' attribute handler function. Wraps child elements\n * of a node with knockout's 'ko template:' comment tag.\n *\n * @param {HTMLElement} node - Element to be processed.\n * @param {String} data - Data specified in 'render' attribute of a node.\n */\n render: function (node, data) {\n data = data || 'getTemplate()';\n data = renderer.wrapArgs(data);\n\n renderer.wrapChildren(node, 'template', data);\n node.removeAttribute('render');\n }\n });\n\n _.extend(preset.nodes, {\n foreach: {\n name: 'each'\n },\n\n /**\n * Custom 'render' node handler function.\n * Replaces node with knockout's 'ko template:' comment tag.\n *\n * @param {HTMLElement} node - Element to be processed.\n * @param {String} data - Data specified in 'args' attribute of a node.\n */\n render: function (node, data) {\n data = data || 'getTemplate()';\n data = renderer.wrapArgs(data);\n\n renderer.wrapNode(node, 'template', data);\n $(node).replaceWith(node.childNodes);\n }\n });\n\n _.each(preset.attributes, function (data, id) {\n renderer.addAttribute(id, data);\n });\n\n _.each(preset.nodes, function (data, id) {\n renderer.addNode(id, data);\n });\n\n return renderer;\n});\n","Magento_Ui/js/lib/knockout/template/engine.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'ko',\n 'underscore',\n './observable_source',\n './renderer',\n '../../logger/console-logger'\n], function ($, ko, _, Source, renderer, consoleLogger) {\n 'use strict';\n\n var RemoteTemplateEngine,\n NativeTemplateEngine = ko.nativeTemplateEngine,\n sources = {};\n\n /**\n * Remote template engine class. Is used to be able to load remote templates via knockout template binding.\n */\n RemoteTemplateEngine = function () {\n // Instance reference for closure.\n var engine = this,\n // Decorate the builtin Knockout \"template\" binding to track synchronous template renders.\n origUpdate = ko.bindingHandlers.template.update;\n\n /**\n * Counter to track the number of currently running render tasks (both synchronous and asynchronous).\n * @type {Number}\n * @private\n */\n this._rendersOutstanding = 0;\n\n /**\n * Use a jQuery object as an event bus (but any event emitter with on/off/emit methods could work)\n * @type {jQuery}\n * @private\n */\n this._events = $(this);\n\n /**\n * Rendered templates\n * @type {Object}\n * @private\n */\n this._templatesRendered = {};\n\n /*eslint-disable no-unused-vars*/\n /**\n * Decorate update method\n *\n * @param {HTMLElement} element\n * @param {Function} valueAccessor\n * @param {Object} allBindings\n * @param {Object} viewModel\n * @param {ko.bindingContext} bindingContext\n * @returns {*}\n */\n ko.bindingHandlers.template.update = function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n /*eslint-enable no-unused-vars*/\n var options = ko.utils.peekObservable(valueAccessor()),\n templateName,\n isSync,\n updated;\n\n if (typeof options === 'object') {\n if (options.templateEngine && options.templateEngine !== engine) {\n return origUpdate.apply(this, arguments);\n }\n\n if (!options.name) {\n consoleLogger.error('Could not find template name', options);\n }\n templateName = options.name;\n } else if (typeof options === 'string') {\n templateName = options;\n } else {\n consoleLogger.error('Could not build a template binding', options);\n }\n engine._trackRender(templateName);\n isSync = engine._hasTemplateLoaded(templateName);\n updated = origUpdate.apply(this, arguments);\n\n if (isSync) {\n engine._releaseRender(templateName, 'sync');\n }\n\n return updated;\n };\n };\n\n /**\n * Creates unique template identifier based on template name and it's extenders (optional)\n * @param {String} templateName\n * @return {String} - unique template identifier\n */\n function createTemplateIdentifier(templateName) {\n return templateName;\n }\n\n RemoteTemplateEngine.prototype = new NativeTemplateEngine;\n RemoteTemplateEngine.prototype.constructor = RemoteTemplateEngine;\n\n /**\n * When an asynchronous render task begins, increment the internal counter for tracking when renders are complete.\n * @private\n */\n RemoteTemplateEngine.prototype._trackRender = function (templateName) {\n var rendersForTemplate = this._templatesRendered[templateName] !== undefined ?\n this._templatesRendered[templateName] : 0;\n\n this._rendersOutstanding++;\n this._templatesRendered[templateName] = rendersForTemplate + 1;\n this._resolveRenderWaits();\n };\n\n /**\n * When an asynchronous render task ends, decrement the internal counter for tracking when renders are complete.\n * @private\n */\n RemoteTemplateEngine.prototype._releaseRender = function (templateName) {\n var rendersForTemplate = this._templatesRendered[templateName];\n\n this._rendersOutstanding--;\n this._templatesRendered[templateName] = rendersForTemplate - 1;\n this._resolveRenderWaits();\n };\n\n /**\n * Check to see if renders are complete and trigger events for listeners.\n * @private\n */\n RemoteTemplateEngine.prototype._resolveRenderWaits = function () {\n if (this._rendersOutstanding === 0) {\n this._events.triggerHandler('finishrender');\n }\n };\n\n /**\n * Get a promise for the end of the current run of renders, both sync and async.\n * @return {jQueryPromise} - promise that resolves when render completes\n */\n RemoteTemplateEngine.prototype.waitForFinishRender = function () {\n var defer = $.Deferred();\n\n this._events.one('finishrender', defer.resolve);\n\n return defer.promise();\n };\n\n /**\n * Returns true if this template has already been asynchronously loaded and will be synchronously rendered.\n * @param {String} templateName\n * @returns {Boolean}\n * @private\n */\n RemoteTemplateEngine.prototype._hasTemplateLoaded = function (templateName) {\n // Sources object will have cached template once makeTemplateSource has run\n return sources.hasOwnProperty(templateName);\n };\n\n /**\n * Overrided method of native knockout template engine.\n * Caches template after it's unique name and renders in once.\n * If template name is not typeof string, delegates work to knockout.templateSources.anonymousTemplate.\n * @param {*} template\n * @param {HTMLElement} templateDocument - document\n * @param {Object} options - options, passed to template binding\n * @param {ko.bindingContext} bindingContext\n * @returns {TemplateSource} Object with methods 'nodes' and 'data'.\n */\n RemoteTemplateEngine.prototype.makeTemplateSource = function (template, templateDocument, options, bindingContext) {\n var engine = this,\n source,\n templateId;\n\n if (typeof template === 'string') {\n templateId = createTemplateIdentifier(template);\n source = sources[templateId];\n\n if (!source) {\n source = new Source(template);\n source.requestedBy = bindingContext.$data.name;\n sources[templateId] = source;\n\n consoleLogger.info('templateStartLoading', {\n template: templateId,\n component: bindingContext.$data.name\n });\n\n renderer.render(template).then(function (rendered) {\n consoleLogger.info('templateLoadedFromServer', {\n template: templateId,\n component: bindingContext.$data.name\n });\n source.nodes(rendered);\n engine._releaseRender(templateId, 'async');\n }).fail(function () {\n consoleLogger.error('templateLoadingFail', {\n template: templateId,\n component: bindingContext.$data.name\n });\n });\n }\n\n if (source.requestedBy !== bindingContext.$data.name) {\n consoleLogger.info('templateLoadedFromCache', {\n template: templateId,\n component: bindingContext.$data.name\n });\n }\n\n return source;\n } else if (template.nodeType === 1 || template.nodeType === 8) {\n source = new ko.templateSources.anonymousTemplate(template);\n\n return source;\n }\n\n throw new Error('Unknown template type: ' + template);\n };\n\n /**\n * Overrided method of native knockout template engine.\n * Should return array of html elements.\n * @param {TemplateSource} templateSource - object with methods 'nodes' and 'data'.\n * @return {Array} - array of html elements\n */\n RemoteTemplateEngine.prototype.renderTemplateSource = function (templateSource) {\n var nodes = templateSource.nodes();\n\n return ko.utils.cloneNodes(nodes);\n };\n\n /**\n * Overrided method of native knockout template engine.\n * Created in order to invoke makeTemplateSource method with custom set of params.\n * @param {*} template - template identifier\n * @param {ko.bindingContext} bindingContext\n * @param {Object} options - options, passed to template binding\n * @param {HTMLElement} templateDocument - document\n * @return {Array} - array of html elements\n */\n RemoteTemplateEngine.prototype.renderTemplate = function (template, bindingContext, options, templateDocument) {\n var templateSource = this.makeTemplateSource(template, templateDocument, options, bindingContext);\n\n return this.renderTemplateSource(templateSource);\n };\n\n return new RemoteTemplateEngine;\n});\n","Magento_Ui/js/lib/knockout/template/loader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery'\n], function ($) {\n 'use strict';\n\n var licenseRegExp = /<!--[\\s\\S]*?-->/,\n defaultPlugin = 'text',\n defaultExt = 'html';\n\n /**\n * Checks of provided string contains a file extension.\n *\n * @param {String} str - String to be checked.\n * @returns {Boolean}\n */\n function hasFileExtension(str) {\n return !!~str.indexOf('.') && !!str.split('.').pop();\n }\n\n /**\n * Checks if provided string contains a requirejs's plugin reference.\n *\n * @param {String} str - String to be checked.\n * @returns {Boolean}\n */\n function hasPlugin(str) {\n return !!~str.indexOf('!');\n }\n\n /**\n * Checks if provided string is a full path to the file.\n *\n * @param {String} str - String to be checked.\n * @returns {Boolean}\n */\n function isFullPath(str) {\n return !!~str.indexOf('://');\n }\n\n /**\n * Removes license comment from the provided string.\n *\n * @param {String} content - String to be processed.\n * @returns {String}\n */\n function removeLicense(content) {\n return content.replace(licenseRegExp, function (match) {\n return ~match.indexOf('/**') ? '' : match;\n });\n }\n\n return {\n\n /**\n * Attempts to extract template by provided path from\n * a DOM element and falls back to a file loading if\n * none of the DOM nodes was found.\n *\n * @param {String} path - Path to the template or a DOM selector.\n * @returns {jQueryPromise}\n */\n loadTemplate: function (path) {\n var content = this.loadFromNode(path),\n defer;\n\n if (content) {\n defer = $.Deferred();\n\n defer.resolve(content);\n\n return defer.promise();\n }\n\n return this.loadFromFile(path);\n },\n\n /**\n * Loads template from external file by provided\n * path, which will be preliminary formatted.\n *\n * @param {String} path - Path to the template.\n * @returns {jQueryPromise}\n */\n loadFromFile: function (path) {\n var loading = $.Deferred();\n\n path = this.formatPath(path);\n\n require([path], function (template) {\n template = removeLicense(template);\n loading.resolve(template);\n }, function (err) {\n loading.reject(err);\n });\n\n return loading.promise();\n },\n\n /**\n * Attempts to extract content of a node found by provided selector.\n *\n * @param {String} selector - Node's selector (not necessary valid).\n * @returns {String|Boolean} If specified node doesn't exists\n * 'false' will be returned, otherwise returns node's content.\n */\n loadFromNode: function (selector) {\n var node;\n\n try {\n node =\n document.getElementById(selector) ||\n document.querySelector(selector);\n\n return node ? node.innerHTML : false;\n } catch (e) {\n return false;\n }\n },\n\n /**\n * Adds requirejs's plugin and file extension to\n * to the provided string if it's necessary.\n *\n * @param {String} path - Path to be processed.\n * @returns {String} Formatted path.\n */\n formatPath: function (path) {\n var result = path;\n\n if (!hasPlugin(path)) {\n result = defaultPlugin + '!' + result;\n }\n\n if (isFullPath(path)) {\n return result;\n }\n\n if (!hasFileExtension(path)) {\n result += '.' + defaultExt;\n }\n\n return result.replace(/^([^\\/]+)/g, '$1/template');\n }\n };\n});\n","Magento_Ui/js/lib/knockout/bindings/keyboard.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n '../template/renderer'\n], function (ko, renderer) {\n 'use strict';\n\n ko.bindingHandlers.keyboard = {\n\n /**\n * Attaches keypress handlers to element\n * @param {HTMLElement} el - Element, that binding is applied to\n * @param {Function} valueAccessor - Function that returns value, passed to binding\n * @param {Object} allBindings - all bindings object\n * @param {Object} viewModel - reference to viewmodel\n */\n init: function (el, valueAccessor, allBindings, viewModel) {\n var map = valueAccessor();\n\n ko.utils.registerEventHandler(el, 'keyup', function (e) {\n var callback = map[e.keyCode];\n\n if (callback) {\n return callback.call(viewModel, e);\n }\n });\n }\n };\n\n renderer.addAttribute('keyboard');\n});\n","Magento_Ui/js/lib/knockout/bindings/tooltip.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'ko',\n 'underscore',\n 'mage/template',\n 'text!ui/template/tooltip/tooltip.html',\n '../template/renderer'\n], function ($, ko, _, template, tooltipTmpl, renderer) {\n 'use strict';\n\n var tooltip,\n defaults,\n positions,\n transformProp,\n checkedPositions = {},\n iterator = 0,\n previousTooltip,\n tooltipData,\n positionData = {},\n tooltipsCollection = {},\n isTouchDevice = (function () {\n return 'ontouchstart' in document.documentElement;\n })(),\n CLICK_EVENT = (function () {\n return isTouchDevice ? 'touchstart' : 'click';\n })();\n\n defaults = {\n tooltipWrapper: '[data-tooltip=tooltip-wrapper]',\n tooltipContentBlock: 'data-tooltip-content',\n closeButtonClass: 'action-close',\n tailClass: 'data-tooltip-tail',\n action: 'hover',\n delay: 300,\n track: false,\n step: 20,\n position: 'top',\n closeButton: false,\n showed: false,\n strict: true,\n center: false,\n closeOnScroll: true\n };\n\n tooltipData = {\n tooltipClasses: '',\n trigger: false,\n timeout: 0,\n element: false,\n event: false,\n targetElement: {},\n showed: false,\n currentID: 0\n };\n\n /**\n * Polyfill for css transform\n */\n transformProp = (function () {\n var style = document.createElement('div').style,\n base = 'Transform',\n vendors = ['webkit', 'moz', 'ms', 'o'],\n vi = vendors.length,\n property;\n\n if (typeof style.transform !== 'undefined') {\n return 'transform';\n }\n\n while (vi--) {\n property = vendors[vi] + base;\n\n if (typeof style[property] !== 'undefined') {\n return property;\n }\n }\n })();\n\n positions = {\n\n /*eslint max-depth: [0, 0]*/\n\n map: {\n horizontal: {\n s: 'w',\n p: 'left'\n },\n vertical: {\n s: 'h',\n p: 'top'\n }\n },\n\n /**\n * Wrapper function to get tooltip data (position, className, etc)\n *\n * @param {Object} s - object with sizes and positions elements\n * @returns {Object} tooltip data (position, className, etc)\n */\n top: function (s) {\n return positions._topLeftChecker(s, positions.map, 'vertical', '_bottom', 'top', 'right');\n },\n\n /**\n * Wrapper function to get tooltip data (position, className, etc)\n *\n * @param {Object} s - object with sizes and positions elements\n * @returns {Object} tooltip data (position, className, etc)\n */\n left: function (s) {\n return positions._topLeftChecker(s, positions.map, 'horizontal', '_right', 'left', 'top');\n },\n\n /**\n * Wrapper function to get tooltip data (position, className, etc)\n *\n * @param {Object} s - object with sizes and positions elements\n * @returns {Object} tooltip data (position, className, etc)\n */\n bottom: function (s) {\n return positions._bottomRightChecker(s, positions.map, 'vertical', '_top', 'bottom', 'left');\n },\n\n /**\n * Wrapper function to get tooltip data (position, className, etc)\n *\n * @param {Object} s - object with sizes and positions elements\n * @returns {Object} tooltip data (position, className, etc)\n */\n right: function (s) {\n return positions._bottomRightChecker(s, positions.map, 'horizontal', '_left', 'right', 'bottom');\n },\n\n /**\n * Check can tooltip setted on current position or not. If can't setted - delegate call.\n *\n * @param {Object} s - object with sizes and positions elements\n * @param {Object} map - mapping for get direction positions\n * @param {String} direction - vertical or horizontal\n * @param {String} className - class whats should be setted to tooltip\n * @param {String} side - parent method name\n * @param {String} delegate - method name if tooltip can't be setted in current position\n * @returns {Object} tooltip data (position, className, etc)\n */\n _topLeftChecker: function (s, map, direction, className, side, delegate) {\n var result = {\n position: {}\n },\n config = tooltip.getTooltip(tooltipData.currentID),\n startPosition = !config.strict ? s.eventPosition : s.elementPosition,\n changedDirection;\n\n checkedPositions[side] = true;\n\n if (\n startPosition[map[direction].p] - s.tooltipSize[map[direction].s] - config.step >\n s.scrollPosition[map[direction].p]\n ) {\n result.position[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] -\n config.step;\n result.className = className;\n result.side = side;\n changedDirection = direction === 'vertical' ? 'horizontal' : 'vertical';\n result = positions._normalize(s, result, config, delegate, map, changedDirection);\n } else if (!checkedPositions[delegate]) {\n result = positions[delegate].apply(null, arguments);\n } else {\n result = positions.positionCenter(s, result);\n }\n\n return result;\n },\n\n /**\n * Check can tooltip setted on current position or not. If can't setted - delegate call.\n *\n * @param {Object} s - object with sizes and positions elements\n * @param {Object} map - mapping for get direction positions\n * @param {String} direction - vertical or horizontal\n * @param {String} className - class whats should be setted to tooltip\n * @param {String} side - parent method name\n * @param {String} delegate - method name if tooltip can't be setted in current position\n * @returns {Object} tooltip data (position, className, etc)\n */\n _bottomRightChecker: function (s, map, direction, className, side, delegate) {\n var result = {\n position: {}\n },\n config = tooltip.getTooltip(tooltipData.currentID),\n startPosition = !config.strict ? s.eventPosition : {\n top: s.elementPosition.top + s.elementSize.h,\n left: s.elementPosition.left + s.elementSize.w\n },\n changedDirection;\n\n checkedPositions[side] = true;\n\n if (\n startPosition[map[direction].p] + s.tooltipSize[map[direction].s] + config.step <\n s.scrollPosition[map[direction].p] + s.windowSize[map[direction].s]\n ) {\n result.position[map[direction].p] = startPosition[map[direction].p] + config.step;\n result.className = className;\n result.side = side;\n changedDirection = direction === 'vertical' ? 'horizontal' : 'vertical';\n result = positions._normalize(s, result, config, delegate, map, changedDirection);\n } else if (!checkedPositions[delegate]) {\n result = positions[delegate].apply(null, arguments);\n } else {\n result = positions.positionCenter(s, result);\n }\n\n return result;\n },\n\n /**\n * Centered tooltip if tooltip does not fit in window\n *\n * @param {Object} s - object with sizes and positions elements\n * @param {Object} data - current data (position, className, etc)\n * @returns {Object} tooltip data (position, className, etc)\n */\n positionCenter: function (s, data) {\n data = positions._positionCenter(s, data, 'horizontal', positions.map);\n data = positions._positionCenter(s, data, 'vertical', positions.map);\n\n return data;\n },\n\n /**\n * Centered tooltip side\n *\n * @param {Object} s - object with sizes and positions elements\n * @param {Object} data - current data (position, className, etc)\n * @param {String} direction - vertical or horizontal\n * @param {Object} map - mapping for get direction positions\n * @returns {Object} tooltip data (position, className, etc)\n */\n _positionCenter: function (s, data, direction, map) {\n if (s.tooltipSize[map[direction].s] < s.windowSize[map[direction].s]) {\n data.position[map[direction].p] = (s.windowSize[map[direction].s] -\n s.tooltipSize[map[direction].s]) / 2 + s.scrollPosition[map[direction].p];\n } else {\n data.position[map[direction].p] = s.scrollPosition[map[direction].p];\n data.tooltipSize = {};\n data.tooltipSize[map[direction].s] = s.windowSize[map[direction].s];\n }\n\n return data;\n },\n\n /**\n * Normalize horizontal or vertical position.\n *\n * @param {Object} s - object with sizes and positions elements\n * @param {Object} data - current data (position, className, etc)\n * @param {Object} config - tooltip config\n * @param {String} delegate - method name if tooltip can't be setted in current position\n * @param {Object} map - mapping for get direction positions\n * @param {String} direction - vertical or horizontal\n * @returns {Object} tooltip data (position, className, etc)\n */\n _normalize: function (s, data, config, delegate, map, direction) {\n var startPosition = !config.center ? s.eventPosition : {\n left: s.elementPosition.left + s.elementSize.w / 2,\n top: s.elementPosition.top + s.elementSize.h / 2\n },\n depResult;\n\n if (startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2 >\n s.scrollPosition[map[direction].p] && startPosition[map[direction].p] +\n s.tooltipSize[map[direction].s] / 2 <\n s.scrollPosition[map[direction].p] + s.windowSize[map[direction].s]\n ) {\n data.position[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2;\n } else {\n\n /*eslint-disable no-lonely-if*/\n if (!checkedPositions[delegate]) {\n depResult = positions[delegate].apply(null, arguments);\n\n if (depResult.hasOwnProperty('className')) {\n data = depResult;\n } else {\n data = positions._normalizeTail(s, data, config, delegate, map, direction, startPosition);\n }\n } else {\n data = positions._normalizeTail(s, data, config, delegate, map, direction, startPosition);\n }\n }\n\n return data;\n },\n\n /**\n * Calc tail position.\n *\n * @param {Object} s - object with sizes and positions elements\n * @param {Object} data - current data (position, className, etc)\n * @param {Object} config - tooltip config\n * @param {String} delegate - method name if tooltip can't be setted in current position\n * @param {Object} map - mapping for get direction positions\n * @param {String} direction - vertical or horizontal\n * @param {Object} startPosition - start position\n * @returns {Object} tooltip data (position, className, etc)\n */\n _normalizeTail: function (s, data, config, delegate, map, direction, startPosition) {\n data.tail = {};\n\n if (s.tooltipSize[map[direction].s] < s.windowSize[map[direction].s]) {\n\n if (\n startPosition[map[direction].p] >\n s.windowSize[map[direction].s] / 2 + s.scrollPosition[map[direction].p]\n ) {\n data.position[map[direction].p] = s.windowSize[map[direction].s] +\n s.scrollPosition[map[direction].p] - s.tooltipSize[map[direction].s];\n data.tail[map[direction].p] = startPosition[map[direction].p] -\n s.tooltipSize[map[direction].s] / 2 - data.position[map[direction].p];\n } else {\n data.position[map[direction].p] = s.scrollPosition[map[direction].p];\n data.tail[map[direction].p] = startPosition[map[direction].p] -\n s.tooltipSize[map[direction].s] / 2 - data.position[map[direction].p];\n }\n } else {\n data.position[map[direction].p] = s.scrollPosition[map[direction].p];\n data.tail[map[direction].p] = s.eventPosition[map[direction].p] - s.windowSize[map[direction].s] / 2;\n data.tooltipSize = {};\n data.tooltipSize[map[direction].s] = s.windowSize[map[direction].s];\n }\n\n return data;\n }\n };\n\n tooltip = {\n\n /**\n * Set new tooltip to tooltipCollection, save config, and add unic id\n *\n * @param {Object} config - tooltip config\n * @returns {String} tooltip id\n */\n setTooltip: function (config) {\n var property = 'id-' + iterator;\n\n tooltipsCollection[property] = config;\n iterator++;\n\n return property;\n },\n\n /**\n * Get tooltip config by id\n *\n * @param {String} id - tooltip id\n * @returns {Object} tooltip config\n */\n getTooltip: function (id) {\n return tooltipsCollection[id];\n },\n\n /**\n * Set content to current tooltip\n *\n * @param {Object} tooltipElement - tooltip element\n * @param {Object} viewModel - tooltip view model\n * @param {String} id - tooltip id\n * @param {Object} bindingCtx - tooltip context\n * @param {Object} event - action event\n */\n setContent: function (tooltipElement, viewModel, id, bindingCtx, event) {\n var html = $(tooltipElement).html(),\n config = tooltip.getTooltip(id),\n body = $('body');\n\n tooltipData.currentID = id;\n tooltipData.trigger = $(event.currentTarget);\n tooltip.setTargetData(event);\n body.on('mousemove.setTargetData', tooltip.setTargetData);\n tooltip.clearTimeout(id);\n\n tooltipData.timeout = _.delay(function () {\n body.off('mousemove.setTargetData', tooltip.setTargetData);\n\n if (tooltipData.trigger[0] === tooltipData.targetElement) {\n tooltip.destroy(id);\n event.stopPropagation();\n tooltipElement = tooltip.createTooltip(id);\n tooltipElement.find('.' + defaults.tooltipContentBlock).append(html);\n tooltipElement.applyBindings(bindingCtx);\n tooltip.setHandlers(id);\n tooltip.setPosition(tooltipElement, id);\n previousTooltip = id;\n }\n\n }, config.delay);\n },\n\n /**\n * Set position to current tooltip\n *\n * @param {Object} tooltipElement - tooltip element\n * @param {String} id - tooltip id\n */\n setPosition: function (tooltipElement, id) {\n var config = tooltip.getTooltip(id);\n\n tooltip.sizeData = {\n windowSize: {\n h: $(window).outerHeight(),\n w: $(window).outerWidth()\n },\n scrollPosition: {\n top: $(window).scrollTop(),\n left: $(window).scrollLeft()\n },\n tooltipSize: {\n h: tooltipElement.outerHeight(),\n w: tooltipElement.outerWidth()\n },\n elementSize: {\n h: tooltipData.trigger.outerHeight(),\n w: tooltipData.trigger.outerWidth()\n },\n elementPosition: tooltipData.trigger.offset(),\n eventPosition: this.getEventPosition(tooltipData.event)\n };\n\n _.extend(positionData, positions[config.position](tooltip.sizeData));\n tooltipElement.css(positionData.position);\n tooltipElement.addClass(positionData.className);\n tooltip._setTooltipSize(positionData, tooltipElement);\n tooltip._setTailPosition(positionData, tooltipElement);\n checkedPositions = {};\n },\n\n /**\n * Check position data and change tooltip size if needs\n *\n * @param {Object} data - position data\n * @param {Object} tooltipElement - tooltip element\n */\n _setTooltipSize: function (data, tooltipElement) {\n if (data.tooltipSize) {\n data.tooltipSize.w ?\n tooltipElement.css('width', data.tooltipSize.w) :\n tooltipElement.css('height', data.tooltipSize.h);\n }\n },\n\n /**\n * Check position data and set position to tail\n *\n * @param {Object} data - position data\n * @param {Object} tooltipElement - tooltip element\n */\n _setTailPosition: function (data, tooltipElement) {\n var tail,\n tailMargin;\n\n if (data.tail) {\n tail = tooltipElement.find('.' + defaults.tailClass);\n\n if (data.tail.left) {\n tailMargin = parseInt(tail.css('margin-left'), 10);\n tail.css('margin-left', tailMargin + data.tail.left);\n } else {\n tailMargin = parseInt(tail.css('margin-top'), 10);\n tail.css('margin-top', tailMargin + data.tail.top);\n }\n }\n },\n\n /**\n * Resolves position for tooltip\n *\n * @param {Object} event\n * @returns {Object}\n */\n getEventPosition: function (event) {\n var position = {\n left: event.originalEvent && event.originalEvent.pageX || 0,\n top: event.originalEvent && event.originalEvent.pageY || 0\n };\n\n if (position.left === 0 && position.top === 0) {\n _.extend(position, event.target.getBoundingClientRect());\n }\n\n return position;\n },\n\n /**\n * Close tooltip if action happened outside handler and tooltip element\n *\n * @param {String} id - tooltip id\n * @param {Object} event - action event\n */\n outerClick: function (id, event) {\n var tooltipElement = $(event.target).parents(defaults.tooltipWrapper)[0],\n isTrigger = event.target === tooltipData.trigger[0] || $.contains(tooltipData.trigger[0], event.target);\n\n if (tooltipData.showed && tooltipElement !== tooltipData.element[0] && !isTrigger) {\n tooltip.destroy(id);\n }\n },\n\n /**\n * Parse keydown event and if event trigger is escape key - close tooltip\n *\n * @param {Object} event - action event\n */\n keydownHandler: function (event) {\n if (tooltipData.showed && event.keyCode === 27) {\n tooltip.destroy(tooltipData.currentID);\n }\n },\n\n /**\n * Change tooltip position when track is enabled\n *\n * @param {Object} event - current event\n */\n track: function (event) {\n var inequality = {},\n map = positions.map,\n translate = {\n left: 'translateX',\n top: 'translateY'\n },\n eventPosition = {\n left: event.pageX,\n top: event.pageY\n },\n tooltipSize = {\n w: tooltipData.element.outerWidth(),\n h: tooltipData.element.outerHeight()\n },\n direction = positionData.side === 'bottom' || positionData.side === 'top' ? 'horizontal' : 'vertical';\n\n inequality[map[direction].p] = eventPosition[map[direction].p] - (positionData.position[map[direction].p] +\n tooltipSize[map[direction].s] / 2);\n\n if (positionData.position[map[direction].p] + inequality[map[direction].p] +\n tooltip.sizeData.tooltipSize[map[direction].s] >\n tooltip.sizeData.windowSize[map[direction].s] + tooltip.sizeData.scrollPosition[map[direction].p] ||\n inequality[map[direction].p] + positionData.position[map[direction].p] <\n tooltip.sizeData.scrollPosition[map[direction].p]) {\n\n return false;\n }\n\n tooltipData.element[0].style[transformProp] = translate[map[direction].p] +\n '(' + inequality[map[direction].p] + 'px)';\n },\n\n /**\n * Set handlers to tooltip\n *\n * @param {String} id - tooltip id\n */\n setHandlers: function (id) {\n var config = tooltip.getTooltip(id);\n\n if (config.track) {\n tooltipData.trigger.on('mousemove.track', tooltip.track);\n }\n\n if (config.action === 'click') {\n $(window).on(CLICK_EVENT + '.outerClick', tooltip.outerClick.bind(null, id));\n }\n\n if (config.closeButton) {\n $('.' + config.closeButtonClass).on('click.closeButton', tooltip.destroy.bind(null, id));\n }\n\n if (config.closeOnScroll) {\n document.addEventListener('scroll', tooltip.destroy, true);\n $(window).on('scroll.tooltip', tooltip.outerClick.bind(null, id));\n }\n\n $(window).on('keydown.tooltip', tooltip.keydownHandler);\n $(window).on('resize.outerClick', tooltip.outerClick.bind(null, id));\n },\n\n /**\n * Toggle tooltip\n *\n * @param {Object} tooltipElement - tooltip element\n * @param {Object} viewModel - tooltip view model\n * @param {String} id - tooltip id\n */\n toggleTooltip: function (tooltipElement, viewModel, id) {\n if (previousTooltip === id && tooltipData.showed) {\n tooltip.destroy(id);\n\n return false;\n }\n\n tooltip.setContent.apply(null, arguments);\n\n return false;\n },\n\n /**\n * Create tooltip and append to DOM\n *\n * @param {String} id - tooltip id\n * @returns {Object} tooltip element\n */\n createTooltip: function (id) {\n var body = $('body'),\n config = tooltip.getTooltip(id);\n\n $(template(tooltipTmpl, {\n data: config\n })).appendTo(body);\n\n tooltipData.showed = true;\n tooltipData.element = $(config.tooltipWrapper);\n\n return tooltipData.element;\n },\n\n /**\n * Check action and clean timeout\n *\n * @param {String} id - tooltip id\n */\n clearTimeout: function (id) {\n var config = tooltip.getTooltip(id);\n\n if (config.action === 'hover') {\n clearTimeout(tooltipData.timeout);\n }\n },\n\n /**\n * Check previous tooltip\n */\n checkPreviousTooltip: function () {\n if (!tooltipData.timeout) {\n tooltip.destroy();\n }\n },\n\n /**\n * Destroy tooltip instance\n */\n destroy: function () {\n if (tooltipData.element) {\n tooltipData.element.remove();\n tooltipData.showed = false;\n }\n\n positionData = {};\n tooltipData.timeout = false;\n tooltip.removeHandlers();\n },\n\n /**\n * Remove tooltip handlers\n */\n removeHandlers: function () {\n $('.' + defaults.closeButtonClass).off('click.closeButton');\n tooltipData.trigger.off('mousemove.track');\n document.removeEventListener('scroll', tooltip.destroy, true);\n $(window).off('scroll.tooltip');\n $(window).off(CLICK_EVENT + '.outerClick');\n $(window).off('keydown.tooltip');\n $(window).off('resize.outerClick');\n },\n\n /**\n * Set target element\n *\n * @param {Object} event - current event\n */\n setTargetData: function (event) {\n tooltipData.event = event;\n\n //TODO: bug chrome v.49; Link to issue https://bugs.chromium.org/p/chromium/issues/detail?id=161464\n if (event.timeStamp - (tooltipData.timestamp || 0) < 1) {\n return;\n }\n\n if (event.type === 'mousemove') {\n tooltipData.targetElement = event.target;\n } else {\n tooltipData.targetElement = event.currentTarget;\n tooltipData.timestamp = event.timeStamp;\n }\n },\n\n /**\n * Merged user config with defaults configuration\n *\n * @param {Object} config - user config\n * @returns {Object} merged config\n */\n processingConfig: function (config) {\n return _.extend({}, defaults, config);\n }\n };\n\n ko.bindingHandlers.tooltip = {\n\n /**\n * Initialize tooltip\n *\n * @param {Object} elem - tooltip DOM element\n * @param {Function} valueAccessor - ko observable property, tooltip data\n * @param {Object} allBindings - all bindings on current element\n * @param {Object} viewModel - current element viewModel\n * @param {Object} bindingCtx - current element binding context\n */\n init: function (elem, valueAccessor, allBindings, viewModel, bindingCtx) {\n var config = tooltip.processingConfig(valueAccessor()),\n $parentScope = config.parentScope ? $(config.parentScope) : $(elem).parent(),\n tooltipId;\n\n $(elem).addClass('hidden');\n\n if (isTouchDevice) {\n config.action = 'click';\n }\n tooltipId = tooltip.setTooltip(config);\n\n if (config.action === 'hover') {\n $parentScope.on(\n 'mouseenter',\n config.trigger,\n tooltip.setContent.bind(null, elem, viewModel, tooltipId, bindingCtx)\n );\n $parentScope.on(\n 'mouseleave',\n config.trigger,\n tooltip.checkPreviousTooltip.bind(null, tooltipId)\n );\n } else if (config.action === 'click') {\n $parentScope.on(\n 'click',\n config.trigger,\n tooltip.toggleTooltip.bind(null, elem, viewModel, tooltipId, bindingCtx)\n );\n }\n\n return {\n controlsDescendantBindings: true\n };\n }\n };\n\n renderer.addAttribute('tooltip');\n});\n","Magento_Ui/js/lib/knockout/bindings/staticChecked.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n '../template/renderer'\n], function (ko, renderer) {\n 'use strict';\n\n ko.bindingHandlers.staticChecked = {\n 'after': ['value', 'attr'],\n\n /**\n * Implements same functionality as a standard 'checked' binding,\n * but with a difference that it wont' change values array if\n * value of DOM element changes.\n */\n init: function (element, valueAccessor, allBindings) {\n var isCheckbox = element.type === 'checkbox',\n isRadio = element.type === 'radio',\n isValueArray,\n oldElemValue,\n useCheckedValue,\n checkedValue,\n updateModel,\n updateView;\n\n if (!isCheckbox && !isRadio) {\n return;\n }\n\n checkedValue = ko.pureComputed(function () {\n if (allBindings.has('checkedValue')) {\n return ko.utils.unwrapObservable(allBindings.get('checkedValue'));\n } else if (allBindings.has('value')) {\n return ko.utils.unwrapObservable(allBindings.get('value'));\n }\n\n return element.value;\n });\n\n isValueArray = isCheckbox && ko.utils.unwrapObservable(valueAccessor()) instanceof Array;\n oldElemValue = isValueArray ? checkedValue() : undefined;\n useCheckedValue = isRadio || isValueArray;\n\n /**\n * Updates values array if it's necessary.\n */\n updateModel = function () {\n var isChecked = element.checked,\n elemValue = useCheckedValue ? checkedValue() : isChecked,\n modelValue;\n\n if (ko.computedContext.isInitial()) {\n return;\n }\n\n if (isRadio && !isChecked) {\n return;\n }\n\n modelValue = ko.dependencyDetection.ignore(valueAccessor);\n\n if (isValueArray) {\n if (oldElemValue !== elemValue) {\n oldElemValue = elemValue;\n } else {\n ko.utils.addOrRemoveItem(modelValue, elemValue, isChecked);\n }\n } else {\n ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);\n }\n };\n\n /**\n * Updates checkbox state.\n */\n updateView = function () {\n var modelValue = ko.utils.unwrapObservable(valueAccessor());\n\n if (isValueArray) {\n element.checked = ko.utils.arrayIndexOf(modelValue, checkedValue()) >= 0;\n } else if (isCheckbox) {\n element.checked = modelValue;\n } else {\n element.checked = checkedValue() === modelValue;\n }\n };\n\n ko.computed(updateModel, null, {\n disposeWhenNodeIsRemoved: element\n });\n\n ko.utils.registerEventHandler(element, 'click', updateModel);\n\n ko.computed(updateView, null, {\n disposeWhenNodeIsRemoved: element\n });\n }\n };\n\n ko.expressionRewriting._twoWayBindings.staticChecked = true;\n\n renderer.addAttribute('staticChecked');\n});\n","Magento_Ui/js/lib/knockout/bindings/bootstrap.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(function (require) {\n 'use strict';\n\n var renderer = require('../template/renderer');\n\n renderer.addAttribute('repeat', renderer.handlers.wrapAttribute);\n\n renderer.addAttribute('outerfasteach', {\n binding: 'fastForEach',\n handler: renderer.handlers.wrapAttribute\n });\n\n renderer\n .addNode('repeat')\n .addNode('fastForEach');\n\n return {\n resizable: require('./resizable'),\n i18n: require('./i18n'),\n scope: require('./scope'),\n range: require('./range'),\n mageInit: require('./mage-init'),\n keyboard: require('./keyboard'),\n optgroup: require('./optgroup'),\n afterRender: require('./after-render'),\n autoselect: require('./autoselect'),\n datepicker: require('./datepicker'),\n outerClick: require('./outer_click'),\n fadeVisible: require('./fadeVisible'),\n collapsible: require('./collapsible'),\n staticChecked: require('./staticChecked'),\n simpleChecked: require('./simple-checked'),\n bindHtml: require('./bind-html'),\n tooltip: require('./tooltip'),\n repeat: require('knockoutjs/knockout-repeat'),\n fastForEach: require('knockoutjs/knockout-fast-foreach'),\n colorPicker: require('./color-picker')\n };\n});\n","Magento_Ui/js/lib/knockout/bindings/simple-checked.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n '../template/renderer'\n], function (ko, renderer) {\n 'use strict';\n\n ko.bindingHandlers.simpleChecked = {\n 'after': ['attr'],\n\n /**\n * Implements same functionality as a standard 'simpleChecked' binding,\n * but with a difference that it wont' change values array if\n * value of DOM element changes.\n */\n init: function (element, valueAccessor) {\n var isCheckbox = element.type === 'checkbox',\n isRadio = element.type === 'radio',\n updateView,\n updateModel;\n\n if (!isCheckbox && !isRadio) {\n return;\n }\n\n /**\n * Updates checked observable\n */\n updateModel = function () {\n var modelValue = ko.dependencyDetection.ignore(valueAccessor),\n isChecked = element.checked;\n\n if (ko.computedContext.isInitial()) {\n return;\n }\n\n if (modelValue.peek() === isChecked) {\n return;\n }\n\n if (isRadio && !isChecked) {\n return;\n }\n\n modelValue(isChecked);\n };\n\n /**\n * Updates checkbox state\n */\n updateView = function () {\n var modelValue = ko.utils.unwrapObservable(valueAccessor());\n\n element.checked = !!modelValue;\n };\n\n ko.utils.registerEventHandler(element, 'change', updateModel);\n\n ko.computed(updateModel, null, {\n disposeWhenNodeIsRemoved: element\n });\n ko.computed(updateView, null, {\n disposeWhenNodeIsRemoved: element\n });\n }\n };\n\n ko.expressionRewriting._twoWayBindings.simpleChecked = true;\n\n renderer.addAttribute('simpleChecked');\n renderer.addAttribute('simple-checked', {\n binding: 'simpleChecked'\n });\n});\n","Magento_Ui/js/lib/knockout/bindings/range.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'jquery',\n 'underscore',\n '../template/renderer'\n], function (ko, $, _, renderer) {\n 'use strict';\n\n var isTouchDevice = !_.isUndefined(document.ontouchstart),\n sliderFn = 'slider',\n sliderModule = 'jquery-ui-modules/slider';\n\n if (isTouchDevice) {\n sliderFn = 'touchSlider';\n sliderModule = 'mage/touch-slider';\n }\n\n ko.bindingHandlers.range = {\n\n /**\n * Initializes binding and a slider update.\n *\n * @param {HTMLElement} element\n * @param {Function} valueAccessor\n */\n init: function (element, valueAccessor) {\n var config = valueAccessor(),\n value = config.value;\n\n _.extend(config, {\n value: value(),\n\n /**\n * Callback which is being called when sliders' value changes.\n *\n * @param {Event} event\n * @param {Object} ui\n */\n slide: function (event, ui) {\n value(ui.value);\n }\n });\n\n require([sliderModule], function () {\n $(element)[sliderFn](config);\n });\n },\n\n /**\n * Updates sliders' plugin configuration.\n *\n * @param {HTMLElement} element\n * @param {Function} valueAccessor\n */\n update: function (element, valueAccessor) {\n var config = valueAccessor();\n\n config.value = ko.unwrap(config.value);\n\n require([sliderModule], function () {\n $(element)[sliderFn]('option', config);\n });\n }\n };\n\n renderer.addAttribute('range');\n});\n","Magento_Ui/js/lib/knockout/bindings/datepicker.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/** Creates datepicker binding and registers in to ko.bindingHandlers object */\ndefine([\n 'ko',\n 'underscore',\n 'jquery',\n 'mage/translate'\n], function (ko, _, $, $t) {\n 'use strict';\n\n var defaults = {\n dateFormat: 'mm\\/dd\\/yyyy',\n showsTime: false,\n timeFormat: null,\n buttonImage: null,\n buttonImageOnly: null,\n buttonText: $t('Select Date')\n };\n\n ko.bindingHandlers.datepicker = {\n /**\n * Initializes calendar widget on element and stores it's value to observable property.\n * Datepicker binding takes either observable property or object\n * { storage: {ko.observable}, options: {Object} }.\n * For more info about options take a look at \"mage/calendar\" and jquery.ui.datepicker widget.\n * @param {HTMLElement} el - Element, that binding is applied to\n * @param {Function} valueAccessor - Function that returns value, passed to binding\n * @param {object} allBindings\n * @param {object} viewModel\n * @param {object} bindingContext\n */\n init: function (el, valueAccessor, allBindings, viewModel, bindingContext) {\n var config = valueAccessor(),\n observable,\n options = {};\n\n _.extend(options, defaults);\n\n if (typeof config === 'object') {\n observable = config.storage;\n _.extend(options, config.options);\n } else {\n observable = config;\n }\n\n require(['mage/calendar'], function () {\n $(el).calendar(options);\n\n ko.utils.registerEventHandler(el, 'change', function () {\n observable(this.value);\n });\n });\n\n if (bindingContext.$data) {\n bindingContext.$data.value.subscribe(function (newVal) {\n if (!newVal) {\n $(el).val('');\n }\n }, this);\n }\n\n\n },\n\n /**\n * Update calendar widget on element and stores it's value to observable property.\n * Datepicker binding takes either observable property or object\n * { storage: {ko.observable}, options: {Object} }.\n * @param {HTMLElement} element - Element, that binding is applied to\n * @param {Function} valueAccessor - Function that returns value, passed to binding\n */\n update: function (element, valueAccessor) {\n var config = valueAccessor(),\n $element = $(element),\n observable,\n options = {},\n newVal;\n\n _.extend(options, defaults);\n\n if (typeof config === 'object') {\n observable = config.storage;\n _.extend(options, config.options);\n } else {\n observable = config;\n }\n\n require(['moment', 'mage/utils/misc', 'mage/calendar'], function (moment, utils) {\n if (_.isEmpty(observable())) {\n newVal = null;\n } else {\n newVal = moment(\n observable(),\n utils.convertToMomentFormat(\n options.dateFormat + (options.showsTime ? ' ' + options.timeFormat : '')\n )\n ).toDate();\n }\n\n if (!options.timeOnly) {\n $element.datepicker('setDate', newVal);\n $element.trigger('blur');\n }\n });\n }\n };\n});\n","Magento_Ui/js/lib/knockout/bindings/optgroup.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'mageUtils'\n ], function (ko, utils) {\n 'use strict';\n\n var captionPlaceholder = {},\n optgroupTmpl = '<optgroup label=\"${ $.label }\"></optgroup>',\n nbspRe = / /g,\n optionsText,\n optionsValue,\n optionTitle;\n\n ko.bindingHandlers.optgroup = {\n /**\n * @param {*} element\n */\n init: function (element) {\n if (ko.utils.tagNameLower(element) !== 'select') {\n throw new Error('options binding applies only to SELECT elements');\n }\n\n // Remove all existing <option>s.\n while (element.length > 0) {\n element.remove(0);\n }\n },\n\n /**\n * @param {*} element\n * @param {*} valueAccessor\n * @param {*} allBindings\n */\n update: function (element, valueAccessor, allBindings) {\n var selectWasPreviouslyEmpty = element.length === 0,\n previousScrollTop = !selectWasPreviouslyEmpty && element.multiple ? element.scrollTop : null,\n includeDestroyed = allBindings.get('optionsIncludeDestroyed'),\n arrayToDomNodeChildrenOptions = {},\n captionValue,\n unwrappedArray = ko.utils.unwrapObservable(valueAccessor()),\n filteredArray,\n previousSelectedValues,\n itemUpdate = false,\n callback = setSelectionCallback,//eslint-disable-line no-use-before-define\n nestedOptionsLevel = -1;\n\n optionsText = ko.utils.unwrapObservable(allBindings.get('optionsText')) || 'text';\n optionsValue = ko.utils.unwrapObservable(allBindings.get('optionsValue')) || 'value';\n optionTitle = optionsText + 'title';\n\n if (element.multiple) {\n previousSelectedValues = ko.utils.arrayMap(\n selectedOptions(),//eslint-disable-line no-use-before-define\n ko.selectExtensions.readValue\n );\n } else {\n previousSelectedValues = element.selectedIndex >= 0 ?\n [ko.selectExtensions.readValue(element.options[element.selectedIndex])] :\n [];\n }\n\n if (unwrappedArray) {\n if (typeof unwrappedArray.length === 'undefined') { // Coerce single value into array\n unwrappedArray = [unwrappedArray];\n }\n\n // Filter out any entries marked as destroyed\n filteredArray = ko.utils.arrayFilter(unwrappedArray, function (item) {\n if (item && !item.label) {\n return false;\n }\n\n return includeDestroyed ||\n item === undefined ||\n item === null ||\n !ko.utils.unwrapObservable(item._destroy);\n });\n filteredArray.map(recursivePathBuilder, null);//eslint-disable-line no-use-before-define\n }\n\n /**\n * @param {*} option\n */\n arrayToDomNodeChildrenOptions.beforeRemove = function (option) {\n element.removeChild(option);\n };\n\n if (allBindings.has('optionsAfterRender')) {\n\n /**\n * @param {*} arrayEntry\n * @param {*} newOptions\n */\n callback = function (arrayEntry, newOptions) {\n setSelectionCallback(arrayEntry, newOptions);//eslint-disable-line no-use-before-define\n ko.dependencyDetection.ignore(\n allBindings.get('optionsAfterRender'),\n null,\n [newOptions[0],\n arrayEntry !== captionPlaceholder ? arrayEntry : undefined]\n );\n };\n }\n\n filteredArray = formatOptions(filteredArray);//eslint-disable-line no-use-before-define\n ko.utils.setDomNodeChildrenFromArrayMapping(\n element,\n filteredArray,\n optionNodeFromArray,//eslint-disable-line no-use-before-define\n arrayToDomNodeChildrenOptions,\n callback\n );\n\n ko.dependencyDetection.ignore(function () {\n var selectionChanged;\n\n if (allBindings.get('valueAllowUnset') && allBindings.has('value')) {\n // The model value is authoritative, so make sure its value is the one selected\n ko.selectExtensions.writeValue(\n element,\n ko.utils.unwrapObservable(allBindings.get('value')),\n true /* allowUnset */\n );\n } else {\n // Determine if the selection has changed as a result of updating the options list\n if (element.multiple) {\n // For a multiple-select box, compare the new selection count to the previous one\n // But if nothing was selected before, the selection can't have changed\n selectionChanged = previousSelectedValues.length &&\n selectedOptions().length < //eslint-disable-line no-use-before-define\n previousSelectedValues.length;\n } else {\n // For a single-select box, compare the current value to the previous value\n // But if nothing was selected before or nothing is selected now,\n // just look for a change in selection\n selectionChanged = previousSelectedValues.length && element.selectedIndex >= 0 ?\n ko.selectExtensions.readValue(element.options[element.selectedIndex]) !==\n previousSelectedValues[0] : previousSelectedValues.length || element.selectedIndex >= 0;\n }\n\n // Ensure consistency between model value and selected option.\n // If the dropdown was changed so that selection is no longer the same,\n // notify the value or selectedOptions binding.\n if (selectionChanged) {\n ko.utils.triggerEvent(element, 'change');\n }\n }\n });\n\n /*eslint-enable max-len, no-use-before-define*/\n\n if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20) {\n element.scrollTop = previousScrollTop;\n }\n\n /**\n * @returns {*}\n */\n function selectedOptions() {\n return ko.utils.arrayFilter(element.options, function (node) {\n return node.selected;\n });\n }\n\n /**\n * @param {*} object\n * @param {*} predicate\n * @param {*} defaultValue\n * @returns {*}\n */\n function applyToObject(object, predicate, defaultValue) {\n var predicateType = typeof predicate;\n\n if (predicateType === 'function') { // run it against the data value\n return predicate(object);\n } else if (predicateType === 'string') { // treat it as a property name on the data value\n return object[predicate];\n }\n\n return defaultValue;\n }\n\n /**\n * @param {*} obj\n */\n function recursivePathBuilder(obj) {\n\n obj[optionTitle] = (this && this[optionTitle] ? this[optionTitle] + '/' : '') + obj[optionsText].trim();\n\n if (Array.isArray(obj[optionsValue])) {\n obj[optionsValue].map(recursivePathBuilder, obj);\n }\n }\n\n /**\n * @param {Array} arrayEntry\n * @param {*} oldOptions\n * @returns {*[]}\n */\n function optionNodeFromArray(arrayEntry, oldOptions) {\n var option;\n\n if (oldOptions.length) {\n previousSelectedValues = oldOptions[0].selected ?\n [ko.selectExtensions.readValue(oldOptions[0])] : [];\n itemUpdate = true;\n }\n\n if (arrayEntry === captionPlaceholder) { // empty value, label === caption\n option = element.ownerDocument.createElement('option');\n ko.utils.setTextContent(option, allBindings.get('optionsCaption'));\n ko.selectExtensions.writeValue(option, undefined);\n } else if (typeof arrayEntry[optionsValue] === 'undefined') { // empty value === optgroup\n if (arrayEntry.__disableTmpl) {\n option = '<optgroup label=\"' + arrayEntry[optionsText] + '\"></optgroup>';\n } else {\n option = utils.template(optgroupTmpl, {\n label: arrayEntry[optionsText],\n title: arrayEntry[optionsText + 'title']\n });\n }\n option = ko.utils.parseHtmlFragment(option)[0];\n\n } else {\n option = element.ownerDocument.createElement('option');\n option.setAttribute('data-title', arrayEntry[optionsText + 'title']);\n ko.selectExtensions.writeValue(option, arrayEntry[optionsValue]);\n ko.utils.setTextContent(option, arrayEntry[optionsText]);\n }\n\n return [option];\n }\n\n /**\n * @param {*} newOptions\n */\n function setSelectionCallback(newOptions) {\n var isSelected;\n\n // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.\n // That's why we first added them without selection. Now it's time to set the selection.\n if (previousSelectedValues.length && newOptions.value) {\n isSelected = ko.utils.arrayIndexOf(\n previousSelectedValues,\n ko.selectExtensions.readValue(newOptions.value)\n ) >= 0;\n\n ko.utils.setOptionNodeSelectionState(newOptions.value, isSelected);\n\n // If this option was changed from being selected during a single-item update, notify the change\n if (itemUpdate && !isSelected) {\n ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, 'change']);\n }\n }\n }\n\n /**\n * @param {*} string\n * @param {Number} times\n * @returns {Array}\n */\n function strPad(string, times) {\n return new Array(times + 1).join(string);\n }\n\n /**\n * @param {*} options\n * @returns {Array}\n */\n function formatOptions(options) {\n var res = [];\n\n nestedOptionsLevel++;\n\n if (!nestedOptionsLevel) { // zero level\n // If caption is included, add it to the array\n if (allBindings.has('optionsCaption')) {\n captionValue = ko.utils.unwrapObservable(allBindings.get('optionsCaption'));\n // If caption value is null or undefined, don't show a caption\n if (//eslint-disable-line max-depth\n captionValue !== null &&\n captionValue !== undefined &&\n captionValue !== false\n ) {\n res.push(captionPlaceholder);\n }\n }\n }\n\n ko.utils.arrayForEach(options, function (option) {\n var value = applyToObject(option, optionsValue, option),\n label = applyToObject(option, optionsText, value) || '',\n disabled = applyToObject(option, 'disabled', false) || false,\n obj = {},\n space = '\\u2007\\u2007\\u2007';\n\n obj[optionTitle] = applyToObject(option, optionsText + 'title', value);\n\n if (disabled) {\n obj.disabled = disabled;\n }\n\n if (option.hasOwnProperty('__disableTmpl')) {\n obj.__disableTmpl = option.__disableTmpl;\n }\n\n label = label.replace(nbspRe, '').trim();\n\n if (Array.isArray(value)) {\n obj[optionsText] = strPad(' ', nestedOptionsLevel * 4) + label;\n res.push(obj);\n res = res.concat(formatOptions(value));\n } else {\n obj[optionsText] = strPad(space, nestedOptionsLevel * 2) + label;\n obj[optionsValue] = value;\n res.push(obj);\n }\n });\n nestedOptionsLevel--;\n\n return res;\n }\n }\n };\n});\n","Magento_Ui/js/lib/knockout/bindings/fadeVisible.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'ko'\n], function ($, ko) {\n 'use strict';\n\n ko.bindingHandlers.fadeVisible = {\n /**\n * Initially set the element to be instantly visible/hidden depending on the value.\n *\n * @param {HTMLElement} element\n * @param {Function} valueAccessor\n */\n init: function (element, valueAccessor) {\n var value = valueAccessor();\n\n // Use \"unwrapObservable\" so we can handle values that may or may not be observable\n $(element).toggle(ko.unwrap(value));\n },\n\n /**\n * Whenever the value subsequently changes, slowly fade the element in or out.\n *\n * @param {HTMLElement} element\n * @param {Function} valueAccessor\n */\n update: function (element, valueAccessor) {\n var value = valueAccessor();\n\n ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut();\n }\n };\n});\n","Magento_Ui/js/lib/knockout/bindings/after-render.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n '../template/renderer'\n], function (ko, renderer) {\n 'use strict';\n\n ko.bindingHandlers.afterRender = {\n\n /**\n * Binding init callback.\n */\n init: function (element, valueAccessor, allBindings, viewModel) {\n var callback = valueAccessor();\n\n if (typeof callback === 'function') {\n callback.call(viewModel, element, viewModel);\n }\n }\n };\n\n renderer.addAttribute('afterRender');\n});\n","Magento_Ui/js/lib/knockout/bindings/mage-init.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'underscore',\n 'mage/apply/main'\n], function (ko, _, mage) {\n 'use strict';\n\n ko.bindingHandlers.mageInit = {\n /**\n * Initializes components assigned to HTML elements.\n *\n * @param {HTMLElement} el\n * @param {Function} valueAccessor\n */\n init: function (el, valueAccessor) {\n var data = valueAccessor();\n\n _.each(data, function (config, component) {\n mage.applyFor(el, config, component);\n });\n }\n };\n});\n","Magento_Ui/js/lib/knockout/bindings/bind-html.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'underscore',\n 'mage/apply/main',\n '../template/renderer'\n], function (ko, _, mage, renderer) {\n 'use strict';\n\n /**\n * Set html to node element.\n *\n * @param {HTMLElement} el - Element to apply bindings to.\n * @param {Function} html - Observable html content.\n */\n function setHtml(el, html) {\n ko.utils.emptyDomNode(el);\n html = ko.utils.unwrapObservable(html);\n\n if (!_.isNull(html) && !_.isUndefined(html)) {\n if (!_.isString(html)) {\n html = html.toString();\n }\n\n el.innerHTML = html;\n }\n }\n\n /**\n * Apply bindings and call magento attributes parser.\n *\n * @param {HTMLElement} el - Element to apply bindings to.\n * @param {ko.bindingContext} ctx - Instance of ko.bindingContext, passed to binding initially.\n */\n function applyComponents(el, ctx) {\n ko.utils.arrayForEach(el.childNodes, ko.cleanNode);\n ko.applyBindingsToDescendants(ctx, el);\n mage.apply();\n }\n\n ko.bindingHandlers.bindHtml = {\n /**\n * Scope binding's init method.\n *\n * @returns {Object} - Knockout declaration for it to let binding control descendants.\n */\n init: function () {\n return {\n controlsDescendantBindings: true\n };\n },\n\n /**\n * Reads params passed to binding.\n * Set html to node element, apply bindings and call magento attributes parser.\n *\n * @param {HTMLElement} el - Element to apply bindings to.\n * @param {Function} valueAccessor - Function that returns value, passed to binding.\n * @param {Object} allBindings - Object, which represents all bindings applied to element.\n * @param {Object} viewModel - Object, which represents view model binded to el.\n * @param {ko.bindingContext} bindingContext - Instance of ko.bindingContext, passed to binding initially.\n */\n update: function (el, valueAccessor, allBindings, viewModel, bindingContext) {\n setHtml(el, valueAccessor());\n applyComponents(el, bindingContext);\n }\n };\n\n renderer.addAttribute('bindHtml');\n});\n","Magento_Ui/js/lib/knockout/bindings/resizable.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n 'jquery',\n 'Magento_Ui/js/lib/view/utils/async',\n 'uiRegistry',\n 'underscore',\n '../template/renderer'\n], function (ko, $, async, registry, _, renderer) {\n 'use strict';\n\n var sizeOptions = [\n 'minHeight',\n 'maxHeight',\n 'minWidth',\n 'maxWidth'\n ],\n\n handles = {\n height: '.ui-resizable-s, .ui-resizable-n',\n width: '.ui-resizable-w, .ui-resizable-e'\n };\n\n /**\n * Recalcs visibility of handles, width and height of resizable based on content\n * @param {HTMLElement} element\n */\n function adjustSize(element) {\n var maxHeight,\n maxWidth;\n\n element = $(element);\n maxHeight = element.resizable('option').maxHeight;\n maxWidth = element.resizable('option').maxWidth;\n\n if (maxHeight && element.height() > maxHeight) {\n element.height(maxHeight + 1);\n $(handles.height).hide();\n } else {\n $(handles.height).show();\n }\n\n if (maxWidth && element.width() > maxWidth) {\n element.width(maxWidth + 1);\n $(handles.width).hide();\n } else {\n $(handles.width).show();\n }\n }\n\n /**\n * Recalcs allowed min, max width and height based on configured selectors\n * @param {Object} sizeConstraints\n * @param {String} componentName\n * @param {HTMLElement} element\n * @param {Boolean} hasWidthUpdate\n */\n function recalcAllowedSize(sizeConstraints, componentName, element, hasWidthUpdate) {\n var size;\n\n element = $(element);\n\n if (!element.data('resizable')) {\n return;\n }\n\n if (!hasWidthUpdate) {\n element.css('width', 'auto');\n }\n\n _.each(sizeConstraints, function (selector, key) {\n async.async({\n component: componentName,\n selector: selector\n }, function (elem) {\n size = key.indexOf('Height') !== -1 ? $(elem).outerHeight(true) : $(elem).outerWidth(true);\n\n if (element.data('resizable')) {\n element.resizable('option', key, size + 1);\n }\n });\n }, this);\n\n adjustSize(element);\n }\n\n /**\n * Preprocess config to separate options,\n * which must be processed further before applying\n *\n * @param {Object} config\n * @param {Object} viewModel\n * @param {*} element\n * @return {Object} config\n */\n function processConfig(config, viewModel, element) {\n var sizeConstraint,\n sizeConstraints = {},\n recalc,\n hasWidthUpdate;\n\n if (_.isEmpty(config)) {\n return {};\n }\n _.each(sizeOptions, function (key) {\n sizeConstraint = config[key];\n\n if (sizeConstraint && !_.isNumber(sizeConstraint)) {\n sizeConstraints[key] = sizeConstraint;\n delete config[key];\n }\n });\n hasWidthUpdate = _.some(sizeConstraints, function (value, key) {\n return key.indexOf('Width') !== -1;\n });\n\n recalc = recalcAllowedSize.bind(null, sizeConstraints, viewModel.name, element, hasWidthUpdate);\n config.start = recalc;\n $(window).on('resize.resizable', recalc);\n registry.get(viewModel.provider).on('reloaded', recalc);\n\n return config;\n }\n\n ko.bindingHandlers.resizable = {\n\n /**\n * Binding init callback.\n *\n * @param {*} element\n * @param {Function} valueAccessor\n * @param {Function} allBindings\n * @param {Object} viewModel\n */\n init: function (element, valueAccessor, allBindings, viewModel) {\n var config = processConfig(valueAccessor(), viewModel, element);\n\n require(['jquery-ui-modules/resizable'], function () {\n if ($.fn.resizable) {\n $(element).resizable(config);\n }\n });\n }\n };\n\n renderer.addAttribute('resizable');\n});\n","Magento_Ui/js/lib/knockout/bindings/outer_click.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/** Creates outerClick binding and registers in to ko.bindingHandlers object */\ndefine([\n 'ko',\n 'jquery',\n 'underscore',\n '../template/renderer'\n], function (ko, $, _, renderer) {\n 'use strict';\n\n var defaults = {\n onlyIfVisible: true\n };\n\n /**\n * Checks if element sis visible.\n *\n * @param {Element} el\n * @returns {Boolean}\n */\n function isVisible(el) {\n var style = window.getComputedStyle(el),\n visibility = {\n display: 'none',\n visibility: 'hidden',\n opacity: '0'\n },\n visible = true;\n\n _.each(visibility, function (val, key) {\n if (style[key] === val) {\n visible = false;\n }\n });\n\n return visible;\n }\n\n /**\n * Document click handler which in case if event target is not\n * a descendant of provided container element,\n * invokes specified in configuration callback.\n *\n * @param {HTMLElement} container\n * @param {Object} config\n * @param {EventObject} e\n */\n function onOuterClick(container, config, e) {\n var target = e.target,\n callback = config.callback;\n\n if (container === target || container.contains(target)) {\n return;\n }\n\n if (config.onlyIfVisible) {\n if (!_.isNull(container.offsetParent) && isVisible(container)) {\n callback();\n }\n } else {\n callback();\n }\n }\n\n /**\n * Prepares configuration for the binding based\n * on a default properties and provided options.\n *\n * @param {(Object|Function)} [options={}]\n * @returns {Object}\n */\n function buildConfig(options) {\n var config = {};\n\n if (_.isFunction(options)) {\n options = {\n callback: options\n };\n } else if (!_.isObject(options)) {\n options = {};\n }\n\n return _.extend(config, defaults, options);\n }\n\n ko.bindingHandlers.outerClick = {\n\n /**\n * Initializes outer click binding.\n */\n init: function (element, valueAccessor) {\n var config = buildConfig(valueAccessor()),\n outerClick = onOuterClick.bind(null, element, config),\n isTouchDevice = typeof document.ontouchstart !== 'undefined';\n\n if (isTouchDevice) {\n $(document).on('touchstart', outerClick);\n\n ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n $(document).off('touchstart', outerClick);\n });\n } else {\n $(document).on('click', outerClick);\n\n ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n $(document).off('click', outerClick);\n });\n }\n }\n };\n\n renderer.addAttribute('outerClick');\n});\n","Magento_Ui/js/lib/knockout/bindings/autoselect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n 'jquery',\n '../template/renderer'\n], function (ko, $, renderer) {\n 'use strict';\n\n /**\n * 'Focus' event handler.\n *\n * @param {EventObject} e\n */\n function onFocus(e) {\n e.target.select();\n }\n\n ko.bindingHandlers.autoselect = {\n\n /**\n * Adds event handler which automatically\n * selects inputs' element text when field gets focused.\n */\n init: function (element, valueAccessor) {\n var enabled = ko.unwrap(valueAccessor());\n\n if (enabled !== false) {\n $(element).on('focus', onFocus);\n }\n }\n };\n\n renderer.addAttribute('autoselect');\n});\n","Magento_Ui/js/lib/knockout/bindings/color-picker.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n 'jquery',\n '../template/renderer',\n 'spectrum',\n 'tinycolor'\n], function (ko, $, renderer, spectrum, tinycolor) {\n 'use strict';\n\n /**\n * Change color picker status to be enabled or disabled\n *\n * @param {HTMLElement} element - Element to apply colorpicker enable/disable status to.\n * @param {Object} viewModel - Object, which represents view model binded to el.\n */\n function changeColorPickerStateBasedOnViewModel(element, viewModel) {\n $(element).spectrum(viewModel.disabled() ? 'disable' : 'enable');\n }\n\n ko.bindingHandlers.colorPicker = {\n /**\n * Binding init callback.\n *\n * @param {*} element\n * @param {Function} valueAccessor\n * @param {Function} allBindings\n * @param {Object} viewModel\n */\n init: function (element, valueAccessor, allBindings, viewModel) {\n var config = valueAccessor(),\n\n /** change value */\n changeValue = function (value) {\n if (value == null) {\n value = '';\n }\n config.value(value.toString());\n };\n\n config.change = changeValue;\n\n config.hide = changeValue;\n\n /** show value */\n config.show = function () {\n if (!viewModel.focused()) {\n viewModel.focused(true);\n }\n\n return true;\n };\n\n $(element).spectrum(config);\n\n changeColorPickerStateBasedOnViewModel(element, viewModel);\n },\n\n /**\n * Reads params passed to binding, parses component declarations.\n * Fetches for those found and attaches them to the new context.\n *\n * @param {HTMLElement} element - Element to apply bindings to.\n * @param {Function} valueAccessor - Function that returns value, passed to binding.\n * @param {Object} allBindings - Object, which represents all bindings applied to element.\n * @param {Object} viewModel - Object, which represents view model binded to element.\n */\n update: function (element, valueAccessor, allBindings, viewModel) {\n var config = valueAccessor();\n\n /** Initialise value as empty if it is undefined when color picker input is reset **/\n if (config.value() === undefined) {\n config.value('');\n }\n\n if (tinycolor(config.value()).isValid() || config.value() === '') {\n $(element).spectrum('set', config.value());\n\n if (config.value() !== '') {\n config.value($(element).spectrum('get').toString());\n }\n }\n\n changeColorPickerStateBasedOnViewModel(element, viewModel);\n }\n };\n\n renderer.addAttribute('colorPicker');\n});\n","Magento_Ui/js/lib/knockout/bindings/scope.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/** Creates scope binding and registers in to ko.bindingHandlers object */\ndefine([\n 'ko',\n 'uiRegistry',\n 'mage/translate',\n '../template/renderer',\n 'jquery',\n '../../logger/console-logger'\n], function (ko, registry, $t, renderer, $, consoleLogger) {\n 'use strict';\n\n /**\n * Creates child context with passed component param as $data. Extends context with $t helper.\n * Applies bindings to descendant nodes.\n * @param {HTMLElement} el - element to apply bindings to.\n * @param {ko.bindingContext} bindingContext - instance of ko.bindingContext, passed to binding initially.\n * @param {Promise} promise - instance of jQuery promise\n * @param {Object} component - component instance to attach to new context\n */\n function applyComponents(el, bindingContext, promise, component) {\n promise.resolve();\n component = bindingContext.createChildContext(component);\n\n ko.utils.extend(component, {\n $t: $t\n });\n\n ko.utils.arrayForEach(ko.virtualElements.childNodes(el), ko.cleanNode);\n\n ko.applyBindingsToDescendants(component, el);\n }\n\n ko.bindingHandlers.scope = {\n\n /**\n * Scope binding's init method.\n * @returns {Object} - Knockout declaration for it to let binding control descendants.\n */\n init: function () {\n return {\n controlsDescendantBindings: true\n };\n },\n\n /**\n * Reads params passed to binding, parses component declarations.\n * Fetches for those found and attaches them to the new context.\n * @param {HTMLElement} el - Element to apply bindings to.\n * @param {Function} valueAccessor - Function that returns value, passed to binding.\n * @param {Object} allBindings - Object, which represents all bindings applied to element.\n * @param {Object} viewModel - Object, which represents view model binded to el.\n * @param {ko.bindingContext} bindingContext - Instance of ko.bindingContext, passed to binding initially.\n */\n update: function (el, valueAccessor, allBindings, viewModel, bindingContext) {\n var component = valueAccessor(),\n promise = $.Deferred(),\n apply = applyComponents.bind(this, el, bindingContext, promise),\n loggerUtils = consoleLogger.utils;\n\n if (typeof component === 'string') {\n loggerUtils.asyncLog(\n promise,\n {\n data: {\n component: component\n },\n messages: loggerUtils.createMessages(\n 'requestingComponent',\n 'requestingComponentIsLoaded',\n 'requestingComponentIsFailed'\n )\n }\n );\n\n registry.get(component, apply);\n } else if (typeof component === 'function') {\n component(apply);\n }\n }\n };\n\n ko.virtualElements.allowedBindings.scope = true;\n\n renderer\n .addNode('scope')\n .addAttribute('scope', {\n name: 'ko-scope'\n });\n});\n","Magento_Ui/js/lib/knockout/bindings/collapsible.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n 'jquery',\n 'underscore',\n '../template/renderer'\n], function (ko, $, _, renderer) {\n 'use strict';\n\n var collapsible,\n defaults;\n\n defaults = {\n closeOnOuter: true,\n onTarget: false,\n openClass: '_active',\n as: '$collapsible'\n };\n\n collapsible = {\n\n /**\n * Sets 'opened' property to true.\n */\n open: function () {\n this.opened(true);\n },\n\n /**\n * Sets 'opened' property to false.\n */\n close: function () {\n this.opened(false);\n },\n\n /**\n * Toggles value of the 'opened' property.\n */\n toggle: function () {\n this.opened(!this.opened());\n }\n };\n\n /**\n * Document click handler which in case if event target is not\n * a descendant of provided container element, closes collapsible model.\n *\n * @param {HTMLElement} container\n * @param {Object} model\n * @param {EventObject} e\n */\n function onOuterClick(container, model, e) {\n var target = e.target;\n\n if (target !== container && !container.contains(target)) {\n model.close();\n }\n }\n\n /**\n * Creates 'css' binding which toggles\n * class specified in 'name' parameter.\n *\n * @param {Object} model\n * @param {String} name\n * @returns {Object}\n */\n function getClassBinding(model, name) {\n var binding = {};\n\n binding[name] = model.opened;\n\n return {\n css: binding\n };\n }\n\n /**\n * Prepares configuration for the binding based\n * on a default properties and provided options.\n *\n * @param {Object} [options={}]\n * @returns {Object} Complete instance configuration.\n */\n function buildConfig(options) {\n if (typeof options !== 'object') {\n options = {};\n }\n\n return _.extend({}, defaults, options);\n }\n\n ko.bindingHandlers.collapsible = {\n\n /**\n * Initializes 'collapsible' binding.\n */\n init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n var $collapsible = Object.create(collapsible),\n config = buildConfig(valueAccessor()),\n outerClick,\n bindings;\n\n _.bindAll($collapsible, 'open', 'close', 'toggle');\n\n $collapsible.opened = ko.observable(!!config.opened);\n\n bindingCtx[config.as] = $collapsible;\n\n if (config.closeOnOuter) {\n outerClick = onOuterClick.bind(null, element, $collapsible);\n\n $(document).on('click', outerClick);\n\n ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n $(document).off('click', outerClick);\n });\n }\n\n if (config.openClass) {\n bindings = getClassBinding($collapsible, config.openClass);\n\n ko.applyBindingsToNode(element, bindings, bindingCtx);\n }\n\n if (config.onTarget) {\n $(element).on('click', $collapsible.toggle);\n }\n\n if (viewModel && _.isFunction(viewModel.on)) {\n viewModel.on({\n close: $collapsible.close,\n open: $collapsible.open,\n toggleOpened: $collapsible.toggle\n });\n }\n }\n };\n\n ko.bindingHandlers.closeCollapsible = {\n\n /**\n * Creates listener for the click event on provided DOM element,\n * which closes associated with it collapsible model.\n */\n init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n var name = valueAccessor() || defaults.as,\n $collapsible = bindingCtx[name];\n\n if ($collapsible) {\n $(element).on('click', $collapsible.close);\n }\n }\n };\n\n ko.bindingHandlers.openCollapsible = {\n\n /**\n * Creates listener for the click event on provided DOM element,\n * which opens associated with it collapsible model.\n */\n init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n var name = valueAccessor() || defaults.as,\n $collapsible = bindingCtx[name];\n\n if ($collapsible) {\n $(element).on('click', $collapsible.open);\n }\n }\n };\n\n ko.bindingHandlers.toggleCollapsible = {\n\n /**\n * Creates listener for the click event on provided DOM element,\n * which toggles associated with it collapsible model.\n */\n init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n var name = valueAccessor() || defaults.as,\n $collapsible = bindingCtx[name];\n\n if ($collapsible) {\n $(element).on('click', $collapsible.toggle);\n }\n }\n };\n\n renderer\n .addAttribute('collapsible')\n .addAttribute('openCollapsible')\n .addAttribute('closeCollapsible')\n .addAttribute('toggleCollapsible');\n});\n","Magento_Ui/js/lib/knockout/bindings/i18n.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'ko',\n 'module',\n '../template/renderer',\n 'mage/translate'\n], function ($, ko, module, renderer) {\n 'use strict';\n\n var locations = {\n 'legend': 'Caption for the fieldset element',\n 'label': 'Label for an input element.',\n 'button': 'Push button',\n 'a': 'Link label',\n 'b': 'Bold text',\n 'strong': 'Strong emphasized text',\n 'i': 'Italic text',\n 'em': 'Emphasized text',\n 'u': 'Underlined text',\n 'sup': 'Superscript text',\n 'sub': 'Subscript text',\n 'span': 'Span element',\n 'small': 'Smaller text',\n 'big': 'Bigger text',\n 'address': 'Contact information',\n 'blockquote': 'Long quotation',\n 'q': 'Short quotation',\n 'cite': 'Citation',\n 'caption': 'Table caption',\n 'abbr': 'Abbreviated phrase',\n 'acronym': 'An acronym',\n 'var': 'Variable part of a text',\n 'dfn': 'Term',\n 'strike': 'Strikethrough text',\n 'del': 'Deleted text',\n 'ins': 'Inserted text',\n 'h1': 'Heading level 1',\n 'h2': 'Heading level 2',\n 'h3': 'Heading level 3',\n 'h4': 'Heading level 4',\n 'h5': 'Heading level 5',\n 'h6': 'Heading level 6',\n 'center': 'Centered text',\n 'select': 'List options',\n 'img': 'Image',\n 'input': 'Form element'\n },\n\n /**\n * Generates [data-translate] attribute's value\n * @param {Object} translationData\n * @param {String} location\n */\n composeTranslateAttr = function (translationData, location) {\n var obj = [{\n 'shown': translationData.shown,\n 'translated': translationData.translated,\n 'original': translationData.original,\n 'location': locations[location] || 'Text'\n }];\n\n return JSON.stringify(obj);\n },\n\n /**\n * Sets text for the element\n * @param {Object} el\n * @param {String} text\n */\n setText = function (el, text) {\n $(el).text(text);\n },\n\n /**\n * Sets [data-translate] attribute for the element\n * @param {Object} el - The element which is binded\n * @param {String} original - The original value of the element\n */\n setTranslateProp = function (el, original) {\n var location = $(el).prop('tagName').toLowerCase(),\n translated = $.mage.__(original),\n translationData = {\n shown: translated,\n translated: translated,\n original: original\n },\n translateAttr = composeTranslateAttr(translationData, location);\n\n $(el).attr('data-translate', translateAttr);\n\n setText(el, translationData.shown);\n },\n\n /**\n * Checks if node represents ko virtual node (nodeType === 8, nodeName === '#comment').\n *\n * @param {HTMLElement} node\n * @returns {Boolean}\n */\n isVirtualElement = function (node) {\n return node.nodeType === 8;\n },\n\n /**\n * Checks if it's real DOM element\n * in case of virtual element, returns span wrapper\n * @param {Object} el\n * @param {bool} isUpdate\n * @return {Object} el\n */\n getRealElement = function (el, isUpdate) {\n if (isVirtualElement(el)) {\n if (isUpdate) {\n return $(el).next('span');\n }\n\n return $('<span></span>').insertAfter(el);\n }\n\n return el;\n },\n\n /**\n * execute i18n binding\n * @param {Object} element\n * @param {Function} valueAccessor\n * @param {bool} isUpdate\n */\n execute = function (element, valueAccessor, isUpdate) {\n var original = ko.unwrap(valueAccessor() || ''),\n el = getRealElement(element, isUpdate),\n inlineTranslation = (module.config() || {}).inlineTranslation;\n\n if (inlineTranslation) {\n setTranslateProp(el, original);\n } else {\n setText(el, $.mage.__(original));\n }\n };\n\n /**\n * i18n binding\n * @property {Function} init\n * @property {Function} update\n */\n ko.bindingHandlers.i18n = {\n\n /**\n * init i18n binding\n * @param {Object} element\n * @param {Function} valueAccessor\n */\n init: function (element, valueAccessor) {\n execute(element, valueAccessor);\n },\n\n /**\n * update i18n binding\n * @param {Object} element\n * @param {Function} valueAccessor\n */\n update: function (element, valueAccessor) {\n execute(element, valueAccessor, true);\n }\n };\n\n ko.virtualElements.allowedBindings.i18n = true;\n\n renderer\n .addNode('translate', {\n binding: 'i18n'\n })\n .addAttribute('translate', {\n binding: 'i18n'\n });\n});\n","Magento_Ui/js/lib/registry/registry.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore'\n], function ($, _) {\n 'use strict';\n\n var privateData = new WeakMap();\n\n /**\n * Extracts private item storage associated\n * with a provided registry instance.\n *\n * @param {Object} container\n * @returns {Object}\n */\n function getItems(container) {\n return privateData.get(container).items;\n }\n\n /**\n * Extracts private requests array associated\n * with a provided registry instance.\n *\n * @param {Object} container\n * @returns {Array}\n */\n function getRequests(container) {\n return privateData.get(container).requests;\n }\n\n /**\n * Wrapper function used for convenient access to the elements.\n * See 'async' method for examples of usage and comparison\n * with a regular 'get' method.\n *\n * @param {(String|Object|Function)} name - Key of the requested element.\n * @param {Registry} registry - Instance of a registry\n * where to search for the element.\n * @param {(Function|String)} [method] - Optional callback function\n * or a name of the elements' method which\n * will be invoked when element is available in registry.\n * @returns {*}\n */\n function async(name, registry, method) {\n var args = _.toArray(arguments).slice(3);\n\n if (_.isString(method)) {\n registry.get(name, function (component) {\n component[method].apply(component, args);\n });\n } else if (_.isFunction(method)) {\n registry.get(name, method);\n } else if (!args.length) {\n return registry.get(name);\n }\n }\n\n /**\n * Checks that every property of the query object\n * is present and equal to the corresponding\n * property in target object.\n * Note that non-strict comparison is used.\n *\n * @param {Object} query - Query object.\n * @param {Object} target - Target object.\n * @returns {Boolean}\n */\n function compare(query, target) {\n var matches = true,\n index,\n keys,\n key;\n\n if (!_.isObject(query) || !_.isObject(target)) {\n return false;\n }\n\n keys = Object.getOwnPropertyNames(query);\n index = keys.length;\n\n while (matches && index--) {\n key = keys[index];\n\n /* eslint-disable eqeqeq */\n if (target[key] != query[key]) {\n matches = false;\n }\n\n /* eslint-enable eqeqeq */\n }\n\n return matches;\n }\n\n /**\n * Explodes incoming string into object if\n * string is defined as a set of key = value pairs.\n *\n * @param {(String|*)} query - String to be processed.\n * @returns {Object|*} Either created object or an unmodified incoming\n * value if conversion was not possible.\n * @example Sample conversions.\n * 'key = value, key2 = value2'\n * => {key: 'value', key2: 'value2'}\n */\n function explode(query) {\n var result = {},\n index,\n data;\n\n if (typeof query !== 'string' || !~query.indexOf('=')) {\n return query;\n }\n\n query = query.split(',');\n index = query.length;\n\n while (index--) {\n data = query[index].split('=');\n\n result[data[0].trim()] = data[1].trim();\n }\n\n return result;\n }\n\n /**\n * Extracts items from the provided data object\n * which matches specified search criteria.\n *\n * @param {Object} data - Data object where to perform a lookup.\n * @param {(String|Object|Function)} query - Search criteria.\n * @param {Boolean} findAll - Flag that defines whether to\n * search for all applicable items or to stop on a first found entry.\n * @returns {Array|Object|*}\n */\n function find(data, query, findAll) {\n var iterator,\n item;\n\n query = explode(query);\n\n if (typeof query === 'string') {\n item = data[query];\n\n if (findAll) {\n return item ? [item] : [];\n }\n\n return item;\n }\n\n iterator = !_.isFunction(query) ?\n compare.bind(null, query) :\n query;\n\n return findAll ?\n _.filter(data, iterator) :\n _.find(data, iterator);\n }\n\n /**\n * @constructor\n */\n function Registry() {\n var data = {\n items: {},\n requests: []\n };\n\n this._updateRequests = _.debounce(this._updateRequests.bind(this), 10);\n privateData.set(this, data);\n }\n\n Registry.prototype = {\n constructor: Registry,\n\n /**\n * Retrieves item from registry which matches specified search criteria.\n *\n * @param {(Object|String|Function|Array)} query - Search condition (see examples).\n * @param {Function} [callback] - Callback that will be invoked when\n * all of the requested items are available.\n * @returns {*}\n *\n * @example Requesting item by it's name.\n * var obj = {index: 'test', sample: true};\n *\n * registry.set('first', obj);\n * registry.get('first') === obj;\n * => true\n *\n * @example Requesting item with a specific properties.\n * registry.get('sample = 1, index = test') === obj;\n * => true\n * registry.get('sample = 0, index = foo') === obj;\n * => false\n *\n * @example Declaring search criteria as an object.\n * registry.get({sample: true}) === obj;\n * => true;\n *\n * @example Providing custom search handler.\n * registry.get(function (item) { return item.sample === true; }) === obj;\n * => true\n *\n * @example Sample asynchronous request declaration.\n * registry.get('index = test', function (item) {});\n *\n * @example Requesting multiple elements.\n * registry.set('second', {index: 'test2'});\n * registry.get(['first', 'second'], function (first, second) {});\n */\n get: function (query, callback) {\n if (typeof callback !== 'function') {\n return find(getItems(this), query);\n }\n\n this._addRequest(query, callback);\n },\n\n /**\n * Sets provided item to the registry.\n *\n * @param {String} id - Item's identifier.\n * @param {*} item - Item's data.\n * returns {Registry} Chainable.\n */\n set: function (id, item) {\n getItems(this)[id] = item;\n\n this._updateRequests();\n\n return this;\n },\n\n /**\n * Removes specified item from registry.\n * Note that search query is not applicable.\n *\n * @param {String} id - Item's identifier.\n * @returns {Registry} Chainable.\n */\n remove: function (id) {\n delete getItems(this)[id];\n\n return this;\n },\n\n /**\n * Retrieves a collection of elements that match\n * provided search criteria.\n *\n * @param {(Object|String|Function)} query - Search query.\n * See 'get' method for the syntax examples.\n * @returns {Array} Found elements.\n */\n filter: function (query) {\n return find(getItems(this), query, true);\n },\n\n /**\n * Checks that at least one element in collection\n * matches provided search criteria.\n *\n * @param {(Object|String|Function)} query - Search query.\n * See 'get' method for the syntax examples.\n * @returns {Boolean}\n */\n has: function (query) {\n return !!this.get(query);\n },\n\n /**\n * Checks that registry contains a provided item.\n *\n * @param {*} item - Item to be checked.\n * @returns {Boolean}\n */\n contains: function (item) {\n return _.contains(getItems(this), item);\n },\n\n /**\n * Extracts identifier of an item if it's present in registry.\n *\n * @param {*} item - Item whose identifier will be extracted.\n * @returns {String|Undefined}\n */\n indexOf: function (item) {\n return _.findKey(getItems(this), function (elem) {\n return item === elem;\n });\n },\n\n /**\n * Same as a 'get' method except that it returns\n * a promise object instead of invoking provided callback.\n *\n * @param {(String|Function|Object|Array)} query - Search query.\n * See 'get' method for the syntax examples.\n * @returns {jQueryPromise}\n */\n promise: function (query) {\n var defer = $.Deferred(),\n callback = defer.resolve.bind(defer);\n\n this.get(query, callback);\n\n return defer.promise();\n },\n\n /**\n * Creates a wrapper function over the provided search query\n * in order to provide somehow more convenient access to the\n * registry's items.\n *\n * @param {(String|Object|Function)} query - Search criteria.\n * See 'get' method for the syntax examples.\n * @returns {Function}\n *\n * @example Comparison with a 'get' method on retrieving items.\n * var module = registry.async('name');\n *\n * module();\n * => registry.get('name');\n *\n * @example Asynchronous request.\n * module(function (component) {});\n * => registry.get('name', function (component) {});\n *\n * @example Requesting item and invoking it's method with specified parameters.\n * module('trigger', true);\n * => registry.get('name', function (component) {\n * component.trigger(true);\n * });\n */\n async: function (query) {\n return async.bind(null, query, this);\n },\n\n /**\n * Creates new instance of a Registry.\n *\n * @returns {Registry} New instance.\n */\n create: function () {\n return new Registry;\n },\n\n /**\n * Adds new request to the queue or resolves it immediately\n * if all of the required items are available.\n *\n * @private\n * @param {(Object|String|Function|Array)} queries - Search criteria.\n * See 'get' method for the syntax examples.\n * @param {Function} callback - Callback that will be invoked when\n * all of the requested items are available.\n * @returns {Registry}\n */\n _addRequest: function (queries, callback) {\n var request;\n\n if (!Array.isArray(queries)) {\n queries = queries ? [queries] : [];\n }\n\n request = {\n queries: queries.map(explode),\n callback: callback\n };\n\n this._canResolve(request) ?\n this._resolveRequest(request) :\n getRequests(this).push(request);\n\n return this;\n },\n\n /**\n * Updates requests list resolving applicable items.\n *\n * @private\n * @returns {Registry} Chainable.\n */\n _updateRequests: function () {\n getRequests(this)\n .filter(this._canResolve, this)\n .forEach(this._resolveRequest, this);\n\n return this;\n },\n\n /**\n * Resolves provided request invoking it's callback\n * with items specified in query parameters.\n *\n * @private\n * @param {Object} request - Request object.\n * @returns {Registry} Chainable.\n */\n _resolveRequest: function (request) {\n var requests = getRequests(this),\n items = request.queries.map(this.get, this),\n index = requests.indexOf(request);\n\n request.callback.apply(null, items);\n\n if (~index) {\n requests.splice(index, 1);\n }\n\n return this;\n },\n\n /**\n * Checks if provided request can be resolved.\n *\n * @private\n * @param {Object} request - Request object.\n * @returns {Boolean}\n */\n _canResolve: function (request) {\n var queries = request.queries;\n\n return queries.every(this.has, this);\n }\n };\n\n return new Registry;\n});\n","Magento_Ui/js/lib/view/utils/dom-observer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'underscore',\n 'domReady!'\n], function ($, _) {\n 'use strict';\n\n var counter = 1,\n watchers,\n globalObserver,\n disabledNodes = [];\n\n watchers = {\n selectors: {},\n nodes: {}\n };\n\n /**\n * Checks if node represents an element node (nodeType === 1).\n *\n * @param {HTMLElement} node\n * @returns {Boolean}\n */\n function isElementNode(node) {\n return node.nodeType === 1;\n }\n\n /**\n * Extracts all child descendant\n * elements of a specified node.\n *\n * @param {HTMLElement} node\n * @returns {Array}\n */\n function extractChildren(node) {\n var children = node.querySelectorAll('*');\n\n return _.toArray(children);\n }\n\n /**\n * Extracts node identifier. If ID is not specified,\n * then it will be created for the provided node.\n *\n * @param {HTMLElement} node\n * @returns {Number}\n */\n function getNodeId(node) {\n var id = node._observeId;\n\n if (!id) {\n id = node._observeId = counter++;\n }\n\n return id;\n }\n\n /**\n * Invokes callback passing node to it.\n *\n * @param {HTMLElement} node\n * @param {Object} data\n */\n function trigger(node, data) {\n var id = getNodeId(node),\n ids = data.invoked;\n\n if (_.contains(ids, id)) {\n return;\n }\n\n data.callback(node);\n data.invoked.push(id);\n }\n\n /**\n * Adds node to the observer list.\n *\n * @param {HTMLElement} node\n * @returns {Object}\n */\n function createNodeData(node) {\n var nodes = watchers.nodes,\n id = getNodeId(node);\n\n nodes[id] = nodes[id] || {};\n\n return nodes[id];\n }\n\n /**\n * Returns data associated with a specified node.\n *\n * @param {HTMLElement} node\n * @returns {Object|Undefined}\n */\n function getNodeData(node) {\n var nodeId = node._observeId;\n\n return watchers.nodes[nodeId];\n }\n\n /**\n * Removes data associated with a specified node.\n *\n * @param {HTMLElement} node\n */\n function removeNodeData(node) {\n var nodeId = node._observeId;\n\n delete watchers.nodes[nodeId];\n }\n\n /**\n * Adds removal listener for a specified node.\n *\n * @param {HTMLElement} node\n * @param {Object} data\n */\n function addRemovalListener(node, data) {\n var nodeData = createNodeData(node);\n\n (nodeData.remove = nodeData.remove || []).push(data);\n }\n\n /**\n * Adds listener for the nodes which matches specified selector.\n *\n * @param {String} selector - CSS selector.\n * @param {Object} data\n */\n function addSelectorListener(selector, data) {\n var storage = watchers.selectors;\n\n (storage[selector] = storage[selector] || []).push(data);\n }\n\n /**\n * Calls handlers associated with an added node.\n * Adds listeners for the node removal.\n *\n * @param {HTMLElement} node - Added node.\n */\n function processAdded(node) {\n _.each(watchers.selectors, function (listeners, selector) {\n listeners.forEach(function (data) {\n if (!data.ctx.contains(node) || !$(node, data.ctx).is(selector)) {\n return;\n }\n\n if (data.type === 'add') {\n trigger(node, data);\n } else if (data.type === 'remove') {\n addRemovalListener(node, data);\n }\n });\n });\n }\n\n /**\n * Calls handlers associated with a removed node.\n *\n * @param {HTMLElement} node - Removed node.\n */\n function processRemoved(node) {\n var nodeData = getNodeData(node),\n listeners = nodeData && nodeData.remove;\n\n if (!listeners) {\n return;\n }\n\n listeners.forEach(function (data) {\n trigger(node, data);\n });\n\n removeNodeData(node);\n }\n\n /**\n * Removes all non-element nodes from provided array\n * and appends to it descendant elements.\n *\n * @param {Array} nodes\n * @returns {Array}\n */\n function formNodesList(nodes) {\n var result = [],\n children;\n\n nodes = _.toArray(nodes).filter(isElementNode);\n\n nodes.forEach(function (node) {\n result.push(node);\n\n children = extractChildren(node);\n result = result.concat(children);\n });\n\n return result;\n }\n\n /**\n * Collects all removed and added nodes from\n * mutation records into separate arrays\n * while removing duplicates between both types of changes.\n *\n * @param {Array} mutations - An array of mutation records.\n * @returns {Object} Object with 'removed' and 'added' nodes arrays.\n */\n function formChangesLists(mutations) {\n var removed = [],\n added = [];\n\n mutations.forEach(function (record) {\n removed = removed.concat(_.toArray(record.removedNodes));\n added = added.concat(_.toArray(record.addedNodes));\n });\n\n removed = removed.filter(function (node) {\n var addIndex = added.indexOf(node),\n wasAdded = !!~addIndex;\n\n if (wasAdded) {\n added.splice(addIndex, 1);\n }\n\n return !wasAdded;\n });\n\n return {\n removed: formNodesList(removed),\n added: formNodesList(added)\n };\n }\n\n /**\n * Verify if the DOM node is a child of a defined disabled node, if so we shouldn't observe provided mutation.\n *\n * @param {Object} mutation - a single mutation\n * @returns {Boolean}\n */\n function shouldObserveMutation(mutation) {\n var isDisabled;\n\n if (disabledNodes.length > 0) {\n // Iterate through the disabled nodes and determine if this mutation is occurring inside one of them\n isDisabled = _.find(disabledNodes, function (node) {\n return node === mutation.target || $.contains(node, mutation.target);\n });\n\n // If we find a matching node we should not observe the mutation\n return !isDisabled;\n }\n\n return true;\n }\n\n /**\n * Should we observe these mutations? Check the first and last mutation to determine if this is a disabled mutation,\n * we check both the first and last in case one has been removed from the DOM during the process of the mutation.\n *\n * @param {Array} mutations - An array of mutation records.\n * @returns {Boolean}\n */\n function shouldObserveMutations(mutations) {\n var firstMutation,\n lastMutation;\n\n if (mutations.length > 0) {\n firstMutation = mutations[0];\n lastMutation = mutations[mutations.length - 1];\n\n return shouldObserveMutation(firstMutation) && shouldObserveMutation(lastMutation);\n }\n\n return true;\n }\n\n globalObserver = new MutationObserver(function (mutations) {\n var changes;\n\n if (shouldObserveMutations(mutations)) {\n changes = formChangesLists(mutations);\n\n changes.removed.forEach(processRemoved);\n changes.added.forEach(processAdded);\n }\n });\n\n globalObserver.observe(document.body, {\n subtree: true,\n childList: true\n });\n\n return {\n /**\n * Disable a node from being observed by the mutations, you may want to disable specific aspects of the\n * application which are heavy on DOM changes. The observer running on some actions could cause significant\n * delays and degrade the performance of that specific part of the application exponentially.\n *\n * @param {HTMLElement} node - a HTML node within the document\n */\n disableNode: function (node) {\n disabledNodes.push(node);\n },\n\n /**\n * Adds listener for the appearance of nodes that matches provided\n * selector and which are inside of the provided context. Callback will be\n * also invoked on elements which a currently present.\n *\n * @param {String} selector - CSS selector.\n * @param {Function} callback - Function that will invoked when node appears.\n * @param {HTMLElement} [ctx=document.body] - Context inside of which to search for the node.\n */\n get: function (selector, callback, ctx) {\n var data,\n nodes;\n\n data = {\n ctx: ctx || document.body,\n type: 'add',\n callback: callback,\n invoked: []\n };\n\n nodes = $(selector, data.ctx).toArray();\n\n nodes.forEach(function (node) {\n trigger(node, data);\n });\n\n addSelectorListener(selector, data);\n },\n\n /**\n * Adds listener for the nodes removal.\n *\n * @param {(jQueryObject|HTMLElement|Array|String)} selector\n * @param {Function} callback - Function that will invoked when node is removed.\n * @param {HTMLElement} [ctx=document.body] - Context inside of which to search for the node.\n */\n remove: function (selector, callback, ctx) {\n var nodes = [],\n data;\n\n data = {\n ctx: ctx || document.body,\n type: 'remove',\n callback: callback,\n invoked: []\n };\n\n if (typeof selector === 'object') {\n nodes = !_.isUndefined(selector.length) ?\n _.toArray(selector) :\n [selector];\n } else if (_.isString(selector)) {\n nodes = $(selector, ctx).toArray();\n\n addSelectorListener(selector, data);\n }\n\n nodes.forEach(function (node) {\n addRemovalListener(node, data);\n });\n },\n\n /**\n * Removes listeners.\n *\n * @param {String} selector\n * @param {Function} [fn]\n */\n off: function (selector, fn) {\n var selectors = watchers.selectors,\n listeners = selectors[selector];\n\n if (selector && !fn) {\n delete selectors[selector];\n } else if (listeners && fn) {\n selectors[selector] = listeners.filter(function (data) {\n return data.callback !== fn;\n });\n }\n }\n };\n});\n","Magento_Ui/js/lib/view/utils/bindings.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'ko',\n 'jquery',\n 'underscore'\n], function (ko, $, _) {\n 'use strict';\n\n /**\n * Checks if provided value is a dom element.\n *\n * @param {*} node - Value to be checked.\n * @returns {Boolean}\n */\n function isDomElement(node) {\n return typeof node === 'object' && node.tagName && node.nodeType;\n }\n\n /**\n * Removes from the provided array all non-root nodes located inside\n * of the comment element as long as the closing comment tags.\n *\n * @param {(Array|ArrayLike)} nodes - An array of nodes to be processed.\n * @returns {Array}\n */\n function normalize(nodes) {\n var result;\n\n nodes = _.toArray(nodes);\n result = nodes.slice();\n\n nodes.forEach(function (node) {\n if (node.nodeType === 8) {\n result = !ko.virtualElements.hasBindingValue(node) ?\n _.without(result, node) :\n _.difference(result, ko.virtualElements.childNodes(node));\n }\n });\n\n return result;\n }\n\n /**\n * Extends binding context of each item in the collection.\n *\n * @param {...Object} extenders - Multiple extender objects to be applied to the context.\n * @returns {jQueryCollection} Chainable.\n */\n $.fn.extendCtx = function () {\n var nodes = normalize(this),\n extenders = _.toArray(arguments);\n\n nodes.forEach(function (node) {\n var ctx = ko.contextFor(node),\n data = [ctx].concat(extenders);\n\n _.extend.apply(_, data);\n });\n\n return this;\n };\n\n /**\n * Evaluates bindings specified in each DOM element of collection.\n *\n * @param {(HTMLElement|Object)} [ctx] - Context to use for bindings evaluation.\n * If not specified then current context of a collections' item will be used.\n * @returns {jQueryCollection} Chainable.\n */\n $.fn.applyBindings = function (ctx) {\n var nodes = normalize(this),\n nodeCtx;\n\n if (isDomElement(ctx)) {\n ctx = ko.contextFor(ctx);\n }\n\n nodes.forEach(function (node) {\n nodeCtx = ctx || ko.contextFor(node);\n\n ko.applyBindings(nodeCtx, node);\n });\n\n return this;\n };\n\n /**\n * Adds specified bindings to each DOM element in\n * collection and evaluates them with provided context.\n *\n * @param {(Object|Function)} data - Either bindings object or a function\n * which returns bindings data for each element in collection.\n * @param {(HTMLElement|Object)} [ctx] - Context to use for bindings evaluation.\n * If not specified then current context of a collections' item will be used.\n * @returns {jQueryCollection} Chainable.\n */\n $.fn.bindings = function (data, ctx) {\n var nodes = normalize(this),\n bindings = data,\n nodeCtx;\n\n if (isDomElement(ctx)) {\n ctx = ko.contextFor(ctx);\n }\n\n nodes.forEach(function (node) {\n nodeCtx = ctx || ko.contextFor(node);\n\n if (_.isFunction(data)) {\n bindings = data(nodeCtx, node);\n }\n\n ko.applyBindingsToNode(node, bindings, nodeCtx);\n });\n\n return this;\n };\n});\n","Magento_Ui/js/lib/view/utils/raf.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n 'use strict';\n\n var processMap = new WeakMap(),\n origRaf,\n raf;\n\n origRaf = window.requestAnimationFrame ||\n window.webkitRequestAnimationFrame ||\n window.mozRequestAnimationFrame ||\n window.onRequestAnimationFrame ||\n window.msRequestAnimationFrame ||\n function (callback) {\n if (typeof callback != 'function') {\n throw new Error('raf argument \"callback\" must be of type function');\n }\n window.setTimeout(callback, 1000 / 60);\n };\n\n /**\n * Creates new process object or extracts the\n * the existing one.\n *\n * @param {*} id - Process identifier.\n * @param {Number} fps - Required FPS count.\n * @returns {Object}\n */\n function getProcess(id, fps) {\n var process = processMap.get(id);\n\n if (!process) {\n process = {};\n processMap.set(id, process);\n }\n\n if (process.fps !== fps) {\n process.fps = fps;\n process.interval = 1000 / fps;\n process.update = Date.now();\n }\n\n return process;\n }\n\n /**\n * Proxy method which delegates call to the 'requestAnimationFrame'\n * function and optionally can keep track of the FPS with which\n * provided function is called.\n *\n * @param {Function} callback - Callback function to be passed to 'requestAnimationFrame'.\n * @param {Number} [fps] - If specified, will update FPS counter for the provided function.\n * @returns {Number|Boolean} ID of request or a flag which indicates\n * whether callback fits specified FPS.\n */\n raf = function (callback, fps) {\n var rafId = origRaf(callback);\n\n return fps ? raf.tick(callback, fps) : rafId;\n };\n\n /**\n * Updates FPS counter for the specified process\n * and returns a flag which indicates whether\n * counter value is equal or greater than the required FPS.\n *\n * @param {*} id - Process identifier.\n * @param {Number} fps - Required FPS count.\n * @returns {Boolean}\n */\n raf.tick = function (id, fps) {\n var process = getProcess(id, fps),\n now = Date.now(),\n delta = now - process.update,\n interval = process.interval;\n\n if (fps >= 60 || delta >= interval) {\n process.update = now - delta % interval;\n\n return true;\n }\n\n return false;\n };\n\n return raf;\n});\n","Magento_Ui/js/lib/view/utils/async.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'ko',\n 'jquery',\n 'underscore',\n 'uiRegistry',\n './dom-observer',\n 'Magento_Ui/js/lib/knockout/extender/bound-nodes',\n './bindings'\n], function (ko, $, _, registry, domObserver, boundedNodes) {\n 'use strict';\n\n /**\n * Checks if provided value is a dom element.\n *\n * @param {*} node - Value to be checked.\n * @returns {Boolean}\n */\n function isDomElement(node) {\n return typeof node === 'object' && node.tagName && node.nodeType;\n }\n\n /**\n * Parses provided string and extracts\n * component, context and selector data from it.\n *\n * @param {String} str - String to be processed.\n * @returns {Object} Data retrieved from string.\n *\n * @example Sample format.\n * '{{component}}:{{ctx}} -> {{selector}}'\n *\n * component - Name of component.\n * ctx - Selector of the root node upon which component is binded.\n * selector - Selector of DOM elements located\n * inside of a previously specified context.\n */\n function parseSelector(str) {\n var data = str.trim().split('->'),\n result = {},\n componentData;\n\n if (data.length === 1) {\n if (!~data[0].indexOf(':')) {\n result.selector = data[0];\n } else {\n componentData = data[0];\n }\n } else {\n componentData = data[0];\n result.selector = data[1];\n }\n\n if (componentData) {\n componentData = componentData.split(':');\n\n result.component = componentData[0];\n result.ctx = componentData[1];\n }\n\n _.each(result, function (value, key) {\n result[key] = value.trim();\n });\n\n return result;\n }\n\n /**\n * Internal method used to normalize argumnets passed\n * to 'async' module methods.\n *\n * @param {(String|Object)} selector\n * @param {(HTMLElement|Object|String)} [ctx]\n * @returns {Object}\n */\n function parseData(selector, ctx) {\n var data = {};\n\n if (arguments.length === 2) {\n data.selector = selector;\n\n if (isDomElement(ctx)) {\n data.ctx = ctx;\n } else {\n data.component = ctx;\n data.ctx = '*';\n }\n } else {\n data = _.isString(selector) ?\n parseSelector(selector) :\n selector;\n }\n\n return data;\n }\n\n /**\n * Creates promise that will be resolved\n * when requested component is registred.\n *\n * @param {String} name - Name of component.\n * @returns {jQueryPromise}\n */\n function waitComponent(name) {\n var deffer = $.Deferred();\n\n if (_.isString(name)) {\n registry.get(name, function (component) {\n deffer.resolve(component);\n });\n } else {\n deffer.resolve(name);\n }\n\n return deffer.promise();\n }\n\n /**\n * Creates listener for the nodes binded to provided component.\n *\n * @param {Object} data - Listener data.\n * @param {Object} component - Associated with nodes component.\n */\n function setRootListener(data, component) {\n boundedNodes.get(component, function (root) {\n if (!$(root).is(data.ctx || '*')) {\n return;\n }\n\n data.selector ?\n domObserver.get(data.selector, data.fn, root) :\n data.fn(root);\n });\n }\n\n /*eslint-disable no-unused-vars*/\n /**\n * Sets listener for the appearance of elements which\n * matches specified selector data.\n *\n * @param {(String|Object)} selector - Valid css selector or a string\n * in format acceptable by 'parseSelector' method or an object with\n * 'component', 'selector' and 'ctx' properties.\n * @param {(HTMLElement|Object|String)} [ctx] - Optional context parameter\n * which might be a DOM element, component instance or components' name.\n * @param {Function} fn - Callback that will be invoked\n * when required DOM element appears.\n *\n * @example\n * Creating listener of the 'span' nodes appearance,\n * located inside of 'div' nodes, which are binded to 'cms_page_listing' component:\n *\n * $.async('cms_page_listing:div -> span', function (node) {});\n *\n * @example Another syntaxes of the previous example.\n * $.async({\n * component: 'cms_page_listing',\n * ctx: 'div',\n * selector: 'span'\n * }, function (node) {});\n *\n * @example Listens for appearance of any child node inside of specified component.\n * $.async('> *', 'cms_page_lsiting', function (node) {});\n *\n * @example Listens for appearance of 'span' nodes inside of specific context.\n * $.async('span', document.getElementById('test'), function (node) {});\n */\n $.async = function (selector, ctx, fn) {\n var args = _.toArray(arguments),\n data = parseData.apply(null, _.initial(args));\n\n data.fn = _.last(args);\n\n if (data.component) {\n waitComponent(data.component)\n .then(setRootListener.bind(null, data));\n } else {\n domObserver.get(data.selector, data.fn, data.ctx);\n }\n };\n\n /*eslint-enable no-unused-vars*/\n\n _.extend($.async, {\n\n /*eslint-disable no-unused-vars*/\n /**\n * Returns collection of elements found by provided selector data.\n *\n * @param {(String|Object)} selector - See 'async' definition.\n * @param {(HTMLElement|Object|String)} [ctx] - See 'async' definition.\n * @returns {Array} An array of DOM elements.\n */\n get: function (selector, ctx) {\n var data = parseData.apply(null, arguments),\n component = data.component,\n nodes;\n\n if (!component) {\n return $(data.selector, data.ctx).toArray();\n } else if (_.isString(component)) {\n component = registry.get(component);\n }\n\n if (!component) {\n return [];\n }\n\n nodes = boundedNodes.get(component);\n nodes = $(nodes).filter(data.ctx).toArray();\n\n return data.selector ?\n $(data.selector, nodes).toArray() :\n nodes;\n },\n\n /*eslint-enable no-unused-vars*/\n\n /**\n * Sets removal listener of the specified nodes.\n *\n * @param {(HTMLElement|Array|ArrayLike)} nodes - Nodes whose removal to track.\n * @param {Function} fn - Callback that will be invoked when node is removed.\n */\n remove: function (nodes, fn) {\n domObserver.remove(nodes, fn);\n },\n\n parseSelector: parseSelector\n });\n\n return $;\n});\n","Magento_Ui/js/lib/logger/console-output-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n './levels-pool'\n], function (logLevels) {\n 'use strict';\n\n var levels = logLevels.getLevels();\n\n /**\n * @param {LogFormatter} formatter\n */\n function ConsoleOutputHandler(formatter) {\n /**\n * @protected\n * @type {LogFormatter}\n */\n this.formatter_ = formatter;\n }\n\n /**\n * Display data of the provided entry to the console.\n *\n * @param {LogEntry} entry - Entry to be displayed.\n */\n ConsoleOutputHandler.prototype.show = function (entry) {\n var displayString = this.formatter_.process(entry);\n\n switch (entry.level) {\n case levels.ERROR:\n console.error(displayString);\n break;\n\n case levels.WARN:\n console.warn(displayString);\n break;\n\n case levels.INFO:\n console.info(displayString);\n break;\n\n case levels.DEBUG:\n console.log(displayString);\n break;\n }\n };\n\n /**\n * Displays the array of entries.\n *\n * @param {Array<LogEntry>} entries\n */\n ConsoleOutputHandler.prototype.dump = function (entries) {\n entries.forEach(this.show, this);\n };\n\n return ConsoleOutputHandler;\n});\n","Magento_Ui/js/lib/logger/logger.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n './levels-pool'\n], function (logLevels) {\n 'use strict';\n\n var levels = logLevels.getLevels();\n\n /**\n * @param {LogOutputHandler} outputHandler\n * @param {LogEntryFactory} entryFactory\n */\n function Logger(outputHandler, entryFactory) {\n /**\n * An array of log entries.\n *\n * @protected\n * @type {Array<LogEntry>}\n */\n this.entries_ = [];\n\n /**\n * Current display level.\n *\n * @protected\n * @type {Number}\n */\n this.displayLevel_ = levels.ERROR;\n\n /**\n * An array of display criteria.\n *\n * @protected\n * @type {Array<LogCriteria>}\n */\n this.displayCriteria_ = [];\n\n /**\n * @protected\n * @type {LogEntryFactory}\n */\n this.entryFactory_ = entryFactory;\n\n /**\n * @protected\n * @type {Array<LogOutputHandler>}\n */\n this.outputHandlers_ = [outputHandler];\n\n this.addDisplayCriteria(this.matchesLevel_);\n }\n\n /**\n * Swaps current display level with the provided one.\n *\n * @param {Number} level - Level's code.\n */\n Logger.prototype.setDisplayLevel = function (level) {\n var levelName = logLevels.getNameByCode(level);\n\n if (!levelName) {\n throw new TypeError('The provided level is not defined in the levels list.');\n }\n\n this.displayLevel_ = level;\n };\n\n /**\n * Sets up the criteria by which log entries will be filtered out from the output.\n *\n * @param {LogCriteria} criteria\n */\n Logger.prototype.addDisplayCriteria = function (criteria) {\n this.displayCriteria_.push(criteria);\n };\n\n /**\n * Removes previously defined criteria.\n *\n * @param {LogCriteria} criteria\n */\n Logger.prototype.removeDisplayCriteria = function (criteria) {\n var index = this.displayCriteria_.indexOf(criteria);\n\n if (~index) {\n this.displayCriteria_.splice(index, 1);\n }\n };\n\n /**\n * @param {String} message\n * @param {Object} [messageData]\n * @returns {LogEntry}\n */\n Logger.prototype.error = function (message, messageData) {\n return this.log_(message, levels.ERROR, messageData);\n };\n\n /**\n * @param {String} message\n * @param {Object} [messageData]\n * @returns {LogEntry}\n */\n Logger.prototype.warn = function (message, messageData) {\n return this.log_(message, levels.WARN, messageData);\n };\n\n /**\n * @param {String} message\n * @param {Object} [messageData]\n * @returns {LogEntry}\n */\n Logger.prototype.info = function (message, messageData) {\n return this.log_(message, levels.INFO, messageData);\n };\n\n /**\n * @param {String} message\n * @param {Object} [messageData]\n * @returns {LogEntry}\n */\n Logger.prototype.debug = function (message, messageData) {\n return this.log_(message, levels.DEBUG, messageData);\n };\n\n /**\n * @protected\n * @param {String} message\n * @param {Number} level\n * @param {Object} [messageData]\n * @returns {LogEntry}\n */\n Logger.prototype.log_ = function (message, level, messageData) {\n var entry = this.createEntry_(message, level, messageData);\n\n this.entries_.push(entry);\n\n if (this.matchesCriteria_(entry)) {\n this.processOutput_(entry);\n }\n\n return entry;\n };\n\n /**\n * @protected\n * @param {String} message\n * @param {Number} level\n * @param {Object} [messageData]\n * @returns {LogEntry}\n */\n Logger.prototype.createEntry_ = function (message, level, messageData) {\n return this.entryFactory_.createEntry(message, level, messageData);\n };\n\n /**\n * Returns an array of log entries that have been added to the logger.\n *\n * @param {LogCriteria} [criteria] - Optional filter criteria.\n * @returns {Array<LogEntry>}\n */\n Logger.prototype.getEntries = function (criteria) {\n if (criteria) {\n return this.entries_.filter(criteria);\n }\n\n return this.entries_;\n };\n\n /**\n * @param {LogCriteria} [criteria]\n */\n Logger.prototype.dump = function (criteria) {\n var entries;\n\n if (!criteria) {\n criteria = this.matchesCriteria_;\n }\n\n entries = this.entries_.filter(criteria, this);\n\n this.outputHandlers_.forEach(function (handler) {\n handler.dump(entries);\n });\n };\n\n /**\n * @protected\n * @param {LogEntry} entry\n */\n Logger.prototype.processOutput_ = function (entry) {\n this.outputHandlers_.forEach(function (handler) {\n handler.show(entry);\n });\n };\n\n /**\n * @protected\n * @param {LogEntry} entry\n * @returns {Boolean}\n */\n Logger.prototype.matchesCriteria_ = function (entry) {\n return this.displayCriteria_.every(function (criteria) {\n return criteria.call(this, entry);\n }, this);\n };\n\n /**\n * Checks that the level of provided entry passes the \"displayLevel_\" threshold.\n *\n * @protected\n * @param {LogEntry} entry - Entry to be checked.\n * @returns {Boolean}\n */\n Logger.prototype.matchesLevel_ = function (entry) {\n return entry.level <= this.displayLevel_;\n };\n\n return Logger;\n});\n","Magento_Ui/js/lib/logger/console-logger.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n './logger',\n './entry-factory',\n './console-output-handler',\n './formatter',\n './message-pool',\n './levels-pool',\n 'Magento_Ui/js/lib/core/storage/local',\n 'underscore',\n './logger-utils'\n], function (Logger, entryFactory, ConsoleHandler, Formatter, messagePoll, levelsPoll, storage, _, LoggerUtils) {\n 'use strict';\n\n var STORAGE_NAMESPACE = 'CONSOLE_LOGGER';\n\n /**\n * Singleton Logger's sub-class instance of which is configured to display its\n * messages to the console. It also provides the support of predefined messages\n * and persists its display level.\n */\n function ConsoleLogger() {\n var formatter = new Formatter(),\n consoleHandler = new ConsoleHandler(formatter),\n savedLevel = storage.get(STORAGE_NAMESPACE),\n utils = new LoggerUtils(this);\n\n Logger.call(this, consoleHandler, entryFactory);\n\n if (savedLevel) {\n this.displayLevel_ = savedLevel;\n }\n\n this.utils = utils;\n this.messages = messagePoll;\n this.levels = levelsPoll.getLevels();\n }\n\n _.extend(ConsoleLogger, Logger);\n\n ConsoleLogger.prototype = Object.create(Logger.prototype);\n ConsoleLogger.prototype.constructor = ConsoleLogger;\n\n /**\n * Overrides parent method to save the provided display level.\n *\n * @override\n */\n ConsoleLogger.prototype.setDisplayLevel = function (level) {\n Logger.prototype.setDisplayLevel.call(this, level);\n\n storage.set(STORAGE_NAMESPACE, level);\n };\n\n /**\n * Adds the support of predefined messages.\n *\n * @protected\n * @override\n */\n ConsoleLogger.prototype.createEntry_ = function (message, level, data) {\n var code;\n\n if (messagePoll.hasMessage(message)) {\n data = data || {};\n code = message;\n message = messagePoll.getMessage(code);\n\n data.messageCode = code;\n }\n\n return Logger.prototype.createEntry_.call(this, message, level, data);\n };\n\n return new ConsoleLogger();\n});\n","Magento_Ui/js/lib/logger/entry.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n './levels-pool'\n], function (logLevels) {\n 'use strict';\n\n /**\n * @param {String} message\n * @param {Number} level\n * @param {Object} [data]\n */\n function LogEntry(message, level, data) {\n /**\n * @readonly\n * @type {Number}\n */\n this.timestamp = Date.now();\n\n /**\n * @readonly\n * @type {Number}\n */\n this.level = level;\n\n /**\n * @readonly\n * @type {String}\n */\n this.levelName = logLevels.getNameByCode(level);\n\n /**\n * @readonly\n * @type {Object}\n */\n this.data = data;\n\n /**\n * @readonly\n * @type {String}\n */\n this.message = message;\n }\n\n return LogEntry;\n});\n","Magento_Ui/js/lib/logger/levels-pool.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore'\n], function (_) {\n 'use strict';\n\n var LEVELS,\n CODE_MAP;\n\n LEVELS = {\n NONE: 0,\n ERROR: 1,\n WARN: 2,\n INFO: 3,\n DEBUG: 4,\n ALL: 5\n };\n\n CODE_MAP = _.invert(LEVELS);\n\n return {\n /**\n * Returns the list of available log levels.\n *\n * @returns {Object}\n */\n getLevels: function () {\n return LEVELS;\n },\n\n /**\n * Returns name of the log level that matches to the provided code.\n *\n * @returns {String}\n */\n getNameByCode: function (code) {\n return CODE_MAP[code];\n }\n };\n});\n","Magento_Ui/js/lib/logger/formatter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'moment',\n 'mage/utils/template'\n], function (moment, mageTemplate) {\n 'use strict';\n\n /**\n * @param {String} dateFormat\n * @param {String} template\n */\n function LogFormatter(dateFormat, template) {\n /**\n * @protected\n * @type {String}\n */\n this.dateFormat_ = 'YYYY-MM-DD hh:mm:ss';\n\n /**\n * @protected\n * @type {String}\n */\n this.template_ = '[${ $.date }] [${ $.entry.levelName }] ${ $.message }';\n\n if (dateFormat) {\n this.dateFormat_ = dateFormat;\n }\n\n if (template) {\n this.template_ = template;\n }\n }\n\n /**\n * @param {LogEntry} entry\n * @returns {String}\n */\n LogFormatter.prototype.process = function (entry) {\n var message = mageTemplate.template(entry.message, entry.data),\n date = moment(entry.timestamp).format(this.dateFormat_);\n\n return mageTemplate.template(this.template_, {\n date: date,\n entry: entry,\n message: message\n });\n };\n\n return LogFormatter;\n});\n","Magento_Ui/js/lib/logger/entry-factory.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n './entry'\n], function (LogEntry) {\n 'use strict';\n\n return {\n /**\n * @param {String} message\n * @param {Number} level\n * @param {Object} [messageData]\n * @returns {LogEntry}\n */\n createEntry: function (message, level, messageData) {\n return new LogEntry(message, level, messageData);\n }\n };\n});\n","Magento_Ui/js/lib/logger/message-pool.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(function () {\n 'use strict';\n\n var MESSAGES = {\n templateStartLoading:\n 'The \"${ $.template }\" template requested by the \"${$.component}\" component started loading.',\n templateLoadedFromServer:\n 'The \"${ $.template }\" template requested by the \"${$.component}\" component was loaded from server.\"',\n templateLoadedFromCache:\n 'The \"${ $.template }\" template requested by the \"${$.component}\" component was loaded from cache.\"',\n templateLoadingFail: 'Failed to load the \"${ $.template }\" template requested by \"${$.component}\".',\n componentStartInitialization:\n 'Component \"${$.component}\" start initialization with instance name \"${$.componentName}\".',\n componentStartLoading: ' Started loading the \"${$.component}\" component.',\n componentFinishLoading: 'The \"${$.component}\" component was loaded.',\n componentLoadingFail: 'Failed to load the \"${$.component}\" component.',\n depsLoadingFail: 'Could not get the declared \"${$.deps}\" dependency for the \"${$.component}\" instance.',\n depsStartRequesting: 'Requesting the \"${$.deps}\" dependency for the \"${$.component}\" instance.',\n depsFinishRequesting: 'The \"${$.deps}\" dependency for the \"${$.component}\" instance was received.',\n requestingComponent: 'Requesting the \"${$.component}\" component.',\n requestingComponentIsLoaded: 'The requested \"${$.component}\" component was received.',\n requestingComponentIsFailed: 'Could not get the requested \"${$.component}\" component.'\n };\n\n return {\n /**\n * Returns message that matches the provided code.\n *\n * @param {String} code - Message's identifier\n * @returns {String}\n */\n getMessage: function (code) {\n return MESSAGES[code];\n },\n\n /**\n * Adds a new message to the poll.\n *\n * @param {String} code - Message's identifier.\n * @param {String} message - Text of the message\n */\n addMessage: function (code, message) {\n MESSAGES[code] = message;\n },\n\n /**\n * Tells whether message with provide code exists in the poll.\n *\n * @param {String} code - Message's identifier.\n * @returns {Boolean}\n */\n hasMessage: function (code) {\n return MESSAGES.hasOwnProperty(code);\n }\n };\n});\n","Magento_Ui/js/lib/logger/logger-utils.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n 'use strict';\n\n /**\n * Utils methods for logger\n * @param {Logger} logger\n */\n function LogUtils(logger) {\n this.logger = logger;\n\n }\n\n /**\n * Method for logging asynchronous operations\n * @param {Promise} promise\n * @param {Object} config\n */\n LogUtils.prototype.asyncLog = function (promise, config) {\n var levels,\n messages,\n wait;\n\n config = config || {};\n levels = config.levels || this.createLevels();\n messages = config.messages || this.createMessages();\n wait = config.wait || 5000;\n\n this.logger[levels.requested](messages.requested, config.data);\n setTimeout(function () {\n promise.state() === 'pending' ?\n this.logger[levels.failed](messages.failed, config.data) :\n this.logger[levels.loaded](messages.loaded, config.data);\n }.bind(this), wait);\n };\n\n /**\n * Method that creates object of messages\n * @param {String} requested - log message that showing that request for class is started\n * @param {String} loaded - log message that show when requested class is loaded\n * @param {String} failed - log message that show when requested class is failed\n * @returns {Object}\n */\n LogUtils.prototype.createMessages = function (requested, loaded, failed) {\n return {\n requested: requested || '',\n loaded: loaded || '',\n failed: failed || ''\n };\n };\n\n /**\n * Method that creates object of log levels\n * @param {String} requested - log message that showing that request for class is started\n * @param {String} loaded - log message that show when requested class is loaded\n * @param {String} failed - log message that show when requested class is failed\n * @returns {Object}\n */\n LogUtils.prototype.createLevels = function (requested, loaded, failed) {\n return {\n requested: requested || 'info',\n loaded: loaded || 'info',\n failed: failed || 'warn'\n };\n };\n\n return LogUtils;\n});\n","Magento_Ui/js/lib/core/events.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'underscore'\n], function (ko, _) {\n 'use strict';\n\n var eventsMap = new WeakMap();\n\n /**\n * Returns events map or a specific event\n * data associated with a provided object.\n *\n * @param {Object} obj - Key in the events weakmap.\n * @param {String} [name] - Name of the event.\n * @returns {Map|Array|Boolean}\n */\n function getEvents(obj, name) {\n var events = eventsMap.get(obj);\n\n if (!events) {\n return false;\n }\n\n return name ? events.get(name) : events;\n }\n\n /**\n * Adds new event handler.\n *\n * @param {Object} obj - Key in the events weakmap.\n * @param {String} ns - Callback namespace.\n * @param {Function} callback - Event callback.\n * @param {String} name - Name of the event.\n */\n function addHandler(obj, ns, callback, name) {\n var events = getEvents(obj),\n observable,\n data;\n\n observable = !ko.isObservable(obj[name]) ?\n ko.getObservable(obj, name) :\n obj[name];\n\n if (observable) {\n observable.subscribe(callback);\n\n return;\n }\n\n if (!events) {\n events = new Map();\n\n eventsMap.set(obj, events);\n }\n\n data = {\n callback: callback,\n ns: ns\n };\n\n events.has(name) ?\n events.get(name).push(data) :\n events.set(name, [data]);\n }\n\n /**\n * Invokes provided callbacks with a specified arguments.\n *\n * @param {Array} handlers\n * @param {Array} args\n * @returns {Boolean}\n */\n function trigger(handlers, args) {\n var bubble = true,\n callback;\n\n handlers.forEach(function (handler) {\n callback = handler.callback;\n\n if (callback.apply(null, args) === false) {\n bubble = false;\n }\n });\n\n return bubble;\n }\n\n return {\n\n /**\n * Calls callback when name event is triggered.\n * @param {String} events\n * @param {Function} callback\n * @param {Function} ns\n * @return {Object} reference to this\n */\n on: function (events, callback, ns) {\n var iterator;\n\n if (arguments.length < 2) {\n ns = callback;\n }\n\n iterator = addHandler.bind(null, this, ns);\n\n _.isObject(events) ?\n _.each(events, iterator) :\n iterator(callback, events);\n\n return this;\n },\n\n /**\n * Removed callback from listening to target event\n * @param {String} ns\n * @return {Object} reference to this\n */\n off: function (ns) {\n var storage = getEvents(this);\n\n if (!storage) {\n return this;\n }\n\n storage.forEach(function (handlers, name) {\n handlers = handlers.filter(function (handler) {\n return !ns ? false : handler.ns !== ns;\n });\n\n handlers.length ?\n storage.set(name, handlers) :\n storage.delete(name);\n });\n\n return this;\n },\n\n /**\n * Triggers event and executes all attached callbacks.\n *\n * @param {String} name - Name of the event to be triggered.\n * @returns {Boolean}\n */\n trigger: function (name) {\n var handlers,\n args;\n\n handlers = getEvents(this, name),\n args = _.toArray(arguments).slice(1);\n\n if (!handlers || !name) {\n return true;\n }\n\n return trigger(handlers, args);\n }\n };\n});\n","Magento_Ui/js/lib/core/class.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'underscore',\n 'mageUtils',\n 'mage/utils/wrapper'\n], function (_, utils, wrapper) {\n 'use strict';\n\n var Class;\n\n /**\n * Returns property of an object if\n * it's his own property.\n *\n * @param {Object} obj - Object whose property should be retrieved.\n * @param {String} prop - Name of the property.\n * @returns {*} Value of the property or false.\n */\n function getOwn(obj, prop) {\n return _.isObject(obj) && obj.hasOwnProperty(prop) && obj[prop];\n }\n\n /**\n * Creates constructor function which allows\n * initialization without usage of a 'new' operator.\n *\n * @param {Object} protoProps - Prototypal properties of a new constructor.\n * @param {Function} constructor\n * @returns {Function} Created constructor.\n */\n function createConstructor(protoProps, constructor) {\n var UiClass = constructor;\n\n if (!UiClass) {\n\n /**\n * Default constructor function.\n */\n UiClass = function () {\n var obj = this;\n\n if (!_.isObject(obj) || Object.getPrototypeOf(obj) !== UiClass.prototype) {\n obj = Object.create(UiClass.prototype);\n }\n\n obj.initialize.apply(obj, arguments);\n\n return obj;\n };\n }\n\n UiClass.prototype = protoProps;\n UiClass.prototype.constructor = UiClass;\n\n return UiClass;\n }\n\n Class = createConstructor({\n\n /**\n * Entry point to the initialization of constructor's instance.\n *\n * @param {Object} [options={}]\n * @returns {Class} Chainable.\n */\n initialize: function (options) {\n this.initConfig(options);\n\n return this;\n },\n\n /**\n * Recursively extends data specified in constructors' 'defaults'\n * property with provided options object. Evaluates resulting\n * object using string templates (see: mage/utils/template.js).\n *\n * @param {Object} [options={}]\n * @returns {Class} Chainable.\n */\n initConfig: function (options) {\n var defaults = this.constructor.defaults,\n config = utils.extend({}, defaults, options || {}),\n ignored = config.ignoreTmpls || {},\n cached = utils.omit(config, ignored);\n\n config = utils.template(config, this, false, true);\n\n _.each(cached, function (value, key) {\n utils.nested(config, key, value);\n });\n\n return _.extend(this, config);\n }\n });\n\n _.extend(Class, {\n defaults: {\n ignoreTmpls: {\n templates: true\n }\n },\n\n /**\n * Creates new constructor based on a current prototype properties,\n * extending them with properties specified in 'exender' object.\n *\n * @param {Object} [extender={}]\n * @returns {Function} New constructor.\n */\n extend: function (extender) {\n var parent = this,\n parentProto = parent.prototype,\n childProto = Object.create(parentProto),\n child = createConstructor(childProto, getOwn(extender, 'constructor')),\n defaults;\n\n extender = extender || {};\n defaults = extender.defaults;\n\n delete extender.defaults;\n\n _.each(extender, function (method, name) {\n childProto[name] = wrapper.wrapSuper(parentProto[name], method);\n });\n\n child.defaults = utils.extend({}, parent.defaults || {});\n\n if (defaults) {\n utils.extend(child.defaults, defaults);\n extender.defaults = defaults;\n }\n\n return _.extend(child, {\n __super__: parentProto,\n extend: parent.extend\n });\n }\n });\n\n return Class;\n});\n","Magento_Ui/js/lib/core/collection.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'mageUtils',\n 'uiRegistry',\n 'uiElement'\n], function (_, utils, registry, Element) {\n 'use strict';\n\n /**\n * Removes non plain object items from the specified array.\n *\n * @param {Array} container - Array whose value should be filtered.\n * @returns {Array}\n */\n function compact(container) {\n return _.values(container).filter(utils.isObject);\n }\n\n /**\n * Defines index of an item in a specified container.\n *\n * @param {*} item - Item whose index should be defined.\n * @param {Array} container - Container upon which to perform search.\n * @returns {Number}\n */\n function _findIndex(item, container) {\n var index = _.findKey(container, function (value) {\n return value === item;\n });\n\n if (typeof index === 'undefined') {\n index = _.findKey(container, function (value) {\n return value && value.name === item;\n });\n }\n\n return typeof index === 'undefined' ? -1 : index;\n }\n\n /**\n * Inserts specified item into container at a specified position.\n *\n * @param {*} item - Item to be inserted into container.\n * @param {Array} container - Container of items.\n * @param {*} [position=-1] - Position at which item should be inserted.\n * Position can represent:\n * - specific index in container\n * - item which might already be present in container\n * - structure with one of these properties: after, before\n * @returns {Boolean|*}\n * - true if element has changed its' position\n * - false if nothing has changed\n * - inserted value if it wasn't present in container\n */\n function _insertAt(item, container, position) {\n var currentIndex = _findIndex(item, container),\n newIndex,\n target;\n\n if (typeof position === 'undefined') {\n position = -1;\n } else if (typeof position === 'string') {\n position = isNaN(+position) ? position : +position;\n }\n\n newIndex = position;\n\n if (~currentIndex) {\n target = container.splice(currentIndex, 1)[0];\n\n if (typeof item === 'string') {\n item = target;\n }\n }\n\n if (typeof position !== 'number') {\n target = position.after || position.before || position;\n\n newIndex = _findIndex(target, container);\n\n if (~newIndex && (position.after || newIndex >= currentIndex)) {\n newIndex++;\n }\n }\n\n if (newIndex < 0) {\n newIndex += container.length + 1;\n }\n\n container[newIndex] ?\n container.splice(newIndex, 0, item) :\n container[newIndex] = item;\n\n return !~currentIndex ? item : currentIndex !== newIndex;\n }\n\n return Element.extend({\n defaults: {\n template: 'ui/collection',\n _elems: [],\n ignoreTmpls: {\n childDefaults: true\n }\n },\n\n /**\n * Initializes observable properties.\n *\n * @returns {Model} Chainable.\n */\n initObservable: function () {\n this._super()\n .observe({\n elems: []\n });\n\n return this;\n },\n\n /**\n * Called when another element was added to current component.\n *\n * @param {Object} elem - Instance of an element that was added.\n * @returns {Collection} Chainable.\n */\n initElement: function (elem) {\n elem.initContainer(this);\n\n return this;\n },\n\n /**\n * Returns instance of a child found by provided index.\n *\n * @param {String} index - Index of a child.\n * @returns {Object}\n */\n getChild: function (index) {\n return _.findWhere(this.elems(), {\n index: index\n });\n },\n\n /**\n * Requests specified components to insert\n * them into 'elems' array starting from provided position.\n *\n * @param {(String|Array)} elems - Name of the component to insert.\n * @param {Number} [position=-1] - Position at which to insert elements.\n * @returns {Collection} Chainable.\n */\n insertChild: function (elems, position) {\n var container = this._elems,\n insert = this._insert.bind(this),\n update;\n\n if (!Array.isArray(elems)) {\n elems = [elems];\n }\n\n elems.map(function (item) {\n return item.elem ?\n _insertAt(item.elem, container, item.position) :\n _insertAt(item, container, position);\n }).forEach(function (item) {\n if (item === true) {\n update = true;\n } else if (_.isString(item)) {\n registry.get(item, insert);\n } else if (utils.isObject(item)) {\n insert(item);\n }\n });\n\n if (update) {\n this._updateCollection();\n }\n\n return this;\n },\n\n /**\n * Removes specified child from collection.\n *\n * @param {(Object|String)} elem - Child or index of a child to be removed.\n * @param {Boolean} skipUpdate - skip collection update when element to be destroyed.\n *\n * @returns {Collection} Chainable.\n */\n removeChild: function (elem, skipUpdate) {\n if (_.isString(elem)) {\n elem = this.getChild(elem);\n }\n\n if (elem) {\n utils.remove(this._elems, elem);\n\n if (!skipUpdate) {\n this._updateCollection();\n }\n }\n\n return this;\n },\n\n /**\n * Destroys collection children with its' elements.\n */\n destroyChildren: function () {\n this.elems.each(function (elem) {\n elem.destroy(true);\n });\n\n this._updateCollection();\n },\n\n /**\n * Clear data. Call method \"clear\"\n * in child components\n *\n * @returns {Object} Chainable.\n */\n clear: function () {\n var elems = this.elems();\n\n _.each(elems, function (elem) {\n if (_.isFunction(elem.clear)) {\n elem.clear();\n }\n }, this);\n\n return this;\n },\n\n /**\n * Checks if specified child exists in collection.\n *\n * @param {String} index - Index of a child.\n * @returns {Boolean}\n */\n hasChild: function (index) {\n return !!this.getChild(index);\n },\n\n /**\n * Creates 'async' wrapper for the specified child\n * using uiRegistry 'async' method and caches it\n * in a '_requested' components object.\n *\n * @param {String} index - Index of a child.\n * @returns {Function} Async module wrapper.\n */\n requestChild: function (index) {\n var name = this.formChildName(index);\n\n return this.requestModule(name);\n },\n\n /**\n * Creates complete child name based on a provided index.\n *\n * @param {String} index - Index of a child.\n * @returns {String}\n */\n formChildName: function (index) {\n return this.name + '.' + index;\n },\n\n /**\n * Retrieves requested region.\n * Creates region if it was not created yet\n *\n * @returns {ObservableArray}\n */\n getRegion: function (name) {\n var regions = this.regions = this.regions || {};\n\n if (!regions[name]) {\n regions[name] = [];\n\n this.observe.call(regions, name);\n }\n\n return regions[name];\n },\n\n /**\n * Checks if the specified region has any elements\n * associated with it.\n *\n * @param {String} name\n * @returns {Boolean}\n */\n regionHasElements: function (name) {\n var region = this.getRegion(name);\n\n return region().length > 0;\n },\n\n /**\n * Replaces specified regions' data with a provided one.\n * Creates region if it was not created yet.\n *\n * @param {Array} items - New regions' data.\n * @param {String} name - Name of the region.\n * @returns {Collection} Chainable.\n */\n updateRegion: function (items, name) {\n this.getRegion(name)(items);\n\n return this;\n },\n\n /**\n * Destroys collection along with its' elements.\n */\n destroy: function () {\n this._super();\n\n this.elems.each('destroy');\n },\n\n /**\n * Inserts provided component into 'elems' array at a specified position.\n * @private\n *\n * @param {Object} elem - Element to insert.\n */\n _insert: function (elem) {\n var index = _.findKey(this._elems, function (value) {\n return value === elem.name;\n });\n\n if (typeof index !== 'undefined') {\n this._elems[index] = elem;\n }\n\n this._updateCollection()\n .initElement(elem);\n },\n\n /**\n * Synchronizes multiple elements arrays with a core '_elems' container.\n * Performs elemets grouping by theirs 'displayArea' property.\n * @private\n *\n * @returns {Collection} Chainable.\n */\n _updateCollection: function () {\n var _elems = compact(this._elems),\n grouped;\n\n grouped = _elems.filter(function (elem) {\n return elem.displayArea && _.isString(elem.displayArea);\n });\n grouped = _.groupBy(grouped, 'displayArea');\n\n _.each(grouped, this.updateRegion, this);\n\n _.each(this.regions, function (items) {\n var hasObsoleteComponents = items().length && !_.intersection(_elems, items()).length;\n\n if (hasObsoleteComponents) {\n items.removeAll();\n }\n });\n\n this.elems(_elems);\n\n return this;\n },\n\n /**\n * Tries to call specified method of a current component,\n * otherwise delegates attempt to its' children.\n *\n * @param {String} target - Name of the method.\n * @param {...*} parameters - Arguments that will be passed to method.\n * @returns {*} Result of the method calls.\n */\n delegate: function (target) {\n var args = _.toArray(arguments);\n\n target = this[target];\n\n if (_.isFunction(target)) {\n return target.apply(this, args.slice(1));\n }\n\n return this._delegate(args);\n },\n\n /**\n * Calls 'delegate' method of all of it's children components.\n * @private\n *\n * @param {Array} args - An array of arguments to pass to the next delegation call.\n * @returns {Array} An array of delegation results.\n */\n _delegate: function (args) {\n var result;\n\n result = this.elems.map(function (elem) {\n var target;\n\n if (!_.isFunction(elem.delegate)) {\n target = elem[args[0]];\n\n if (_.isFunction(target)) {\n return target.apply(elem, args.slice(1));\n }\n } else {\n return elem.delegate.apply(elem, args);\n }\n });\n\n return _.flatten(result);\n }\n });\n});\n","Magento_Ui/js/lib/core/storage/local.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'underscore',\n 'uiRegistry',\n 'mageUtils',\n 'uiEvents'\n], function (_, registry, utils, EventsBus) {\n 'use strict';\n\n var root = 'appData',\n localStorage,\n hasSupport,\n storage;\n\n /**\n * Flag which indicates whether localStorage is supported.\n */\n hasSupport = (function () {\n var key = '_storageSupported';\n\n try {\n localStorage = window.localStorage;\n localStorage.setItem(key, 'true');\n\n if (localStorage.getItem(key) === 'true') {\n localStorage.removeItem(key);\n\n return true;\n }\n\n return false;\n } catch (e) {\n return false;\n }\n })();\n\n if (!hasSupport) {\n localStorage = {\n _data: {},\n\n /**\n * Sets value of the specified item.\n *\n * @param {String} key - Key of the property.\n * @param {*} value - Properties' value.\n */\n setItem: function (key, value) {\n this._data[key] = value + '';\n },\n\n /**\n * Retrieves specified item.\n *\n * @param {String} key - Key of the property to be retrieved.\n */\n getItem: function (key) {\n return this._data[key];\n },\n\n /**\n * Removes specified item.\n *\n * @param {String} key - Key of the property to be removed.\n */\n removeItem: function (key) {\n delete this._data[key];\n },\n\n /**\n * Removes all items.\n */\n clear: function () {\n this._data = {};\n }\n };\n }\n\n /**\n * Extracts and parses data stored in localStorage by the\n * key specified in 'root' variable.\n *\n * @returns {Object}\n */\n function getRoot() {\n var data = localStorage.getItem(root),\n result = {};\n\n if (!_.isNull(data) && typeof data != 'undefined') {\n result = JSON.parse(data);\n }\n\n return result;\n }\n\n /**\n * Writes provided data to the localStorage.\n *\n * @param {*} data - Data to be stored.\n */\n function setRoot(data) {\n localStorage.setItem(root, JSON.stringify(data));\n }\n\n /**\n * Provides methods to work with a localStorage\n * as a single nested structure.\n */\n storage = _.extend({\n\n /**\n * Retrieves value of the specified property.\n *\n * @param {String} path - Path to the property.\n *\n * @example Retrieving data.\n * localStorage =>\n * 'appData' => '\n * \"one\": {\"two\": \"three\"}\n * '\n * storage.get('one.two')\n * => \"three\"\n *\n * storage.get('one')\n * => {\"two\": \"three\"}\n */\n get: function (path) {\n var data = getRoot();\n\n return utils.nested(data, path);\n },\n\n /**\n * Sets specified data to the localStorage.\n *\n * @param {String} path - Path of the property.\n * @param {*} value - Value of the property.\n *\n * @example Setting data.\n * storage.set('one.two', 'four');\n * => localStorage =>\n * 'appData' => '\n * \"one\": {\"two\": \"four\"}\n * '\n */\n set: function (path, value) {\n var data = getRoot();\n\n utils.nested(data, path, value);\n\n setRoot(data);\n },\n\n /**\n * Removes specified data from the localStorage.\n *\n * @param {String} path - Path to the property that should be removed.\n *\n * @example Removing data.\n * storage.remove('one.two', 'four');\n * => localStorage =>\n * 'appData' => '\n * \"one\": {}\n * '\n */\n remove: function (path) {\n var data = getRoot();\n\n utils.nestedRemove(data, path);\n\n setRoot(data);\n }\n }, EventsBus);\n\n registry.set('localStorage', storage);\n\n return storage;\n});\n","Magento_Ui/js/lib/core/element/element.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'ko',\n 'underscore',\n 'mageUtils',\n 'uiRegistry',\n 'uiEvents',\n 'uiClass',\n './links',\n '../storage/local'\n], function (ko, _, utils, registry, Events, Class, links) {\n 'use strict';\n\n var Element;\n\n /**\n * Creates observable property using knockouts'\n * 'observableArray' or 'observable' methods,\n * depending on a type of 'value' parameter.\n *\n * @param {Object} obj - Object to whom property belongs.\n * @param {String} key - Key of the property.\n * @param {*} value - Initial value.\n */\n function observable(obj, key, value) {\n var method = Array.isArray(value) ? 'observableArray' : 'observable';\n\n if (_.isFunction(obj[key]) && !ko.isObservable(obj[key])) {\n return;\n }\n\n if (ko.isObservable(value)) {\n value = value();\n }\n\n ko.isObservable(obj[key]) ?\n obj[key](value) :\n obj[key] = ko[method](value);\n }\n\n /**\n * Creates observable property using 'track' method.\n *\n * @param {Object} obj - Object to whom property belongs.\n * @param {String} key - Key of the property.\n * @param {*} value - Initial value.\n */\n function accessor(obj, key, value) {\n if (_.isFunction(obj[key]) || ko.isObservable(obj[key])) {\n return;\n }\n\n obj[key] = value;\n\n if (!ko.es5.isTracked(obj, key)) {\n ko.track(obj, [key]);\n }\n }\n\n Element = _.extend({\n defaults: {\n _requested: {},\n containers: [],\n exports: {},\n imports: {},\n links: {},\n listens: {},\n name: '',\n ns: '${ $.name.split(\".\")[0] }',\n provider: '',\n registerNodes: true,\n source: null,\n statefull: {},\n template: '',\n tracks: {},\n storageConfig: {\n provider: 'localStorage',\n namespace: '${ $.name }',\n path: '${ $.storageConfig.provider }:${ $.storageConfig.namespace }'\n },\n maps: {\n imports: {},\n exports: {}\n },\n modules: {\n storage: '${ $.storageConfig.provider }'\n }\n },\n\n /**\n * Initializes model instance.\n *\n * @returns {Element} Chainable.\n */\n initialize: function () {\n this._super()\n .initObservable()\n .initModules()\n .initStatefull()\n .initLinks()\n .initUnique();\n\n return this;\n },\n\n /**\n * Initializes observable properties.\n *\n * @returns {Element} Chainable.\n */\n initObservable: function () {\n _.each(this.tracks, function (enabled, key) {\n if (enabled) {\n this.track(key);\n }\n }, this);\n\n return this;\n },\n\n /**\n * Parses 'modules' object and creates\n * async wrappers for specified components.\n *\n * @returns {Element} Chainable.\n */\n initModules: function () {\n _.each(this.modules, function (name, property) {\n if (name) {\n this[property] = this.requestModule(name);\n }\n }, this);\n\n if (!_.isFunction(this.source)) {\n this.source = registry.get(this.provider);\n }\n\n return this;\n },\n\n /**\n * Called when current element was injected to another component.\n *\n * @param {Object} parent - Instance of a 'parent' component.\n * @returns {Collection} Chainable.\n */\n initContainer: function (parent) {\n this.containers.push(parent);\n\n return this;\n },\n\n /**\n * Initializes statefull properties\n * based on the keys of 'statefull' object.\n *\n * @returns {Element} Chainable.\n */\n initStatefull: function () {\n _.each(this.statefull, function (path, key) {\n if (path) {\n this.setStatefull(key, path);\n }\n }, this);\n\n return this;\n },\n\n /**\n * Initializes links between properties.\n *\n * @returns {Element} Chainbale.\n */\n initLinks: function () {\n return this.setListeners(this.listens)\n .setLinks(this.links, 'imports')\n .setLinks(this.links, 'exports')\n .setLinks(this.exports, 'exports')\n .setLinks(this.imports, 'imports');\n },\n\n /**\n * Initializes listeners of the unique property.\n *\n * @returns {Element} Chainable.\n */\n initUnique: function () {\n var update = this.onUniqueUpdate.bind(this),\n uniqueNs = this.uniqueNs;\n\n this.hasUnique = this.uniqueProp && uniqueNs;\n\n if (this.hasUnique) {\n this.source.on(uniqueNs, update, this.name);\n }\n\n return this;\n },\n\n /**\n * Makes specified property to be stored automatically.\n *\n * @param {String} key - Name of the property\n * that will be stored.\n * @param {String} [path=key] - Path to the property in storage.\n * @returns {Element} Chainable.\n */\n setStatefull: function (key, path) {\n var link = {};\n\n path = !_.isString(path) || !path ? key : path;\n link[key] = this.storageConfig.path + '.' + path;\n\n this.setLinks(link, 'imports')\n .setLinks(link, 'exports');\n\n return this;\n },\n\n /**\n * Updates property specified in uniqueNs\n * if elements' unique property is set to 'true'.\n *\n * @returns {Element} Chainable.\n */\n setUnique: function () {\n var property = this.uniqueProp;\n\n if (this[property]()) {\n this.source.set(this.uniqueNs, this.name);\n }\n\n return this;\n },\n\n /**\n * Creates 'async' wrapper for the specified component\n * using uiRegistry 'async' method and caches it\n * in a '_requested' components object.\n *\n * @param {String} name - Name of requested component.\n * @returns {Function} Async module wrapper.\n */\n requestModule: function (name) {\n var requested = this._requested;\n\n if (!requested[name]) {\n requested[name] = registry.async(name);\n }\n\n return requested[name];\n },\n\n /**\n * Returns path to elements' template.\n *\n * @returns {String}\n */\n getTemplate: function () {\n return this.template;\n },\n\n /**\n * Checks if template was specified for an element.\n *\n * @returns {Boolean}\n */\n hasTemplate: function () {\n return !!this.template;\n },\n\n /**\n * Returns value of the nested property.\n *\n * @param {String} path - Path to the property.\n * @returns {*} Value of the property.\n */\n get: function (path) {\n return utils.nested(this, path);\n },\n\n /**\n * Sets provided value as a value of the specified nested property.\n * Triggers changes notifications, if value has mutated.\n *\n * @param {String} path - Path to property.\n * @param {*} value - New value of the property.\n * @returns {Element} Chainable.\n */\n set: function (path, value) {\n var data = this.get(path),\n diffs;\n\n diffs = !_.isFunction(data) && !this.isTracked(path) ?\n utils.compare(data, value, path) :\n false;\n\n utils.nested(this, path, value);\n\n if (diffs) {\n this._notifyChanges(diffs);\n }\n\n return this;\n },\n\n /**\n * Removes nested property from the object.\n *\n * @param {String} path - Path to the property.\n * @returns {Element} Chainable.\n */\n remove: function (path) {\n var data = utils.nested(this, path),\n diffs;\n\n if (_.isUndefined(data) || _.isFunction(data)) {\n return this;\n }\n\n diffs = utils.compare(data, undefined, path);\n\n utils.nestedRemove(this, path);\n\n this._notifyChanges(diffs);\n\n return this;\n },\n\n /**\n * Creates observable properties for the current object.\n *\n * If 'useTrack' flag is set to 'true' then each property will be\n * created with a ES5 get/set accessor descriptors, instead of\n * making them an observable functions.\n * See 'knockout-es5' library for more information.\n *\n * @param {Boolean} [useAccessors=false] - Whether to create an\n * observable function or to use property accesessors.\n * @param {(Object|String|Array)} properties - List of observable properties.\n * @returns {Element} Chainable.\n *\n * @example Sample declaration and equivalent knockout methods.\n * this.key = 'value';\n * this.array = ['value'];\n *\n * this.observe(['key', 'array']);\n * =>\n * this.key = ko.observable('value');\n * this.array = ko.observableArray(['value']);\n *\n * @example Another syntaxes of the previous example.\n * this.observe({\n * key: 'value',\n * array: ['value']\n * });\n */\n observe: function (useAccessors, properties) {\n var model = this,\n trackMethod;\n\n if (typeof useAccessors !== 'boolean') {\n properties = useAccessors;\n useAccessors = false;\n }\n\n trackMethod = useAccessors ? accessor : observable;\n\n if (_.isString(properties)) {\n properties = properties.split(' ');\n }\n\n if (Array.isArray(properties)) {\n properties.forEach(function (key) {\n trackMethod(model, key, model[key]);\n });\n } else if (typeof properties === 'object') {\n _.each(properties, function (value, key) {\n trackMethod(model, key, value);\n });\n }\n\n return this;\n },\n\n /**\n * Delegates call to 'observe' method but\n * with a predefined 'useAccessors' flag.\n *\n * @param {(String|Array|Object)} properties - List of observable properties.\n * @returns {Element} Chainable.\n */\n track: function (properties) {\n this.observe(true, properties);\n\n return this;\n },\n\n /**\n * Checks if specified property is tracked.\n *\n * @param {String} property - Property to be checked.\n * @returns {Boolean}\n */\n isTracked: function (property) {\n return ko.es5.isTracked(this, property);\n },\n\n /**\n * Invokes subscribers for the provided changes.\n *\n * @param {Object} diffs - Object with changes descriptions.\n * @returns {Element} Chainable.\n */\n _notifyChanges: function (diffs) {\n diffs.changes.forEach(function (change) {\n this.trigger(change.path, change.value, change);\n }, this);\n\n _.each(diffs.containers, function (changes, name) {\n var value = utils.nested(this, name);\n\n this.trigger(name, value, changes);\n }, this);\n\n return this;\n },\n\n /**\n * Extracts all stored data and sets it to element.\n *\n * @returns {Element} Chainable.\n */\n restore: function () {\n var ns = this.storageConfig.namespace,\n storage = this.storage();\n\n if (storage) {\n utils.extend(this, storage.get(ns));\n }\n\n return this;\n },\n\n /**\n * Stores value of the specified property in components' storage module.\n *\n * @param {String} property\n * @param {*} [data=this[property]]\n * @returns {Element} Chainable.\n */\n store: function (property, data) {\n var ns = this.storageConfig.namespace,\n path = utils.fullPath(ns, property);\n\n if (arguments.length < 2) {\n data = this.get(property);\n }\n\n this.storage('set', path, data);\n\n return this;\n },\n\n /**\n * Extracts specified property from storage.\n *\n * @param {String} [property] - Name of the property\n * to be extracted. If not specified then all of the\n * stored will be returned.\n * @returns {*}\n */\n getStored: function (property) {\n var ns = this.storageConfig.namespace,\n path = utils.fullPath(ns, property),\n storage = this.storage(),\n data;\n\n if (storage) {\n data = storage.get(path);\n }\n\n return data;\n },\n\n /**\n * Removes stored property.\n *\n * @param {String} property - Property to be removed from storage.\n * @returns {Element} Chainable.\n */\n removeStored: function (property) {\n var ns = this.storageConfig.namespace,\n path = utils.fullPath(ns, property);\n\n this.storage('remove', path);\n\n return this;\n },\n\n /**\n * Destroys current instance along with all of its' children.\n * @param {Boolean} skipUpdate - skip collection update when element to be destroyed.\n */\n destroy: function (skipUpdate) {\n this._dropHandlers()\n ._clearRefs(skipUpdate);\n },\n\n /**\n * Removes events listeners.\n * @private\n *\n * @returns {Element} Chainable.\n */\n _dropHandlers: function () {\n this.off();\n\n if (_.isFunction(this.source)) {\n this.source().off(this.name);\n } else if (this.source) {\n this.source.off(this.name);\n }\n\n return this;\n },\n\n /**\n * Removes all references to current instance and\n * calls 'destroy' method on all of its' children.\n * @private\n * @param {Boolean} skipUpdate - skip collection update when element to be destroyed.\n *\n * @returns {Element} Chainable.\n */\n _clearRefs: function (skipUpdate) {\n registry.remove(this.name);\n\n this.containers.forEach(function (parent) {\n parent.removeChild(this, skipUpdate);\n }, this);\n\n return this;\n },\n\n /**\n * Overrides 'EventsBus.trigger' method to implement events bubbling.\n *\n * @param {...*} arguments - Any number of arguments that should be passed to the events' handler.\n * @returns {Boolean} False if event bubbling was canceled.\n */\n bubble: function () {\n var args = _.toArray(arguments),\n bubble = this.trigger.apply(this, args),\n result;\n\n if (!bubble) {\n return false;\n }\n\n this.containers.forEach(function (parent) {\n result = parent.bubble.apply(parent, args);\n\n if (result === false) {\n bubble = false;\n }\n });\n\n return !!bubble;\n },\n\n /**\n * Callback which fires when property under uniqueNs has changed.\n */\n onUniqueUpdate: function (name) {\n var active = name === this.name,\n property = this.uniqueProp;\n\n this[property](active);\n },\n\n /**\n * Clean data form data source.\n *\n * @returns {Element}\n */\n cleanData: function () {\n if (this.source && this.source.componentType === 'dataSource') {\n if (this.elems) {\n _.each(this.elems(), function (val) {\n val.cleanData();\n });\n } else {\n this.source.remove(this.dataScope);\n }\n }\n\n return this;\n },\n\n /**\n * Fallback data.\n */\n cacheData: function () {\n this.cachedComponent = utils.copy(this);\n },\n\n /**\n * Update configuration in component.\n *\n * @param {*} oldValue\n * @param {*} newValue\n * @param {String} path - path to value.\n * @returns {Element}\n */\n updateConfig: function (oldValue, newValue, path) {\n var names = path.split('.'),\n index = _.lastIndexOf(names, 'config') + 1;\n\n names = names.splice(index, names.length - index).join('.');\n this.set(names, newValue);\n\n return this;\n }\n }, Events, links);\n\n return Class.extend(Element);\n});\n","Magento_Ui/js/lib/core/element/links.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'underscore',\n 'mageUtils',\n 'uiRegistry'\n], function (ko, _, utils, registry) {\n 'use strict';\n\n /**\n * Parse provided data.\n *\n * @param {String} placeholder\n * @param {String} data\n * @param {String} direction\n * @returns {Boolean|Object}\n */\n function parseData(placeholder, data, direction) {\n if (typeof data !== 'string') {\n return false;\n }\n\n data = data.split(':');\n\n if (!data[0]) {\n return false;\n }\n\n if (!data[1]) {\n data[1] = data[0];\n data[0] = placeholder;\n }\n\n return {\n target: data[0],\n property: data[1],\n direction: direction\n };\n }\n\n /**\n * Check if value not empty.\n *\n * @param {*} value\n * @returns {Boolean}\n */\n function notEmpty(value) {\n return typeof value !== 'undefined' && value != null;\n }\n\n /**\n * Update value for linked component.\n *\n * @param {Object} data\n * @param {Object} owner\n * @param {Object} target\n * @param {*} value\n */\n function updateValue(data, owner, target, value) {\n var component = target.component,\n property = target.property,\n linked = data.linked;\n\n if (data.mute) {\n return;\n }\n\n if (linked) {\n linked.mute = true;\n }\n\n if (owner.component !== target.component) {\n value = data.inversionValue ? !utils.copy(value) : utils.copy(value);\n }\n\n component.set(property, value, owner);\n\n if (property === 'disabled' && value) {\n component.set('validate', value, owner);\n }\n\n if (linked) {\n linked.mute = false;\n }\n }\n\n /**\n * Get value form owner component property.\n *\n * @param {Object} owner\n * @returns {*}\n */\n function getValue(owner) {\n var component = owner.component,\n property = owner.property;\n\n return component.get(property);\n }\n\n /**\n * Format provided params to object.\n *\n * @param {String} ownerComponent\n * @param {String} targetComponent\n * @param {String} ownerProp\n * @param {String} targetProp\n * @param {String} direction\n * @returns {Object}\n */\n function form(ownerComponent, targetComponent, ownerProp, targetProp, direction) {\n var result,\n tmp;\n\n result = {\n owner: {\n component: ownerComponent,\n property: ownerProp\n },\n target: {\n component: targetComponent,\n property: targetProp\n }\n };\n\n if (direction === 'exports') {\n tmp = result.owner;\n result.owner = result.target;\n result.target = tmp;\n }\n\n return result;\n }\n\n /**\n * Set data to linked property.\n *\n * @param {Object} map\n * @param {Object} data\n */\n function setLinked(map, data) {\n var match;\n\n if (!map) {\n return;\n }\n\n match = _.findWhere(map, {\n linked: false,\n target: data.target,\n property: data.property\n });\n\n if (match) {\n match.linked = data;\n data.linked = match;\n }\n }\n\n /**\n * Set data by direction.\n *\n * @param {Object} maps\n * @param {String} property\n * @param {Object} data\n */\n function setData(maps, property, data) {\n var direction = data.direction,\n map = maps[direction];\n\n data.linked = false;\n\n (map[property] = map[property] || []).push(data);\n\n direction = direction === 'imports' ? 'exports' : 'imports';\n\n setLinked(maps[direction][property], data);\n }\n\n /**\n * Set links for components.\n *\n * @param {String} target\n * @param {String} owner\n * @param {Object} data\n * @param {String} property\n * @param {Boolean} immediate\n */\n function setLink(target, owner, data, property, immediate) {\n var direction = data.direction,\n formated = form(target, owner, data.property, property, direction),\n callback,\n value;\n\n owner = formated.owner;\n target = formated.target;\n\n callback = updateValue.bind(null, data, owner, target);\n\n owner.component.on(owner.property, callback, target.component.name);\n\n if (immediate) {\n value = getValue(owner);\n\n if (notEmpty(value)) {\n updateValue(data, owner, target, value);\n }\n }\n }\n\n /**\n * Transfer data between components.\n *\n * @param {Object} owner\n * @param {Object} data\n */\n function transfer(owner, data) {\n var args = _.toArray(arguments);\n\n if (data.target.substr(0, 1) === '!') {\n data.target = data.target.substr(1);\n data.inversionValue = true;\n }\n\n if (owner.name === data.target) {\n args.unshift(owner);\n\n setLink.apply(null, args);\n } else {\n registry.get(data.target, function (target) {\n args.unshift(target);\n\n setLink.apply(null, args);\n });\n }\n }\n\n return {\n /**\n * Assign listeners.\n *\n * @param {Object} listeners\n * @returns {Object} Chainable\n */\n setListeners: function (listeners) {\n var owner = this,\n data;\n\n _.each(listeners, function (callbacks, sources) {\n sources = sources.split(' ');\n callbacks = callbacks.split(' ');\n\n sources.forEach(function (target) {\n callbacks.forEach(function (callback) {//eslint-disable-line max-nested-callbacks\n data = parseData(owner.name, target, 'imports');\n\n if (data) {\n setData(owner.maps, callback, data);\n transfer(owner, data, callback);\n }\n });\n });\n });\n\n return this;\n },\n\n /**\n * Set links in provided direction.\n *\n * @param {Object} links\n * @param {String} direction\n * @returns {Object} Chainable\n */\n setLinks: function (links, direction) {\n var owner = this,\n property,\n data;\n\n for (property in links) {\n if (links.hasOwnProperty(property)) {\n data = parseData(owner.name, links[property], direction);\n\n if (data) {//eslint-disable-line max-depth\n setData(owner.maps, property, data);\n transfer(owner, data, property, true);\n }\n }\n }\n\n return this;\n }\n };\n});\n","Magento_Ui/js/lib/validation/validator.js":"/*\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'underscore',\n './rules'\n], function (_, rulesList) {\n 'use strict';\n\n /**\n * Validates provided value be the specified rule.\n *\n * @param {String} id - Rule identifier.\n * @param {*} value - Value to be checked.\n * @param {*} [params]\n * @param {*} additionalParams - additional validation params set by method caller\n * @returns {Object}\n */\n function validate(id, value, params, additionalParams) {\n var rule,\n message,\n valid,\n result = {\n rule: id,\n passed: true,\n message: ''\n };\n\n if (_.isObject(params)) {\n message = params.message || '';\n }\n\n if (!rulesList[id]) {\n return result;\n }\n\n rule = rulesList[id];\n message = message || rule.message;\n valid = rule.handler(value, params, additionalParams);\n\n if (!valid) {\n params = Array.isArray(params) ?\n params :\n [params];\n\n if (typeof message === 'function') {\n message = message.call(rule);\n }\n\n message = params.reduce(function (msg, param, idx) {\n return msg.replace(new RegExp('\\\\{' + idx + '\\\\}', 'g'), param);\n }, message);\n\n result.passed = false;\n result.message = message;\n }\n\n return result;\n }\n\n /**\n * Validates provided value by a specified set of rules.\n *\n * @param {(String|Object)} rules - One or many validation rules.\n * @param {*} value - Value to be checked.\n * @param {*} additionalParams - additional validation params set by method caller\n * @returns {Object}\n */\n function validator(rules, value, additionalParams) {\n var result;\n\n if (typeof rules === 'object') {\n result = {\n passed: true\n };\n\n _.every(rules, function (ruleParams, id) {\n if (ruleParams.validate || ruleParams !== false || additionalParams) {\n result = validate(id, value, ruleParams, additionalParams);\n\n return result.passed;\n }\n\n return true;\n });\n\n return result;\n }\n\n return validate.apply(null, arguments);\n }\n\n /**\n * Adds new validation rule.\n *\n * @param {String} id - Rule identifier.\n * @param {Function} handler - Validation function.\n * @param {String} message - Error message.\n */\n validator.addRule = function (id, handler, message) {\n rulesList[id] = {\n handler: handler,\n message: message\n };\n };\n\n /**\n * Returns rule object found by provided identifier.\n *\n * @param {String} id - Rule identifier.\n * @returns {Object}\n */\n validator.getRule = function (id) {\n return rulesList[id];\n };\n\n return validator;\n});\n","Magento_Ui/js/lib/validation/rules.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n './utils',\n 'moment',\n 'tinycolor',\n 'jquery/validate',\n 'mage/translate'\n], function ($, _, utils, moment, tinycolor) {\n 'use strict';\n\n /**\n * validate credit card number using mod10\n * @param {String} s\n * @return {Boolean}\n */\n function validateCreditCard(s) {\n // remove non-numerics\n var v = '0123456789',\n w = '',\n i, j, k, m, c, a, x;\n\n for (i = 0; i < s.length; i++) {\n x = s.charAt(i);\n\n if (v.indexOf(x, 0) !== -1) {\n w += x;\n }\n }\n // validate number\n j = w.length / 2;\n k = Math.floor(j);\n m = Math.ceil(j) - k;\n c = 0;\n\n for (i = 0; i < k; i++) {\n a = w.charAt(i * 2 + m) * 2;\n c += a > 9 ? Math.floor(a / 10 + a % 10) : a;\n }\n\n for (i = 0; i < k + m; i++) {\n c += w.charAt(i * 2 + 1 - m) * 1;\n }\n\n return c % 10 === 0;\n }\n\n /**\n * Collection of validation rules including rules from additional-methods.js\n * @type {Object}\n */\n return _.mapObject({\n 'min_text_length': [\n function (value, params) {\n return _.isUndefined(value) || value.length === 0 || value.length >= +params;\n },\n $.mage.__('Please enter more or equal than {0} symbols.')\n ],\n 'max_text_length': [\n function (value, params) {\n return !_.isUndefined(value) && value.length <= +params;\n },\n $.mage.__('Please enter less or equal than {0} symbols.')\n ],\n 'max-words': [\n function (value, params) {\n return utils.isEmpty(value) || utils.stripHtml(value).match(/\\b\\w+\\b/g).length < params;\n },\n $.mage.__('Please enter {0} words or less.')\n ],\n 'min-words': [\n function (value, params) {\n return utils.isEmpty(value) || utils.stripHtml(value).match(/\\b\\w+\\b/g).length >= params;\n },\n $.mage.__('Please enter at least {0} words.')\n ],\n 'range-words': [\n function (value, params) {\n var match = utils.stripHtml(value).match(/\\b\\w+\\b/g) || [];\n\n return utils.isEmpty(value) || match.length >= params[0] &&\n match.length <= params[1];\n },\n $.mage.__('Please enter between {0} and {1} words.')\n ],\n 'letters-with-basic-punc': [\n function (value) {\n return utils.isEmpty(value) || /^[a-z\\-.,()\\u0027\\u0022\\s]+$/i.test(value);\n },\n $.mage.__('Letters or punctuation only please')\n ],\n 'alphanumeric': [\n function (value) {\n return utils.isEmpty(value) || /^\\w+$/i.test(value);\n },\n $.mage.__('Letters, numbers, spaces or underscores only please')\n ],\n 'letters-only': [\n function (value) {\n return utils.isEmpty(value) || /^[a-z]+$/i.test(value);\n },\n $.mage.__('Letters only please')\n ],\n 'no-whitespace': [\n function (value) {\n return utils.isEmpty(value) || /^\\S+$/i.test(value);\n },\n $.mage.__('No white space please')\n ],\n 'no-marginal-whitespace': [\n function (value) {\n return !/^\\s+|\\s+$/i.test(value);\n },\n $.mage.__('No marginal white space please')\n ],\n 'zip-range': [\n function (value) {\n return utils.isEmpty(value) || /^90[2-5]-\\d{2}-\\d{4}$/.test(value);\n },\n $.mage.__('Your ZIP-code must be in the range 902xx-xxxx to 905-xx-xxxx')\n ],\n 'integer': [\n function (value) {\n return utils.isEmpty(value) || /^-?\\d+$/.test(value);\n },\n $.mage.__('A positive or negative non-decimal number please')\n ],\n 'vinUS': [\n function (value) {\n if (utils.isEmpty(value)) {\n return true;\n }\n\n if (value.length !== 17) {\n return false;\n }\n var i, n, d, f, cd, cdv,//eslint-disable-line vars-on-top\n LL = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],//eslint-disable-line max-len\n VL = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9],\n FL = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2],\n rs = 0;\n\n for (i = 0; i < 17; i++) {\n f = FL[i];\n d = value.slice(i, i + 1);\n\n if (i === 8) {\n cdv = d;\n }\n\n if (!isNaN(d)) {\n d *= f;\n } else {\n for (n = 0; n < LL.length; n++) {//eslint-disable-line max-depth\n if (d.toUpperCase() === LL[n]) {//eslint-disable-line max-depth\n d = VL[n];\n d *= f;\n\n if (isNaN(cdv) && n === 8) {//eslint-disable-line max-depth\n cdv = LL[n];\n }\n break;\n }\n }\n }\n rs += d;\n }\n cd = rs % 11;\n\n if (cd === 10) {\n cd = 'X';\n }\n\n if (cd === cdv) {\n return true;\n }\n\n return false;\n },\n $.mage.__('The specified vehicle identification number (VIN) is invalid.')\n ],\n 'dateITA': [\n function (value) {\n var check = false,\n re = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/,\n adata, gg, mm, aaaa, xdata;\n\n if (re.test(value)) {\n adata = value.split('/');\n gg = parseInt(adata[0], 10);\n mm = parseInt(adata[1], 10);\n aaaa = parseInt(adata[2], 10);\n xdata = new Date(aaaa, mm - 1, gg);\n\n if (xdata.getFullYear() === aaaa &&\n xdata.getMonth() === mm - 1 &&\n xdata.getDate() === gg\n ) {\n check = true;\n } else {\n check = false;\n }\n } else {\n check = false;\n }\n\n return check;\n },\n $.mage.__('Please enter a correct date')\n ],\n 'dateNL': [\n function (value) {\n return /^\\d\\d?[\\.\\/-]\\d\\d?[\\.\\/-]\\d\\d\\d?\\d?$/.test(value);\n },\n $.mage.__('Vul hier een geldige datum in.')\n ],\n 'time': [\n function (value) {\n return utils.isEmpty(value) || /^([01]\\d|2[0-3])(:[0-5]\\d){0,2}$/.test(value);\n },\n $.mage.__('Please enter a valid time, between 00:00 and 23:59')\n ],\n 'time12h': [\n function (value) {\n return utils.isEmpty(value) || /^((0?[1-9]|1[012])(:[0-5]\\d){0,2}(\\s[AP]M))$/i.test(value);\n },\n $.mage.__('Please enter a valid time, between 00:00 am and 12:00 pm')\n ],\n 'phoneUS': [\n function (value) {\n value = value.replace(/\\s+/g, '');\n\n return utils.isEmpty(value) || value.length > 9 &&\n value.match(/^(1-?)?(\\([2-9]\\d{2}\\)|[2-9]\\d{2})-?[2-9]\\d{2}-?\\d{4}$/);\n },\n $.mage.__('Please specify a valid phone number')\n ],\n 'phoneUK': [\n function (value) {\n return utils.isEmpty(value) || value.length > 9 &&\n value.match(/^(\\(?(0|\\+44)[1-9]{1}\\d{1,4}?\\)?\\s?\\d{3,4}\\s?\\d{3,4})$/);\n },\n $.mage.__('Please specify a valid phone number')\n ],\n 'mobileUK': [\n function (value) {\n return utils.isEmpty(value) || value.length > 9 && value.match(/^((0|\\+44)7\\d{3}\\s?\\d{6})$/);\n },\n $.mage.__('Please specify a valid mobile number')\n ],\n 'stripped-min-length': [\n function (value, param) {\n return _.isUndefined(value) || value.length === 0 || utils.stripHtml(value).length >= param;\n },\n $.mage.__('Please enter at least {0} characters')\n ],\n 'email2': [\n function (value) {\n return utils.isEmpty(value) || /^((([a-z]|\\d|[!#\\$%&\\u0027\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&\\u0027\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\u0022)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\u0022)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?$/i.test(value);//eslint-disable-line max-len\n },\n $.validator.messages.email\n ],\n 'url2': [\n function (value) {\n return utils.isEmpty(value) || /^(https?|ftp):\\/\\/(((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)|[\\uE000-\\uF8FF]|\\/|\\?)*)?(\\#((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.test(value);//eslint-disable-line max-len\n },\n $.validator.messages.url\n ],\n 'credit-card-types': [\n function (value, param) {\n var validTypes;\n\n if (utils.isEmpty(value)) {\n return true;\n }\n\n if (/[^0-9-]+/.test(value)) {\n return false;\n }\n value = value.replace(/\\D/g, '');\n validTypes = 0x0000;\n\n if (param.mastercard) {\n validTypes |= 0x0001;\n }\n\n if (param.visa) {\n validTypes |= 0x0002;\n }\n\n if (param.amex) {\n validTypes |= 0x0004;\n }\n\n if (param.dinersclub) {\n validTypes |= 0x0008;\n }\n\n if (param.enroute) {\n validTypes |= 0x0010;\n }\n\n if (param.discover) {\n validTypes |= 0x0020;\n }\n\n if (param.jcb) {\n validTypes |= 0x0040;\n }\n\n if (param.unknown) {\n validTypes |= 0x0080;\n }\n\n if (param.all) {\n validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;\n }\n\n if (validTypes & 0x0001 && /^(51|52|53|54|55)/.test(value)) { //mastercard\n return value.length === 16;\n }\n\n if (validTypes & 0x0002 && /^(4)/.test(value)) { //visa\n return value.length === 16;\n }\n\n if (validTypes & 0x0004 && /^(34|37)/.test(value)) { //amex\n return value.length === 15;\n }\n\n if (validTypes & 0x0008 && /^(300|301|302|303|304|305|36|38)/.test(value)) { //dinersclub\n return value.length === 14;\n }\n\n if (validTypes & 0x0010 && /^(2014|2149)/.test(value)) { //enroute\n return value.length === 15;\n }\n\n if (validTypes & 0x0020 && /^(6011)/.test(value)) { //discover\n return value.length === 16;\n }\n\n if (validTypes & 0x0040 && /^(3)/.test(value)) { //jcb\n return value.length === 16;\n }\n\n if (validTypes & 0x0040 && /^(2131|1800)/.test(value)) { //jcb\n return value.length === 15;\n }\n\n if (validTypes & 0x0080) { //unknown\n return true;\n }\n\n return false;\n },\n $.mage.__('Please enter a valid credit card number.')\n ],\n 'ipv4': [\n function (value) {\n return utils.isEmpty(value) || /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i.test(value);//eslint-disable-line max-len\n },\n $.mage.__('Please enter a valid IP v4 address.')\n ],\n 'ipv6': [\n function (value) {\n return utils.isEmpty(value) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value);//eslint-disable-line max-len\n },\n $.mage.__('Please enter a valid IP v6 address.')\n ],\n 'pattern': [\n function (value, param) {\n return utils.isEmpty(value) || new RegExp(param).test(value);\n },\n $.mage.__('Invalid format.')\n ],\n 'validate-no-html-tags': [\n function (value) {\n return !/<(\\/)?\\w+/.test(value);\n },\n $.mage.__('HTML tags are not allowed.')\n ],\n 'validate-select': [\n function (value) {\n return value !== 'none' && value != null && value.length !== 0;\n },\n $.mage.__('Please select an option.')\n ],\n 'validate-no-empty': [\n function (value) {\n return !utils.isEmpty(value);\n },\n $.mage.__('Empty Value.')\n ],\n 'validate-alphanum-with-spaces': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^[a-zA-Z0-9 ]+$/.test(value);\n },\n $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or spaces only in this field.')\n ],\n 'validate-data': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^[A-Za-z]+[A-Za-z0-9_]+$/.test(value);\n },\n $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.')//eslint-disable-line max-len\n ],\n 'validate-street': [\n function (value) {\n return utils.isEmptyNoTrim(value) ||\n /^[ \\w]{3,}([A-Za-z]\\.)?([ \\w]*\\#\\d+)?(\\r\\n| )[ \\w]{3,}/.test(value);\n },\n $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9), spaces and \"#\" in this field.')\n ],\n 'validate-phoneStrict': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^(\\()?\\d{3}(\\))?(-|\\s)?\\d{3}(-|\\s)\\d{4}$/.test(value);\n },\n $.mage.__('Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.')\n ],\n 'validate-phoneLax': [\n function (value) {\n return utils.isEmptyNoTrim(value) ||\n /^((\\d[\\-. ]?)?((\\(\\d{3}\\))|\\d{3}))?[\\-. ]?\\d{3}[\\-. ]?\\d{4}$/.test(value);\n },\n $.mage.__('Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.')\n ],\n 'validate-fax': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^(\\()?\\d{3}(\\))?(-|\\s)?\\d{3}(-|\\s)\\d{4}$/.test(value);\n },\n $.mage.__('Please enter a valid fax number (Ex: 123-456-7890).')\n ],\n 'validate-email': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*@([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*\\.(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]){2,})$/i.test(value);//eslint-disable-line max-len\n },\n $.mage.__('Please enter a valid email address (Ex: johndoe@domain.com).')\n ],\n 'validate-emailSender': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^[\\S ]+$/.test(value);\n },\n $.mage.__('Please enter a valid email address (Ex: johndoe@domain.com).')\n ],\n 'validate-password': [\n function (value) {\n var pass;\n\n if (value == null) {\n return false;\n }\n\n pass = value.trim();\n\n if (!pass.length) {\n return true;\n }\n\n return !(pass.length > 0 && pass.length < 6);\n },\n $.mage.__('Please enter 6 or more characters. Leading and trailing spaces will be ignored.')\n ],\n 'validate-admin-password': [\n function (value) {\n var pass;\n\n if (value == null) {\n return false;\n }\n\n pass = value.trim();\n\n if (pass.length === 0) {\n return true;\n }\n\n if (!/[a-z]/i.test(value) || !/[0-9]/.test(value)) {\n return false;\n }\n\n if (pass.length < 7) {\n return false;\n }\n\n return true;\n },\n $.mage.__('Please enter 7 or more characters, using both numeric and alphabetic.')\n ],\n 'validate-customer-password': [\n function (v, elm) {\n var validator = this,\n counter = 0,\n passwordMinLength = $(elm).data('password-min-length'),\n passwordMinCharacterSets = $(elm).data('password-min-character-sets'),\n pass = v.trim(),\n result = pass.length >= passwordMinLength;\n\n if (result === false) {\n validator.passwordErrorMessage = $.mage.__('Minimum length of this field must be equal or greater than %1 symbols. Leading and trailing spaces will be ignored.').replace('%1', passwordMinLength);//eslint-disable-line max-len\n\n return result;\n }\n\n if (pass.match(/\\d+/)) {\n counter++;\n }\n\n if (pass.match(/[a-z]+/)) {\n counter++;\n }\n\n if (pass.match(/[A-Z]+/)) {\n counter++;\n }\n\n if (pass.match(/[^a-zA-Z0-9]+/)) {\n counter++;\n }\n\n if (counter < passwordMinCharacterSets) {\n result = false;\n validator.passwordErrorMessage = $.mage.__('Minimum of different classes of characters in password is %1. Classes of characters: Lower Case, Upper Case, Digits, Special Characters.').replace('%1', passwordMinCharacterSets);//eslint-disable-line max-len\n }\n\n return result;\n }, function () {\n return this.passwordErrorMessage;\n }\n ],\n 'validate-url': [\n function (value) {\n if (utils.isEmptyNoTrim(value)) {\n return true;\n }\n value = (value || '').replace(/^\\s+/, '').replace(/\\s+$/, '');\n\n return (/^(http|https|ftp):\\/\\/(([A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))(\\.[A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))*)(:(\\d+))?(\\/[A-Z0-9~](([A-Z0-9_~-]|\\.)*[A-Z0-9~]|))*\\/?(.*)?$/i).test(value);//eslint-disable-line max-len\n\n },\n $.mage.__('Please enter a valid URL. Protocol is required (http://, https:// or ftp://).')\n ],\n 'validate-clean-url': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^(http|https|ftp):\\/\\/(([A-Z0-9][A-Z0-9_-]*)(\\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\\d+))?\\/?/i.test(value) || /^(www)((\\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\\d+))?\\/?/i.test(value);//eslint-disable-line max-len\n\n },\n $.mage.__('Please enter a valid URL. For example http://www.example.com or www.example.com.')\n ],\n 'validate-xml-identifier': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^[A-Z][A-Z0-9_\\/-]*$/i.test(value);\n\n },\n $.mage.__('Please enter a valid XML-identifier (Ex: something_1, block5, id-4).')\n ],\n 'validate-ssn': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^\\d{3}-?\\d{2}-?\\d{4}$/.test(value);\n\n },\n $.mage.__('Please enter a valid social security number (Ex: 123-45-6789).')\n ],\n 'validate-zip-us': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /(^\\d{5}$)|(^\\d{5}-\\d{4}$)/.test(value);\n\n },\n $.mage.__('Please enter a valid zip code (Ex: 90602 or 90602-1234).')\n ],\n 'validate-date-au': [\n function (value) {\n var regex = /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/,\n d;\n\n if (utils.isEmptyNoTrim(value)) {\n return true;\n }\n\n if (utils.isEmpty(value) || !regex.test(value)) {\n return false;\n }\n d = new Date(value.replace(regex, '$2/$1/$3'));\n\n return parseInt(RegExp.$2, 10) === 1 + d.getMonth() &&\n parseInt(RegExp.$1, 10) === d.getDate() &&\n parseInt(RegExp.$3, 10) === d.getFullYear();\n\n },\n $.mage.__('Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.')\n ],\n 'validate-currency-dollar': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^\\$?\\-?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}\\d*(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$/.test(value);//eslint-disable-line max-len\n\n },\n $.mage.__('Please enter a valid $ amount. For example $100.00.')\n ],\n 'validate-not-negative-number': [\n function (value) {\n return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value))\n && value >= 0 && (/^\\s*-?\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n\n },\n $.mage.__('Please enter a number 0 or greater, without comma in this field.')\n ],\n // validate-not-negative-number should be replaced in all places with this one and then removed\n 'validate-zero-or-greater': [\n function (value) {\n return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value))\n && value >= 0 && (/^\\s*-?\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n },\n $.mage.__('Please enter a number 0 or greater, without comma in this field.')\n ],\n 'validate-greater-than-zero': [\n function (value) {\n return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value))\n && value > 0 && (/^\\s*-?\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n },\n $.mage.__('Please enter a number greater than 0, without comma in this field.')\n ],\n 'validate-css-length': [\n function (value) {\n if (value !== '') {\n return (/^[0-9]*\\.*[0-9]+(px|pc|pt|ex|em|mm|cm|in|%)?$/).test(value);\n }\n\n return true;\n },\n $.mage.__('Please input a valid CSS-length (Ex: 100px, 77pt, 20em, .5ex or 50%).')\n ],\n 'validate-number': [\n function (value) {\n return utils.isEmptyNoTrim(value) ||\n !isNaN(utils.parseNumber(value)) &&\n /^\\s*-?\\d*(?:[.,|'|\\s]\\d+)*(?:[.,|'|\\s]\\d{2})?-?\\s*$/.test(value);\n },\n $.mage.__('Please enter a valid number in this field.')\n ],\n 'validate-integer': [\n function (value) {\n return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value)) && /^\\s*-?\\d*\\s*$/.test(value);\n },\n $.mage.__('Please enter a valid integer in this field.')\n ],\n 'validate-number-range': [\n function (value, param) {\n var numValue, dataAttrRange, result, range, m;\n\n if (utils.isEmptyNoTrim(value)) {\n return true;\n }\n\n numValue = utils.parseNumber(value);\n\n if (isNaN(numValue)) {\n return false;\n }\n\n dataAttrRange = /^(-?[\\d.,]+)?-(-?[\\d.,]+)?$/;\n result = true;\n range = param;\n\n if (range) {\n m = dataAttrRange.exec(range);\n\n if (m) {\n result = result && utils.isBetween(numValue, m[1], m[2]);\n }\n }\n\n return result;\n },\n $.mage.__('The value is not within the specified range.')\n ],\n 'validate-positive-percent-decimal': [\n function (value) {\n var numValue;\n\n if (utils.isEmptyNoTrim(value) || !/^\\s*-?\\d*(\\.\\d*)?\\s*$/.test(value)) {\n return false;\n }\n\n numValue = utils.parseNumber(value);\n\n if (isNaN(numValue)) {\n return false;\n }\n\n return utils.isBetween(numValue, 0.01, 100);\n },\n $.mage.__('Please enter a valid percentage discount value greater than 0.')\n ],\n 'validate-digits': [\n function (value) {\n return utils.isEmptyNoTrim(value) || !/[^\\d]/.test(value);\n },\n $.mage.__('Please enter a valid number in this field.')\n ],\n 'validate-digits-range': [\n function (value, param) {\n var numValue, dataAttrRange, result, range, m;\n\n if (utils.isEmptyNoTrim(value)) {\n return true;\n }\n\n numValue = utils.parseNumber(value);\n\n if (isNaN(numValue)) {\n return false;\n }\n\n dataAttrRange = /^(-?\\d+)?-(-?\\d+)?$/;\n result = true;\n range = param;\n\n if (range) {\n m = dataAttrRange.exec(range);\n\n if (m) {\n result = result && utils.isBetween(numValue, m[1], m[2]);\n }\n }\n\n return result;\n },\n $.mage.__('The value is not within the specified range.')\n ],\n 'validate-range': [\n function (value) {\n var minValue, maxValue, ranges;\n\n if (utils.isEmptyNoTrim(value)) {\n return true;\n } else if ($.validator.methods['validate-digits'] && $.validator.methods['validate-digits'](value)) {\n minValue = maxValue = utils.parseNumber(value);\n } else {\n ranges = /^(-?\\d+)?-(-?\\d+)?$/.exec(value);\n\n if (ranges) {\n minValue = utils.parseNumber(ranges[1]);\n maxValue = utils.parseNumber(ranges[2]);\n\n if (minValue > maxValue) {//eslint-disable-line max-depth\n return false;\n }\n } else {\n return false;\n }\n }\n },\n $.mage.__('The value is not within the specified range.')\n ],\n 'validate-alpha': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^[a-zA-Z]+$/.test(value);\n },\n $.mage.__('Please use letters only (a-z or A-Z) in this field.')\n ],\n 'validate-code': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^[a-z]+[a-z0-9_]+$/.test(value);\n },\n $.mage.__('Please use only lowercase letters (a-z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.')//eslint-disable-line max-len\n ],\n 'validate-alphanum': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^[a-zA-Z0-9]+$/.test(value);\n },\n $.mage.__('Please use only letters (a-z or A-Z) or numbers (0-9) in this field. No spaces or other characters are allowed.')//eslint-disable-line max-len\n ],\n 'validate-not-number-first': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^[^0-9-\\.].*$/.test(value.trim());\n },\n $.mage.__('First character must be letter.')\n ],\n 'validate-date': [\n function (value, params, additionalParams) {\n var test = moment(value, additionalParams.dateFormat);\n\n return utils.isEmptyNoTrim(value) || test.isValid();\n },\n $.mage.__('Please enter a valid date.')\n ],\n 'validate-date-range': [\n function (value, params) {\n var fromDate = $('input[name*=\"' + params + '\"]').val();\n\n return moment.utc(value).unix() >= moment.utc(fromDate).unix() || isNaN(moment.utc(value).unix());\n },\n $.mage.__('Make sure the To Date is later than or the same as the From Date.')\n ],\n 'validate-identifier': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^[a-z0-9][a-z0-9_\\/-]+(\\.[a-z0-9_-]+)?$/.test(value);\n },\n $.mage.__('Please enter a valid URL Key (Ex: \"example-page\", \"example-page.html\" or \"anotherlevel/example-page\").')//eslint-disable-line max-len\n ],\n 'validate-trailing-hyphen': [\n function (value) {\n return utils.isEmptyNoTrim(value) || /^(?!-)(?!.*-$).+$/.test(value);\n },\n $.mage.__('Trailing hyphens are not allowed.')\n ],\n 'validate-zip-international': [\n\n /*function(v) {\n // @TODO: Cleanup\n return Validation.get('IsEmpty').test(v) || /(^[A-z0-9]{2,10}([\\s]{0,1}|[\\-]{0,1})[A-z0-9]{2,10}$)/.test(v);\n }*/\n function () {\n return true;\n },\n $.mage.__('Please enter a valid zip code.')\n ],\n 'validate-state': [\n function (value) {\n return value !== 0;\n },\n $.mage.__('Please select State/Province.')\n ],\n 'less-than-equals-to': [\n function (value, params) {\n value = utils.parseNumber(value);\n\n if (isNaN(parseFloat(params))) {\n params = $(params).val();\n }\n\n params = utils.parseNumber(params);\n\n if (!isNaN(params) && !isNaN(value)) {\n this.lteToVal = params;\n\n return value <= params;\n }\n\n return true;\n },\n function () {\n return $.mage.__('Please enter a value less than or equal to %s.').replace('%s', this.lteToVal);\n }\n ],\n 'greater-than-equals-to': [\n function (value, params) {\n value = utils.parseNumber(value);\n\n if (isNaN(parseFloat(params))) {\n params = $(params).val();\n }\n\n params = utils.parseNumber(params);\n\n if (!isNaN(params) && !isNaN(value)) {\n this.gteToVal = params;\n\n return value >= params;\n }\n\n return true;\n },\n function () {\n return $.mage.__('Please enter a value greater than or equal to %s.').replace('%s', this.gteToVal);\n }\n ],\n 'validate-emails': [\n function (value) {\n var validRegexp, emails, i;\n\n if (utils.isEmpty(value)) {\n return true;\n }\n validRegexp = /^[a-z0-9\\._-]{1,30}@([a-z0-9_-]{1,30}\\.){1,5}[a-z]{2,4}$/i;\n emails = value.split(/[\\s\\n\\,]+/g);\n\n for (i = 0; i < emails.length; i++) {\n if (!validRegexp.test(emails[i].strip())) {\n return false;\n }\n }\n\n return true;\n },\n $.mage.__('Please enter valid email addresses, separated by commas. For example, johndoe@domain.com, johnsmith@domain.com.')//eslint-disable-line max-len\n ],\n 'validate-cc-number': [\n\n /**\n * Validate credit card number based on mod 10.\n *\n * @param {String} value - credit card number\n * @return {Boolean}\n */\n function (value) {\n if (value) {\n return validateCreditCard(value);\n }\n\n return true;\n },\n $.mage.__('Please enter a valid credit card number.')\n ],\n 'validate-cc-ukss': [\n\n /**\n * Validate Switch/Solo/Maestro issue number and start date is filled.\n *\n * @param {String} value - input field value\n * @return {*}\n */\n function (value) {\n return value;\n },\n $.mage.__('Please enter issue number or start date for switch/solo card type.')\n ],\n 'required-entry': [\n function (value) {\n return !utils.isEmpty(value);\n },\n $.mage.__('This is a required field.')\n ],\n 'checked': [\n function (value) {\n return value;\n },\n $.mage.__('This is a required field.')\n ],\n 'not-negative-amount': [\n function (value) {\n if (value.length) {\n return (/^\\s*\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n }\n\n return true;\n },\n $.mage.__('Please enter positive number in this field.')\n ],\n 'validate-per-page-value-list': [\n function (value) {\n var isValid = true,\n values = value.split(','),\n i;\n\n if (utils.isEmpty(value)) {\n return isValid;\n }\n\n for (i = 0; i < values.length; i++) {\n if (!/^[0-9]+$/.test(values[i])) {\n isValid = false;\n }\n }\n\n return isValid;\n },\n $.mage.__('Please enter a valid value, ex: 10,20,30')\n ],\n 'validate-new-password': [\n function (value) {\n if ($.validator.methods['validate-password'] && !$.validator.methods['validate-password'](value)) {\n return false;\n }\n\n if (utils.isEmpty(value) && value !== '') {\n return false;\n }\n\n return true;\n },\n $.mage.__('Please enter 6 or more characters. Leading and trailing spaces will be ignored.')\n ],\n 'validate-item-quantity': [\n function (value, params) {\n var validator = this,\n result = false,\n // obtain values for validation\n qty = utils.parseNumber(value),\n isMinAllowedValid = typeof params.minAllowed === 'undefined' ||\n qty >= utils.parseNumber(params.minAllowed),\n isMaxAllowedValid = typeof params.maxAllowed === 'undefined' ||\n qty <= utils.parseNumber(params.maxAllowed),\n isQtyIncrementsValid = typeof params.qtyIncrements === 'undefined' ||\n qty % utils.parseNumber(params.qtyIncrements) === 0;\n\n result = qty > 0;\n\n if (result === false) {\n validator.itemQtyErrorMessage = $.mage.__('Please enter a quantity greater than 0.');//eslint-disable-line max-len\n\n return result;\n }\n\n result = isMinAllowedValid;\n\n if (result === false) {\n validator.itemQtyErrorMessage = $.mage.__('The fewest you may purchase is %1.').replace('%1', params.minAllowed);//eslint-disable-line max-len\n\n return result;\n }\n\n result = isMaxAllowedValid;\n\n if (result === false) {\n validator.itemQtyErrorMessage = $.mage.__('The maximum you may purchase is %1.').replace('%1', params.maxAllowed);//eslint-disable-line max-len\n\n return result;\n }\n\n result = isQtyIncrementsValid;\n\n if (result === false) {\n validator.itemQtyErrorMessage = $.mage.__('You can buy this product only in quantities of %1 at a time.').replace('%1', params.qtyIncrements);//eslint-disable-line max-len\n\n return result;\n }\n\n return result;\n }, function () {\n return this.itemQtyErrorMessage;\n }\n ],\n 'equalTo': [\n function (value, param) {\n return value === $(param).val();\n },\n $.validator.messages.equalTo\n ],\n 'validate-file-type': [\n function (name, types) {\n var extension = name.split('.').pop().toLowerCase();\n\n if (types && typeof types === 'string') {\n types = types.split(' ');\n }\n\n return !types || !types.length || ~types.indexOf(extension);\n },\n $.mage.__('We don\\'t recognize or support this file extension type.')\n ],\n 'validate-max-size': [\n function (size, maxSize) {\n return maxSize === false || size < maxSize;\n },\n $.mage.__('File you are trying to upload exceeds maximum file size limit.')\n ],\n 'validate-if-tag-script-exist': [\n function (value) {\n return !value || (/<script\\b[^>]*>([\\s\\S]*?)<\\/script>$/ig).test(value);\n },\n $.mage.__('Please use tag SCRIPT with SRC attribute or with proper content to include JavaScript to the document.')//eslint-disable-line max-len\n ],\n 'date_range_min': [\n function (value, minValue, params) {\n return moment.utc(value, params.dateFormat).unix() >= minValue;\n },\n $.mage.__('The date is not within the specified range.')\n ],\n 'date_range_max': [\n function (value, maxValue, params) {\n return moment.utc(value, params.dateFormat).unix() <= maxValue;\n },\n $.mage.__('The date is not within the specified range.')\n ],\n 'validate-color': [\n function (value) {\n if (value === '') {\n return true;\n }\n\n return tinycolor(value).isValid();\n },\n $.mage.__('Wrong color format. Please specify color in HEX, RGBa, HSVa, HSLa or use color name.')\n ],\n 'blacklist-url': [\n function (value, param) {\n return new RegExp(param).test(value);\n },\n $.mage.__('This link is not allowed.')\n ],\n 'validate-dob': [\n function (value, param, params) {\n if (value === '') {\n return true;\n }\n\n return moment.utc(value, params.dateFormat).isSameOrBefore(moment.utc());\n },\n $.mage.__('The Date of Birth should not be greater than today.')\n ],\n 'validate-no-utf8mb4-characters': [\n function (value) {\n var validator = this,\n message = $.mage.__('Please remove invalid characters: {0}.'),\n matches = value.match(/(?:[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])/g),\n result = matches === null;\n\n if (!result) {\n validator.charErrorMessage = message.replace('{0}', matches.join());\n }\n\n return result;\n }, function () {\n return this.charErrorMessage;\n }\n ]\n }, function (data) {\n return {\n handler: data[0],\n message: data[1]\n };\n });\n});\n","Magento_Ui/js/lib/validation/utils.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine(function () {\n 'use strict';\n\n var utils = {\n /**\n * Check if string is empty with trim.\n *\n * @param {String} value\n * @return {Boolean}\n */\n isEmpty: function (value) {\n return value === '' || value == null || value.length === 0 || /^\\s+$/.test(value);\n },\n\n /**\n * Check if string is empty no trim.\n *\n * @param {String} value\n * @return {Boolean}\n */\n isEmptyNoTrim: function (value) {\n return value === '' || value == null || value.length === 0;\n },\n\n /**\n * Checks if {value} is between numbers {from} and {to}.\n *\n * @param {String} value\n * @param {String} from\n * @param {String} to\n * @return {Boolean}\n */\n isBetween: function (value, from, to) {\n return (from === null || from === '' || value >= utils.parseNumber(from)) &&\n (to === null || to === '' || value <= utils.parseNumber(to));\n },\n\n /**\n * Parse price string.\n *\n * @param {String} value\n * @return {Number}\n */\n parseNumber: function (value) {\n var isDot, isComa;\n\n if (typeof value !== 'string') {\n return parseFloat(value);\n }\n isDot = value.indexOf('.');\n isComa = value.indexOf(',');\n\n if (isDot !== -1 && isComa !== -1) {\n if (isComa > isDot) {\n value = value.replace('.', '').replace(',', '.');\n } else {\n value = value.replace(',', '');\n }\n } else if (isComa !== -1) {\n value = value.replace(',', '.');\n }\n\n return parseFloat(value);\n },\n\n /**\n * Removes HTML tags and space characters, numbers and punctuation.\n *\n * @param {String} value - Value being stripped.\n * @return {String}\n */\n stripHtml: function (value) {\n return value.replace(/<.[^<>]*?>/g, ' ').replace(/ | /gi, ' ')\n .replace(/[0-9.(),;:!?%#$'\"_+=\\/-]*/g, '');\n }\n };\n\n return utils;\n});\n","Magento_Ui/js/modal/modalToggle.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'Magento_Ui/js/modal/modal'\n], function ($) {\n 'use strict';\n\n return function (config, el) {\n var widget,\n content;\n\n if (config.contentSelector) {\n content = $(config.contentSelector);\n } else if (config.content) {\n content = $('<div></div>').html(config.content);\n } else {\n content = $('<div></div>');\n }\n\n widget = content.modal(config);\n\n $(el).on(config.toggleEvent, function () {\n var state = widget.data('mage-modal').options.isOpen;\n\n if (state) {\n widget.modal('closeModal');\n } else {\n widget.modal('openModal');\n }\n\n return false;\n });\n\n return widget;\n };\n});\n","Magento_Ui/js/modal/modal-component.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'Magento_Ui/js/lib/view/utils/async',\n 'uiCollection',\n 'uiRegistry',\n 'underscore',\n './modal'\n], function ($, Collection, registry, _) {\n 'use strict';\n\n return Collection.extend({\n defaults: {\n template: 'ui/modal/modal-component',\n title: '',\n subTitle: '',\n options: {\n modalClass: '',\n title: '',\n subTitle: '',\n buttons: [],\n keyEventHandlers: {}\n },\n valid: true,\n links: {\n title: 'options.title',\n subTitle: 'options.subTitle'\n },\n listens: {\n state: 'onState',\n title: 'setTitle',\n 'options.subTitle': 'setSubTitle'\n },\n modalClass: 'modal-component',\n onCancel: 'closeModal'\n },\n\n /**\n * Initializes component.\n *\n * @returns {Object} Chainable.\n */\n initialize: function () {\n this._super();\n _.bindAll(this,\n 'initModal',\n 'openModal',\n 'closeModal',\n 'toggleModal',\n 'setPrevValues',\n 'validate');\n this.initializeContent();\n\n return this;\n },\n\n /**\n * Initializes modal configuration\n *\n * @returns {Object} Chainable.\n */\n initConfig: function () {\n return this._super()\n .initSelector()\n .initModalEvents();\n },\n\n /**\n * Configure modal selector\n *\n * @returns {Object} Chainable.\n */\n initSelector: function () {\n var modalClass = this.name.replace(/\\./g, '_');\n\n this.contentSelector = '.' + this.modalClass;\n this.options.modalClass = this.options.modalClass + ' ' + modalClass;\n this.rootSelector = '.' + modalClass;\n\n return this;\n },\n\n /**\n * Configure modal keyboard handlers\n * and outer click\n *\n * @returns {Object} Chainable.\n */\n initModalEvents: function () {\n this.options.keyEventHandlers.escapeKey = this.options.outerClickHandler = this[this.onCancel].bind(this);\n\n return this;\n },\n\n /**\n * Initialize modal's content components\n */\n initializeContent: function () {\n $.async({\n component: this.name\n }, this.initModal);\n },\n\n /**\n * Init toolbar section so other components will be able to place something in it\n */\n initToolbarSection: function () {\n this.set('toolbarSection', this.modal.data('mage-modal').modal.find('header').get(0));\n },\n\n /**\n * Initializes observable properties.\n *\n * @returns {Object} Chainable.\n */\n initObservable: function () {\n this._super();\n this.observe(['state', 'focused']);\n\n return this;\n },\n\n /**\n * Wrap content in a modal of certain type\n *\n * @param {HTMLElement} element\n * @returns {Object} Chainable.\n */\n initModal: function (element) {\n if (!this.modal) {\n this.overrideModalButtonCallback();\n this.options.modalCloseBtnHandler = this[this.onCancel].bind(this);\n this.modal = $(element).modal(this.options);\n this.initToolbarSection();\n\n if (this.waitCbk) {\n this.waitCbk();\n this.waitCbk = null;\n }\n }\n\n return this;\n },\n\n /**\n * Open modal\n */\n openModal: function () {\n if (this.modal) {\n this.state(true);\n } else {\n this.waitCbk = this.openModal;\n }\n },\n\n /**\n * Close modal\n */\n closeModal: function () {\n if (this.modal) {\n this.state(false);\n } else {\n this.waitCbk = this.closeModal;\n }\n },\n\n /**\n * Toggle modal\n */\n toggleModal: function () {\n if (this.modal) {\n this.state(!this.state());\n } else {\n this.waitCbk = this.toggleModal;\n }\n },\n\n /**\n * Sets title for modal\n *\n * @param {String} title\n */\n setTitle: function (title) {\n if (this.title !== title) {\n this.title = title;\n }\n\n if (this.modal) {\n this.modal.modal('setTitle', title);\n }\n },\n\n /**\n * Sets subTitle for modal\n *\n * @param {String} subTitle\n */\n setSubTitle: function (subTitle) {\n if (this.subTitle !== subTitle) {\n this.subTitle = subTitle;\n }\n\n if (this.modal) {\n this.modal.modal('setSubTitle', subTitle);\n }\n },\n\n /**\n * Wrap content in a modal of certain type\n *\n * @param {Boolean} state\n */\n onState: function (state) {\n if (state) {\n this.modal.modal('openModal');\n this.applyData();\n } else {\n this.modal.modal('closeModal');\n }\n },\n\n /**\n * Validate everything validatable in modal\n */\n validate: function (elem) {\n if (typeof elem === 'undefined') {\n return;\n }\n\n if (typeof elem.validate === 'function') {\n this.valid &= elem.validate().valid;\n } else if (elem.elems) {\n elem.elems().forEach(this.validate, this);\n }\n },\n\n /**\n * Reset data from provider\n */\n resetData: function () {\n this.elems().forEach(this.resetValue, this);\n },\n\n /**\n * Update 'applied' property with data from modal content\n */\n applyData: function () {\n var applied = {};\n\n this.elems().forEach(this.gatherValues.bind(this, applied), this);\n this.applied = applied;\n },\n\n /**\n * Gather values from modal content\n *\n * @param {Array} applied\n * @param {HTMLElement} elem\n */\n gatherValues: function (applied, elem) {\n if (typeof elem.value === 'function') {\n applied[elem.name] = elem.value();\n } else if (elem.elems) {\n elem.elems().forEach(this.gatherValues.bind(this, applied), this);\n }\n },\n\n /**\n * Set to previous values from modal content\n *\n * @param {HTMLElement} elem\n */\n setPrevValues: function (elem) {\n if (typeof elem.value === 'function') {\n this.modal.focus();\n elem.value(this.applied[elem.name]);\n } else if (elem.elems) {\n elem.elems().forEach(this.setPrevValues, this);\n }\n },\n\n /**\n * Triggers some method in every modal child elem, if this method is defined\n *\n * @param {Object} action - action configuration,\n * must contain actionName and targetName and\n * can contain params\n */\n triggerAction: function (action) {\n var targetName = action.targetName,\n params = action.params || [],\n actionName = action.actionName,\n target;\n\n target = registry.async(targetName);\n\n if (target && typeof target === 'function' && actionName) {\n params.unshift(actionName);\n target.apply(target, params);\n }\n },\n\n /**\n * Override modal buttons callback placeholders with real callbacks\n */\n overrideModalButtonCallback: function () {\n var buttons = this.options.buttons;\n\n if (buttons && buttons.length) {\n buttons.forEach(function (button) {\n button.click = this.getButtonClickHandler(button.actions);\n }, this);\n }\n },\n\n /**\n * Generate button click handler based on button's 'actions' configuration\n */\n getButtonClickHandler: function (actionsConfig) {\n var actions = actionsConfig.map(\n function (actionConfig) {\n if (_.isObject(actionConfig)) {\n return this.triggerAction.bind(this, actionConfig);\n }\n\n return this[actionConfig] ? this[actionConfig].bind(this) : function () {};\n }, this);\n\n return function () {\n actions.forEach(\n function (action) {\n action();\n }\n );\n };\n },\n\n /**\n * Cancels changes in modal:\n * returning elems values to the previous state,\n * and close modal\n */\n actionCancel: function () {\n this.elems().forEach(this.setPrevValues, this);\n this.closeModal();\n },\n\n /**\n * Accept changes in modal by not preventing them.\n * Can be extended by exporting 'gatherValues' result somewhere\n */\n actionDone: function () {\n this.valid = true;\n this.elems().forEach(this.validate, this);\n\n if (this.valid) {\n this.closeModal();\n }\n }\n });\n});\n","Magento_Ui/js/modal/confirm.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n 'mage/translate',\n 'jquery-ui-modules/widget',\n 'Magento_Ui/js/modal/modal'\n], function ($, _, $t) {\n 'use strict';\n\n $.widget('mage.confirm', $.mage.modal, {\n options: {\n modalClass: 'confirm',\n title: '',\n focus: '.action-accept',\n actions: {\n\n /**\n * Callback always - called on all actions.\n */\n always: function () {},\n\n /**\n * Callback confirm.\n */\n confirm: function () {},\n\n /**\n * Callback cancel.\n */\n cancel: function () {}\n },\n buttons: [{\n text: $t('Cancel'),\n class: 'action-secondary action-dismiss',\n\n /**\n * Click handler.\n */\n click: function (event) {\n this.closeModal(event);\n }\n }, {\n text: $t('OK'),\n class: 'action-primary action-accept',\n\n /**\n * Click handler.\n */\n click: function (event) {\n this.closeModal(event, true);\n }\n }]\n },\n\n /**\n * Create widget.\n */\n _create: function () {\n this._super();\n this.modal.find(this.options.modalCloseBtn).off().on('click', _.bind(this.closeModal, this));\n this.openModal();\n },\n\n /**\n * Remove modal window.\n */\n _remove: function () {\n this.modal.remove();\n },\n\n /**\n * Open modal window.\n */\n openModal: function () {\n return this._super();\n },\n\n /**\n * Close modal window.\n */\n closeModal: function (event, result) {\n result = result || false;\n\n if (result) {\n this.options.actions.confirm(event);\n } else {\n this.options.actions.cancel(event);\n }\n this.options.actions.always(event);\n this.element.on('confirmclosed', _.bind(this._remove, this));\n\n return this._super();\n }\n });\n\n return function (config) {\n return $('<div></div>').html(config.content).confirm(config);\n };\n});\n","Magento_Ui/js/modal/prompt.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n 'mage/template',\n 'text!ui/template/modal/modal-prompt-content.html',\n 'jquery-ui-modules/widget',\n 'Magento_Ui/js/modal/modal',\n 'mage/translate'\n], function ($, _, template, promptContentTmpl) {\n 'use strict';\n\n $.widget('mage.prompt', $.mage.modal, {\n options: {\n modalClass: 'prompt',\n promptContentTmpl: promptContentTmpl,\n promptField: '[data-role=\"promptField\"]',\n attributesForm: {},\n attributesField: {},\n value: '',\n validation: false,\n validationRules: [],\n keyEventHandlers: {\n\n /**\n * Enter key press handler,\n * submit result and close modal window\n * @param {Object} event - event\n */\n enterKey: function (event) {\n if (this.options.isOpen && this.modal.find(document.activeElement).length ||\n this.options.isOpen && this.modal[0] === document.activeElement) {\n this.closeModal(true);\n event.preventDefault();\n }\n },\n\n /**\n * Tab key press handler,\n * set focus to elements\n */\n tabKey: function () {\n if (document.activeElement === this.modal[0]) {\n this._setFocus('start');\n }\n },\n\n /**\n * Escape key press handler,\n * cancel and close modal window\n * @param {Object} event - event\n */\n escapeKey: function (event) {\n if (this.options.isOpen && this.modal.find(document.activeElement).length ||\n this.options.isOpen && this.modal[0] === document.activeElement) {\n this.closeModal();\n event.preventDefault();\n }\n }\n },\n actions: {\n\n /**\n * Callback always - called on all actions.\n */\n always: function () {},\n\n /**\n * Callback confirm.\n */\n confirm: function () {},\n\n /**\n * Callback cancel.\n */\n cancel: function () {}\n },\n buttons: [{\n text: $.mage.__('Cancel'),\n class: 'action-secondary action-dismiss',\n\n /**\n * Click handler.\n */\n click: function () {\n this.closeModal();\n }\n }, {\n text: $.mage.__('OK'),\n class: 'action-primary action-accept',\n\n /**\n * Click handler.\n */\n click: function () {\n this.closeModal(true);\n }\n }]\n },\n\n /**\n * Create widget.\n */\n _create: function () {\n this.options.focus = this.options.promptField;\n this.options.validation = this.options.validation && this.options.validationRules.length;\n this.options.outerClickHandler = this.options.outerClickHandler || _.bind(this.closeModal, this, false);\n this._super();\n this.modal.find(this.options.modalContent).append(this.getFormTemplate());\n this.modal.find(this.options.modalCloseBtn).off().on('click', _.bind(this.closeModal, this, false));\n\n if (this.options.validation) {\n this.setValidationClasses();\n }\n\n this.openModal();\n },\n\n /**\n * Form template getter.\n *\n * @returns {Object} Form template.\n */\n getFormTemplate: function () {\n var formTemplate,\n formAttr = '',\n inputAttr = '',\n attributeName;\n\n for (attributeName in this.options.attributesForm) {\n if (this.options.attributesForm.hasOwnProperty(attributeName)) {\n formAttr = formAttr + ' ' + attributeName + '=\"' +\n this.options.attributesForm[attributeName] + '\"';\n }\n }\n\n for (attributeName in this.options.attributesField) {\n if (this.options.attributesField.hasOwnProperty(attributeName)) {\n inputAttr = inputAttr + ' ' + attributeName + '=\"' +\n this.options.attributesField[attributeName] + '\"';\n }\n }\n\n formTemplate = $(template(this.options.promptContentTmpl, {\n data: this.options,\n formAttr: formAttr,\n inputAttr: inputAttr\n }));\n\n return formTemplate;\n },\n\n /**\n * Remove widget\n */\n _remove: function () {\n this.modal.remove();\n },\n\n /**\n * Validate prompt field\n */\n validate: function () {\n return $.validator.validateSingleElement(this.options.promptField);\n },\n\n /**\n * Add validation classes to prompt field\n */\n setValidationClasses: function () {\n this.modal.find(this.options.promptField).attr('class', $.proxy(function (i, val) {\n return val + ' ' + this.options.validationRules.join(' ');\n }, this));\n },\n\n /**\n * Open modal window\n */\n openModal: function () {\n this._super();\n this.modal.find(this.options.promptField).val(this.options.value);\n },\n\n /**\n * Close modal window\n */\n closeModal: function (result) {\n var value;\n\n if (result) {\n if (this.options.validation && !this.validate()) {\n return false;\n }\n\n value = this.modal.find(this.options.promptField).val();\n this.options.actions.confirm.call(this, value);\n } else {\n this.options.actions.cancel.call(this, result);\n }\n\n this.options.actions.always();\n this.element.on('promptclosed', _.bind(this._remove, this));\n\n return this._super();\n }\n });\n\n return function (config) {\n return $('<div class=\"prompt-message\"></div>').html(config.content).prompt(config);\n };\n});\n","Magento_Ui/js/modal/modal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n 'mage/template',\n 'text!ui/template/modal/modal-popup.html',\n 'text!ui/template/modal/modal-slide.html',\n 'text!ui/template/modal/modal-custom.html',\n 'Magento_Ui/js/lib/key-codes',\n 'jquery-ui-modules/widget',\n 'jquery-ui-modules/core',\n 'mage/translate',\n 'jquery/z-index'\n], function ($, _, template, popupTpl, slideTpl, customTpl, keyCodes) {\n 'use strict';\n\n /**\n * Detect browser transition end event.\n * @return {String|undefined} - transition event.\n */\n var transitionEvent = (function () {\n var transition,\n elementStyle = document.createElement('div').style,\n transitions = {\n 'transition': 'transitionend',\n 'OTransition': 'oTransitionEnd',\n 'MozTransition': 'transitionend',\n 'WebkitTransition': 'webkitTransitionEnd'\n };\n\n for (transition in transitions) {\n if (elementStyle[transition] !== undefined && transitions.hasOwnProperty(transition)) {\n return transitions[transition];\n }\n }\n })();\n\n /**\n * Modal Window Widget\n */\n $.widget('mage.modal', {\n options: {\n id: null,\n type: 'popup',\n title: '',\n subTitle: '',\n modalClass: '',\n focus: '[data-role=\"closeBtn\"]',\n autoOpen: false,\n clickableOverlay: true,\n popupTpl: popupTpl,\n slideTpl: slideTpl,\n customTpl: customTpl,\n modalVisibleClass: '_show',\n parentModalClass: '_has-modal',\n innerScrollClass: '_inner-scroll',\n responsive: false,\n innerScroll: false,\n modalTitle: '[data-role=\"title\"]',\n modalSubTitle: '[data-role=\"subTitle\"]',\n modalBlock: '[data-role=\"modal\"]',\n modalCloseBtn: '[data-role=\"closeBtn\"]',\n modalContent: '[data-role=\"content\"]',\n modalAction: '[data-role=\"action\"]',\n focusableScope: '[data-role=\"focusable-scope\"]',\n focusableStart: '[data-role=\"focusable-start\"]',\n focusableEnd: '[data-role=\"focusable-end\"]',\n appendTo: 'body',\n wrapperClass: 'modals-wrapper',\n overlayClass: 'modals-overlay',\n responsiveClass: 'modal-slide',\n trigger: '',\n modalLeftMargin: 45,\n closeText: $.mage.__('Close'),\n buttons: [{\n text: $.mage.__('Ok'),\n class: '',\n attr: {},\n\n /**\n * Default action on button click\n */\n click: function (event) {\n this.closeModal(event);\n }\n }],\n keyEventHandlers: {\n\n /**\n * Tab key press handler,\n * set focus to elements\n */\n tabKey: function () {\n if (document.activeElement === this.modal[0]) {\n this._setFocus('start');\n }\n },\n\n /**\n * Escape key press handler,\n * close modal window\n * @param {Object} event - event\n */\n escapeKey: function (event) {\n if (this.options.isOpen && this.modal.find(document.activeElement).length ||\n this.options.isOpen && this.modal[0] === document.activeElement) {\n this.closeModal(event);\n }\n }\n }\n },\n\n /**\n * Creates modal widget.\n */\n _create: function () {\n _.bindAll(\n this,\n 'keyEventSwitcher',\n '_tabSwitcher',\n 'closeModal'\n );\n\n this.options.id = this.uuid;\n this.options.transitionEvent = transitionEvent;\n this._createWrapper();\n this._renderModal();\n this._createButtons();\n\n if (this.options.trigger) {\n $(document).on('click', this.options.trigger, _.bind(this.toggleModal, this));\n }\n this._on(this.modal.find(this.options.modalCloseBtn), {\n 'click': this.options.modalCloseBtnHandler ? this.options.modalCloseBtnHandler : this.closeModal\n });\n this._on(this.element, {\n 'openModal': this.openModal,\n 'closeModal': this.closeModal\n });\n this.options.autoOpen ? this.openModal() : false;\n },\n\n /**\n * Returns element from modal node.\n * @return {Object} - element.\n */\n _getElem: function (elem) {\n return this.modal.find(elem);\n },\n\n /**\n * Gets visible modal count.\n * * @return {Number} - visible modal count.\n */\n _getVisibleCount: function () {\n var modals = this.modalWrapper.find(this.options.modalBlock);\n\n return modals.filter('.' + this.options.modalVisibleClass).length;\n },\n\n /**\n * Gets count of visible modal by slide type.\n * * @return {Number} - visible modal count.\n */\n _getVisibleSlideCount: function () {\n var elems = this.modalWrapper.find('[data-type=\"slide\"]');\n\n return elems.filter('.' + this.options.modalVisibleClass).length;\n },\n\n /**\n * Listener key events.\n * Call handler function if it exists\n */\n keyEventSwitcher: function (event) {\n var key = keyCodes[event.keyCode];\n\n if (this.options.keyEventHandlers.hasOwnProperty(key)) {\n this.options.keyEventHandlers[key].apply(this, arguments);\n }\n },\n\n /**\n * Set title for modal.\n *\n * @param {String} title\n */\n setTitle: function (title) {\n var $title = this.modal.find(this.options.modalTitle),\n $subTitle = this.modal.find(this.options.modalSubTitle);\n\n $title.text(title);\n $title.append($subTitle);\n },\n\n /**\n * Set sub title for modal.\n *\n * @param {String} subTitle\n */\n setSubTitle: function (subTitle) {\n this.options.subTitle = subTitle;\n this.modal.find(this.options.modalSubTitle).html(subTitle);\n },\n\n /**\n * Toggle modal.\n * * @return {Element} - current element.\n */\n toggleModal: function () {\n if (this.options.isOpen === true) {\n this.closeModal();\n } else {\n this.openModal();\n }\n },\n\n /**\n * Open modal.\n * * @return {Element} - current element.\n */\n openModal: function () {\n this.options.isOpen = true;\n this.focussedElement = document.activeElement;\n this._createOverlay();\n this._setActive();\n this._setKeyListener();\n this.modal.one(this.options.transitionEvent, _.bind(this._setFocus, this, 'end', 'opened'));\n this.modal.one(this.options.transitionEvent, _.bind(this._trigger, this, 'opened'));\n this.modal.addClass(this.options.modalVisibleClass);\n\n if (!this.options.transitionEvent) {\n this._trigger('opened');\n }\n\n return this.element;\n },\n\n /**\n * Set focus to element.\n * @param {String} position - can be \"start\" and \"end\"\n * positions.\n * If position is \"end\" - sets focus to first\n * focusable element in modal window scope.\n * If position is \"start\" - sets focus to last\n * focusable element in modal window scope\n *\n * @param {String} type - can be \"opened\" or false\n * If type is \"opened\" - looks to \"this.options.focus\"\n * property and sets focus\n */\n _setFocus: function (position, type) {\n var focusableElements,\n infelicity;\n\n if (type === 'opened' && this.options.focus) {\n this.modal.find($(this.options.focus)).trigger('focus');\n } else if (type === 'opened' && !this.options.focus) {\n this.modal.find(this.options.focusableScope).trigger('focus');\n } else if (position === 'end') {\n this.modal.find(this.options.modalCloseBtn).trigger('focus');\n } else if (position === 'start') {\n infelicity = 2; //Constant for find last focusable element\n focusableElements = this.modal.find(':focusable');\n focusableElements.eq(focusableElements.length - infelicity).trigger('focus');\n }\n },\n\n /**\n * Set events listener when modal is opened.\n */\n _setKeyListener: function () {\n this.modal.find(this.options.focusableStart).on('focusin', this._tabSwitcher);\n this.modal.find(this.options.focusableEnd).on('focusin', this._tabSwitcher);\n this.modal.on('keydown', this.keyEventSwitcher);\n },\n\n /**\n * Remove events listener when modal is closed.\n */\n _removeKeyListener: function () {\n this.modal.find(this.options.focusableStart).off('focusin', this._tabSwitcher);\n this.modal.find(this.options.focusableEnd).off('focusin', this._tabSwitcher);\n this.modal.off('keydown', this.keyEventSwitcher);\n },\n\n /**\n * Switcher for focus event.\n * @param {Object} e - event\n */\n _tabSwitcher: function (e) {\n var target = $(e.target);\n\n if (target.is(this.options.focusableStart)) {\n this._setFocus('start');\n } else if (target.is(this.options.focusableEnd)) {\n this._setFocus('end');\n }\n },\n\n /**\n * Close modal.\n * * @return {Element} - current element.\n */\n closeModal: function () {\n var that = this;\n\n this._removeKeyListener();\n this.options.isOpen = false;\n this.modal.one(this.options.transitionEvent, function () {\n that._close();\n });\n this.modal.removeClass(this.options.modalVisibleClass);\n\n if (!this.options.transitionEvent) {\n that._close();\n }\n\n return this.element;\n },\n\n /**\n * Helper for closeModal function.\n */\n _close: function () {\n var trigger = _.bind(this._trigger, this, 'closed', this.modal);\n\n $(this.focussedElement).trigger('focus');\n this._destroyOverlay();\n this._unsetActive();\n _.defer(trigger, this);\n },\n\n /**\n * Set z-index and margin for modal and overlay.\n */\n _setActive: function () {\n var zIndex = this.modal.zIndex(),\n baseIndex = zIndex + this._getVisibleCount();\n\n if (this.modal.data('active')) {\n return;\n }\n\n this.modal.data('active', true);\n\n this.overlay.zIndex(++baseIndex);\n this.prevOverlayIndex = this.overlay.zIndex();\n this.modal.zIndex(this.overlay.zIndex() + 1);\n\n if (this._getVisibleSlideCount()) {\n this.modal.css('marginLeft', this.options.modalLeftMargin * this._getVisibleSlideCount());\n }\n },\n\n /**\n * Unset styles for modal and set z-index for previous modal.\n */\n _unsetActive: function () {\n this.modal.removeAttr('style');\n this.modal.data('active', false);\n\n if (this.overlay) {\n this.overlay.zIndex(this.prevOverlayIndex - 1);\n }\n },\n\n /**\n * Creates wrapper to hold all modals.\n */\n _createWrapper: function () {\n this.modalWrapper = $(this.options.appendTo).find('.' + this.options.wrapperClass);\n\n if (!this.modalWrapper.length) {\n this.modalWrapper = $('<div></div>')\n .addClass(this.options.wrapperClass)\n .appendTo(this.options.appendTo);\n }\n },\n\n /**\n * Compile template and append to wrapper.\n */\n _renderModal: function () {\n $(template(\n this.options[this.options.type + 'Tpl'],\n {\n data: this.options\n })).appendTo(this.modalWrapper);\n this.modal = this.modalWrapper.find(this.options.modalBlock).last();\n this.element.appendTo(this._getElem(this.options.modalContent));\n\n if (this.element.is(':hidden')) {\n this.element.show();\n }\n },\n\n /**\n * Creates buttons pane.\n */\n _createButtons: function () {\n this.buttons = this._getElem(this.options.modalAction);\n _.each(this.options.buttons, function (btn, key) {\n var button = this.buttons[key];\n\n if (btn.attr) {\n $(button).attr(btn.attr);\n }\n\n if (btn.class) {\n $(button).addClass(btn.class);\n }\n\n if (!btn.click) {\n btn.click = this.closeModal;\n }\n $(button).on('click', _.bind(btn.click, this));\n }, this);\n },\n\n /**\n * Creates overlay, append it to wrapper, set previous click event on overlay.\n */\n _createOverlay: function () {\n var events,\n outerClickHandler = this.options.outerClickHandler || this.closeModal;\n\n this.overlay = $('.' + this.options.overlayClass);\n\n if (!this.overlay.length) {\n $(this.options.appendTo).addClass(this.options.parentModalClass);\n this.overlay = $('<div></div>')\n .addClass(this.options.overlayClass)\n .appendTo(this.modalWrapper);\n }\n events = $._data(this.overlay.get(0), 'events');\n events ? this.prevOverlayHandler = events.click[0].handler : false;\n this.options.clickableOverlay ? this.overlay.off().on('click', outerClickHandler) : false;\n },\n\n /**\n * Destroy overlay.\n */\n _destroyOverlay: function () {\n if (this._getVisibleCount()) {\n this.overlay.off().on('click', this.prevOverlayHandler);\n } else {\n $(this.options.appendTo).removeClass(this.options.parentModalClass);\n this.overlay.remove();\n this.overlay = null;\n }\n }\n });\n\n return $.mage.modal;\n});\n","Magento_Ui/js/modal/alert.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'underscore',\n 'jquery-ui-modules/widget',\n 'Magento_Ui/js/modal/confirm',\n 'mage/translate'\n], function ($, _) {\n 'use strict';\n\n $.widget('mage.alert', $.mage.confirm, {\n options: {\n modalClass: 'confirm',\n title: $.mage.__('Attention'),\n actions: {\n\n /**\n * Callback always - called on all actions.\n */\n always: function () {}\n },\n buttons: [{\n text: $.mage.__('OK'),\n class: 'action-primary action-accept',\n\n /**\n * Click handler.\n */\n click: function () {\n this.closeModal(true);\n }\n }]\n },\n\n /**\n * Close modal window.\n */\n closeModal: function () {\n this.options.actions.always();\n this.element.on('alertclosed', _.bind(this._remove, this));\n\n return this._super();\n }\n });\n\n return function (config) {\n return $('<div></div>').html(config.content).alert(config);\n };\n});\n","Mageplaza_Smtp/js/action/send-address.js":"/**\n * Mageplaza\n *\n * NOTICE OF LICENSE\n *\n * This source file is subject to the Mageplaza.com license that is\n * available through the world-wide-web at this URL:\n * https://www.mageplaza.com/LICENSE.txt\n *\n * DISCLAIMER\n *\n * Do not edit or add to this file if you wish to upgrade this extension to newer\n * version in the future.\n *\n * @category Mageplaza\n * @package Mageplaza_Smtp\n * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)\n * @license https://www.mageplaza.com/LICENSE.txt\n */\n\ndefine([\n 'mage/storage',\n 'Mageplaza_Smtp/js/model/resource-url-manager',\n 'Magento_Checkout/js/model/quote'\n], function (storage, resourceUrlManager, quote) {\n 'use strict';\n\n return function (address, isOsc) {\n return storage.post(\n resourceUrlManager.getUrlForUpdateOrder(quote),\n JSON.stringify({\n address: address,\n isOsc: isOsc\n }),\n false\n );\n };\n});\n","Mageplaza_Smtp/js/view/shipping-mixins.js":"/**\n * Mageplaza\n *\n * NOTICE OF LICENSE\n *\n * This source file is subject to the Mageplaza.com license that is\n * available through the world-wide-web at this URL:\n * https://www.mageplaza.com/LICENSE.txt\n *\n * DISCLAIMER\n *\n * Do not edit or add to this file if you wish to upgrade this extension to newer\n * version in the future.\n *\n * @category Mageplaza\n * @package Mageplaza_StoreLocator\n * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)\n * @license https://www.mageplaza.com/LICENSE.txt\n */\n\ndefine(\n [\n 'jquery',\n 'underscore',\n 'Magento_Ui/js/form/form',\n 'ko',\n 'Magento_Customer/js/model/customer',\n 'Magento_Customer/js/model/address-list',\n 'Magento_Checkout/js/model/address-converter',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/action/create-shipping-address',\n 'Magento_Checkout/js/action/select-shipping-address',\n 'Magento_Checkout/js/model/shipping-rates-validator',\n 'Magento_Checkout/js/model/shipping-address/form-popup-state',\n 'Magento_Checkout/js/model/shipping-service',\n 'Magento_Checkout/js/action/select-shipping-method',\n 'Magento_Checkout/js/model/shipping-rate-registry',\n 'Magento_Checkout/js/action/set-shipping-information',\n 'Magento_Checkout/js/model/step-navigator',\n 'Magento_Ui/js/modal/modal',\n 'Magento_Checkout/js/model/checkout-data-resolver',\n 'Magento_Checkout/js/checkout-data',\n 'uiRegistry',\n 'mage/translate',\n 'Magento_Checkout/js/model/shipping-rate-service',\n 'Mageplaza_Smtp/js/model/address-on-change'\n ],\n function (\n $,\n _,\n Component,\n ko,\n customer,\n addressList,\n addressConverter,\n quote,\n createShippingAddress,\n selectShippingAddress,\n shippingRatesValidator,\n formPopUpState,\n shippingService,\n selectShippingMethodAction,\n rateRegistry,\n setShippingInformationAction,\n stepNavigator,\n modal,\n checkoutDataResolver,\n checkoutData,\n registry,\n $t,\n shippingRateService,\n shippingAddressOnChange\n ) {\n 'use strict';\n\n var mixin = {\n\n initialize: function () {\n var fieldsetName = 'checkout.steps.shipping-step.shippingAddress.shipping-address-fieldset';\n\n this._super();\n\n shippingAddressOnChange.initFields(fieldsetName);\n }\n };\n\n return function (target) {\n return target.extend(mixin);\n };\n }\n);\n","Mageplaza_Smtp/js/view/billing-address-mixins.js":"/**\n * Mageplaza\n *\n * NOTICE OF LICENSE\n *\n * This source file is subject to the Mageplaza.com license that is\n * available through the world-wide-web at this URL:\n * https://www.mageplaza.com/LICENSE.txt\n *\n * DISCLAIMER\n *\n * Do not edit or add to this file if you wish to upgrade this extension to newer\n * version in the future.\n *\n * @category Mageplaza\n * @package Mageplaza_StoreLocator\n * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)\n * @license https://www.mageplaza.com/LICENSE.txt\n */\n\ndefine(\n [\n 'jquery',\n 'ko',\n 'underscore',\n 'Magento_Ui/js/form/form',\n 'Magento_Customer/js/model/customer',\n 'Magento_Customer/js/model/address-list',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/action/create-billing-address',\n 'Magento_Checkout/js/action/select-billing-address',\n 'Magento_Checkout/js/checkout-data',\n 'Magento_Checkout/js/model/checkout-data-resolver',\n 'Magento_Customer/js/customer-data',\n 'Magento_Checkout/js/action/set-billing-address',\n 'Magento_Ui/js/model/messageList',\n 'mage/translate',\n 'Magento_Checkout/js/model/billing-address-postcode-validator',\n 'Mageplaza_Smtp/js/model/address-on-change'\n ],\n function (\n $,\n ko,\n _,\n Component,\n customer,\n addressList,\n quote,\n createBillingAddress,\n selectBillingAddress,\n checkoutData,\n checkoutDataResolver,\n customerData,\n setBillingAddressAction,\n globalMessageList,\n $t,\n billingAddressPostcodeValidator,\n billingAddressOnChange\n ) {\n 'use strict';\n\n var mixin = {\n initialize: function () {\n var fieldset;\n\n this._super();\n\n if (window.checkoutConfig.oscConfig) {\n fieldset = this.get('name') + '.billing-address-fieldset';\n } else {\n fieldset = this.get('name') + '.form-fields';\n }\n\n billingAddressOnChange.initFields(fieldset);\n },\n };\n\n return function (target) {\n return target.extend(mixin);\n };\n }\n);\n","Mageplaza_Smtp/js/model/address-on-change.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n 'jquery',\n 'ko',\n 'mage/translate',\n 'uiRegistry',\n 'Magento_Checkout/js/model/quote',\n 'Mageplaza_Smtp/js/action/send-address'\n], function (\n $,\n ko,\n $t,\n uiRegistry,\n quote,\n sendAddress\n) {\n 'use strict';\n\n var elements = ['firstname', 'lastname', 'company', 'street', 'country_id', 'region_id', 'city', 'postcode', 'telephone'],\n observedElements = [];\n\n return {\n validateAddressTimeout: 0,\n validateDelay: 1000,\n\n /**\n * Perform postponed binding for fieldset elements\n *\n * @param {String} formPath\n */\n initFields: function (formPath) {\n var self = this;\n\n $.each(elements, function (index, field) {\n uiRegistry.async(formPath + '.' + field)(self.smtpBindHandler.bind(self));\n });\n },\n\n /**\n * @param {Object} element\n * @param {Number} delay\n */\n smtpBindHandler: function (element, delay) {\n var self = this;\n\n delay = typeof delay === 'undefined' ? self.validateDelay : delay;\n\n if (element.component.indexOf('/group') !== -1) {\n $.each(element.elems(), function (index, elem) {\n uiRegistry.async(elem.name)(function () {\n self.smtpBindHandler(elem);\n });\n });\n } else if (element && element.hasOwnProperty('value')) {\n element.on('value', function () {\n clearTimeout(self.validateAddressTimeout);\n self.validateAddressTimeout = setTimeout(function () {\n sendAddress(JSON.stringify(self.collectObservedData()), self.isOsc());\n }, delay);\n });\n\n observedElements.push(element);\n }\n },\n /**\n * Collect observed fields data to object\n *\n * @returns {*}\n */\n collectObservedData: function () {\n var observedValues = {};\n\n $.each(observedElements, function (index, field) {\n var value = field.value();\n\n if ($.type(value) === 'undefined') {\n value = '';\n }\n observedValues[field.dataScope] = value;\n });\n\n return observedValues;\n },\n isOsc: function () {\n return !!window.checkoutConfig.oscConfig;\n }\n };\n});\n","Mageplaza_Smtp/js/model/resource-url-manager.js":"/**\n * Mageplaza\n *\n * NOTICE OF LICENSE\n *\n * This source file is subject to the Mageplaza.com license that is\n * available through the world-wide-web at this URL:\n * https://www.mageplaza.com/LICENSE.txt\n *\n * DISCLAIMER\n *\n * Do not edit or add to this file if you wish to upgrade this extension to newer\n * version in the future.\n *\n * @category Mageplaza\n * @package Mageplaza_Smtp\n * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)\n * @license https://www.mageplaza.com/LICENSE.txt\n */\n\ndefine(\n [\n 'jquery',\n 'Magento_Checkout/js/model/resource-url-manager'\n ],\n function ($, resourceUrlManager) {\n \"use strict\";\n\n return $.extend({\n /** Get url for send the address to update order */\n getUrlForUpdateOrder: function (quote) {\n var params = {cartId: quote.getQuoteId()};\n var urls = {\n 'default': '/carts/:cartId/update-order'\n };\n\n return this.getUrl(urls, params);\n }\n }, resourceUrlManager);\n }\n);\n","Magento_Swatches/js/swatch-renderer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'underscore',\n 'mage/template',\n 'mage/smart-keyboard-handler',\n 'mage/translate',\n 'priceUtils',\n 'jquery-ui-modules/widget',\n 'jquery/jquery.parsequery',\n 'mage/validation/validation'\n], function ($, _, mageTemplate, keyboardHandler, $t, priceUtils) {\n 'use strict';\n\n /**\n * Extend form validation to support swatch accessibility\n */\n $.widget('mage.validation', $.mage.validation, {\n /**\n * Handle form with swatches validation. Focus on first invalid swatch block.\n *\n * @param {jQuery.Event} event\n * @param {Object} validation\n */\n listenFormValidateHandler: function (event, validation) {\n var swatchWrapper, firstActive, swatches, swatch, successList, errorList, firstSwatch;\n\n this._superApply(arguments);\n\n swatchWrapper = '.swatch-attribute-options';\n swatches = $(event.target).find(swatchWrapper);\n\n if (!swatches.length) {\n return;\n }\n\n swatch = '.swatch-attribute';\n firstActive = $(validation.errorList[0].element || []);\n successList = validation.successList;\n errorList = validation.errorList;\n firstSwatch = $(firstActive).parent(swatch).find(swatchWrapper);\n\n keyboardHandler.focus(swatches);\n\n $.each(successList, function (index, item) {\n $(item).parent(swatch).find(swatchWrapper).attr('aria-invalid', false);\n });\n\n $.each(errorList, function (index, item) {\n $(item.element).parent(swatch).find(swatchWrapper).attr('aria-invalid', true);\n });\n\n if (firstSwatch.length) {\n $(firstSwatch).trigger('focus');\n }\n }\n });\n\n /**\n * Render tooltips by attributes (only to up).\n * Required element attributes:\n * - data-option-type (integer, 0-3)\n * - data-option-label (string)\n * - data-option-tooltip-thumb\n * - data-option-tooltip-value\n * - data-thumb-width\n * - data-thumb-height\n */\n $.widget('mage.SwatchRendererTooltip', {\n options: {\n delay: 200, //how much ms before tooltip to show\n tooltipClass: 'swatch-option-tooltip' //configurable, but remember about css\n },\n\n /**\n * @private\n */\n _init: function () {\n var $widget = this,\n $this = this.element,\n $element = $('.' + $widget.options.tooltipClass),\n timer,\n type = parseInt($this.data('option-type'), 10),\n label = $this.data('option-label'),\n thumb = $this.data('option-tooltip-thumb'),\n value = $this.data('option-tooltip-value'),\n width = $this.data('thumb-width'),\n height = $this.data('thumb-height'),\n $image,\n $title,\n $corner;\n\n if (!$element.length) {\n $element = $('<div class=\"' +\n $widget.options.tooltipClass +\n '\"><div class=\"image\"></div><div class=\"title\"></div><div class=\"corner\"></div></div>'\n );\n $('body').append($element);\n }\n\n $image = $element.find('.image');\n $title = $element.find('.title');\n $corner = $element.find('.corner');\n\n $this.on('mouseenter', function () {\n if (!$this.hasClass('disabled')) {\n timer = setTimeout(\n function () {\n var leftOpt = null,\n leftCorner = 0,\n left,\n $window;\n\n if (type === 2) {\n // Image\n $image.css({\n 'background': 'url(\"' + thumb + '\") no-repeat center', //Background case\n 'background-size': 'initial',\n 'width': width + 'px',\n 'height': height + 'px'\n });\n $image.show();\n } else if (type === 1) {\n // Color\n $image.css({\n background: value\n });\n $image.show();\n } else if (type === 0 || type === 3) {\n // Default\n $image.hide();\n }\n\n $title.text(label);\n\n leftOpt = $this.offset().left;\n left = leftOpt + $this.width() / 2 - $element.width() / 2;\n $window = $(window);\n\n // the numbers (5 and 5) is magick constants for offset from left or right page\n if (left < 0) {\n left = 5;\n } else if (left + $element.width() > $window.width()) {\n left = $window.width() - $element.width() - 5;\n }\n\n // the numbers (6, 3 and 18) is magick constants for offset tooltip\n leftCorner = 0;\n\n if ($element.width() < $this.width()) {\n leftCorner = $element.width() / 2 - 3;\n } else {\n leftCorner = (leftOpt > left ? leftOpt - left : left - leftOpt) + $this.width() / 2 - 6;\n }\n\n $corner.css({\n left: leftCorner\n });\n $element.css({\n left: left,\n top: $this.offset().top - $element.height() - $corner.height() - 18\n }).show();\n },\n $widget.options.delay\n );\n }\n });\n\n $this.on('mouseleave', function () {\n $element.hide();\n clearTimeout(timer);\n });\n\n $(document).on('tap', function () {\n $element.hide();\n clearTimeout(timer);\n });\n\n $this.on('tap', function (event) {\n event.stopPropagation();\n });\n }\n });\n\n /**\n * Render swatch controls with options and use tooltips.\n * Required two json:\n * - jsonConfig (magento's option config)\n * - jsonSwatchConfig (swatch's option config)\n *\n * Tuning:\n * - numberToShow (show \"more\" button if options are more)\n * - onlySwatches (hide selectboxes)\n * - moreButtonText (text for \"more\" button)\n * - selectorProduct (selector for product container)\n * - selectorProductPrice (selector for change price)\n */\n $.widget('mage.SwatchRenderer', {\n options: {\n classes: {\n attributeClass: 'swatch-attribute',\n attributeLabelClass: 'swatch-attribute-label',\n attributeSelectedOptionLabelClass: 'swatch-attribute-selected-option',\n attributeOptionsWrapper: 'swatch-attribute-options',\n attributeInput: 'swatch-input',\n optionClass: 'swatch-option',\n selectClass: 'swatch-select',\n moreButton: 'swatch-more',\n loader: 'swatch-option-loading'\n },\n // option's json config\n jsonConfig: {},\n\n // swatch's json config\n jsonSwatchConfig: {},\n\n // selector of parental block of prices and swatches (need to know where to seek for price block)\n selectorProduct: '.product-info-main',\n\n // selector of price wrapper (need to know where set price)\n selectorProductPrice: '[data-role=priceBox]',\n\n //selector of product images gallery wrapper\n mediaGallerySelector: '[data-gallery-role=gallery-placeholder]',\n\n // selector of category product tile wrapper\n selectorProductTile: '.product-item',\n\n // number of controls to show (false or zero = show all)\n numberToShow: false,\n\n // show only swatch controls\n onlySwatches: false,\n\n // enable label for control\n enableControlLabel: true,\n\n // control label id\n controlLabelId: '',\n\n // text for more button\n moreButtonText: $t('More'),\n\n // Callback url for media\n mediaCallback: '',\n\n // Local media cache\n mediaCache: {},\n\n // Cache for BaseProduct images. Needed when option unset\n mediaGalleryInitial: [{}],\n\n // Use ajax to get image data\n useAjax: false,\n\n /**\n * Defines the mechanism of how images of a gallery should be\n * updated when user switches between configurations of a product.\n *\n * As for now value of this option can be either 'replace' or 'prepend'.\n *\n * @type {String}\n */\n gallerySwitchStrategy: 'replace',\n\n // whether swatches are rendered in product list or on product page\n inProductList: false,\n\n // sly-old-price block selector\n slyOldPriceSelector: '.sly-old-price',\n\n // tier prise selectors start\n tierPriceTemplateSelector: '#tier-prices-template',\n tierPriceBlockSelector: '[data-role=\"tier-price-block\"]',\n tierPriceTemplate: '',\n // tier prise selectors end\n\n // A price label selector\n normalPriceLabelSelector: '.product-info-main .normal-price .price-label',\n qtyInfo: '#qty'\n },\n\n /**\n * Get chosen product\n *\n * @returns int|null\n */\n getProduct: function () {\n var products = this._CalcProducts();\n\n return _.isArray(products) ? products[0] : null;\n },\n\n /**\n * Get chosen product id\n *\n * @returns int|null\n */\n getProductId: function () {\n var products = this._CalcProducts();\n\n return _.isArray(products) && products.length === 1 ? products[0] : null;\n },\n\n /**\n * @private\n */\n _init: function () {\n // Don't render the same set of swatches twice\n if ($(this.element).attr('data-rendered')) {\n return;\n }\n\n $(this.element).attr('data-rendered', true);\n\n if (_.isEmpty(this.options.jsonConfig.images)) {\n this.options.useAjax = true;\n // creates debounced variant of _LoadProductMedia()\n // to use it in events handlers instead of _LoadProductMedia()\n this._debouncedLoadProductMedia = _.debounce(this._LoadProductMedia.bind(this), 500);\n }\n\n this.options.tierPriceTemplate = $(this.options.tierPriceTemplateSelector).html();\n\n if (this.options.jsonConfig !== '' && this.options.jsonSwatchConfig !== '') {\n // store unsorted attributes\n this.options.jsonConfig.mappedAttributes = _.clone(this.options.jsonConfig.attributes);\n this._sortAttributes();\n this._RenderControls();\n this._setPreSelectedGallery();\n $(this.element).trigger('swatch.initialized');\n } else {\n console.log('SwatchRenderer: No input data received');\n }\n },\n\n /**\n * @private\n */\n _sortAttributes: function () {\n this.options.jsonConfig.attributes = _.sortBy(this.options.jsonConfig.attributes, function (attribute) {\n return parseInt(attribute.position, 10);\n });\n },\n\n /**\n * @private\n */\n _create: function () {\n var options = this.options,\n gallery = $('[data-gallery-role=gallery-placeholder]', '.column.main'),\n productData = this._determineProductData(),\n $main = productData.isInProductView ?\n this.element.parents('.column.main') :\n this.element.parents('.product-item-info');\n\n if (productData.isInProductView) {\n gallery.data('gallery') ?\n this._onGalleryLoaded(gallery) :\n gallery.on('gallery:loaded', this._onGalleryLoaded.bind(this, gallery));\n } else {\n options.mediaGalleryInitial = [{\n 'img': $main.find('.product-image-photo').attr('src')\n }];\n }\n\n this.productForm = this.element.parents(this.options.selectorProductTile).find('form:first');\n this.inProductList = this.productForm.length > 0;\n $(this.options.qtyInfo).on('input', this._onQtyChanged.bind(this));\n },\n\n /**\n * Determine product id and related data\n *\n * @returns {{productId: *, isInProductView: bool}}\n * @private\n */\n _determineProductData: function () {\n // Check if product is in a list of products.\n var productId,\n isInProductView = false;\n\n productId = this.element.parents('.product-item-details')\n .find('.price-box.price-final_price').attr('data-product-id');\n\n if (!productId) {\n // Check individual product.\n productId = $('[name=product]').val();\n isInProductView = productId > 0;\n }\n\n return {\n productId: productId,\n isInProductView: isInProductView\n };\n },\n\n /**\n * Render controls\n *\n * @private\n */\n _RenderControls: function () {\n var $widget = this,\n container = this.element,\n classes = this.options.classes,\n chooseText = this.options.jsonConfig.chooseText,\n showTooltip = this.options.showTooltip;\n\n $widget.optionsMap = {};\n\n $.each(this.options.jsonConfig.attributes, function () {\n var item = this,\n controlLabelId = 'option-label-' + item.code + '-' + item.id,\n options = $widget._RenderSwatchOptions(item, controlLabelId),\n select = $widget._RenderSwatchSelect(item, chooseText),\n input = $widget._RenderFormInput(item),\n listLabel = '',\n label = '';\n\n // Show only swatch controls\n if ($widget.options.onlySwatches && !$widget.options.jsonSwatchConfig.hasOwnProperty(item.id)) {\n return;\n }\n\n if ($widget.options.enableControlLabel) {\n label +=\n '<span id=\"' + controlLabelId + '\" class=\"' + classes.attributeLabelClass + '\">' +\n $('<i></i>').text(item.label).html() +\n '</span>' +\n '<span class=\"' + classes.attributeSelectedOptionLabelClass + '\"></span>';\n }\n\n if ($widget.inProductList) {\n $widget.productForm.append(input);\n input = '';\n listLabel = 'aria-label=\"' + $('<i></i>').text(item.label).html() + '\"';\n } else {\n listLabel = 'aria-labelledby=\"' + controlLabelId + '\"';\n }\n\n // Create new control\n container.append(\n '<div class=\"' + classes.attributeClass + ' ' + item.code + '\" ' +\n 'data-attribute-code=\"' + item.code + '\" ' +\n 'data-attribute-id=\"' + item.id + '\">' +\n label +\n '<div aria-activedescendant=\"\" ' +\n 'tabindex=\"0\" ' +\n 'aria-invalid=\"false\" ' +\n 'aria-required=\"true\" ' +\n 'role=\"listbox\" ' + listLabel +\n 'class=\"' + classes.attributeOptionsWrapper + ' clearfix\">' +\n options + select +\n '</div>' + input +\n '</div>'\n );\n\n $widget.optionsMap[item.id] = {};\n\n // Aggregate options array to hash (key => value)\n $.each(item.options, function () {\n if (this.products.length > 0) {\n $widget.optionsMap[item.id][this.id] = {\n price: parseInt(\n $widget.options.jsonConfig.optionPrices[this.products[0]].finalPrice.amount,\n 10\n ),\n products: this.products\n };\n }\n });\n });\n\n if (showTooltip === 1) {\n // Connect Tooltip\n container\n .find('[data-option-type=\"1\"], [data-option-type=\"2\"],' +\n ' [data-option-type=\"0\"], [data-option-type=\"3\"]')\n .SwatchRendererTooltip();\n }\n\n // Hide all elements below more button\n $('.' + classes.moreButton).nextAll().hide();\n\n // Handle events like click or change\n $widget._EventListener();\n\n // Rewind options\n $widget._Rewind(container);\n\n //Emulate click on all swatches from Request\n $widget._EmulateSelected($.parseQuery());\n $widget._EmulateSelected($widget._getSelectedAttributes());\n },\n\n disableSwatchForOutOfStockProducts: function () {\n let $widget = this, container = this.element;\n\n $.each(this.options.jsonConfig.attributes, function () {\n let item = this;\n\n if ($widget.options.jsonConfig.canDisplayShowOutOfStockStatus) {\n let salableProducts = $widget.options.jsonConfig.salable[item.id],\n swatchOptions = $(container).find(`[data-attribute-id='${item.id}']`).find('.swatch-option');\n\n swatchOptions.each(function (key, value) {\n let optionId = $(value).data('option-id');\n\n if (!salableProducts.hasOwnProperty(optionId)) {\n $(value).attr('disabled', true).addClass('disabled');\n }\n });\n }\n });\n },\n\n /**\n * Render swatch options by part of config\n *\n * @param {Object} config\n * @param {String} controlId\n * @returns {String}\n * @private\n */\n _RenderSwatchOptions: function (config, controlId) {\n var optionConfig = this.options.jsonSwatchConfig[config.id],\n optionClass = this.options.classes.optionClass,\n sizeConfig = this.options.jsonSwatchImageSizeConfig,\n moreLimit = parseInt(this.options.numberToShow, 10),\n moreClass = this.options.classes.moreButton,\n moreText = this.options.moreButtonText,\n countAttributes = 0,\n html = '';\n\n if (!this.options.jsonSwatchConfig.hasOwnProperty(config.id)) {\n return '';\n }\n\n $.each(config.options, function (index) {\n var id,\n type,\n value,\n thumb,\n label,\n width,\n height,\n attr,\n swatchImageWidth,\n swatchImageHeight;\n\n if (!optionConfig.hasOwnProperty(this.id)) {\n return '';\n }\n\n // Add more button\n if (moreLimit === countAttributes++) {\n html += '<a href=\"#\" class=\"' + moreClass + '\"><span>' + moreText + '</span></a>';\n }\n\n id = this.id;\n type = parseInt(optionConfig[id].type, 10);\n value = optionConfig[id].hasOwnProperty('value') ?\n $('<i></i>').text(optionConfig[id].value).html() : '';\n thumb = optionConfig[id].hasOwnProperty('thumb') ? optionConfig[id].thumb : '';\n width = _.has(sizeConfig, 'swatchThumb') ? sizeConfig.swatchThumb.width : 110;\n height = _.has(sizeConfig, 'swatchThumb') ? sizeConfig.swatchThumb.height : 90;\n label = this.label ? $('<i></i>').text(this.label).html() : '';\n attr =\n ' id=\"' + controlId + '-item-' + id + '\"' +\n ' index=\"' + index + '\"' +\n ' aria-checked=\"false\"' +\n ' aria-describedby=\"' + controlId + '\"' +\n ' tabindex=\"0\"' +\n ' data-option-type=\"' + type + '\"' +\n ' data-option-id=\"' + id + '\"' +\n ' data-option-label=\"' + label + '\"' +\n ' aria-label=\"' + label + '\"' +\n ' role=\"option\"' +\n ' data-thumb-width=\"' + width + '\"' +\n ' data-thumb-height=\"' + height + '\"';\n\n attr += thumb !== '' ? ' data-option-tooltip-thumb=\"' + thumb + '\"' : '';\n attr += value !== '' ? ' data-option-tooltip-value=\"' + value + '\"' : '';\n\n swatchImageWidth = _.has(sizeConfig, 'swatchImage') ? sizeConfig.swatchImage.width : 30;\n swatchImageHeight = _.has(sizeConfig, 'swatchImage') ? sizeConfig.swatchImage.height : 20;\n\n if (!this.hasOwnProperty('products') || this.products.length <= 0) {\n attr += ' data-option-empty=\"true\"';\n }\n\n if (type === 0) {\n // Text\n html += '<div class=\"' + optionClass + ' text\" ' + attr + '>' + (value ? value : label) +\n '</div>';\n } else if (type === 1) {\n // Color\n html += '<div class=\"' + optionClass + ' color\" ' + attr +\n ' style=\"background: ' + value +\n ' no-repeat center; background-size: initial;\">' + '' +\n '</div>';\n } else if (type === 2) {\n // Image\n html += '<div class=\"' + optionClass + ' image\" ' + attr +\n ' style=\"background: url(' + value + ') no-repeat center; background-size: initial;width:' +\n swatchImageWidth + 'px; height:' + swatchImageHeight + 'px\">' + '' +\n '</div>';\n } else if (type === 3) {\n // Clear\n html += '<div class=\"' + optionClass + '\" ' + attr + '></div>';\n } else {\n // Default\n html += '<div class=\"' + optionClass + '\" ' + attr + '>' + label + '</div>';\n }\n });\n\n return html;\n },\n\n /**\n * Render select by part of config\n *\n * @param {Object} config\n * @param {String} chooseText\n * @returns {String}\n * @private\n */\n _RenderSwatchSelect: function (config, chooseText) {\n var html;\n\n if (this.options.jsonSwatchConfig.hasOwnProperty(config.id)) {\n return '';\n }\n\n html =\n '<select class=\"' + this.options.classes.selectClass + ' ' + config.code + '\">' +\n '<option value=\"0\" data-option-id=\"0\">' + chooseText + '</option>';\n\n $.each(config.options, function () {\n var label = this.label,\n attr = ' value=\"' + this.id + '\" data-option-id=\"' + this.id + '\"';\n\n if (!this.hasOwnProperty('products') || this.products.length <= 0) {\n attr += ' data-option-empty=\"true\"';\n }\n\n html += '<option ' + attr + '>' + label + '</option>';\n });\n\n html += '</select>';\n\n return html;\n },\n\n /**\n * Input for submit form.\n * This control shouldn't have \"type=hidden\", \"display: none\" for validation work :(\n *\n * @param {Object} config\n * @private\n */\n _RenderFormInput: function (config) {\n return '<input class=\"' + this.options.classes.attributeInput + ' super-attribute-select\" ' +\n 'name=\"super_attribute[' + config.id + ']\" ' +\n 'type=\"text\" ' +\n 'value=\"\" ' +\n 'data-selector=\"super_attribute[' + config.id + ']\" ' +\n 'data-validate=\"{required: true}\" ' +\n 'aria-required=\"true\" ' +\n 'aria-invalid=\"false\">';\n },\n\n /**\n * Event listener\n *\n * @private\n */\n _EventListener: function () {\n var $widget = this,\n options = this.options.classes,\n target;\n\n $widget.element.on('click', '.' + options.optionClass, function () {\n return $widget._OnClick($(this), $widget);\n });\n\n $widget.element.on('change', '.' + options.selectClass, function () {\n return $widget._OnChange($(this), $widget);\n });\n\n $widget.element.on('click', '.' + options.moreButton, function (e) {\n e.preventDefault();\n\n return $widget._OnMoreClick($(this));\n });\n\n $widget.element.on('keydown', function (e) {\n if (e.which === 13) {\n target = $(e.target);\n\n if (target.is('.' + options.optionClass)) {\n return $widget._OnClick(target, $widget);\n } else if (target.is('.' + options.selectClass)) {\n return $widget._OnChange(target, $widget);\n } else if (target.is('.' + options.moreButton)) {\n e.preventDefault();\n\n return $widget._OnMoreClick(target);\n }\n }\n });\n },\n\n /**\n * Load media gallery using ajax or json config.\n *\n * @private\n */\n _loadMedia: function () {\n var $main = this.inProductList ?\n this.element.parents('.product-item-info') :\n this.element.parents('.column.main'),\n images;\n\n if (this.options.useAjax) {\n this._debouncedLoadProductMedia();\n } else {\n images = this.options.jsonConfig.images[this.getProduct()];\n\n if (!images) {\n images = this.options.mediaGalleryInitial;\n }\n this.updateBaseImage(this._sortImages(images), $main, !this.inProductList);\n }\n },\n\n /**\n * Sorting images array\n *\n * @private\n */\n _sortImages: function (images) {\n return _.sortBy(images, function (image) {\n return parseInt(image.position, 10);\n });\n },\n\n /**\n * Event for swatch options\n *\n * @param {Object} $this\n * @param {Object} $widget\n * @private\n */\n _OnClick: function ($this, $widget) {\n var $parent = $this.parents('.' + $widget.options.classes.attributeClass),\n $wrapper = $this.parents('.' + $widget.options.classes.attributeOptionsWrapper),\n $label = $parent.find('.' + $widget.options.classes.attributeSelectedOptionLabelClass),\n attributeId = $parent.data('attribute-id'),\n $input = $parent.find('.' + $widget.options.classes.attributeInput),\n checkAdditionalData = JSON.parse(this.options.jsonSwatchConfig[attributeId]['additional_data']),\n $priceBox = $widget.element.parents($widget.options.selectorProduct)\n .find(this.options.selectorProductPrice);\n\n if ($widget.inProductList) {\n $input = $widget.productForm.find(\n '.' + $widget.options.classes.attributeInput + '[name=\"super_attribute[' + attributeId + ']\"]'\n );\n }\n\n if ($this.hasClass('disabled')) {\n return;\n }\n\n if ($this.hasClass('selected')) {\n $parent.removeAttr('data-option-selected').find('.selected').removeClass('selected');\n $input.val('');\n $label.text('');\n $this.attr('aria-checked', false);\n } else {\n $parent.attr('data-option-selected', $this.data('option-id')).find('.selected').removeClass('selected');\n $label.text($this.data('option-label'));\n $input.val($this.data('option-id'));\n $input.attr('data-attr-name', this._getAttributeCodeById(attributeId));\n $this.addClass('selected');\n $widget._toggleCheckedAttributes($this, $wrapper);\n }\n\n $widget._Rebuild();\n\n if ($priceBox.is(':data(mage-priceBox)')) {\n $widget._UpdatePrice();\n }\n\n $(document).trigger('updateMsrpPriceBlock',\n [\n this._getSelectedOptionPriceIndex(),\n $widget.options.jsonConfig.optionPrices,\n $priceBox\n ]);\n\n if (parseInt(checkAdditionalData['update_product_preview_image'], 10) === 1) {\n $widget._loadMedia();\n }\n\n $input.trigger('change');\n },\n\n /**\n * Get selected option price index\n *\n * @return {String|undefined}\n * @private\n */\n _getSelectedOptionPriceIndex: function () {\n var allowedProduct = this._getAllowedProductWithMinPrice(this._CalcProducts());\n\n if (_.isEmpty(allowedProduct)) {\n return undefined;\n }\n\n return allowedProduct;\n },\n\n /**\n * Get human readable attribute code (eg. size, color) by it ID from configuration\n *\n * @param {Number} attributeId\n * @returns {*}\n * @private\n */\n _getAttributeCodeById: function (attributeId) {\n var attribute = this.options.jsonConfig.mappedAttributes[attributeId];\n\n return attribute ? attribute.code : attributeId;\n },\n\n /**\n * Toggle accessibility attributes\n *\n * @param {Object} $this\n * @param {Object} $wrapper\n * @private\n */\n _toggleCheckedAttributes: function ($this, $wrapper) {\n $wrapper.attr('aria-activedescendant', $this.attr('id'))\n .find('.' + this.options.classes.optionClass).attr('aria-checked', false);\n $this.attr('aria-checked', true);\n },\n\n /**\n * Event for select\n *\n * @param {Object} $this\n * @param {Object} $widget\n * @private\n */\n _OnChange: function ($this, $widget) {\n var $parent = $this.parents('.' + $widget.options.classes.attributeClass),\n attributeId = $parent.data('attribute-id'),\n $input = $parent.find('.' + $widget.options.classes.attributeInput);\n\n if ($widget.productForm.length > 0) {\n $input = $widget.productForm.find(\n '.' + $widget.options.classes.attributeInput + '[name=\"super_attribute[' + attributeId + ']\"]'\n );\n }\n\n if ($this.val() > 0) {\n $parent.attr('data-option-selected', $this.val());\n $input.val($this.val());\n } else {\n $parent.removeAttr('data-option-selected');\n $input.val('');\n }\n\n $widget._Rebuild();\n $widget._UpdatePrice();\n $widget._loadMedia();\n $input.trigger('change');\n },\n\n /**\n * Event for more switcher\n *\n * @param {Object} $this\n * @private\n */\n _OnMoreClick: function ($this) {\n $this.nextAll().show();\n $this.trigger('blur').remove();\n },\n\n /**\n * Rewind options for controls\n *\n * @private\n */\n _Rewind: function (controls) {\n controls.find('div[data-option-id], option[data-option-id]')\n .removeClass('disabled')\n .prop('disabled', false);\n controls.find('div[data-option-empty], option[data-option-empty]')\n .attr('disabled', true)\n .addClass('disabled')\n .attr('tabindex', '-1');\n this.disableSwatchForOutOfStockProducts();\n },\n\n /**\n * Rebuild container\n *\n * @private\n */\n _Rebuild: function () {\n var $widget = this,\n controls = $widget.element.find('.' + $widget.options.classes.attributeClass + '[data-attribute-id]'),\n selected = controls.filter('[data-option-selected]');\n\n // Enable all options\n $widget._Rewind(controls);\n\n // done if nothing selected\n if (selected.length <= 0) {\n return;\n }\n\n // Disable not available options\n controls.each(function () {\n var $this = $(this),\n id = $this.data('attribute-id'),\n products = $widget._CalcProducts(id);\n\n if (selected.length === 1 && selected.first().data('attribute-id') === id) {\n return;\n }\n\n $this.find('[data-option-id]').each(function () {\n var $element = $(this),\n option = $element.data('option-id');\n\n if (!$widget.optionsMap.hasOwnProperty(id) || !$widget.optionsMap[id].hasOwnProperty(option) ||\n $element.hasClass('selected') ||\n $element.is(':selected')) {\n return;\n }\n\n if (_.intersection(products, $widget.optionsMap[id][option].products).length <= 0) {\n $element.attr('disabled', true).addClass('disabled');\n }\n });\n });\n },\n\n /**\n * Get selected product list\n *\n * @returns {Array}\n * @private\n */\n _CalcProducts: function ($skipAttributeId) {\n var $widget = this,\n selectedOptions = '.' + $widget.options.classes.attributeClass + '[data-option-selected]',\n products = [];\n\n // Generate intersection of products\n $widget.element.find(selectedOptions).each(function () {\n var id = $(this).data('attribute-id'),\n option = $(this).attr('data-option-selected');\n\n if ($skipAttributeId !== undefined && $skipAttributeId === id) {\n return;\n }\n\n if (!$widget.optionsMap.hasOwnProperty(id) || !$widget.optionsMap[id].hasOwnProperty(option)) {\n return;\n }\n\n if (products.length === 0) {\n products = $widget.optionsMap[id][option].products;\n } else {\n products = _.intersection(products, $widget.optionsMap[id][option].products);\n }\n });\n\n return products;\n },\n\n /**\n * Update total price\n *\n * @private\n */\n _UpdatePrice: function () {\n var $widget = this,\n $product = $widget.element.parents($widget.options.selectorProduct),\n $productPrice = $product.find(this.options.selectorProductPrice),\n result = $widget._getNewPrices(),\n tierPriceHtml,\n isShow;\n\n $productPrice.trigger(\n 'updatePrice',\n {\n 'prices': $widget._getPrices(result, $productPrice.priceBox('option').prices)\n }\n );\n\n isShow = typeof result != 'undefined' && result.oldPrice.amount !== result.finalPrice.amount;\n\n $productPrice.find('span:first').toggleClass('special-price', isShow);\n\n $product.find(this.options.slyOldPriceSelector)[isShow ? 'show' : 'hide']();\n\n if (typeof result != 'undefined' && result.tierPrices && result.tierPrices.length) {\n if (this.options.tierPriceTemplate) {\n tierPriceHtml = mageTemplate(\n this.options.tierPriceTemplate,\n {\n 'tierPrices': result.tierPrices,\n '$t': $t,\n 'currencyFormat': this.options.jsonConfig.currencyFormat,\n 'priceUtils': priceUtils\n }\n );\n $(this.options.tierPriceBlockSelector).html(tierPriceHtml).show();\n }\n } else {\n $(this.options.tierPriceBlockSelector).hide();\n }\n\n $(this.options.normalPriceLabelSelector).hide();\n\n _.each($('.' + this.options.classes.attributeOptionsWrapper), function (attribute) {\n if ($(attribute).find('.' + this.options.classes.optionClass + '.selected').length === 0) {\n if ($(attribute).find('.' + this.options.classes.selectClass).length > 0) {\n _.each($(attribute).find('.' + this.options.classes.selectClass), function (dropdown) {\n if ($(dropdown).val() === '0') {\n $(this.options.normalPriceLabelSelector).show();\n }\n }.bind(this));\n } else {\n $(this.options.normalPriceLabelSelector).show();\n }\n }\n }.bind(this));\n },\n\n /**\n * Get new prices for selected options\n *\n * @returns {*}\n * @private\n */\n _getNewPrices: function () {\n var $widget = this,\n newPrices = $widget.options.jsonConfig.prices,\n allowedProduct = this._getAllowedProductWithMinPrice(this._CalcProducts());\n\n if (!_.isEmpty(allowedProduct)) {\n newPrices = this.options.jsonConfig.optionPrices[allowedProduct];\n }\n\n return newPrices;\n },\n\n /**\n * Get prices\n *\n * @param {Object} newPrices\n * @param {Object} displayPrices\n * @returns {*}\n * @private\n */\n _getPrices: function (newPrices, displayPrices) {\n var $widget = this;\n\n if (_.isEmpty(newPrices)) {\n newPrices = $widget._getNewPrices();\n }\n _.each(displayPrices, function (price, code) {\n\n if (newPrices[code]) {\n displayPrices[code].amount = newPrices[code].amount - displayPrices[code].amount;\n }\n });\n\n return displayPrices;\n },\n\n /**\n * Get product with minimum price from selected options.\n *\n * @param {Array} allowedProducts\n * @returns {String}\n * @private\n */\n _getAllowedProductWithMinPrice: function (allowedProducts) {\n var optionPrices = this.options.jsonConfig.optionPrices,\n product = {},\n optionFinalPrice, optionMinPrice;\n\n _.each(allowedProducts, function (allowedProduct) {\n optionFinalPrice = parseFloat(optionPrices[allowedProduct].finalPrice.amount);\n\n if (_.isEmpty(product) || optionFinalPrice < optionMinPrice) {\n optionMinPrice = optionFinalPrice;\n product = allowedProduct;\n }\n }, this);\n\n return product;\n },\n\n /**\n * Gets all product media and change current to the needed one\n *\n * @private\n */\n _LoadProductMedia: function () {\n var $widget = this,\n $this = $widget.element,\n productData = this._determineProductData(),\n mediaCallData,\n mediaCacheKey,\n\n /**\n * Processes product media data\n *\n * @param {Object} data\n * @returns void\n */\n mediaSuccessCallback = function (data) {\n if (!(mediaCacheKey in $widget.options.mediaCache)) {\n $widget.options.mediaCache[mediaCacheKey] = data;\n }\n $widget._ProductMediaCallback($this, data, productData.isInProductView);\n setTimeout(function () {\n $widget._DisableProductMediaLoader($this);\n }, 300);\n };\n\n if (!$widget.options.mediaCallback) {\n return;\n }\n\n mediaCallData = {\n 'product_id': this.getProduct()\n };\n\n mediaCacheKey = JSON.stringify(mediaCallData);\n\n if (mediaCacheKey in $widget.options.mediaCache) {\n $widget._XhrKiller();\n $widget._EnableProductMediaLoader($this);\n mediaSuccessCallback($widget.options.mediaCache[mediaCacheKey]);\n } else {\n mediaCallData.isAjax = true;\n $widget._XhrKiller();\n $widget._EnableProductMediaLoader($this);\n $widget.xhr = $.ajax({\n url: $widget.options.mediaCallback,\n cache: true,\n type: 'GET',\n dataType: 'json',\n data: mediaCallData,\n success: mediaSuccessCallback\n }).done(function () {\n $widget._XhrKiller();\n });\n }\n },\n\n /**\n * Enable loader\n *\n * @param {Object} $this\n * @private\n */\n _EnableProductMediaLoader: function ($this) {\n var $widget = this;\n\n if ($('body.catalog-product-view').length > 0) {\n $this.parents('.column.main').find('.photo.image')\n .addClass($widget.options.classes.loader);\n } else {\n //Category View\n $this.parents('.product-item-info').find('.product-image-photo')\n .addClass($widget.options.classes.loader);\n }\n },\n\n /**\n * Disable loader\n *\n * @param {Object} $this\n * @private\n */\n _DisableProductMediaLoader: function ($this) {\n var $widget = this;\n\n if ($('body.catalog-product-view').length > 0) {\n $this.parents('.column.main').find('.photo.image')\n .removeClass($widget.options.classes.loader);\n } else {\n //Category View\n $this.parents('.product-item-info').find('.product-image-photo')\n .removeClass($widget.options.classes.loader);\n }\n },\n\n /**\n * Callback for product media\n *\n * @param {Object} $this\n * @param {String} response\n * @param {Boolean} isInProductView\n * @private\n */\n _ProductMediaCallback: function ($this, response, isInProductView) {\n var $main = isInProductView ? $this.parents('.column.main') : $this.parents('.product-item-info'),\n $widget = this,\n images = [],\n\n /**\n * Check whether object supported or not\n *\n * @param {Object} e\n * @returns {*|Boolean}\n */\n support = function (e) {\n return e.hasOwnProperty('large') && e.hasOwnProperty('medium') && e.hasOwnProperty('small');\n };\n\n if (_.size($widget) < 1 || !support(response)) {\n this.updateBaseImage(this.options.mediaGalleryInitial, $main, isInProductView);\n\n return;\n }\n\n images.push({\n full: response.large,\n img: response.medium,\n thumb: response.small,\n isMain: true\n });\n\n if (response.hasOwnProperty('gallery')) {\n $.each(response.gallery, function () {\n if (!support(this) || response.large === this.large) {\n return;\n }\n images.push({\n full: this.large,\n img: this.medium,\n thumb: this.small\n });\n });\n }\n\n this.updateBaseImage(images, $main, isInProductView);\n },\n\n /**\n * Check if images to update are initial and set their type\n * @param {Array} images\n */\n _setImageType: function (images) {\n\n images.map(function (img) {\n if (!img.type) {\n img.type = 'image';\n }\n });\n\n return images;\n },\n\n /**\n * Update [gallery-placeholder] or [product-image-photo]\n * @param {Array} images\n * @param {jQuery} context\n * @param {Boolean} isInProductView\n */\n updateBaseImage: function (images, context, isInProductView) {\n var justAnImage = images[0],\n initialImages = this.options.mediaGalleryInitial,\n imagesToUpdate,\n gallery = context.find(this.options.mediaGallerySelector).data('gallery'),\n isInitial;\n\n if (isInProductView) {\n if (_.isUndefined(gallery)) {\n context.find(this.options.mediaGallerySelector).on('gallery:loaded', function () {\n this.updateBaseImage(images, context, isInProductView);\n }.bind(this));\n\n return;\n }\n\n imagesToUpdate = images.length ? this._setImageType($.extend(true, [], images)) : [];\n isInitial = _.isEqual(imagesToUpdate, initialImages);\n\n if (this.options.gallerySwitchStrategy === 'prepend' && !isInitial) {\n imagesToUpdate = imagesToUpdate.concat(initialImages);\n }\n\n imagesToUpdate = this._setImageIndex(imagesToUpdate);\n\n gallery.updateData(imagesToUpdate);\n this._addFotoramaVideoEvents(isInitial);\n } else if (justAnImage && justAnImage.img) {\n context.find('.product-image-photo').attr('src', justAnImage.img);\n }\n },\n\n /**\n * Add video events\n *\n * @param {Boolean} isInitial\n * @private\n */\n _addFotoramaVideoEvents: function (isInitial) {\n if (_.isUndefined($.mage.AddFotoramaVideoEvents)) {\n return;\n }\n\n if (isInitial) {\n $(this.options.mediaGallerySelector).AddFotoramaVideoEvents();\n\n return;\n }\n\n $(this.options.mediaGallerySelector).AddFotoramaVideoEvents({\n selectedOption: this.getProduct(),\n dataMergeStrategy: this.options.gallerySwitchStrategy\n });\n },\n\n /**\n * Set correct indexes for image set.\n *\n * @param {Array} images\n * @private\n */\n _setImageIndex: function (images) {\n var length = images.length,\n i;\n\n for (i = 0; length > i; i++) {\n images[i].i = i + 1;\n }\n\n return images;\n },\n\n /**\n * Kill doubled AJAX requests\n *\n * @private\n */\n _XhrKiller: function () {\n var $widget = this;\n\n if ($widget.xhr !== undefined && $widget.xhr !== null) {\n $widget.xhr.abort();\n $widget.xhr = null;\n }\n },\n\n /**\n * Emulate mouse click on all swatches that should be selected\n * @param {Object} [selectedAttributes]\n * @private\n */\n _EmulateSelected: function (selectedAttributes) {\n $.each(selectedAttributes, $.proxy(function (attributeCode, optionId) {\n var elem = this.element.find('.' + this.options.classes.attributeClass +\n '[data-attribute-code=\"' + attributeCode + '\"] [data-option-id=\"' + optionId + '\"]'),\n parentInput = elem.parent();\n\n if (elem.hasClass('selected')) {\n return;\n }\n\n if (parentInput.hasClass(this.options.classes.selectClass)) {\n parentInput.val(optionId);\n parentInput.trigger('change');\n } else {\n elem.trigger('click');\n }\n }, this));\n },\n\n /**\n * Emulate mouse click or selection change on all swatches that should be selected\n * @param {Object} [selectedAttributes]\n * @private\n */\n _EmulateSelectedByAttributeId: function (selectedAttributes) {\n $.each(selectedAttributes, $.proxy(function (attributeId, optionId) {\n var elem = this.element.find('.' + this.options.classes.attributeClass +\n '[data-attribute-id=\"' + attributeId + '\"] [data-option-id=\"' + optionId + '\"]'),\n parentInput = elem.parent();\n\n if (elem.hasClass('selected')) {\n return;\n }\n\n if (parentInput.hasClass(this.options.classes.selectClass)) {\n parentInput.val(optionId);\n parentInput.trigger('change');\n } else {\n elem.trigger('click');\n }\n }, this));\n },\n\n /**\n * Get default options values settings with either URL query parameters\n * @private\n */\n _getSelectedAttributes: function () {\n var hashIndex = window.location.href.indexOf('#'),\n selectedAttributes = {},\n params;\n\n if (hashIndex !== -1) {\n params = $.parseQuery(window.location.href.substr(hashIndex + 1));\n\n selectedAttributes = _.invert(_.mapObject(_.invert(params), function (attributeId) {\n var attribute = this.options.jsonConfig.mappedAttributes[attributeId];\n\n return attribute ? attribute.code : attributeId;\n }.bind(this)));\n }\n\n return selectedAttributes;\n },\n\n /**\n * Callback which fired after gallery gets initialized.\n *\n * @param {HTMLElement} element - DOM element associated with a gallery.\n */\n _onGalleryLoaded: function (element) {\n var galleryObject = element.data('gallery');\n\n this.options.mediaGalleryInitial = galleryObject.returnCurrentImages();\n },\n\n /**\n * Sets mediaCache for cases when jsonConfig contains preSelectedGallery on layered navigation result pages\n *\n * @private\n */\n _setPreSelectedGallery: function () {\n var mediaCallData;\n\n if (this.options.jsonConfig.preSelectedGallery) {\n mediaCallData = {\n 'product_id': this.getProduct()\n };\n\n this.options.mediaCache[JSON.stringify(mediaCallData)] = this.options.jsonConfig.preSelectedGallery;\n }\n },\n\n /**\n * Callback for quantity change event.\n */\n _onQtyChanged: function () {\n var $price = this.element.parents(this.options.selectorProduct)\n .find(this.options.selectorProductPrice);\n\n $price.trigger(\n 'updatePrice',\n {\n 'prices': this._getPrices(this._getNewPrices(), $price.priceBox('option').prices)\n }\n );\n }\n });\n\n return $.mage.SwatchRenderer;\n});\n","Magento_Swatches/js/configurable-customer-data.js":"require([\n 'jquery',\n 'Magento_ConfigurableProduct/js/options-updater'\n], function ($, Updater) {\n 'use strict';\n\n var selectors = {\n formSelector: '#product_addtocart_form',\n swatchSelector: '.swatch-opt'\n },\n swatchWidgetName = 'mage-SwatchRenderer',\n widgetInitEvent = 'swatch.initialized',\n\n /**\n * Sets all configurable swatch attribute's selected values\n */\n updateSwatchOptions = function () {\n var swatchWidget = $(selectors.swatchSelector).data(swatchWidgetName);\n\n if (!swatchWidget || !swatchWidget._EmulateSelectedByAttributeId) {\n return;\n }\n swatchWidget._EmulateSelectedByAttributeId(this.productOptions);\n },\n updater = new Updater(widgetInitEvent, updateSwatchOptions);\n\n updater.listen();\n});\n","Magento_Swatches/js/catalog-add-to-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\nrequire([\n 'jquery'\n], function ($) {\n 'use strict';\n\n /**\n * Add selected swatch attributes to redirect url\n *\n * @see Magento_Catalog/js/catalog-add-to-cart\n */\n $('body').on('catalogCategoryAddToCartRedirect', function (event, data) {\n $(data.form).find('[name*=\"super\"]').each(function (index, item) {\n var $item = $(item),\n attr;\n\n if ($item.attr('data-attr-name')) {\n attr = $item.attr('data-attr-name');\n } else {\n attr = $item.parent().attr('attribute-code');\n }\n data.redirectParameters.push(attr + '=' + $item.val());\n\n });\n });\n});\n","Mageplaza_Blog/js/postAction.js":"/**\r\n * Mageplaza\r\n *\r\n * NOTICE OF LICENSE\r\n *\r\n * This source file is subject to the Mageplaza.com license that is\r\n * available through the world-wide-web at this URL:\r\n * https://www.mageplaza.com/LICENSE.txt\r\n *\r\n * DISCLAIMER\r\n *\r\n * Do not edit or add to this file if you wish to upgrade this extension to newer\r\n * version in the future.\r\n *\r\n * @category Mageplaza\r\n * @package Mageplaza_Blog\r\n * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)\r\n * @license https://www.mageplaza.com/LICENSE.txt\r\n */\r\ndefine([\r\n 'jquery',\r\n \"mage/adminhtml/events\",\r\n \"mage/adminhtml/wysiwyg/tiny_mce/setup\"\r\n], function ($) {\r\n 'use strict';\r\n\r\n $.widget('mageplaza.mpBlogPostAction', {\r\n options: {},\r\n _create: function () {\r\n var self = this;\r\n\r\n $('button.mpblog-action-new').on('click', function () {\r\n self._AddNew();\r\n });\r\n },\r\n _AddNew: function () {\r\n var form = $('#mp_blog_post_form'),\r\n formData = new FormData(form[0]),\r\n htmlPopup = $('#mp-blog-new-post-popup'),\r\n url = form.attr('action');\r\n\r\n $.ajax({\r\n url: url,\r\n type: \"post\",\r\n data: formData,\r\n cache: false,\r\n contentType: false,\r\n processData: false,\r\n showLoader: true,\r\n success: function (result) {\r\n htmlPopup.data('mageModal').closeModal();\r\n if (result.status === 1) {\r\n setTimeout(function () {\r\n location.reload();\r\n }, 500);\r\n }\r\n }\r\n });\r\n }\r\n }\r\n );\r\n\r\n return $.mageplaza.mpBlogPostAction;\r\n});\r\n","Mageplaza_Blog/js/comment.js":"/**\r\n * Mageplaza\r\n *\r\n * NOTICE OF LICENSE\r\n *\r\n * This source file is subject to the Mageplaza.com license that is\r\n * available through the world-wide-web at this URL:\r\n * https://www.mageplaza.com/LICENSE.txt\r\n *\r\n * DISCLAIMER\r\n *\r\n * Do not edit or add to this file if you wish to upgrade this extension to newer\r\n * version in the future.\r\n *\r\n * @category Mageplaza\r\n * @package Mageplaza_Blog\r\n * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)\r\n * @license https://www.mageplaza.com/LICENSE.txt\r\n */\r\n\r\n\r\nrequire([\r\n 'jquery'\r\n], function ($) {\r\n 'use strict';\r\n\r\n var cmtBox = $('.default-cmt__content__cmt-block__cmt-box__cmt-input'),\r\n submitCmt = $('.default-cmt__content__cmt-block__cmt-box__cmt-btn__btn-submit'),\r\n defaultCmt = $('ul.default-cmt__content__cmt-content:first'),\r\n likeBtn = defaultCmt.find('.btn-like'),\r\n replyBtn = defaultCmt.find('.btn-reply');\r\n\r\n submitComment();\r\n likeComment(likeBtn);\r\n showReply(replyBtn);\r\n\r\n $('li.default-cmt__content__cmt-content__cmt-row:first').css({'border-top': 'none'});\r\n $('.default-cmt__cmt-login__btn-login').click(function () {\r\n var socialPopup = $(\"[href$='social-login-popup']\");\r\n\r\n if (socialPopup.length) {\r\n socialPopup.first().trigger(\"click\");\r\n } else {\r\n window.location.href = loginUrl;\r\n }\r\n });\r\n\r\n /**\r\n * Check the guest name and email input is valid\r\n *\r\n * @returns {boolean}\r\n */\r\n function checkGuestFormValidate() {\r\n if (isLogged == 'No') {\r\n return $(\"#default-cmt__content__cmt-block__guest-form\").valid();\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * The comment submit button action\r\n */\r\n function submitComment() {\r\n submitCmt.click(function () {\r\n $(\".default-cmt__content__cmt-block__cmt-box\").find('.messages').hide();\r\n if (checkGuestFormValidate()) {\r\n var cmtText = cmtBox.val();\r\n\r\n if (cmtText.trim().length) {\r\n $('.default-cmt_loading').show();\r\n $(this).prop('disabled', true);\r\n var ajaxRequest = ajaxCommentActions(cmtText, submitCmt);\r\n ajaxRequest.done(function () {\r\n cmtBox.val('');\r\n $('.default-cmt_loading').hide();\r\n $(this).prop('disabled', false);\r\n }.bind(this));\r\n } else {\r\n $('.default-cmt__content__cmt-block__cmt-box__cmt-input').parent().append(messengerBox.cmt_warning);\r\n }\r\n }\r\n });\r\n }\r\n\r\n //like action\r\n function likeComment(btn) {\r\n btn.each(function () {\r\n var likeEl = $(this);\r\n\r\n likeEl.click(function () {\r\n var cmtId = $(this).attr('data-cmt-id'),\r\n cmtRowContainer = $(this).closest('.default-cmt__content__cmt-content__cmt-row');\r\n if (isLogged === 'Yes') {\r\n var likeCount = $(this).find('span').text();\r\n if ($(this).attr('click') === '1') {\r\n if ($(this).hasClass('mpblog-liked')) {\r\n $(this).css('color', '#333333');\r\n likeCount--;\r\n $(this).find('span').text((likeCount === 0) ? \"\" : likeCount);\r\n $(this).removeClass('mpblog-liked')\r\n\r\n } else {\r\n likeCount++;\r\n $(this).find('span').text(likeCount);\r\n $(this).css('color', likedColor);\r\n $(this).addClass('mpblog-liked')\r\n }\r\n $.ajax({\r\n type: \"POST\",\r\n url: window.location.href,\r\n data: {cmtId: cmtId},\r\n success: function (response) {\r\n if (response.status === 'ok') {\r\n $(likeEl).attr('click', '1');\r\n } else if (response.status === 'error' && response.hasOwnProperty(error)) {\r\n defaultCmt.append(response.error);\r\n }\r\n }\r\n });\r\n }\r\n $(this).attr('click', '0');\r\n\r\n } else {\r\n cmtRowContainer.append(messengerBox.login_warning);\r\n jQuery.fn.fadeOutAndRemove = function (speed) {\r\n $(this).fadeOut(speed, function () {\r\n $(this).remove();\r\n })\r\n };\r\n var removeNotification = function () {\r\n $('.message.error.message-error').fadeOutAndRemove('normal');\r\n };\r\n setTimeout(removeNotification, 3000);\r\n }\r\n\r\n });\r\n });\r\n }\r\n\r\n //show reply\r\n function showReply(btn) {\r\n btn.each(function () {\r\n\r\n $(this).click(function () {\r\n var cmtId = (typeof $(this).closest('.default-cmt__content__cmt-content__cmt-row').parent().parent().attr('data-cmt-id') !== 'undefined') ? $(this).closest('.default-cmt__content__cmt-content__cmt-row').parent().parent().attr('data-cmt-id') : $(this).attr('data-cmt-id'),\r\n inputCmtID = $(this).attr('data-cmt-id'),\r\n cmtRowCmt = $(\"div\").find('#cmt-row');\r\n var cmtRowContainer = $(this).closest('.default-cmt__content__cmt-content__cmt-row');\r\n if ($(\"li.cmt-row-\" + cmtId).find(\"ul\").length) {\r\n var cmtRowContainer = $(\"#cmt-id-\" + cmtId + \" ul:last-child\");\r\n }\r\n var cmtRow = cmtRowContainer.find('.row__' + inputCmtID);\r\n var cmtName = $(\".username__\" + inputCmtID).text();\r\n\r\n if (isLogged === 'Yes') {\r\n if (cmtRowCmt.length) {\r\n cmtRowCmt.toggle();\r\n $(\"#cmt-row\").remove();\r\n }\r\n if (cmtRow.length) {\r\n cmtRow.toggle();\r\n $(\"#cmt-row\").remove();\r\n } else {\r\n cmtRowContainer.append('<div id=\"cmt-row\" class=\"cmt-row__reply-row row row__' + inputCmtID + ' col-md-12\">' +\r\n '<div class=\"reply-form__form-input form-group col-xs-8 col-md-6\">' +\r\n '<label for=\"reply_cmt' + inputCmtID + '\"></label>' +\r\n '<input type=\"text\" id=\"reply_cmt' + inputCmtID + '\" class=\"form-group__input form-control\" placeholder=\"Press enter to submit reply\" value=\"' + cmtName + ' \" autofocus onfocus=\"this.setSelectionRange(1000,1001);\"/>' +\r\n '</div>' +\r\n '</div>');\r\n var input = $('#reply_cmt' + inputCmtID);\r\n input.closest('.form-group').append(\r\n $('.default-cmt__content__cmt-block__cmt-box__cmt-btn .default-cmt_loading').clone()\r\n );\r\n input.focus();\r\n submitReply(input, cmtId, cmtRowContainer);\r\n }\r\n } else {\r\n cmtRowContainer.append(messengerBox.login_warning);\r\n jQuery.fn.fadeOutAndRemove = function (speed) {\r\n $(this).fadeOut(speed, function () {\r\n $(this).remove();\r\n })\r\n };\r\n var removeNotification = function () {\r\n $('.message.error.message-error').fadeOutAndRemove('normal');\r\n };\r\n setTimeout(removeNotification, 3000);\r\n }\r\n });\r\n });\r\n }\r\n\r\n //submit reply\r\n function submitReply(input, replyId, parentComment) {\r\n input.keypress(function (e) {\r\n var text = input.val();\r\n if (text !== '') {\r\n if (e.keyCode === 13) {\r\n input.siblings('.default-cmt_loading').show();\r\n input.prop('disabled', true);\r\n var ajaxRequest = ajaxCommentActions(text, input, true, replyId, parentComment);\r\n ajaxRequest.done(function () {\r\n input.closest('.cmt-row__reply-row').hide();\r\n input.siblings('.default-cmt_loading').hide();\r\n input.prop('disabled', false);\r\n $(\"#cmt-row\").remove();\r\n });\r\n }\r\n }\r\n });\r\n }\r\n\r\n //submit comment actions\r\n function ajaxCommentActions(cmtText, inputEl, checkReply, cmtId, parentComment) {\r\n var isReply = (typeof checkReply !== 'undefined') ? 1 : 0,\r\n replyId = (typeof cmtId !== 'undefined') ? cmtId : 0,\r\n displayReply = (typeof checkReply !== 'undefined');\r\n var guestName = $('#default-cmt__content__cmt-block__guest-box__name-input').val();\r\n var guestEmail = $('#default-cmt__content__cmt-block__guest-box__email-input').val();\r\n return $.ajax({\r\n type: 'POST',\r\n url: window.location.href,\r\n // async: false,\r\n data: {cmt_text: cmtText, isReply: isReply, replyId: replyId, guestName: guestName, guestEmail: guestEmail},\r\n success: function (response) {\r\n switch (response.status) {\r\n case 'duplicated':\r\n $('.default-cmt__content__cmt-block__cmt-box__cmt-input').parent().append(messengerBox.exist_email_warning);\r\n break;\r\n case 3:\r\n $('.default-cmt__content__cmt-block').prepend(messengerBox.comment_approve);\r\n break;\r\n case 1:\r\n displayComment(response, displayReply);\r\n inputEl.val('');\r\n break;\r\n case 'error':\r\n if (checkReply !== 'undefined') {\r\n parentComment.append(response.error);\r\n } else {\r\n defaultCmt.append(response.error);\r\n }\r\n break;\r\n }\r\n }\r\n });\r\n }\r\n\r\n // display comment\r\n function displayComment(cmt, isReply) {\r\n function htmlComment(text) {\r\n var html = '';\r\n var sub = text.split(\"\\n\");\r\n for (var i = 0; i < sub.length; i++) {\r\n html += '<p>' + sub[i] + '</p>';\r\n }\r\n return html;\r\n }\r\n var cmtRow = '<li style=\"width: 100%\" id=\"cmt-id-' + cmt.cmt_id + '\" class=\"default-cmt__content__cmt-content__cmt-row cmt-row-' + cmt.cmt_id + ' cmt-row col-m-12 '\r\n + (isReply ? ('reply-row') : '') + '\" data-cmt-id=\"' + cmt.cmt_id + '\"' + (isReply ? ('data-reply-id=\"' + cmt.reply_cmt + '\"') : '')\r\n + '> <div class=\"cmt-row__cmt-username\"> <span class=\"cmt-row__cmt-username username username__' + cmt.cmt_id + '\">' + cmt.user_cmt\r\n + '</span> </div> <div class=\"cmt-row__cmt-content\"> <p>' + htmlComment(cmt.cmt_text)\r\n + '</p> </div> <div class=\"cmt-row__cmt-interactions interactions\"> <div class=\"interactions__btn-actions\"> <a class=\"interactions__btn-actions action btn-like mpblog-like\" data-cmt-id=\"'\r\n + cmt.cmt_id + '\" click=\"1\"><i class=\"fa fa-thumbs-up\" aria-hidden=\"true\" style=\"margin-right: 3px\"></i><span class=\"count-like__like-text\"></span></a> <a class=\"interactions__btn-actions action btn-reply\" data-cmt-id=\"'\r\n + cmt.cmt_id + '\">' + reply + '</a> </div> <div class=\"interactions__cmt-createdat\"> <span>' + cmt.created_at + '</span> </div> </div> </li>';\r\n\r\n if (isReply) {\r\n var replyCmtId = cmt.reply_cmt;\r\n var replyCmt = defaultCmt.find('.default-cmt__content__cmt-content__cmt-row');\r\n\r\n replyCmt.each(function () {\r\n var cmtEl = $(this);\r\n if (cmtEl.attr('data-cmt-id') === replyCmtId) {\r\n var replyList = cmtEl.find('ul.default-cmt__content__cmt-content:first');\r\n\r\n if (!replyList.length) {\r\n cmtRow = $('<ul class=\"default-cmt__content__cmt-content row\">' + cmtRow + '</ul>');\r\n cmtEl.append(cmtRow);\r\n\r\n likeComment(cmtRow.find('.btn-like'));\r\n showReply(cmtRow.find('.btn-reply'));\r\n } else {\r\n cmtRow = $(cmtRow);\r\n replyList.append(cmtRow);\r\n\r\n likeComment(cmtRow.find('.btn-like'));\r\n showReply(cmtRow.find('.btn-reply'));\r\n\r\n }\r\n\r\n return false;\r\n }\r\n });\r\n } else {\r\n cmtRow = $(cmtRow);\r\n defaultCmt.append(cmtRow);\r\n\r\n likeComment(cmtRow.find('.btn-like'));\r\n showReply(cmtRow.find('.btn-reply'));\r\n }\r\n }\r\n});","Mageplaza_Blog/js/helpful-rate.js":"/**\r\n * Mageplaza\r\n *\r\n * NOTICE OF LICENSE\r\n *\r\n * This source file is subject to the Mageplaza.com license that is\r\n * available through the world-wide-web at this URL:\r\n * https://www.mageplaza.com/LICENSE.txt\r\n *\r\n * DISCLAIMER\r\n *\r\n * Do not edit or add to this file if you wish to upgrade this extension to newer\r\n * version in the future.\r\n *\r\n * @category Mageplaza\r\n * @package Mageplaza_Blog\r\n * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)\r\n * @license https://www.mageplaza.com/LICENSE.txt\r\n */\r\ndefine([\r\n 'jquery'\r\n], function ($) {\r\n 'use strict';\r\n\r\n $.widget('mageplaza.mpBlogHelpfulRate', {\r\n options: {\r\n url: '',\r\n post_id: '',\r\n mode: ''\r\n },\r\n _create: function () {\r\n var post_id = this.options.post_id,\r\n url = this.options.url,\r\n self = this,\r\n subPostId = {};\r\n\r\n if (self.options.mode === 1) {\r\n $.ajax({\r\n url: url,\r\n type: \"post\",\r\n data: {\r\n post_id: post_id,\r\n action: '3',\r\n mode: self.options.mode\r\n },\r\n showLoader: false,\r\n success: function (response) {\r\n if (response.status === 0) {\r\n self.disableReview(response.action);\r\n }\r\n }\r\n });\r\n } else if (JSON.parse(self.getCookie('mpblog_post_data'))) {\r\n subPostId = JSON.parse(self.getCookie('mpblog_post_data'));\r\n if (typeof subPostId[post_id] !== \"undefined\") {\r\n self.disableReview(subPostId[post_id].type);\r\n }\r\n }\r\n\r\n $('#mp-blog-review div').each(function () {\r\n var el = this;\r\n\r\n\r\n $(el).on('click', function () {\r\n var action = 0,\r\n currentPostIds = {},\r\n likeId = 0;\r\n\r\n if (JSON.parse(self.getCookie('mpblog_post_data'))) {\r\n currentPostIds = JSON.parse(self.getCookie('mpblog_post_data'));\r\n }\r\n\r\n if ($(this).hasClass('mp-blog-like')) {\r\n action = 1;\r\n }\r\n\r\n if (typeof currentPostIds[post_id] !== \"undefined\" && self.options.mode === 0) {\r\n likeId = currentPostIds[post_id].likeId;\r\n self.enableReview(currentPostIds[post_id].type);\r\n if (action === currentPostIds[post_id].type) {\r\n delete currentPostIds[post_id];\r\n document.cookie = 'mpblog_post_data = ' + JSON.stringify(currentPostIds);\r\n } else {\r\n currentPostIds[post_id].type = action;\r\n self.disableReview(action);\r\n }\r\n }\r\n $.ajax({\r\n url: url,\r\n type: \"post\",\r\n data: {\r\n post_id: post_id,\r\n action: action,\r\n mode: self.options.mode,\r\n likeId: likeId\r\n },\r\n showLoader: true,\r\n success: function (response) {\r\n var storedPostIds,\r\n jsonStringIds;\r\n\r\n if (response['postLike']\r\n && self.options.mode === 0 && typeof currentPostIds[post_id] === \"undefined\") {\r\n storedPostIds =\r\n self.receiveCookiePostIds(post_id, action, response['postLike'], self);\r\n jsonStringIds = JSON.stringify(storedPostIds);\r\n document.cookie = 'mpblog_post_data = ' + jsonStringIds;\r\n }\r\n\r\n if (response['status']) {\r\n if (response[\"sumLike\"]) {\r\n $('#mp-blog-review .mp-blog-like .mp-blog-view')\r\n .text('(' + response[\"sumLike\"] + ')');\r\n } else {\r\n $('#mp-blog-review .mp-blog-like .mp-blog-view')\r\n .text('');\r\n }\r\n if (response[\"sumDislike\"]) {\r\n $('#mp-blog-review .mp-blog-dislike .mp-blog-view')\r\n .text('(' + response[\"sumDislike\"] + ')');\r\n } else {\r\n $('#mp-blog-review .mp-blog-dislike .mp-blog-view')\r\n .text('');\r\n }\r\n }\r\n\r\n if (response['status']) {\r\n self.enableAllReview();\r\n if (response['postLike']) {\r\n self.disableReview(action);\r\n }\r\n }\r\n\r\n $('html, body').animate({\r\n scrollTop: $('body').offset().top\r\n }, 500);\r\n }\r\n });\r\n\r\n });\r\n });\r\n },\r\n disableReview: function (action) {\r\n if ('' + action === '1') {\r\n $('.mp-blog-like').css('background-color', '#658259');\r\n\r\n } else {\r\n $('.mp-blog-dislike').css('background-color', '#9a6464');\r\n }\r\n },\r\n enableReview: function (action) {\r\n if ('' + action === '1') {\r\n $('.mp-blog-like').css('background-color', '#6AA84F');\r\n\r\n } else {\r\n $('.mp-blog-dislike').css('background-color', '#EC3A3C');\r\n }\r\n },\r\n enableAllReview: function () {\r\n $('.mp-blog-like').css('background-color', '#6AA84F');\r\n $('.mp-blog-dislike').css('background-color', '#EC3A3C');\r\n\r\n },\r\n getCookie: function (name) {\r\n var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');\r\n\r\n return v ? v[2] : null;\r\n },\r\n receiveCookiePostIds: function (postId, action, likeId, self) {\r\n var postData = {\r\n id: postId,\r\n type: action,\r\n likeId: likeId\r\n },\r\n receivedJsonStr = self.getCookie('mpblog_post_data'),\r\n postIds = JSON.parse(receivedJsonStr);\r\n\r\n if (postIds == null) {\r\n postIds = {};\r\n }\r\n if (typeof postIds[postId] !== \"undefined\") {\r\n\r\n return postIds;\r\n }\r\n postIds[postId] = postData;\r\n\r\n return postIds;\r\n }\r\n }\r\n );\r\n\r\n return $.mageplaza.mpBlogHelpfulRate;\r\n});\r\n","Mageplaza_Blog/js/managePost.js":"/**\r\n * Mageplaza\r\n *\r\n * NOTICE OF LICENSE\r\n *\r\n * This source file is subject to the Mageplaza.com license that is\r\n * available through the world-wide-web at this URL:\r\n * https://www.mageplaza.com/LICENSE.txt\r\n *\r\n * DISCLAIMER\r\n *\r\n * Do not edit or add to this file if you wish to upgrade this extension to newer\r\n * version in the future.\r\n *\r\n * @category Mageplaza\r\n * @package Mageplaza_Blog\r\n * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)\r\n * @license https://www.mageplaza.com/LICENSE.txt\r\n */\r\ndefine([\r\n 'jquery',\r\n 'mage/translate',\r\n 'underscore',\r\n 'Magento_Ui/js/modal/modal',\r\n 'uiRegistry',\r\n 'moment',\r\n \"Mageplaza_Blog/js/get-editor\"\r\n], function ($, $t, _, modal, registry, moment, editor) {\r\n 'use strict';\r\n\r\n $.widget('mageplaza.mpBlogManagePost', {\r\n options: {\r\n deleteUrl: '',\r\n basePubUrl: '',\r\n postDatas: {},\r\n editorVersion: '',\r\n magentoVersion: ''\r\n },\r\n _create: function () {\r\n var self = this,\r\n htmlPopup = $('#mp-blog-new-post-popup');\r\n\r\n $('.mp-blog-new-post button').on('click', function () {\r\n self._AddNewPost(self, htmlPopup);\r\n });\r\n\r\n $('.mpblog-post-edit').on('click', function () {\r\n self._EditPost(self, this, htmlPopup);\r\n });\r\n\r\n $('.mpblog-post-duplicate').on('click', function () {\r\n self._DuplicatePost(self, this, htmlPopup);\r\n });\r\n\r\n $('.mpblog-post-delete').on('click', function () {\r\n self._DeletePost(self, this);\r\n });\r\n },\r\n _AddNewPost: function (self, htmlPopup) {\r\n var options = {\r\n 'type': 'popup',\r\n 'title': $t('Add New Post'),\r\n 'responsive': true,\r\n 'innerScroll': true,\r\n 'buttons': []\r\n };\r\n\r\n self._resetForm('');\r\n self._openPopup(options, htmlPopup, self);\r\n },\r\n _resetForm: function (postContent) {\r\n var iframe = document.getElementById('post_content_ifr');\r\n\r\n $('#mp_blog_post_form').trigger(\"reset\");\r\n $('#short_description').empty();\r\n $('#post_content').empty();\r\n $('#post_id').removeAttr('value');\r\n\r\n if (iframe){\r\n iframe.contentWindow.document.open();\r\n iframe.contentWindow.document.write(postContent);\r\n iframe.contentWindow.document.close();\r\n }\r\n\r\n $('.mp-field .mp-image-link').remove();\r\n registry.get('customCategory').value('');\r\n registry.get('customTag').value('');\r\n registry.get('customTopic').value('');\r\n },\r\n _EditPost: function (self, click, htmlPopup) {\r\n var postId = $(click).parent().data('postid'),\r\n postData = self.options.postDatas[postId],\r\n pubUrl = self.options.basePubUrl,\r\n options = {\r\n 'type': 'popup',\r\n 'title': $t('Edit Post'),\r\n 'responsive': true,\r\n 'innerScroll': true,\r\n 'buttons': []\r\n };\r\n\r\n if (htmlPopup.find('#mp_blog_post_form [name=\"name\"]').length > 0) {\r\n self._resetForm(postData['post_content']);\r\n }\r\n self._openPopup(options, htmlPopup, self);\r\n self._setPopupFormData(postData, pubUrl, htmlPopup);\r\n },\r\n _setPopupFormData: function(postData, pubUrl, htmlPopup){\r\n _.each(postData, function (value, name) {\r\n var field = htmlPopup.find('#mp_blog_post_form [name=\"' + name + '\"]'),\r\n imageEL,\r\n deleteEL,\r\n date;\r\n\r\n if (field.is('[type=\"file\"]') && value) {\r\n imageEL = '<a class=\"mp-image-link\" href=\"' + pubUrl + 'mageplaza/blog/post/' + value\r\n + '\" onclick=\"imagePreview(\\'post_image_image\\'); return false;\" >' +\r\n '<img src=\"' + pubUrl + 'mageplaza/blog/post/' + value + '\" id=\"post_image_image\"' +\r\n ' title=\"' + value + '\" alt=\"' + value + '\" height=\"22\" width=\"22\"' +\r\n ' class=\"small-image-preview v-middle\">' +\r\n '</a>';\r\n field.parent().prepend(imageEL);\r\n deleteEL = '<span class=\"delete-image\">'\r\n + '<input style=\"width: 8%\" type=\"checkbox\" name=\"image[delete]\"'\r\n + ' value=\"1\" class=\"checkbox\" id=\"post_image_delete\">'\r\n + '<label for=\"post_image_delete\"> Delete Image</label>'\r\n + '</span>';\r\n if (!field.parent().find('.delete-image').lenth) {\r\n field.parent().append(deleteEL);\r\n }\r\n } else if (field.is('[type=\"datetime-local\"]')) {\r\n date = moment(value).format(\"YYYY-MM-DDTkk:mm\");\r\n field.val(date);\r\n } else if (field.is('input') || field.is('select')) {\r\n field.val(value);\r\n } else if (field.is('textarea')) {\r\n field.html(value);\r\n }\r\n if (name === 'category_ids') {\r\n registry.get('customCategory').value(value);\r\n }\r\n if (name === 'tag_ids') {\r\n registry.get('customTag').value(value);\r\n }\r\n if (name === 'topic_ids') {\r\n registry.get('customTopic').value(value);\r\n }\r\n });\r\n },\r\n _DuplicatePost: function (self, click, htmlPopup) {\r\n var postId = $(click).parent().data('postid'),\r\n postData = self.options.postDatas[postId],\r\n pubUrl = self.options.basePubUrl,\r\n options = {\r\n 'type': 'popup',\r\n 'title': $t('Duplicate Post'),\r\n 'responsive': true,\r\n 'innerScroll': true,\r\n 'buttons': []\r\n };\r\n\r\n if (htmlPopup.find('#mp_blog_post_form [name=\"name\"]').length > 0) {\r\n self._resetForm(postData['post_content']);\r\n }\r\n self._openPopup(options, htmlPopup, self);\r\n self._setPopupFormData(postData, pubUrl, htmlPopup);\r\n $('#post_id').removeAttr('value');\r\n $('#image').parent().append('<input type=\"hidden\" name=\"image\" value=\"'+postData[\"image\"]+'\" />');\r\n },\r\n _DeletePost: function (self, widget) {\r\n var url = self.options.deleteUrl,\r\n id = $(widget).parent().data('postid');\r\n\r\n $.ajax({\r\n url: url,\r\n type: \"post\",\r\n data: {\r\n post_id: id\r\n },\r\n showLoader: true,\r\n success: function (result) {\r\n if (result['status'] === 1){\r\n $('.post-list-item[data-post-id=\"'+result['post_id']+'\"]').remove();\r\n }\r\n },\r\n complete: function () {\r\n\r\n }\r\n });\r\n },\r\n _openPopup: function (options, htmlPopup, self) {\r\n var popupModal,\r\n editorVersion = self.options.editorVersion,\r\n magentoVersion = self.options.magentoVersion;\r\n\r\n popupModal = modal(options, htmlPopup);\r\n popupModal.openModal();\r\n $('#mp_blog_post_form').trigger('contentUpdated');\r\n\r\n editor.config('post_content', editorVersion, magentoVersion);\r\n }\r\n }\r\n );\r\n\r\n return $.mageplaza.mpBlogManagePost;\r\n});\r\n","Mageplaza_Blog/js/get-editor.js":"/**\r\n * Mageplaza\r\n *\r\n * NOTICE OF LICENSE\r\n *\r\n * This source file is subject to the Mageplaza.com license that is\r\n * available through the world-wide-web at this URL:\r\n * https://www.mageplaza.com/LICENSE.txt\r\n *\r\n * DISCLAIMER\r\n *\r\n * Do not edit or add to this file if you wish to upgrade this extension to newer\r\n * version in the future.\r\n *\r\n * @category Mageplaza\r\n * @package Mageplaza_Blog\r\n * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)\r\n * @license https://www.mageplaza.com/LICENSE.txt\r\n */\r\ndefine([\r\n 'jquery',\r\n \"mage/adminhtml/events\",\r\n \"mage/adminhtml/wysiwyg/tiny_mce/setup\"\r\n], function ($) {\r\n 'use strict';\r\n\r\n return {\r\n config: function (nameEL, versionEditor, versionMagento, width) {\r\n var wysiwygcompany_description,\r\n config = {},\r\n editor;\r\n\r\n if (typeof width === 'undefined') {\r\n width = '99%';\r\n }\r\n\r\n if (versionMagento === \"2\") {\r\n $.extend(config, {\r\n settings: {\r\n theme_advanced_buttons1: 'bold,italic,|,justifyleft,justifycenter,justifyright,|,' +\r\n 'fontselect,fontsizeselect,|,forecolor,backcolor,|,link,unlink,image,|,' +\r\n 'bullist,numlist,|,code',\r\n theme_advanced_buttons2: null,\r\n theme_advanced_buttons3: null,\r\n theme_advanced_buttons4: null\r\n }\r\n });\r\n editor = new tinyMceWysiwygSetup(\r\n nameEL,\r\n config\r\n );\r\n editor.turnOn();\r\n $('#' + nameEL).addClass('wysiwyg-editor').data('wysiwygEditor', editor);\r\n } else if (versionEditor === \"4\") {\r\n wysiwygcompany_description = new wysiwygSetup(nameEL, {\r\n \"width\": width,\r\n \"height\": \"200px\",\r\n \"plugins\": [{\"name\": \"image\"}],\r\n \"tinymce4\": {\r\n \"toolbar\": \"formatselect | bold italic underline | alignleft aligncenter alignright |\" +\r\n \" bullist numlist | link table charmap\",\r\n \"plugins\": \"advlist autolink lists link charmap media noneditable\" +\r\n \" table contextmenu paste code help table\"\r\n }\r\n });\r\n wysiwygcompany_description.setup(\"exact\");\r\n } else {\r\n $.extend(config, {\r\n settings: {\r\n theme_advanced_buttons1: 'bold,italic,|,justifyleft,justifycenter,justifyright,|,' +\r\n 'fontselect,fontsizeselect,|,forecolor,backcolor,|,link,unlink,image,|,' +\r\n 'bullist,numlist,|,code',\r\n theme_advanced_buttons2: null,\r\n theme_advanced_buttons3: null,\r\n theme_advanced_buttons4: null\r\n },\r\n tinymce : {\r\n content_css : null\r\n }\r\n });\r\n editor = new wysiwygSetup(\r\n nameEL,\r\n config\r\n );\r\n editor.setup(\"exact\");\r\n $('#' + nameEL).addClass('wysiwyg-editor').data('wysiwygEditor', editor);\r\n }\r\n }\r\n };\r\n});","Mageplaza_Blog/js/categorytree.js":"/**\r\n * Mageplaza\r\n *\r\n * NOTICE OF LICENSE\r\n *\r\n * This source file is subject to the Mageplaza.com license that is\r\n * available through the world-wide-web at this URL:\r\n * https://www.mageplaza.com/LICENSE.txt\r\n *\r\n * DISCLAIMER\r\n *\r\n * Do not edit or add to this file if you wish to upgrade this extension to newer\r\n * version in the future.\r\n *\r\n * @category Mageplaza\r\n * @package Mageplaza_Blog\r\n * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)\r\n * @license https://www.mageplaza.com/LICENSE.txt\r\n */\r\n\r\ndefine([\r\n 'jquery'\r\n ], function ($) {\r\n \"use strict\";\r\n\r\n var parentCategory = $(\".mp-blog-expand-tree-2\");\r\n var childCategory = $(\".mp-blog-expand-tree-3\");\r\n\r\n parentCategory.click(function () {\r\n if ($(this).hasClass(\"mp-blog-expand-tree-2\")) {\r\n $(this).parent().find(\".category-level3\").slideDown(\"fast\");\r\n $(this).removeClass(\"mp-blog-expand-tree-2 fa fa-plus-square-o\")\r\n .addClass(\"mp-blog-narrow-tree-2 fa fa-minus-square-o\");\r\n } else {\r\n $(this).parent().find(\".category-level4\").slideUp(\"fast\");\r\n $(this).parent().find(\".category-level3\").slideUp(\"fast\");\r\n $(this).removeClass(\"mp-blog-narrow-tree-2 fa fa-minus-square-o\")\r\n .addClass(\"mp-blog-expand-tree-2 fa fa-plus-square-o\");\r\n $(this).parent().find(\".mp-blog-narrow-tree-3\")\r\n .removeClass(\"mp-blog-narrow-tree-3 fa fa-minus-square-o\")\r\n .addClass(\"mp-blog-expand-tree-3 fa fa-plus-square-o\");\r\n }\r\n\r\n });\r\n\r\n childCategory.click(function () {\r\n if ($(this).hasClass(\"mp-blog-expand-tree-3\")) {\r\n $(this).parent().find(\".category-level4\").slideDown(\"fast\");\r\n $(this).removeClass(\"mp-blog-expand-tree-3 fa fa-plus-square-o\")\r\n .addClass(\"mp-blog-narrow-tree-3 fa fa-minus-square-o\");\r\n } else {\r\n $(this).parent().find(\".category-level4\").slideUp(\"fast\");\r\n $(this).removeClass(\"mp-blog-narrow-tree-3 fa fa-minus-square-o\")\r\n .addClass(\"mp-blog-expand-tree-3 fa fa-plus-square-o\");\r\n }\r\n });\r\n }\r\n);","fotorama/fotorama.js":"/*!\n * Fotorama 4.6.4 | http://fotorama.io/license/\n */\nfotoramaVersion = '4.6.4';\n(function (window, document, location, $, undefined) {\n \"use strict\";\n var _fotoramaClass = 'fotorama',\n _fullscreenClass = 'fotorama__fullscreen',\n\n wrapClass = _fotoramaClass + '__wrap',\n wrapCss2Class = wrapClass + '--css2',\n wrapCss3Class = wrapClass + '--css3',\n wrapVideoClass = wrapClass + '--video',\n wrapFadeClass = wrapClass + '--fade',\n wrapSlideClass = wrapClass + '--slide',\n wrapNoControlsClass = wrapClass + '--no-controls',\n wrapNoShadowsClass = wrapClass + '--no-shadows',\n wrapPanYClass = wrapClass + '--pan-y',\n wrapRtlClass = wrapClass + '--rtl',\n wrapOnlyActiveClass = wrapClass + '--only-active',\n wrapNoCaptionsClass = wrapClass + '--no-captions',\n wrapToggleArrowsClass = wrapClass + '--toggle-arrows',\n\n stageClass = _fotoramaClass + '__stage',\n stageFrameClass = stageClass + '__frame',\n stageFrameVideoClass = stageFrameClass + '--video',\n stageShaftClass = stageClass + '__shaft',\n\n grabClass = _fotoramaClass + '__grab',\n pointerClass = _fotoramaClass + '__pointer',\n\n arrClass = _fotoramaClass + '__arr',\n arrDisabledClass = arrClass + '--disabled',\n arrPrevClass = arrClass + '--prev',\n arrNextClass = arrClass + '--next',\n\n navClass = _fotoramaClass + '__nav',\n navWrapClass = navClass + '-wrap',\n navShaftClass = navClass + '__shaft',\n navShaftVerticalClass = navWrapClass + '--vertical',\n navShaftListClass = navWrapClass + '--list',\n navShafthorizontalClass = navWrapClass + '--horizontal',\n navDotsClass = navClass + '--dots',\n navThumbsClass = navClass + '--thumbs',\n navFrameClass = navClass + '__frame',\n\n fadeClass = _fotoramaClass + '__fade',\n fadeFrontClass = fadeClass + '-front',\n fadeRearClass = fadeClass + '-rear',\n\n shadowClass = _fotoramaClass + '__shadow',\n shadowsClass = shadowClass + 's',\n shadowsLeftClass = shadowsClass + '--left',\n shadowsRightClass = shadowsClass + '--right',\n shadowsTopClass = shadowsClass + '--top',\n shadowsBottomClass = shadowsClass + '--bottom',\n\n activeClass = _fotoramaClass + '__active',\n selectClass = _fotoramaClass + '__select',\n\n hiddenClass = _fotoramaClass + '--hidden',\n\n fullscreenClass = _fotoramaClass + '--fullscreen',\n fullscreenIconClass = _fotoramaClass + '__fullscreen-icon',\n\n errorClass = _fotoramaClass + '__error',\n loadingClass = _fotoramaClass + '__loading',\n loadedClass = _fotoramaClass + '__loaded',\n loadedFullClass = loadedClass + '--full',\n loadedImgClass = loadedClass + '--img',\n\n grabbingClass = _fotoramaClass + '__grabbing',\n\n imgClass = _fotoramaClass + '__img',\n imgFullClass = imgClass + '--full',\n\n thumbClass = _fotoramaClass + '__thumb',\n thumbArrLeft = thumbClass + '__arr--left',\n thumbArrRight = thumbClass + '__arr--right',\n thumbBorderClass = thumbClass + '-border',\n\n htmlClass = _fotoramaClass + '__html',\n\n videoContainerClass = _fotoramaClass + '-video-container',\n videoClass = _fotoramaClass + '__video',\n videoPlayClass = videoClass + '-play',\n videoCloseClass = videoClass + '-close',\n\n\n horizontalImageClass = _fotoramaClass + '_horizontal_ratio',\n verticalImageClass = _fotoramaClass + '_vertical_ratio',\n fotoramaSpinnerClass = _fotoramaClass + '__spinner',\n spinnerShowClass = fotoramaSpinnerClass + '--show';\n var JQUERY_VERSION = $ && $.fn.jquery.split('.');\n\n if (!JQUERY_VERSION\n || JQUERY_VERSION[0] < 1\n || (JQUERY_VERSION[0] == 1 && JQUERY_VERSION[1] < 8)) {\n throw 'Fotorama requires jQuery 1.8 or later and will not run without it.';\n }\n\n var _ = {};\n /* Modernizr 2.8.3 (Custom Build) | MIT & BSD\n * Build: http://modernizr.com/download/#-csstransforms3d-csstransitions-touch-prefixed\n */\n\n var Modernizr = (function (window, document, undefined) {\n var version = '2.8.3',\n Modernizr = {},\n\n\n docElement = document.documentElement,\n\n mod = 'modernizr',\n modElem = document.createElement(mod),\n mStyle = modElem.style,\n inputElem,\n\n\n toString = {}.toString,\n\n prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),\n\n\n omPrefixes = 'Webkit Moz O ms',\n\n cssomPrefixes = omPrefixes.split(' '),\n\n domPrefixes = omPrefixes.toLowerCase().split(' '),\n\n\n tests = {},\n inputs = {},\n attrs = {},\n\n classes = [],\n\n slice = classes.slice,\n\n featureName,\n\n\n injectElementWithStyles = function (rule, callback, nodes, testnames) {\n\n var style, ret, node, docOverflow,\n div = document.createElement('div'),\n body = document.body,\n fakeBody = body || document.createElement('body');\n\n if (parseInt(nodes, 10)) {\n while (nodes--) {\n node = document.createElement('div');\n node.id = testnames ? testnames[nodes] : mod + (nodes + 1);\n div.appendChild(node);\n }\n }\n\n style = ['­', '<style id=\"s', mod, '\">', rule, '</style>'].join('');\n div.id = mod;\n (body ? div : fakeBody).innerHTML += style;\n fakeBody.appendChild(div);\n if (!body) {\n fakeBody.style.background = '';\n fakeBody.style.overflow = 'hidden';\n docOverflow = docElement.style.overflow;\n docElement.style.overflow = 'hidden';\n docElement.appendChild(fakeBody);\n }\n\n ret = callback(div, rule);\n if (!body) {\n fakeBody.parentNode.removeChild(fakeBody);\n docElement.style.overflow = docOverflow;\n } else {\n div.parentNode.removeChild(div);\n }\n\n return !!ret;\n\n },\n _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;\n\n if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {\n hasOwnProp = function (object, property) {\n return _hasOwnProperty.call(object, property);\n };\n }\n else {\n hasOwnProp = function (object, property) {\n return ((property in object) && is(object.constructor.prototype[property], 'undefined'));\n };\n }\n\n\n if (!Function.prototype.bind) {\n Function.prototype.bind = function bind(that) {\n\n var target = this;\n\n if (typeof target != \"function\") {\n throw new TypeError();\n }\n\n var args = slice.call(arguments, 1),\n bound = function () {\n\n if (this instanceof bound) {\n\n var F = function () {\n };\n F.prototype = target.prototype;\n var self = new F();\n\n var result = target.apply(\n self,\n args.concat(slice.call(arguments))\n );\n if (Object(result) === result) {\n return result;\n }\n return self;\n\n } else {\n\n return target.apply(\n that,\n args.concat(slice.call(arguments))\n );\n\n }\n\n };\n\n return bound;\n };\n }\n\n function setCss(str) {\n mStyle.cssText = str;\n }\n\n function setCssAll(str1, str2) {\n return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));\n }\n\n function is(obj, type) {\n return typeof obj === type;\n }\n\n function contains(str, substr) {\n return !!~('' + str).indexOf(substr);\n }\n\n function testProps(props, prefixed) {\n for (var i in props) {\n var prop = props[i];\n if (!contains(prop, \"-\") && mStyle[prop] !== undefined) {\n return prefixed == 'pfx' ? prop : true;\n }\n }\n return false;\n }\n\n function testDOMProps(props, obj, elem) {\n for (var i in props) {\n var item = obj[props[i]];\n if (item !== undefined) {\n\n if (elem === false) return props[i];\n\n if (is(item, 'function')) {\n return item.bind(elem || obj);\n }\n\n return item;\n }\n }\n return false;\n }\n\n function testPropsAll(prop, prefixed, elem) {\n\n var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),\n props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');\n\n if (is(prefixed, \"string\") || is(prefixed, \"undefined\")) {\n return testProps(props, prefixed);\n\n } else {\n props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');\n return testDOMProps(props, prefixed, elem);\n }\n }\n\n tests['touch'] = function () {\n var bool;\n\n if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {\n bool = true;\n } else {\n injectElementWithStyles(['@media (', prefixes.join('touch-enabled),('), mod, ')', '{#modernizr{top:9px;position:absolute}}'].join(''), function (node) {\n bool = node.offsetTop === 9;\n });\n }\n\n return bool;\n };\n tests['csstransforms3d'] = function () {\n\n var ret = !!testPropsAll('perspective');\n\n if (ret && 'webkitPerspective' in docElement.style) {\n\n injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function (node, rule) {\n ret = node.offsetLeft === 9 && node.offsetHeight === 3;\n });\n }\n return ret;\n };\n\n\n tests['csstransitions'] = function () {\n return testPropsAll('transition');\n };\n\n\n for (var feature in tests) {\n if (hasOwnProp(tests, feature)) {\n featureName = feature.toLowerCase();\n Modernizr[featureName] = tests[feature]();\n\n classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);\n }\n }\n\n\n Modernizr.addTest = function (feature, test) {\n if (typeof feature == 'object') {\n for (var key in feature) {\n if (hasOwnProp(feature, key)) {\n Modernizr.addTest(key, feature[key]);\n }\n }\n } else {\n\n feature = feature.toLowerCase();\n\n if (Modernizr[feature] !== undefined) {\n return Modernizr;\n }\n\n test = typeof test == 'function' ? test() : test;\n\n if (typeof enableClasses !== \"undefined\" && enableClasses) {\n docElement.className += ' ' + (test ? '' : 'no-') + feature;\n }\n Modernizr[feature] = test;\n\n }\n\n return Modernizr;\n };\n\n\n setCss('');\n modElem = inputElem = null;\n\n\n Modernizr._version = version;\n\n Modernizr._prefixes = prefixes;\n Modernizr._domPrefixes = domPrefixes;\n Modernizr._cssomPrefixes = cssomPrefixes;\n\n\n Modernizr.testProp = function (prop) {\n return testProps([prop]);\n };\n\n Modernizr.testAllProps = testPropsAll;\n Modernizr.testStyles = injectElementWithStyles;\n Modernizr.prefixed = function (prop, obj, elem) {\n if (!obj) {\n return testPropsAll(prop, 'pfx');\n } else {\n return testPropsAll(prop, obj, elem);\n }\n };\n return Modernizr;\n })(window, document);\n\n var fullScreenApi = {\n ok: false,\n is: function () {\n return false;\n },\n request: function () {\n },\n cancel: function () {\n },\n event: '',\n prefix: ''\n },\n browserPrefixes = 'webkit moz o ms khtml'.split(' ');\n\n// check for native support\n if (typeof document.cancelFullScreen != 'undefined') {\n fullScreenApi.ok = true;\n } else {\n // check for fullscreen support by vendor prefix\n for (var i = 0, il = browserPrefixes.length; i < il; i++) {\n fullScreenApi.prefix = browserPrefixes[i];\n if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') {\n fullScreenApi.ok = true;\n break;\n }\n }\n }\n\n// update methods to do something useful\n if (fullScreenApi.ok) {\n fullScreenApi.event = fullScreenApi.prefix + 'fullscreenchange';\n fullScreenApi.is = function () {\n switch (this.prefix) {\n case '':\n return document.fullScreen;\n case 'webkit':\n return document.webkitIsFullScreen;\n default:\n return document[this.prefix + 'FullScreen'];\n }\n };\n fullScreenApi.request = function (el) {\n return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();\n };\n fullScreenApi.cancel = function (el) {\n if (!this.is()) {\n return false;\n }\n return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();\n };\n }\n /* Bez v1.0.10-g5ae0136\n * http://github.com/rdallasgray/bez\n *\n * A plugin to convert CSS3 cubic-bezier co-ordinates to jQuery-compatible easing functions\n *\n * With thanks to Nikolay Nemshilov for clarification on the cubic-bezier maths\n * See http://st-on-it.blogspot.com/2011/05/calculating-cubic-bezier-function.html\n *\n * Copyright 2011 Robert Dallas Gray. All rights reserved.\n * Provided under the FreeBSD license: https://github.com/rdallasgray/bez/blob/master/LICENSE.txt\n */\n function bez(coOrdArray) {\n var encodedFuncName = \"bez_\" + $.makeArray(arguments).join(\"_\").replace(\".\", \"p\");\n if (typeof $['easing'][encodedFuncName] !== \"function\") {\n var polyBez = function (p1, p2) {\n var A = [null, null],\n B = [null, null],\n C = [null, null],\n bezCoOrd = function (t, ax) {\n C[ax] = 3 * p1[ax];\n B[ax] = 3 * (p2[ax] - p1[ax]) - C[ax];\n A[ax] = 1 - C[ax] - B[ax];\n return t * (C[ax] + t * (B[ax] + t * A[ax]));\n },\n xDeriv = function (t) {\n return C[0] + t * (2 * B[0] + 3 * A[0] * t);\n },\n xForT = function (t) {\n var x = t, i = 0, z;\n while (++i < 14) {\n z = bezCoOrd(x, 0) - t;\n if (Math.abs(z) < 1e-3) break;\n x -= z / xDeriv(x);\n }\n return x;\n };\n return function (t) {\n return bezCoOrd(xForT(t), 1);\n }\n };\n $['easing'][encodedFuncName] = function (x, t, b, c, d) {\n return c * polyBez([coOrdArray[0], coOrdArray[1]], [coOrdArray[2], coOrdArray[3]])(t / d) + b;\n }\n }\n return encodedFuncName;\n }\n\n var $WINDOW = $(window),\n $DOCUMENT = $(document),\n $HTML,\n $BODY,\n\n QUIRKS_FORCE = location.hash.replace('#', '') === 'quirks',\n TRANSFORMS3D = Modernizr.csstransforms3d,\n CSS3 = TRANSFORMS3D && !QUIRKS_FORCE,\n COMPAT = TRANSFORMS3D || document.compatMode === 'CSS1Compat',\n FULLSCREEN = fullScreenApi.ok,\n\n MOBILE = navigator.userAgent.match(/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i),\n SLOW = !CSS3 || MOBILE,\n\n MS_POINTER = navigator.msPointerEnabled,\n\n WHEEL = \"onwheel\" in document.createElement(\"div\") ? \"wheel\" : document.onmousewheel !== undefined ? \"mousewheel\" : \"DOMMouseScroll\",\n\n TOUCH_TIMEOUT = 250,\n TRANSITION_DURATION = 300,\n\n SCROLL_LOCK_TIMEOUT = 1400,\n\n AUTOPLAY_INTERVAL = 5000,\n MARGIN = 2,\n THUMB_SIZE = 64,\n\n WIDTH = 500,\n HEIGHT = 333,\n\n STAGE_FRAME_KEY = '$stageFrame',\n NAV_DOT_FRAME_KEY = '$navDotFrame',\n NAV_THUMB_FRAME_KEY = '$navThumbFrame',\n\n AUTO = 'auto',\n\n BEZIER = bez([.1, 0, .25, 1]),\n\n MAX_WIDTH = 1200,\n\n /**\n * Number of thumbnails in slide. Calculated only on setOptions and resize.\n * @type {number}\n */\n thumbsPerSlide = 1,\n\n OPTIONS = {\n\n /**\n * Set width for gallery.\n * Default value - width of first image\n * Number - set value in px\n * String - set value in quotes\n *\n */\n width: null,\n\n /**\n * Set min-width for gallery\n *\n */\n minwidth: null,\n\n /**\n * Set max-width for gallery\n *\n */\n maxwidth: '100%',\n\n /**\n * Set height for gallery\n * Default value - height of first image\n * Number - set value in px\n * String - set value in quotes\n *\n */\n height: null,\n\n /**\n * Set min-height for gallery\n *\n */\n minheight: null,\n\n /**\n * Set max-height for gallery\n *\n */\n maxheight: null,\n\n /**\n * Set proportion ratio for gallery depends of image\n *\n */\n ratio: null, // '16/9' || 500/333 || 1.5\n\n margin: MARGIN,\n\n nav: 'dots', // 'thumbs' || false\n navposition: 'bottom', // 'top'\n navwidth: null,\n thumbwidth: THUMB_SIZE,\n thumbheight: THUMB_SIZE,\n thumbmargin: MARGIN,\n thumbborderwidth: MARGIN,\n\n allowfullscreen: false, // true || 'native'\n\n transition: 'slide', // 'crossfade' || 'dissolve'\n clicktransition: null,\n transitionduration: TRANSITION_DURATION,\n\n captions: true,\n\n startindex: 0,\n\n loop: false,\n\n autoplay: false,\n stopautoplayontouch: true,\n\n keyboard: false,\n\n arrows: true,\n click: true,\n swipe: false,\n trackpad: false,\n\n shuffle: false,\n\n direction: 'ltr', // 'rtl'\n\n shadows: true,\n\n showcaption: true,\n\n /**\n * Set type of thumbnail navigation\n */\n navdir: 'horizontal',\n\n /**\n * Set configuration to show or hide arrows in thumb navigation\n */\n navarrows: true,\n\n /**\n * Set type of navigation. Can be thumbs or slides\n */\n navtype: 'thumbs'\n\n },\n\n KEYBOARD_OPTIONS = {\n left: true,\n right: true,\n down: true,\n up: true,\n space: false,\n home: false,\n end: false\n };\n\n function noop() {\n }\n\n function minMaxLimit(value, min, max) {\n return Math.max(isNaN(min) ? -Infinity : min, Math.min(isNaN(max) ? Infinity : max, value));\n }\n\n function readTransform(css, dir) {\n return css.match(/ma/) && css.match(/-?\\d+(?!d)/g)[css.match(/3d/) ?\n (dir === 'vertical' ? 13 : 12) : (dir === 'vertical' ? 5 : 4)\n ]\n }\n\n function readPosition($el, dir) {\n if (CSS3) {\n return +readTransform($el.css('transform'), dir);\n } else {\n return +$el.css(dir === 'vertical' ? 'top' : 'left').replace('px', '');\n }\n }\n\n function getTranslate(pos, direction) {\n var obj = {};\n\n if (CSS3) {\n\n switch (direction) {\n case 'vertical':\n obj.transform = 'translate3d(0, ' + (pos) + 'px,0)';\n break;\n case 'list':\n break;\n default :\n obj.transform = 'translate3d(' + (pos) + 'px,0,0)';\n break;\n }\n } else {\n direction === 'vertical' ?\n obj.top = pos :\n obj.left = pos;\n }\n return obj;\n }\n\n function getDuration(time) {\n return {'transition-duration': time + 'ms'};\n }\n\n function unlessNaN(value, alternative) {\n return isNaN(value) ? alternative : value;\n }\n\n function numberFromMeasure(value, measure) {\n return unlessNaN(+String(value).replace(measure || 'px', ''));\n }\n\n function numberFromPercent(value) {\n return /%$/.test(value) ? numberFromMeasure(value, '%') : undefined;\n }\n\n function numberFromWhatever(value, whole) {\n return unlessNaN(numberFromPercent(value) / 100 * whole, numberFromMeasure(value));\n }\n\n function measureIsValid(value) {\n return (!isNaN(numberFromMeasure(value)) || !isNaN(numberFromMeasure(value, '%'))) && value;\n }\n\n function getPosByIndex(index, side, margin, baseIndex) {\n\n return (index - (baseIndex || 0)) * (side + (margin || 0));\n }\n\n function getIndexByPos(pos, side, margin, baseIndex) {\n return -Math.round(pos / (side + (margin || 0)) - (baseIndex || 0));\n }\n\n function bindTransitionEnd($el) {\n var elData = $el.data();\n\n if (elData.tEnd) return;\n\n var el = $el[0],\n transitionEndEvent = {\n WebkitTransition: 'webkitTransitionEnd',\n MozTransition: 'transitionend',\n OTransition: 'oTransitionEnd otransitionend',\n msTransition: 'MSTransitionEnd',\n transition: 'transitionend'\n };\n addEvent(el, transitionEndEvent[Modernizr.prefixed('transition')], function (e) {\n elData.tProp && e.propertyName.match(elData.tProp) && elData.onEndFn();\n });\n elData.tEnd = true;\n }\n\n function afterTransition($el, property, fn, time) {\n var ok,\n elData = $el.data();\n\n if (elData) {\n elData.onEndFn = function () {\n if (ok) return;\n ok = true;\n clearTimeout(elData.tT);\n fn();\n };\n elData.tProp = property;\n\n // Passive call, just in case of fail of native transition-end event\n clearTimeout(elData.tT);\n elData.tT = setTimeout(function () {\n elData.onEndFn();\n }, time * 1.5);\n\n bindTransitionEnd($el);\n }\n }\n\n\n function stop($el, pos/*, _001*/) {\n var dir = $el.navdir || 'horizontal';\n if ($el.length) {\n var elData = $el.data();\n if (CSS3) {\n $el.css(getDuration(0));\n elData.onEndFn = noop;\n clearTimeout(elData.tT);\n } else {\n $el.stop();\n }\n var lockedPos = getNumber(pos, function () {\n return readPosition($el, dir);\n });\n\n $el.css(getTranslate(lockedPos, dir/*, _001*/));//.width(); // `.width()` for reflow\n return lockedPos;\n }\n }\n\n function getNumber() {\n var number;\n for (var _i = 0, _l = arguments.length; _i < _l; _i++) {\n number = _i ? arguments[_i]() : arguments[_i];\n if (typeof number === 'number') {\n break;\n }\n }\n\n return number;\n }\n\n function edgeResistance(pos, edge) {\n return Math.round(pos + ((edge - pos) / 1.5));\n }\n\n function getProtocol() {\n getProtocol.p = getProtocol.p || (location.protocol === 'https:' ? 'https://' : 'http://');\n return getProtocol.p;\n }\n\n function parseHref(href) {\n var a = document.createElement('a');\n a.href = href;\n return a;\n }\n\n function findVideoId(href, forceVideo) {\n if (typeof href !== 'string') return href;\n href = parseHref(href);\n\n var id,\n type;\n\n if (href.host.match(/youtube\\.com/) && href.search) {\n //.log();\n id = href.search.split('v=')[1];\n if (id) {\n var ampersandPosition = id.indexOf('&');\n if (ampersandPosition !== -1) {\n id = id.substring(0, ampersandPosition);\n }\n type = 'youtube';\n }\n } else if (href.host.match(/youtube\\.com|youtu\\.be|youtube-nocookie.com/)) {\n id = href.pathname.replace(/^\\/(embed\\/|v\\/)?/, '').replace(/\\/.*/, '');\n type = 'youtube';\n } else if (href.host.match(/vimeo\\.com/)) {\n type = 'vimeo';\n id = href.pathname.replace(/^\\/(video\\/)?/, '').replace(/\\/.*/, '');\n }\n\n if ((!id || !type) && forceVideo) {\n id = href.href;\n type = 'custom';\n }\n\n return id ? {id: id, type: type, s: href.search.replace(/^\\?/, ''), p: getProtocol()} : false;\n }\n\n function getVideoThumbs(dataFrame, data, fotorama) {\n var img, thumb, video = dataFrame.video;\n if (video.type === 'youtube') {\n thumb = getProtocol() + 'img.youtube.com/vi/' + video.id + '/default.jpg';\n img = thumb.replace(/\\/default.jpg$/, '/hqdefault.jpg');\n dataFrame.thumbsReady = true;\n } else if (video.type === 'vimeo') {\n $.ajax({\n url: getProtocol() + 'vimeo.com/api/oembed.json',\n data: {\n url: 'https://vimeo.com/' + video.id\n },\n dataType: 'jsonp',\n success: function (json) {\n dataFrame.thumbsReady = true;\n updateData(data, {\n img: json[0].thumbnail_url,\n thumb: json[0].thumbnail_url\n }, dataFrame.i, fotorama);\n }\n });\n } else {\n dataFrame.thumbsReady = true;\n }\n\n return {\n img: img,\n thumb: thumb\n }\n }\n\n function updateData(data, _dataFrame, i, fotorama) {\n for (var _i = 0, _l = data.length; _i < _l; _i++) {\n var dataFrame = data[_i];\n\n if (dataFrame.i === i && dataFrame.thumbsReady) {\n var clear = {videoReady: true};\n clear[STAGE_FRAME_KEY] = clear[NAV_THUMB_FRAME_KEY] = clear[NAV_DOT_FRAME_KEY] = false;\n\n fotorama.splice(_i, 1, $.extend(\n {},\n dataFrame,\n clear,\n _dataFrame\n ));\n\n break;\n }\n }\n }\n\n function getDataFromHtml($el) {\n var data = [];\n\n function getDataFromImg($img, imgData, checkVideo) {\n var $child = $img.children('img').eq(0),\n _imgHref = $img.attr('href'),\n _imgSrc = $img.attr('src'),\n _thumbSrc = $child.attr('src'),\n _video = imgData.video,\n video = checkVideo ? findVideoId(_imgHref, _video === true) : false;\n\n if (video) {\n _imgHref = false;\n } else {\n video = _video;\n }\n\n getDimensions($img, $child, $.extend(imgData, {\n video: video,\n img: imgData.img || _imgHref || _imgSrc || _thumbSrc,\n thumb: imgData.thumb || _thumbSrc || _imgSrc || _imgHref\n }));\n }\n\n function getDimensions($img, $child, imgData) {\n var separateThumbFLAG = imgData.thumb && imgData.img !== imgData.thumb,\n width = numberFromMeasure(imgData.width || $img.attr('width')),\n height = numberFromMeasure(imgData.height || $img.attr('height'));\n\n $.extend(imgData, {\n width: width,\n height: height,\n thumbratio: getRatio(imgData.thumbratio || (numberFromMeasure(imgData.thumbwidth || ($child && $child.attr('width')) || separateThumbFLAG || width) / numberFromMeasure(imgData.thumbheight || ($child && $child.attr('height')) || separateThumbFLAG || height)))\n });\n }\n\n $el.children().each(function () {\n var $this = $(this),\n dataFrame = optionsToLowerCase($.extend($this.data(), {id: $this.attr('id')}));\n if ($this.is('a, img')) {\n getDataFromImg($this, dataFrame, true);\n } else if (!$this.is(':empty')) {\n getDimensions($this, null, $.extend(dataFrame, {\n html: this,\n _html: $this.html() // Because of IE\n }));\n } else return;\n\n data.push(dataFrame);\n });\n\n return data;\n }\n\n function isHidden(el) {\n return el.offsetWidth === 0 && el.offsetHeight === 0;\n }\n\n function isDetached(el) {\n return !$.contains(document.documentElement, el);\n }\n\n function waitFor(test, fn, timeout, i) {\n if (!waitFor.i) {\n waitFor.i = 1;\n waitFor.ii = [true];\n }\n\n i = i || waitFor.i;\n\n if (typeof waitFor.ii[i] === 'undefined') {\n waitFor.ii[i] = true;\n }\n\n if (test()) {\n fn();\n } else {\n waitFor.ii[i] && setTimeout(function () {\n waitFor.ii[i] && waitFor(test, fn, timeout, i);\n }, timeout || 100);\n }\n\n return waitFor.i++;\n }\n\n waitFor.stop = function (i) {\n waitFor.ii[i] = false;\n };\n\n function fit($el, measuresToFit) {\n var elData = $el.data(),\n measures = elData.measures;\n\n if (measures && (!elData.l ||\n elData.l.W !== measures.width ||\n elData.l.H !== measures.height ||\n elData.l.r !== measures.ratio ||\n elData.l.w !== measuresToFit.w ||\n elData.l.h !== measuresToFit.h)) {\n\n var height = minMaxLimit(measuresToFit.h, 0, measures.height),\n width = height * measures.ratio;\n\n UTIL.setRatio($el, width, height);\n\n elData.l = {\n W: measures.width,\n H: measures.height,\n r: measures.ratio,\n w: measuresToFit.w,\n h: measuresToFit.h\n };\n }\n\n return true;\n }\n\n function setStyle($el, style) {\n var el = $el[0];\n if (el.styleSheet) {\n el.styleSheet.cssText = style;\n } else {\n $el.html(style);\n }\n }\n\n function findShadowEdge(pos, min, max, dir) {\n return min === max ? false :\n dir === 'vertical' ?\n (pos <= min ? 'top' : pos >= max ? 'bottom' : 'top bottom') :\n (pos <= min ? 'left' : pos >= max ? 'right' : 'left right');\n }\n\n function smartClick($el, fn, _options) {\n _options = _options || {};\n\n $el.each(function () {\n var $this = $(this),\n thisData = $this.data(),\n startEvent;\n\n if (thisData.clickOn) return;\n\n thisData.clickOn = true;\n\n $.extend(touch($this, {\n onStart: function (e) {\n startEvent = e;\n (_options.onStart || noop).call(this, e);\n },\n onMove: _options.onMove || noop,\n onTouchEnd: _options.onTouchEnd || noop,\n onEnd: function (result) {\n if (result.moved) return;\n fn.call(this, startEvent);\n }\n }), {noMove: true});\n });\n }\n\n function div(classes, child) {\n return '<div class=\"' + classes + '\">' + (child || '') + '</div>';\n }\n\n\n /**\n * Function transforming into valid classname\n * @param className - name of the class\n * @returns {string} - dom format of class name\n */\n function cls(className) {\n return \".\" + className;\n }\n\n /**\n *\n * @param {json-object} videoItem Parsed object from data.video item or href from link a in input dates\n * @returns {string} DOM view of video iframe\n */\n function createVideoFrame(videoItem) {\n var frame = '<iframe src=\"' + videoItem.p + videoItem.type + '.com/embed/' + videoItem.id + '\" frameborder=\"0\" allowfullscreen></iframe>';\n return frame;\n }\n\n// Fisher\u2013Yates Shuffle\n// http://bost.ocks.org/mike/shuffle/\n function shuffle(array) {\n // While there remain elements to shuffle\n var l = array.length;\n while (l) {\n // Pick a remaining element\n var i = Math.floor(Math.random() * l--);\n\n // And swap it with the current element\n var t = array[l];\n array[l] = array[i];\n array[i] = t;\n }\n\n return array;\n }\n\n function clone(array) {\n return Object.prototype.toString.call(array) == '[object Array]'\n && $.map(array, function (frame) {\n return $.extend({}, frame);\n });\n }\n\n function lockScroll($el, left, top) {\n $el\n .scrollLeft(left || 0)\n .scrollTop(top || 0);\n }\n\n function optionsToLowerCase(options) {\n if (options) {\n var opts = {};\n $.each(options, function (key, value) {\n opts[key.toLowerCase()] = value;\n });\n\n return opts;\n }\n }\n\n function getRatio(_ratio) {\n if (!_ratio) return;\n var ratio = +_ratio;\n if (!isNaN(ratio)) {\n return ratio;\n } else {\n ratio = _ratio.split('/');\n return +ratio[0] / +ratio[1] || undefined;\n }\n }\n\n function addEvent(el, e, fn, bool) {\n if (!e) return;\n el.addEventListener ? el.addEventListener(e, fn, !!bool) : el.attachEvent('on' + e, fn);\n }\n\n /**\n *\n * @param position guess position for navShaft\n * @param restriction object contains min and max values for position\n * @returns {*} filtered value of position\n */\n function validateRestrictions(position, restriction) {\n if (position > restriction.max) {\n position = restriction.max;\n } else {\n if (position < restriction.min) {\n position = restriction.min;\n }\n }\n return position;\n }\n\n function validateSlidePos(opt, navShaftTouchTail, guessIndex, offsetNav, $guessNavFrame, $navWrap, dir) {\n var position,\n size,\n wrapSize;\n if (dir === 'horizontal') {\n size = opt.thumbwidth;\n wrapSize = $navWrap.width();\n } else {\n size = opt.thumbheight;\n wrapSize = $navWrap.height();\n }\n if ( (size + opt.margin) * (guessIndex + 1) >= (wrapSize - offsetNav) ) {\n if (dir === 'horizontal') {\n position = -$guessNavFrame.position().left;\n } else {\n position = -$guessNavFrame.position().top;\n }\n } else {\n if ((size + opt.margin) * (guessIndex) <= Math.abs(offsetNav)) {\n if (dir === 'horizontal') {\n position = -$guessNavFrame.position().left + wrapSize - (size + opt.margin);\n } else {\n position = -$guessNavFrame.position().top + wrapSize - (size + opt.margin);\n }\n } else {\n position = offsetNav;\n }\n }\n position = validateRestrictions(position, navShaftTouchTail);\n\n return position || 0;\n }\n\n function elIsDisabled(el) {\n return !!el.getAttribute('disabled');\n }\n\n function disableAttr(FLAG, disable) {\n if (disable) {\n return {disabled: FLAG};\n } else {\n return {tabindex: FLAG * -1 + '', disabled: FLAG};\n\n }\n }\n\n function addEnterUp(el, fn) {\n addEvent(el, 'keyup', function (e) {\n elIsDisabled(el) || e.keyCode == 13 && fn.call(el, e);\n });\n }\n\n function addFocus(el, fn) {\n addEvent(el, 'focus', el.onfocusin = function (e) {\n fn.call(el, e);\n }, true);\n }\n\n function stopEvent(e, stopPropagation) {\n e.preventDefault ? e.preventDefault() : (e.returnValue = false);\n stopPropagation && e.stopPropagation && e.stopPropagation();\n }\n\n function getDirectionSign(forward) {\n return forward ? '>' : '<';\n }\n\n var UTIL = (function () {\n\n function setRatioClass($el, wh, ht) {\n var rateImg = wh / ht;\n\n if (rateImg <= 1) {\n $el.parent().removeClass(horizontalImageClass);\n $el.parent().addClass(verticalImageClass);\n } else {\n $el.parent().removeClass(verticalImageClass);\n $el.parent().addClass(horizontalImageClass);\n }\n }\n\n /**\n * Set specific attribute in thumbnail template\n * @param $frame DOM item of specific thumbnail\n * @param value Value which must be setted into specific attribute\n * @param searchAttr Name of attribute where value must be included\n */\n function setThumbAttr($frame, value, searchAttr) {\n var attr = searchAttr;\n\n if (!$frame.attr(attr) && $frame.attr(attr) !== undefined) {\n $frame.attr(attr, value);\n }\n\n if ($frame.find(\"[\" + attr + \"]\").length) {\n $frame.find(\"[\" + attr + \"]\")\n .each(function () {\n $(this).attr(attr, value);\n });\n }\n }\n\n /**\n * Method describe behavior need to render caption on preview or not\n * @param frameItem specific item from data\n * @param isExpected {bool} if items with caption need render them or not\n * @returns {boolean} if true then caption should be rendered\n */\n function isExpectedCaption(frameItem, isExpected, undefined) {\n var expected = false,\n frameExpected;\n\n frameItem.showCaption === undefined || frameItem.showCaption === true ? frameExpected = true : frameExpected = false;\n\n if (!isExpected) {\n return false;\n }\n\n if (frameItem.caption && frameExpected) {\n expected = true;\n }\n\n return expected;\n }\n\n return {\n setRatio: setRatioClass,\n setThumbAttr: setThumbAttr,\n isExpectedCaption: isExpectedCaption\n };\n\n }(UTIL || {}, jQuery));\n\n function slide($el, options) {\n var elData = $el.data(),\n elPos = Math.round(options.pos),\n onEndFn = function () {\n if (elData && elData.sliding) {\n elData.sliding = false;\n }\n (options.onEnd || noop)();\n };\n\n if (typeof options.overPos !== 'undefined' && options.overPos !== options.pos) {\n elPos = options.overPos;\n }\n\n var translate = $.extend(getTranslate(elPos, options.direction), options.width && {width: options.width}, options.height && {height: options.height});\n if (elData && elData.sliding) {\n elData.sliding = true;\n }\n\n if (CSS3) {\n $el.css($.extend(getDuration(options.time), translate));\n\n if (options.time > 10) {\n afterTransition($el, 'transform', onEndFn, options.time);\n } else {\n onEndFn();\n }\n } else {\n $el.stop().animate(translate, options.time, BEZIER, onEndFn);\n }\n }\n\n function fade($el1, $el2, $frames, options, fadeStack, chain) {\n var chainedFLAG = typeof chain !== 'undefined';\n if (!chainedFLAG) {\n fadeStack.push(arguments);\n Array.prototype.push.call(arguments, fadeStack.length);\n if (fadeStack.length > 1) return;\n }\n\n $el1 = $el1 || $($el1);\n $el2 = $el2 || $($el2);\n\n var _$el1 = $el1[0],\n _$el2 = $el2[0],\n crossfadeFLAG = options.method === 'crossfade',\n onEndFn = function () {\n if (!onEndFn.done) {\n onEndFn.done = true;\n var args = (chainedFLAG || fadeStack.shift()) && fadeStack.shift();\n args && fade.apply(this, args);\n (options.onEnd || noop)(!!args);\n }\n },\n time = options.time / (chain || 1);\n\n $frames.removeClass(fadeRearClass + ' ' + fadeFrontClass);\n\n $el1\n .stop()\n .addClass(fadeRearClass);\n $el2\n .stop()\n .addClass(fadeFrontClass);\n\n crossfadeFLAG && _$el2 && $el1.fadeTo(0, 0);\n\n $el1.fadeTo(crossfadeFLAG ? time : 0, 1, crossfadeFLAG && onEndFn);\n $el2.fadeTo(time, 0, onEndFn);\n\n (_$el1 && crossfadeFLAG) || _$el2 || onEndFn();\n }\n\n var lastEvent,\n moveEventType,\n preventEvent,\n preventEventTimeout,\n dragDomEl;\n\n function extendEvent(e) {\n var touch = (e.touches || [])[0] || e;\n e._x = touch.pageX || touch.originalEvent.pageX;\n e._y = touch.clientY || touch.originalEvent.clientY;\n e._now = $.now();\n }\n\n function touch($el, options) {\n var el = $el[0],\n tail = {},\n touchEnabledFLAG,\n startEvent,\n $target,\n controlTouch,\n touchFLAG,\n targetIsSelectFLAG,\n targetIsLinkFlag,\n isDisabledSwipe,\n tolerance,\n moved;\n\n function onStart(e) {\n $target = $(e.target);\n tail.checked = targetIsSelectFLAG = targetIsLinkFlag = isDisabledSwipe = moved = false;\n\n if (touchEnabledFLAG\n || tail.flow\n || (e.touches && e.touches.length > 1)\n || e.which > 1\n || (lastEvent && lastEvent.type !== e.type && preventEvent)\n || (targetIsSelectFLAG = options.select && $target.is(options.select, el))) return targetIsSelectFLAG;\n\n touchFLAG = e.type === 'touchstart';\n targetIsLinkFlag = $target.is('a, a *', el);\n isDisabledSwipe = $target.hasClass('disableSwipe');\n controlTouch = tail.control;\n\n tolerance = (tail.noMove || tail.noSwipe || controlTouch) ? 16 : !tail.snap ? 4 : 0;\n\n extendEvent(e);\n\n startEvent = lastEvent = e;\n moveEventType = e.type.replace(/down|start/, 'move').replace(/Down/, 'Move');\n\n (options.onStart || noop).call(el, e, {control: controlTouch, $target: $target});\n\n touchEnabledFLAG = tail.flow = true;\n\n if (!isDisabledSwipe && (!touchFLAG || tail.go)) stopEvent(e);\n }\n\n function onMove(e) {\n if ((e.touches && e.touches.length > 1)\n || (MS_POINTER && !e.isPrimary)\n || moveEventType !== e.type\n || !touchEnabledFLAG) {\n touchEnabledFLAG && onEnd();\n (options.onTouchEnd || noop)();\n return;\n }\n\n isDisabledSwipe = $(e.target).hasClass('disableSwipe');\n\n if (isDisabledSwipe) {\n return;\n }\n\n extendEvent(e);\n\n var xDiff = Math.abs(e._x - startEvent._x), // opt _x \u2192 _pageX\n yDiff = Math.abs(e._y - startEvent._y),\n xyDiff = xDiff - yDiff,\n xWin = (tail.go || tail.x || xyDiff >= 0) && !tail.noSwipe,\n yWin = xyDiff < 0;\n\n if (touchFLAG && !tail.checked) {\n if (touchEnabledFLAG = xWin) {\n stopEvent(e);\n }\n } else {\n stopEvent(e);\n if (movedEnough(xDiff,yDiff)) {\n (options.onMove || noop).call(el, e, {touch: touchFLAG});\n }\n }\n\n if (!moved && movedEnough(xDiff, yDiff) && Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2)) > tolerance) {\n moved = true;\n }\n\n tail.checked = tail.checked || xWin || yWin;\n }\n\n function movedEnough(xDiff, yDiff) {\n return xDiff > yDiff && xDiff > 1.5;\n }\n\n function onEnd(e) {\n (options.onTouchEnd || noop)();\n\n var _touchEnabledFLAG = touchEnabledFLAG;\n tail.control = touchEnabledFLAG = false;\n\n if (_touchEnabledFLAG) {\n tail.flow = false;\n }\n\n if (!_touchEnabledFLAG || (targetIsLinkFlag && !tail.checked)) return;\n\n e && stopEvent(e);\n\n preventEvent = true;\n clearTimeout(preventEventTimeout);\n preventEventTimeout = setTimeout(function () {\n preventEvent = false;\n }, 1000);\n\n (options.onEnd || noop).call(el, {\n moved: moved,\n $target: $target,\n control: controlTouch,\n touch: touchFLAG,\n startEvent: startEvent,\n aborted: !e || e.type === 'MSPointerCancel'\n });\n }\n\n function onOtherStart() {\n if (tail.flow) return;\n tail.flow = true;\n }\n\n function onOtherEnd() {\n if (!tail.flow) return;\n tail.flow = false;\n }\n\n if (MS_POINTER) {\n addEvent(el, 'MSPointerDown', onStart);\n addEvent(document, 'MSPointerMove', onMove);\n addEvent(document, 'MSPointerCancel', onEnd);\n addEvent(document, 'MSPointerUp', onEnd);\n } else {\n addEvent(el, 'touchstart', onStart);\n addEvent(el, 'touchmove', onMove);\n addEvent(el, 'touchend', onEnd);\n\n addEvent(document, 'touchstart', onOtherStart, true);\n addEvent(document, 'touchend', onOtherEnd);\n addEvent(document, 'touchcancel', onOtherEnd);\n\n $WINDOW.on('scroll', onOtherEnd);\n\n $el.on('mousedown', onStart);\n $DOCUMENT\n .on('mousemove', onMove)\n .on('mouseup', onEnd);\n }\n if (Modernizr.touch) {\n dragDomEl = 'a';\n } else {\n dragDomEl = 'div';\n }\n $el.on('click', dragDomEl, function (e) {\n tail.checked && stopEvent(e);\n });\n\n return tail;\n }\n\n function moveOnTouch($el, options) {\n var el = $el[0],\n elData = $el.data(),\n tail = {},\n startCoo,\n coo,\n startElPos,\n moveElPos,\n edge,\n moveTrack,\n startTime,\n endTime,\n min,\n max,\n snap,\n dir,\n slowFLAG,\n controlFLAG,\n moved,\n tracked;\n\n function startTracking(e, noStop) {\n tracked = true;\n startCoo = coo = (dir === 'vertical') ? e._y : e._x;\n startTime = e._now;\n\n moveTrack = [\n [startTime, startCoo]\n ];\n\n startElPos = moveElPos = tail.noMove || noStop ? 0 : stop($el, (options.getPos || noop)()/*, options._001*/);\n\n (options.onStart || noop).call(el, e);\n }\n\n function onStart(e, result) {\n min = tail.min;\n max = tail.max;\n snap = tail.snap,\n dir = tail.direction || 'horizontal',\n $el.navdir = dir;\n\n slowFLAG = e.altKey;\n tracked = moved = false;\n\n controlFLAG = result.control;\n\n if (!controlFLAG && !elData.sliding) {\n startTracking(e);\n }\n }\n\n function onMove(e, result) {\n if (!tail.noSwipe) {\n if (!tracked) {\n startTracking(e);\n }\n coo = (dir === 'vertical') ? e._y : e._x;\n\n moveTrack.push([e._now, coo]);\n\n moveElPos = startElPos - (startCoo - coo);\n\n edge = findShadowEdge(moveElPos, min, max, dir);\n\n if (moveElPos <= min) {\n moveElPos = edgeResistance(moveElPos, min);\n } else if (moveElPos >= max) {\n moveElPos = edgeResistance(moveElPos, max);\n }\n\n if (!tail.noMove) {\n $el.css(getTranslate(moveElPos, dir));\n if (!moved) {\n moved = true;\n // only for mouse\n result.touch || MS_POINTER || $el.addClass(grabbingClass);\n }\n\n (options.onMove || noop).call(el, e, {pos: moveElPos, edge: edge});\n }\n }\n }\n\n function onEnd(result) {\n if (tail.noSwipe && result.moved) return;\n\n if (!tracked) {\n startTracking(result.startEvent, true);\n }\n\n result.touch || MS_POINTER || $el.removeClass(grabbingClass);\n\n endTime = $.now();\n\n var _backTimeIdeal = endTime - TOUCH_TIMEOUT,\n _backTime,\n _timeDiff,\n _timeDiffLast,\n backTime = null,\n backCoo,\n virtualPos,\n limitPos,\n newPos,\n overPos,\n time = TRANSITION_DURATION,\n speed,\n friction = options.friction;\n\n for (var _i = moveTrack.length - 1; _i >= 0; _i--) {\n _backTime = moveTrack[_i][0];\n _timeDiff = Math.abs(_backTime - _backTimeIdeal);\n if (backTime === null || _timeDiff < _timeDiffLast) {\n backTime = _backTime;\n backCoo = moveTrack[_i][1];\n } else if (backTime === _backTimeIdeal || _timeDiff > _timeDiffLast) {\n break;\n }\n _timeDiffLast = _timeDiff;\n }\n\n newPos = minMaxLimit(moveElPos, min, max);\n\n var cooDiff = backCoo - coo,\n forwardFLAG = cooDiff >= 0,\n timeDiff = endTime - backTime,\n longTouchFLAG = timeDiff > TOUCH_TIMEOUT,\n swipeFLAG = !longTouchFLAG && moveElPos !== startElPos && newPos === moveElPos;\n\n if (snap) {\n newPos = minMaxLimit(Math[swipeFLAG ? (forwardFLAG ? 'floor' : 'ceil') : 'round'](moveElPos / snap) * snap, min, max);\n min = max = newPos;\n }\n\n if (swipeFLAG && (snap || newPos === moveElPos)) {\n speed = -(cooDiff / timeDiff);\n time *= minMaxLimit(Math.abs(speed), options.timeLow, options.timeHigh);\n virtualPos = Math.round(moveElPos + speed * time / friction);\n\n if (!snap) {\n newPos = virtualPos;\n }\n\n if (!forwardFLAG && virtualPos > max || forwardFLAG && virtualPos < min) {\n limitPos = forwardFLAG ? min : max;\n overPos = virtualPos - limitPos;\n if (!snap) {\n newPos = limitPos;\n }\n overPos = minMaxLimit(newPos + overPos * .03, limitPos - 50, limitPos + 50);\n time = Math.abs((moveElPos - overPos) / (speed / friction));\n }\n }\n\n time *= slowFLAG ? 10 : 1;\n\n (options.onEnd || noop).call(el, $.extend(result, {\n moved: result.moved || longTouchFLAG && snap,\n pos: moveElPos,\n newPos: newPos,\n overPos: overPos,\n time: time,\n dir: dir\n }));\n }\n\n tail = $.extend(touch(options.$wrap, $.extend({}, options, {\n onStart: onStart,\n onMove: onMove,\n onEnd: onEnd\n })), tail);\n\n return tail;\n }\n\n function wheel($el, options) {\n var el = $el[0],\n lockFLAG,\n lastDirection,\n lastNow,\n tail = {\n prevent: {}\n };\n\n addEvent(el, WHEEL, function (e) {\n var yDelta = e.wheelDeltaY || -1 * e.deltaY || 0,\n xDelta = e.wheelDeltaX || -1 * e.deltaX || 0,\n xWin = Math.abs(xDelta) && !Math.abs(yDelta),\n direction = getDirectionSign(xDelta < 0),\n sameDirection = lastDirection === direction,\n now = $.now(),\n tooFast = now - lastNow < TOUCH_TIMEOUT;\n\n lastDirection = direction;\n lastNow = now;\n\n if (!xWin || !tail.ok || tail.prevent[direction] && !lockFLAG) {\n return;\n } else {\n stopEvent(e, true);\n if (lockFLAG && sameDirection && tooFast) {\n return;\n }\n }\n\n if (options.shift) {\n lockFLAG = true;\n clearTimeout(tail.t);\n tail.t = setTimeout(function () {\n lockFLAG = false;\n }, SCROLL_LOCK_TIMEOUT);\n }\n\n (options.onEnd || noop)(e, options.shift ? direction : xDelta);\n\n });\n\n return tail;\n }\n\n jQuery.Fotorama = function ($fotorama, opts) {\n $HTML = $('html');\n $BODY = $('body');\n\n var that = this,\n stamp = $.now(),\n stampClass = _fotoramaClass + stamp,\n fotorama = $fotorama[0],\n data,\n dataFrameCount = 1,\n fotoramaData = $fotorama.data(),\n size,\n\n $style = $('<style></style>'),\n\n $anchor = $(div(hiddenClass)),\n $wrap = $fotorama.find(cls(wrapClass)),\n $stage = $wrap.find(cls(stageClass)),\n stage = $stage[0],\n\n $stageShaft = $fotorama.find(cls(stageShaftClass)),\n $stageFrame = $(),\n $arrPrev = $fotorama.find(cls(arrPrevClass)),\n $arrNext = $fotorama.find(cls(arrNextClass)),\n $arrs = $fotorama.find(cls(arrClass)),\n $navWrap = $fotorama.find(cls(navWrapClass)),\n $nav = $navWrap.find(cls(navClass)),\n $navShaft = $nav.find(cls(navShaftClass)),\n $navFrame,\n $navDotFrame = $(),\n $navThumbFrame = $(),\n\n stageShaftData = $stageShaft.data(),\n navShaftData = $navShaft.data(),\n\n $thumbBorder = $fotorama.find(cls(thumbBorderClass)),\n $thumbArrLeft = $fotorama.find(cls(thumbArrLeft)),\n $thumbArrRight = $fotorama.find(cls(thumbArrRight)),\n\n $fullscreenIcon = $fotorama.find(cls(fullscreenIconClass)),\n fullscreenIcon = $fullscreenIcon[0],\n $videoPlay = $(div(videoPlayClass)),\n $videoClose = $fotorama.find(cls(videoCloseClass)),\n videoClose = $videoClose[0],\n\n $spinner = $fotorama.find(cls(fotoramaSpinnerClass)),\n\n $videoPlaying,\n\n activeIndex = false,\n activeFrame,\n activeIndexes,\n repositionIndex,\n dirtyIndex,\n lastActiveIndex,\n prevIndex,\n nextIndex,\n nextAutoplayIndex,\n startIndex,\n\n o_loop,\n o_nav,\n o_navThumbs,\n o_navTop,\n o_allowFullScreen,\n o_nativeFullScreen,\n o_fade,\n o_thumbSide,\n o_thumbSide2,\n o_transitionDuration,\n o_transition,\n o_shadows,\n o_rtl,\n o_keyboard,\n lastOptions = {},\n\n measures = {},\n measuresSetFLAG,\n\n stageShaftTouchTail = {},\n stageWheelTail = {},\n navShaftTouchTail = {},\n navWheelTail = {},\n\n scrollTop,\n scrollLeft,\n\n showedFLAG,\n pausedAutoplayFLAG,\n stoppedAutoplayFLAG,\n\n toDeactivate = {},\n toDetach = {},\n\n measuresStash,\n\n touchedFLAG,\n\n hoverFLAG,\n\n navFrameKey,\n stageLeft = 0,\n\n fadeStack = [];\n\n $wrap[STAGE_FRAME_KEY] = $('<div class=\"' + stageFrameClass + '\"></div>');\n $wrap[NAV_THUMB_FRAME_KEY] = $($.Fotorama.jst.thumb());\n $wrap[NAV_DOT_FRAME_KEY] = $($.Fotorama.jst.dots());\n\n toDeactivate[STAGE_FRAME_KEY] = [];\n toDeactivate[NAV_THUMB_FRAME_KEY] = [];\n toDeactivate[NAV_DOT_FRAME_KEY] = [];\n toDetach[STAGE_FRAME_KEY] = {};\n\n $wrap.addClass(CSS3 ? wrapCss3Class : wrapCss2Class);\n\n fotoramaData.fotorama = this;\n\n /**\n * Search video items in incoming data and transform object for video layout.\n *\n */\n function checkForVideo() {\n $.each(data, function (i, dataFrame) {\n if (!dataFrame.i) {\n dataFrame.i = dataFrameCount++;\n var video = findVideoId(dataFrame.video, true);\n if (video) {\n var thumbs = {};\n dataFrame.video = video;\n if (!dataFrame.img && !dataFrame.thumb) {\n thumbs = getVideoThumbs(dataFrame, data, that);\n } else {\n dataFrame.thumbsReady = true;\n }\n updateData(data, {img: thumbs.img, thumb: thumbs.thumb}, dataFrame.i, that);\n }\n }\n });\n }\n\n /**\n * Checks if current media object is YouTube or Vimeo video stream\n * @returns {boolean}\n */\n function isVideo() {\n return $((that.activeFrame || {}).$stageFrame || {}).hasClass('fotorama-video-container');\n }\n\n function allowKey(key) {\n return o_keyboard[key];\n }\n\n function setStagePosition() {\n if ($stage !== undefined) {\n\n if (opts.navdir == 'vertical') {\n var padding = opts.thumbwidth + opts.thumbmargin;\n\n $stage.css('left', padding);\n $arrNext.css('right', padding);\n $fullscreenIcon.css('right', padding);\n $wrap.css('width', $wrap.css('width') + padding);\n $stageShaft.css('max-width', $wrap.width() - padding);\n } else {\n $stage.css('left', '');\n $arrNext.css('right', '');\n $fullscreenIcon.css('right', '');\n $wrap.css('width', $wrap.css('width') + padding);\n $stageShaft.css('max-width', '');\n }\n }\n }\n\n function bindGlobalEvents(FLAG) {\n var keydownCommon = 'keydown.' + _fotoramaClass,\n localStamp = _fotoramaClass + stamp,\n keydownLocal = 'keydown.' + localStamp,\n keyupLocal = 'keyup.' + localStamp,\n resizeLocal = 'resize.' + localStamp + ' ' + 'orientationchange.' + localStamp,\n showParams;\n\n if (FLAG) {\n $DOCUMENT\n .on(keydownLocal, function (e) {\n var catched,\n index;\n\n if ($videoPlaying && e.keyCode === 27) {\n catched = true;\n unloadVideo($videoPlaying, true, true);\n } else if (that.fullScreen || (opts.keyboard && !that.index)) {\n if (e.keyCode === 27) {\n catched = true;\n that.cancelFullScreen();\n } else if ((e.shiftKey && e.keyCode === 32 && allowKey('space')) || (!e.altKey && !e.metaKey && e.keyCode === 37 && allowKey('left')) || (e.keyCode === 38 && allowKey('up') && $(':focus').attr('data-gallery-role'))) {\n that.longPress.progress();\n index = '<';\n } else if ((e.keyCode === 32 && allowKey('space')) || (!e.altKey && !e.metaKey && e.keyCode === 39 && allowKey('right')) || (e.keyCode === 40 && allowKey('down') && $(':focus').attr('data-gallery-role'))) {\n that.longPress.progress();\n index = '>';\n } else if (e.keyCode === 36 && allowKey('home')) {\n that.longPress.progress();\n index = '<<';\n } else if (e.keyCode === 35 && allowKey('end')) {\n that.longPress.progress();\n index = '>>';\n }\n }\n\n (catched || index) && stopEvent(e);\n showParams = {index: index, slow: e.altKey, user: true};\n index && (that.longPress.inProgress ?\n that.showWhileLongPress(showParams) :\n that.show(showParams));\n });\n\n if (FLAG) {\n $DOCUMENT\n .on(keyupLocal, function (e) {\n if (that.longPress.inProgress) {\n that.showEndLongPress({user: true});\n }\n that.longPress.reset();\n });\n }\n\n if (!that.index) {\n $DOCUMENT\n .off(keydownCommon)\n .on(keydownCommon, 'textarea, input, select', function (e) {\n !$BODY.hasClass(_fullscreenClass) && e.stopPropagation();\n });\n }\n\n $WINDOW.on(resizeLocal, that.resize);\n } else {\n $DOCUMENT.off(keydownLocal);\n $WINDOW.off(resizeLocal);\n }\n }\n\n function appendElements(FLAG) {\n if (FLAG === appendElements.f) return;\n\n if (FLAG) {\n $fotorama\n .addClass(_fotoramaClass + ' ' + stampClass)\n .before($anchor)\n .before($style);\n addInstance(that);\n } else {\n $anchor.detach();\n $style.detach();\n $fotorama\n .html(fotoramaData.urtext)\n .removeClass(stampClass);\n\n hideInstance(that);\n }\n\n bindGlobalEvents(FLAG);\n appendElements.f = FLAG;\n }\n\n /**\n * Set and install data from incoming @param {JSON} options or takes data attr from data-\"name\"=... values.\n */\n function setData() {\n data = that.data = data || clone(opts.data) || getDataFromHtml($fotorama);\n size = that.size = data.length;\n\n ready.ok && opts.shuffle && shuffle(data);\n\n checkForVideo();\n\n activeIndex = limitIndex(activeIndex);\n\n size && appendElements(true);\n }\n\n function stageNoMove() {\n var _noMove = size < 2 || $videoPlaying;\n stageShaftTouchTail.noMove = _noMove || o_fade;\n stageShaftTouchTail.noSwipe = _noMove || !opts.swipe;\n\n !o_transition && $stageShaft.toggleClass(grabClass, !opts.click && !stageShaftTouchTail.noMove && !stageShaftTouchTail.noSwipe);\n MS_POINTER && $wrap.toggleClass(wrapPanYClass, !stageShaftTouchTail.noSwipe);\n }\n\n function setAutoplayInterval(interval) {\n if (interval === true) interval = '';\n opts.autoplay = Math.max(+interval || AUTOPLAY_INTERVAL, o_transitionDuration * 1.5);\n }\n\n function updateThumbArrow(opt) {\n if (opt.navarrows && opt.nav === 'thumbs') {\n $thumbArrLeft.show();\n $thumbArrRight.show();\n } else {\n $thumbArrLeft.hide();\n $thumbArrRight.hide();\n }\n\n }\n\n function getThumbsInSlide($el, opts) {\n return Math.floor($wrap.width() / (opts.thumbwidth + opts.thumbmargin));\n }\n\n /**\n * Options on the fly\n * */\n function setOptions() {\n if (!opts.nav || opts.nav === 'dots') {\n opts.navdir = 'horizontal'\n }\n\n that.options = opts = optionsToLowerCase(opts);\n thumbsPerSlide = getThumbsInSlide($wrap, opts);\n\n o_fade = (opts.transition === 'crossfade' || opts.transition === 'dissolve');\n\n o_loop = opts.loop && (size > 2 || (o_fade && (!o_transition || o_transition !== 'slide')));\n\n o_transitionDuration = +opts.transitionduration || TRANSITION_DURATION;\n\n o_rtl = opts.direction === 'rtl';\n\n o_keyboard = $.extend({}, opts.keyboard && KEYBOARD_OPTIONS, opts.keyboard);\n updateThumbArrow(opts);\n var classes = {add: [], remove: []};\n\n function addOrRemoveClass(FLAG, value) {\n classes[FLAG ? 'add' : 'remove'].push(value);\n }\n\n if (size > 1) {\n o_nav = opts.nav;\n o_navTop = opts.navposition === 'top';\n classes.remove.push(selectClass);\n\n $arrs.toggle(!!opts.arrows);\n } else {\n o_nav = false;\n $arrs.hide();\n }\n\n arrsUpdate();\n stageWheelUpdate();\n thumbArrUpdate();\n if (opts.autoplay) setAutoplayInterval(opts.autoplay);\n\n o_thumbSide = numberFromMeasure(opts.thumbwidth) || THUMB_SIZE;\n o_thumbSide2 = numberFromMeasure(opts.thumbheight) || THUMB_SIZE;\n\n stageWheelTail.ok = navWheelTail.ok = opts.trackpad && !SLOW;\n\n stageNoMove();\n\n extendMeasures(opts, [measures]);\n\n o_navThumbs = o_nav === 'thumbs';\n\n if ($navWrap.filter(':hidden') && !!o_nav) {\n $navWrap.show();\n }\n if (o_navThumbs) {\n frameDraw(size, 'navThumb');\n\n $navFrame = $navThumbFrame;\n navFrameKey = NAV_THUMB_FRAME_KEY;\n\n setStyle($style, $.Fotorama.jst.style({\n w: o_thumbSide,\n h: o_thumbSide2,\n b: opts.thumbborderwidth,\n m: opts.thumbmargin,\n s: stamp,\n q: !COMPAT\n }));\n\n $nav\n .addClass(navThumbsClass)\n .removeClass(navDotsClass);\n } else if (o_nav === 'dots') {\n frameDraw(size, 'navDot');\n\n $navFrame = $navDotFrame;\n navFrameKey = NAV_DOT_FRAME_KEY;\n\n $nav\n .addClass(navDotsClass)\n .removeClass(navThumbsClass);\n } else {\n $navWrap.hide();\n o_nav = false;\n $nav.removeClass(navThumbsClass + ' ' + navDotsClass);\n }\n\n if (o_nav) {\n if (o_navTop) {\n $navWrap.insertBefore($stage);\n } else {\n $navWrap.insertAfter($stage);\n }\n frameAppend.nav = false;\n\n frameAppend($navFrame, $navShaft, 'nav');\n }\n\n o_allowFullScreen = opts.allowfullscreen;\n\n if (o_allowFullScreen) {\n $fullscreenIcon.prependTo($stage);\n o_nativeFullScreen = FULLSCREEN && o_allowFullScreen === 'native';\n } else {\n $fullscreenIcon.detach();\n o_nativeFullScreen = false;\n }\n\n addOrRemoveClass(o_fade, wrapFadeClass);\n addOrRemoveClass(!o_fade, wrapSlideClass);\n addOrRemoveClass(!opts.captions, wrapNoCaptionsClass);\n addOrRemoveClass(o_rtl, wrapRtlClass);\n addOrRemoveClass(opts.arrows, wrapToggleArrowsClass);\n\n o_shadows = opts.shadows && !SLOW;\n addOrRemoveClass(!o_shadows, wrapNoShadowsClass);\n\n $wrap\n .addClass(classes.add.join(' '))\n .removeClass(classes.remove.join(' '));\n\n lastOptions = $.extend({}, opts);\n setStagePosition();\n }\n\n function normalizeIndex(index) {\n return index < 0 ? (size + (index % size)) % size : index >= size ? index % size : index;\n }\n\n function limitIndex(index) {\n return minMaxLimit(index, 0, size - 1);\n }\n\n function edgeIndex(index) {\n return o_loop ? normalizeIndex(index) : limitIndex(index);\n }\n\n function getPrevIndex(index) {\n return index > 0 || o_loop ? index - 1 : false;\n }\n\n function getNextIndex(index) {\n return index < size - 1 || o_loop ? index + 1 : false;\n }\n\n function setStageShaftMinmaxAndSnap() {\n stageShaftTouchTail.min = o_loop ? -Infinity : -getPosByIndex(size - 1, measures.w, opts.margin, repositionIndex);\n stageShaftTouchTail.max = o_loop ? Infinity : -getPosByIndex(0, measures.w, opts.margin, repositionIndex);\n stageShaftTouchTail.snap = measures.w + opts.margin;\n }\n\n function setNavShaftMinMax() {\n\n var isVerticalDir = (opts.navdir === 'vertical');\n var param = isVerticalDir ? $navShaft.height() : $navShaft.width();\n var mainParam = isVerticalDir ? measures.h : measures.nw;\n navShaftTouchTail.min = Math.min(0, mainParam - param);\n navShaftTouchTail.max = 0;\n navShaftTouchTail.direction = opts.navdir;\n $navShaft.toggleClass(grabClass, !(navShaftTouchTail.noMove = navShaftTouchTail.min === navShaftTouchTail.max));\n }\n\n function eachIndex(indexes, type, fn) {\n if (typeof indexes === 'number') {\n indexes = new Array(indexes);\n var rangeFLAG = true;\n }\n return $.each(indexes, function (i, index) {\n if (rangeFLAG) index = i;\n if (typeof index === 'number') {\n var dataFrame = data[normalizeIndex(index)];\n\n if (dataFrame) {\n var key = '$' + type + 'Frame',\n $frame = dataFrame[key];\n\n fn.call(this, i, index, dataFrame, $frame, key, $frame && $frame.data());\n }\n }\n });\n }\n\n function setMeasures(width, height, ratio, index) {\n if (!measuresSetFLAG || (measuresSetFLAG === '*' && index === startIndex)) {\n\n width = measureIsValid(opts.width) || measureIsValid(width) || WIDTH;\n height = measureIsValid(opts.height) || measureIsValid(height) || HEIGHT;\n that.resize({\n width: width,\n ratio: opts.ratio || ratio || width / height\n }, 0, index !== startIndex && '*');\n }\n }\n\n function loadImg(indexes, type, specialMeasures, again) {\n\n eachIndex(indexes, type, function (i, index, dataFrame, $frame, key, frameData) {\n\n if (!$frame) return;\n\n var fullFLAG = that.fullScreen && !frameData.$full && type === 'stage';\n\n if (frameData.$img && !again && !fullFLAG) return;\n\n var img = new Image(),\n $img = $(img),\n imgData = $img.data();\n\n frameData[fullFLAG ? '$full' : '$img'] = $img;\n\n var srcKey = type === 'stage' ? (fullFLAG ? 'full' : 'img') : 'thumb',\n src = dataFrame[srcKey],\n dummy = fullFLAG ? dataFrame['img'] : dataFrame[type === 'stage' ? 'thumb' : 'img'];\n\n if (type === 'navThumb') $frame = frameData.$wrap;\n\n function triggerTriggerEvent(event) {\n var _index = normalizeIndex(index);\n triggerEvent(event, {\n index: _index,\n src: src,\n frame: data[_index]\n });\n }\n\n function error() {\n $img.remove();\n\n $.Fotorama.cache[src] = 'error';\n\n if ((!dataFrame.html || type !== 'stage') && dummy && dummy !== src) {\n dataFrame[srcKey] = src = dummy;\n frameData.$full = null;\n loadImg([index], type, specialMeasures, true);\n } else {\n if (src && !dataFrame.html && !fullFLAG) {\n $frame\n .trigger('f:error')\n .removeClass(loadingClass)\n .addClass(errorClass);\n\n triggerTriggerEvent('error');\n } else if (type === 'stage') {\n $frame\n .trigger('f:load')\n .removeClass(loadingClass + ' ' + errorClass)\n .addClass(loadedClass);\n\n triggerTriggerEvent('load');\n setMeasures();\n }\n\n frameData.state = 'error';\n\n if (size > 1 && data[index] === dataFrame && !dataFrame.html && !dataFrame.deleted && !dataFrame.video && !fullFLAG) {\n dataFrame.deleted = true;\n that.splice(index, 1);\n }\n }\n }\n\n function loaded() {\n $.Fotorama.measures[src] = imgData.measures = $.Fotorama.measures[src] || {\n width: img.width,\n height: img.height,\n ratio: img.width / img.height\n };\n\n setMeasures(imgData.measures.width, imgData.measures.height, imgData.measures.ratio, index);\n\n $img\n .off('load error')\n .addClass('' + (fullFLAG ? imgFullClass: imgClass))\n .attr('aria-hidden', 'false')\n .prependTo($frame);\n\n if ($frame.hasClass(stageFrameClass) && !$frame.hasClass(videoContainerClass)) {\n $frame.attr(\"href\", $img.attr(\"src\"));\n }\n\n fit($img, (\n $.isFunction(specialMeasures) ? specialMeasures() : specialMeasures) || measures);\n\n $.Fotorama.cache[src] = frameData.state = 'loaded';\n\n setTimeout(function () {\n $frame\n .trigger('f:load')\n .removeClass(loadingClass + ' ' + errorClass)\n .addClass(loadedClass + ' ' + (fullFLAG ? loadedFullClass : loadedImgClass));\n\n if (type === 'stage') {\n triggerTriggerEvent('load');\n } else if (dataFrame.thumbratio === AUTO || !dataFrame.thumbratio && opts.thumbratio === AUTO) {\n // danger! reflow for all thumbnails\n dataFrame.thumbratio = imgData.measures.ratio;\n reset();\n }\n }, 0);\n }\n\n if (!src) {\n error();\n return;\n }\n\n function waitAndLoad() {\n var _i = 10;\n waitFor(function () {\n return !touchedFLAG || !_i-- && !SLOW;\n }, function () {\n loaded();\n });\n }\n\n if (!$.Fotorama.cache[src]) {\n $.Fotorama.cache[src] = '*';\n\n $img\n .on('load', waitAndLoad)\n .on('error', error);\n } else {\n (function justWait() {\n if ($.Fotorama.cache[src] === 'error') {\n error();\n } else if ($.Fotorama.cache[src] === 'loaded') {\n setTimeout(waitAndLoad, 0);\n } else {\n setTimeout(justWait, 100);\n }\n })();\n }\n\n frameData.state = '';\n img.src = src;\n\n if (frameData.data.caption) {\n img.alt = frameData.data.caption || \"\";\n }\n\n if (frameData.data.full) {\n $(img).data('original', frameData.data.full);\n }\n\n if (UTIL.isExpectedCaption(dataFrame, opts.showcaption)) {\n $(img).attr('aria-labelledby', dataFrame.labelledby);\n }\n });\n }\n\n function updateFotoramaState() {\n var $frame = activeFrame[STAGE_FRAME_KEY];\n\n if ($frame && !$frame.data().state) {\n $spinner.addClass(spinnerShowClass);\n $frame.on('f:load f:error', function () {\n $frame.off('f:load f:error');\n $spinner.removeClass(spinnerShowClass);\n });\n }\n }\n\n function addNavFrameEvents(frame) {\n addEnterUp(frame, onNavFrameClick);\n addFocus(frame, function () {\n\n setTimeout(function () {\n lockScroll($nav);\n }, 0);\n slideNavShaft({time: o_transitionDuration, guessIndex: $(this).data().eq, minMax: navShaftTouchTail});\n });\n }\n\n function frameDraw(indexes, type) {\n eachIndex(indexes, type, function (i, index, dataFrame, $frame, key, frameData) {\n if ($frame) return;\n\n $frame = dataFrame[key] = $wrap[key].clone();\n frameData = $frame.data();\n frameData.data = dataFrame;\n var frame = $frame[0],\n labelledbyValue = \"labelledby\" + $.now();\n\n if (type === 'stage') {\n\n if (dataFrame.html) {\n $('<div class=\"' + htmlClass + '\"></div>')\n .append(\n dataFrame._html ? $(dataFrame.html)\n .removeAttr('id')\n .html(dataFrame._html) // Because of IE\n : dataFrame.html\n )\n .appendTo($frame);\n }\n\n if (dataFrame.id) {\n labelledbyValue = dataFrame.id || labelledbyValue;\n }\n dataFrame.labelledby = labelledbyValue;\n\n if (UTIL.isExpectedCaption(dataFrame, opts.showcaption)) {\n $($.Fotorama.jst.frameCaption({\n caption: dataFrame.caption,\n labelledby: labelledbyValue\n })).appendTo($frame);\n }\n\n dataFrame.video && $frame\n .addClass(stageFrameVideoClass)\n .append($videoPlay.clone());\n\n // This solves tabbing problems\n addFocus(frame, function (e) {\n setTimeout(function () {\n lockScroll($stage);\n }, 0);\n clickToShow({index: frameData.eq, user: true}, e);\n });\n\n $stageFrame = $stageFrame.add($frame);\n } else if (type === 'navDot') {\n addNavFrameEvents(frame);\n $navDotFrame = $navDotFrame.add($frame);\n } else if (type === 'navThumb') {\n addNavFrameEvents(frame);\n frameData.$wrap = $frame.children(':first');\n\n $navThumbFrame = $navThumbFrame.add($frame);\n if (dataFrame.video) {\n frameData.$wrap.append($videoPlay.clone());\n }\n }\n });\n }\n\n function callFit($img, measuresToFit) {\n return $img && $img.length && fit($img, measuresToFit);\n }\n\n function stageFramePosition(indexes) {\n eachIndex(indexes, 'stage', function (i, index, dataFrame, $frame, key, frameData) {\n if (!$frame) return;\n\n var normalizedIndex = normalizeIndex(index);\n frameData.eq = normalizedIndex;\n\n toDetach[STAGE_FRAME_KEY][normalizedIndex] = $frame.css($.extend({left: o_fade ? 0 : getPosByIndex(index, measures.w, opts.margin, repositionIndex)}, o_fade && getDuration(0)));\n\n if (isDetached($frame[0])) {\n $frame.appendTo($stageShaft);\n unloadVideo(dataFrame.$video);\n }\n\n callFit(frameData.$img, measures);\n callFit(frameData.$full, measures);\n\n if ($frame.hasClass(stageFrameClass) && !($frame.attr('aria-hidden') === \"false\" && $frame.hasClass(activeClass))) {\n $frame.attr('aria-hidden', 'true');\n }\n });\n }\n\n function thumbsDraw(pos, loadFLAG) {\n var leftLimit,\n rightLimit,\n exceedLimit;\n\n\n if (o_nav !== 'thumbs' || isNaN(pos)) return;\n\n leftLimit = -pos;\n rightLimit = -pos + measures.nw;\n\n if (opts.navdir === 'vertical') {\n pos = pos - opts.thumbheight;\n rightLimit = -pos + measures.h;\n }\n\n $navThumbFrame.each(function () {\n var $this = $(this),\n thisData = $this.data(),\n eq = thisData.eq,\n getSpecialMeasures = function () {\n return {\n h: o_thumbSide2,\n w: thisData.w\n }\n },\n specialMeasures = getSpecialMeasures(),\n exceedLimit = opts.navdir === 'vertical' ?\n thisData.t > rightLimit : thisData.l > rightLimit;\n specialMeasures.w = thisData.w;\n\n if ((opts.navdir !== 'vertical' && thisData.l + thisData.w < leftLimit)\n || exceedLimit\n || callFit(thisData.$img, specialMeasures)) return;\n\n loadFLAG && loadImg([eq], 'navThumb', getSpecialMeasures);\n });\n }\n\n function frameAppend($frames, $shaft, type) {\n if (!frameAppend[type]) {\n\n var thumbsFLAG = type === 'nav' && o_navThumbs,\n left = 0,\n top = 0;\n\n $shaft.append(\n $frames\n .filter(function () {\n var actual,\n $this = $(this),\n frameData = $this.data();\n for (var _i = 0, _l = data.length; _i < _l; _i++) {\n if (frameData.data === data[_i]) {\n actual = true;\n frameData.eq = _i;\n break;\n }\n }\n return actual || $this.remove() && false;\n })\n .sort(function (a, b) {\n return $(a).data().eq - $(b).data().eq;\n })\n .each(function () {\n var $this = $(this),\n frameData = $this.data();\n UTIL.setThumbAttr($this, frameData.data.caption, \"aria-label\");\n })\n .each(function () {\n\n if (!thumbsFLAG) return;\n\n var $this = $(this),\n frameData = $this.data(),\n thumbwidth = Math.round(o_thumbSide2 * frameData.data.thumbratio) || o_thumbSide,\n thumbheight = Math.round(o_thumbSide / frameData.data.thumbratio) || o_thumbSide2;\n frameData.t = top;\n frameData.h = thumbheight;\n frameData.l = left;\n frameData.w = thumbwidth;\n\n $this.css({width: thumbwidth});\n\n top += thumbheight + opts.thumbmargin;\n left += thumbwidth + opts.thumbmargin;\n })\n );\n\n frameAppend[type] = true;\n }\n }\n\n function getDirection(x) {\n return x - stageLeft > measures.w / 3;\n }\n\n function disableDirrection(i) {\n return !o_loop && (!(activeIndex + i) || !(activeIndex - size + i)) && !$videoPlaying;\n }\n\n function arrsUpdate() {\n var disablePrev = disableDirrection(0),\n disableNext = disableDirrection(1);\n $arrPrev\n .toggleClass(arrDisabledClass, disablePrev)\n .attr(disableAttr(disablePrev, false));\n $arrNext\n .toggleClass(arrDisabledClass, disableNext)\n .attr(disableAttr(disableNext, false));\n }\n\n function thumbArrUpdate() {\n var isLeftDisable = false,\n isRightDisable = false;\n if (opts.navtype === 'thumbs' && !opts.loop) {\n (activeIndex == 0) ? isLeftDisable = true : isLeftDisable = false;\n (activeIndex == opts.data.length - 1) ? isRightDisable = true : isRightDisable = false;\n }\n if (opts.navtype === 'slides') {\n var pos = readPosition($navShaft, opts.navdir);\n pos >= navShaftTouchTail.max ? isLeftDisable = true : isLeftDisable = false;\n pos <= Math.round(navShaftTouchTail.min) ? isRightDisable = true : isRightDisable = false;\n }\n $thumbArrLeft\n .toggleClass(arrDisabledClass, isLeftDisable)\n .attr(disableAttr(isLeftDisable, true));\n $thumbArrRight\n .toggleClass(arrDisabledClass, isRightDisable)\n .attr(disableAttr(isRightDisable, true));\n }\n\n function stageWheelUpdate() {\n if (stageWheelTail.ok) {\n stageWheelTail.prevent = {'<': disableDirrection(0), '>': disableDirrection(1)};\n }\n }\n\n function getNavFrameBounds($navFrame) {\n var navFrameData = $navFrame.data(),\n left,\n top,\n width,\n height;\n\n if (o_navThumbs) {\n left = navFrameData.l;\n top = navFrameData.t;\n width = navFrameData.w;\n height = navFrameData.h;\n } else {\n left = $navFrame.position().left;\n width = $navFrame.width();\n }\n\n var horizontalBounds = {\n c: left + width / 2,\n min: -left + opts.thumbmargin * 10,\n max: -left + measures.w - width - opts.thumbmargin * 10\n };\n\n var verticalBounds = {\n c: top + height / 2,\n min: -top + opts.thumbmargin * 10,\n max: -top + measures.h - height - opts.thumbmargin * 10\n };\n\n return opts.navdir === 'vertical' ? verticalBounds : horizontalBounds;\n }\n\n function slideThumbBorder(time) {\n var navFrameData = activeFrame[navFrameKey].data();\n slide($thumbBorder, {\n time: time * 1.2,\n pos: (opts.navdir === 'vertical' ? navFrameData.t : navFrameData.l),\n width: navFrameData.w,\n height: navFrameData.h,\n direction: opts.navdir\n });\n }\n\n function slideNavShaft(options) {\n var $guessNavFrame = data[options.guessIndex][navFrameKey],\n typeOfAnimation = opts.navtype;\n\n var overflowFLAG,\n time,\n minMax,\n boundTop,\n boundLeft,\n l,\n pos,\n x;\n\n if ($guessNavFrame) {\n if (typeOfAnimation === 'thumbs') {\n overflowFLAG = navShaftTouchTail.min !== navShaftTouchTail.max;\n minMax = options.minMax || overflowFLAG && getNavFrameBounds(activeFrame[navFrameKey]);\n boundTop = overflowFLAG && (options.keep && slideNavShaft.t ? slideNavShaft.l : minMaxLimit((options.coo || measures.nw / 2) - getNavFrameBounds($guessNavFrame).c, minMax.min, minMax.max));\n boundLeft = overflowFLAG && (options.keep && slideNavShaft.l ? slideNavShaft.l : minMaxLimit((options.coo || measures.nw / 2) - getNavFrameBounds($guessNavFrame).c, minMax.min, minMax.max));\n l = (opts.navdir === 'vertical' ? boundTop : boundLeft);\n pos = overflowFLAG && minMaxLimit(l, navShaftTouchTail.min, navShaftTouchTail.max) || 0;\n time = options.time * 1.1;\n slide($navShaft, {\n time: time,\n pos: pos,\n direction: opts.navdir,\n onEnd: function () {\n thumbsDraw(pos, true);\n thumbArrUpdate();\n }\n });\n\n setShadow($nav, findShadowEdge(pos, navShaftTouchTail.min, navShaftTouchTail.max, opts.navdir));\n slideNavShaft.l = l;\n } else {\n x = readPosition($navShaft, opts.navdir);\n time = options.time * 1.11;\n\n pos = validateSlidePos(opts, navShaftTouchTail, options.guessIndex, x, $guessNavFrame, $navWrap, opts.navdir);\n\n slide($navShaft, {\n time: time,\n pos: pos,\n direction: opts.navdir,\n onEnd: function () {\n thumbsDraw(pos, true);\n thumbArrUpdate();\n }\n });\n setShadow($nav, findShadowEdge(pos, navShaftTouchTail.min, navShaftTouchTail.max, opts.navdir));\n }\n }\n }\n\n function navUpdate() {\n deactivateFrames(navFrameKey);\n toDeactivate[navFrameKey].push(activeFrame[navFrameKey].addClass(activeClass).attr('data-active', true));\n }\n\n function deactivateFrames(key) {\n var _toDeactivate = toDeactivate[key];\n\n while (_toDeactivate.length) {\n _toDeactivate.shift().removeClass(activeClass).attr('data-active', false);\n }\n }\n\n function detachFrames(key) {\n var _toDetach = toDetach[key];\n\n $.each(activeIndexes, function (i, index) {\n delete _toDetach[normalizeIndex(index)];\n });\n\n $.each(_toDetach, function (index, $frame) {\n delete _toDetach[index];\n $frame.detach();\n });\n }\n\n function stageShaftReposition(skipOnEnd) {\n\n repositionIndex = dirtyIndex = activeIndex;\n\n var $frame = activeFrame[STAGE_FRAME_KEY];\n\n if ($frame) {\n deactivateFrames(STAGE_FRAME_KEY);\n toDeactivate[STAGE_FRAME_KEY].push($frame.addClass(activeClass).attr('data-active', true));\n\n if ($frame.hasClass(stageFrameClass)) {\n $frame.attr('aria-hidden', 'false');\n }\n\n skipOnEnd || that.showStage.onEnd(true);\n stop($stageShaft, 0, true);\n\n detachFrames(STAGE_FRAME_KEY);\n stageFramePosition(activeIndexes);\n setStageShaftMinmaxAndSnap();\n setNavShaftMinMax();\n addEnterUp($stageShaft[0], function () {\n if (!$fotorama.hasClass(fullscreenClass)) {\n that.requestFullScreen();\n $fullscreenIcon.focus();\n }\n });\n }\n }\n\n function extendMeasures(options, measuresArray) {\n if (!options) return;\n\n $.each(measuresArray, function (i, measures) {\n if (!measures) return;\n\n $.extend(measures, {\n width: options.width || measures.width,\n height: options.height,\n minwidth: options.minwidth,\n maxwidth: options.maxwidth,\n minheight: options.minheight,\n maxheight: options.maxheight,\n ratio: getRatio(options.ratio)\n })\n });\n }\n\n function triggerEvent(event, extra) {\n $fotorama.trigger(_fotoramaClass + ':' + event, [that, extra]);\n }\n\n function onTouchStart() {\n clearTimeout(onTouchEnd.t);\n touchedFLAG = 1;\n\n if (opts.stopautoplayontouch) {\n that.stopAutoplay();\n } else {\n pausedAutoplayFLAG = true;\n }\n }\n\n function onTouchEnd() {\n if (!touchedFLAG) return;\n if (!opts.stopautoplayontouch) {\n releaseAutoplay();\n changeAutoplay();\n }\n\n onTouchEnd.t = setTimeout(function () {\n touchedFLAG = 0;\n }, TRANSITION_DURATION + TOUCH_TIMEOUT);\n }\n\n function releaseAutoplay() {\n pausedAutoplayFLAG = !!($videoPlaying || stoppedAutoplayFLAG);\n }\n\n function changeAutoplay() {\n\n clearTimeout(changeAutoplay.t);\n waitFor.stop(changeAutoplay.w);\n\n if (!opts.autoplay || pausedAutoplayFLAG) {\n if (that.autoplay) {\n that.autoplay = false;\n triggerEvent('stopautoplay');\n }\n\n return;\n }\n\n if (!that.autoplay) {\n that.autoplay = true;\n triggerEvent('startautoplay');\n }\n\n var _activeIndex = activeIndex;\n\n\n var frameData = activeFrame[STAGE_FRAME_KEY].data();\n changeAutoplay.w = waitFor(function () {\n return frameData.state || _activeIndex !== activeIndex;\n }, function () {\n changeAutoplay.t = setTimeout(function () {\n\n if (pausedAutoplayFLAG || _activeIndex !== activeIndex) return;\n\n var _nextAutoplayIndex = nextAutoplayIndex,\n nextFrameData = data[_nextAutoplayIndex][STAGE_FRAME_KEY].data();\n\n changeAutoplay.w = waitFor(function () {\n\n return nextFrameData.state || _nextAutoplayIndex !== nextAutoplayIndex;\n }, function () {\n if (pausedAutoplayFLAG || _nextAutoplayIndex !== nextAutoplayIndex) return;\n that.show(o_loop ? getDirectionSign(!o_rtl) : nextAutoplayIndex);\n });\n }, opts.autoplay);\n });\n\n }\n\n that.startAutoplay = function (interval) {\n if (that.autoplay) return this;\n pausedAutoplayFLAG = stoppedAutoplayFLAG = false;\n setAutoplayInterval(interval || opts.autoplay);\n changeAutoplay();\n\n return this;\n };\n\n that.stopAutoplay = function () {\n if (that.autoplay) {\n pausedAutoplayFLAG = stoppedAutoplayFLAG = true;\n changeAutoplay();\n }\n return this;\n };\n\n that.showSlide = function (slideDir) {\n var currentPosition = readPosition($navShaft, opts.navdir),\n pos,\n time = 500 * 1.1,\n size = opts.navdir === 'horizontal' ? opts.thumbwidth : opts.thumbheight,\n onEnd = function () {\n thumbArrUpdate();\n };\n if (slideDir === 'next') {\n pos = currentPosition - (size + opts.margin) * thumbsPerSlide;\n }\n if (slideDir === 'prev') {\n pos = currentPosition + (size + opts.margin) * thumbsPerSlide;\n }\n pos = validateRestrictions(pos, navShaftTouchTail);\n thumbsDraw(pos, true);\n slide($navShaft, {\n time: time,\n pos: pos,\n direction: opts.navdir,\n onEnd: onEnd\n });\n };\n\n that.showWhileLongPress = function (options) {\n if (that.longPress.singlePressInProgress) {\n return;\n }\n\n var index = calcActiveIndex(options);\n calcGlobalIndexes(index);\n var time = calcTime(options) / 50;\n var _activeFrame = activeFrame;\n that.activeFrame = activeFrame = data[activeIndex];\n var silent = _activeFrame === activeFrame && !options.user;\n\n that.showNav(silent, options, time);\n\n return this;\n };\n\n that.showEndLongPress = function (options) {\n if (that.longPress.singlePressInProgress) {\n return;\n }\n\n var index = calcActiveIndex(options);\n calcGlobalIndexes(index);\n var time = calcTime(options) / 50;\n var _activeFrame = activeFrame;\n that.activeFrame = activeFrame = data[activeIndex];\n\n var silent = _activeFrame === activeFrame && !options.user;\n\n that.showStage(silent, options, time);\n\n showedFLAG = typeof lastActiveIndex !== 'undefined' && lastActiveIndex !== activeIndex;\n lastActiveIndex = activeIndex;\n return this;\n };\n\n function calcActiveIndex (options) {\n var index;\n\n if (typeof options !== 'object') {\n index = options;\n options = {};\n } else {\n index = options.index;\n }\n\n index = index === '>' ? dirtyIndex + 1 : index === '<' ? dirtyIndex - 1 : index === '<<' ? 0 : index === '>>' ? size - 1 : index;\n index = isNaN(index) ? undefined : index;\n index = typeof index === 'undefined' ? activeIndex || 0 : index;\n\n return index;\n }\n\n function calcGlobalIndexes (index) {\n that.activeIndex = activeIndex = edgeIndex(index);\n prevIndex = getPrevIndex(activeIndex);\n nextIndex = getNextIndex(activeIndex);\n nextAutoplayIndex = normalizeIndex(activeIndex + (o_rtl ? -1 : 1));\n activeIndexes = [activeIndex, prevIndex, nextIndex];\n\n dirtyIndex = o_loop ? index : activeIndex;\n }\n\n function calcTime (options) {\n var diffIndex = Math.abs(lastActiveIndex - dirtyIndex),\n time = getNumber(options.time, function () {\n return Math.min(o_transitionDuration * (1 + (diffIndex - 1) / 12), o_transitionDuration * 2);\n });\n\n if (options.slow) {\n time *= 10;\n }\n\n return time;\n }\n\n that.showStage = function (silent, options, time, e) {\n if (e !== undefined && e.target.tagName == 'IFRAME') {\n return;\n }\n unloadVideo($videoPlaying, activeFrame.i !== data[normalizeIndex(repositionIndex)].i);\n frameDraw(activeIndexes, 'stage');\n stageFramePosition(SLOW ? [dirtyIndex] : [dirtyIndex, getPrevIndex(dirtyIndex), getNextIndex(dirtyIndex)]);\n updateTouchTails('go', true);\n\n silent || triggerEvent('show', {\n user: options.user,\n time: time\n });\n\n pausedAutoplayFLAG = true;\n\n var overPos = options.overPos;\n var onEnd = that.showStage.onEnd = function (skipReposition) {\n if (onEnd.ok) return;\n onEnd.ok = true;\n\n skipReposition || stageShaftReposition(true);\n\n if (!silent) {\n triggerEvent('showend', {\n user: options.user\n });\n }\n\n if (!skipReposition && o_transition && o_transition !== opts.transition) {\n that.setOptions({transition: o_transition});\n o_transition = false;\n return;\n }\n\n updateFotoramaState();\n loadImg(activeIndexes, 'stage');\n\n updateTouchTails('go', false);\n stageWheelUpdate();\n\n stageCursor();\n releaseAutoplay();\n changeAutoplay();\n\n if (that.fullScreen) {\n activeFrame[STAGE_FRAME_KEY].find('.' + imgFullClass).attr('aria-hidden', false);\n activeFrame[STAGE_FRAME_KEY].find('.' + imgClass).attr('aria-hidden', true)\n } else {\n activeFrame[STAGE_FRAME_KEY].find('.' + imgFullClass).attr('aria-hidden', true);\n activeFrame[STAGE_FRAME_KEY].find('.' + imgClass).attr('aria-hidden', false)\n }\n };\n\n if (!o_fade) {\n slide($stageShaft, {\n pos: -getPosByIndex(dirtyIndex, measures.w, opts.margin, repositionIndex),\n overPos: overPos,\n time: time,\n onEnd: onEnd\n });\n } else {\n var $activeFrame = activeFrame[STAGE_FRAME_KEY],\n $prevActiveFrame = data[lastActiveIndex] && activeIndex !== lastActiveIndex ? data[lastActiveIndex][STAGE_FRAME_KEY] : null;\n\n fade($activeFrame, $prevActiveFrame, $stageFrame, {\n time: time,\n method: opts.transition,\n onEnd: onEnd\n }, fadeStack);\n }\n\n arrsUpdate();\n };\n\n that.showNav = function(silent, options, time){\n thumbArrUpdate();\n if (o_nav) {\n navUpdate();\n\n var guessIndex = limitIndex(activeIndex + minMaxLimit(dirtyIndex - lastActiveIndex, -1, 1));\n slideNavShaft({\n time: time,\n coo: guessIndex !== activeIndex && options.coo,\n guessIndex: typeof options.coo !== 'undefined' ? guessIndex : activeIndex,\n keep: silent\n });\n if (o_navThumbs) slideThumbBorder(time);\n }\n };\n\n that.show = function (options, e) {\n that.longPress.singlePressInProgress = true;\n\n var index = calcActiveIndex(options);\n calcGlobalIndexes(index);\n var time = calcTime(options);\n var _activeFrame = activeFrame;\n that.activeFrame = activeFrame = data[activeIndex];\n\n var silent = _activeFrame === activeFrame && !options.user;\n\n that.showStage(silent, options, time, e);\n that.showNav(silent, options, time);\n\n showedFLAG = typeof lastActiveIndex !== 'undefined' && lastActiveIndex !== activeIndex;\n lastActiveIndex = activeIndex;\n that.longPress.singlePressInProgress = false;\n\n return this;\n };\n\n that.requestFullScreen = function () {\n if (o_allowFullScreen && !that.fullScreen) {\n\n //check that this is not video\n if(isVideo()) {\n return;\n }\n\n scrollTop = $WINDOW.scrollTop();\n scrollLeft = $WINDOW.scrollLeft();\n\n lockScroll($WINDOW);\n\n updateTouchTails('x', true);\n\n measuresStash = $.extend({}, measures);\n\n $fotorama\n .addClass(fullscreenClass)\n .appendTo($BODY.addClass(_fullscreenClass));\n\n $HTML.addClass(_fullscreenClass);\n\n unloadVideo($videoPlaying, true, true);\n\n that.fullScreen = true;\n\n if (o_nativeFullScreen) {\n fullScreenApi.request(fotorama);\n }\n\n loadImg(activeIndexes, 'stage');\n updateFotoramaState();\n triggerEvent('fullscreenenter');\n that.resize();\n\n if (!('ontouchstart' in window)) {\n $fullscreenIcon.focus();\n }\n }\n\n return this;\n };\n\n function cancelFullScreen() {\n if (that.fullScreen) {\n that.fullScreen = false;\n\n if (FULLSCREEN) {\n fullScreenApi.cancel(fotorama);\n }\n\n $BODY.removeClass(_fullscreenClass);\n $HTML.removeClass(_fullscreenClass);\n\n $fotorama\n .removeClass(fullscreenClass)\n .insertAfter($anchor);\n\n measures = $.extend({}, measuresStash);\n\n unloadVideo($videoPlaying, true, true);\n\n updateTouchTails('x', false);\n\n that.resize();\n loadImg(activeIndexes, 'stage');\n\n lockScroll($WINDOW, scrollLeft, scrollTop);\n\n triggerEvent('fullscreenexit');\n }\n }\n\n that.cancelFullScreen = function () {\n if (o_nativeFullScreen && fullScreenApi.is()) {\n fullScreenApi.cancel(document);\n } else {\n cancelFullScreen();\n }\n\n return this;\n };\n\n that.toggleFullScreen = function () {\n return that[(that.fullScreen ? 'cancel' : 'request') + 'FullScreen']();\n };\n\n that.resize = function (options) {\n if (!data) return this;\n\n var time = arguments[1] || 0,\n setFLAG = arguments[2];\n\n thumbsPerSlide = getThumbsInSlide($wrap, opts);\n extendMeasures(!that.fullScreen ? optionsToLowerCase(options) : {\n width: $(window).width(),\n maxwidth: null,\n minwidth: null,\n height: $(window).height(),\n maxheight: null,\n minheight: null\n }, [measures, setFLAG || that.fullScreen || opts]);\n\n var width = measures.width,\n height = measures.height,\n ratio = measures.ratio,\n windowHeight = $WINDOW.height() - (o_nav ? $nav.height() : 0);\n\n if (measureIsValid(width)) {\n $wrap.css({width: ''});\n $stage.css({width: ''});\n $stageShaft.css({width: ''});\n $nav.css({width: ''});\n $wrap.css({minWidth: measures.minwidth || 0, maxWidth: measures.maxwidth || MAX_WIDTH});\n\n if (o_nav === 'dots') {\n $navWrap.hide();\n }\n width = measures.W = measures.w = $wrap.width();\n measures.nw = o_nav && numberFromWhatever(opts.navwidth, width) || width;\n\n $stageShaft.css({width: measures.w, marginLeft: (measures.W - measures.w) / 2});\n\n height = numberFromWhatever(height, windowHeight);\n\n height = height || (ratio && width / ratio);\n\n if (height) {\n width = Math.round(width);\n height = measures.h = Math.round(minMaxLimit(height, numberFromWhatever(measures.minheight, windowHeight), numberFromWhatever(measures.maxheight, windowHeight)));\n $stage.css({'width': width, 'height': height});\n\n if (opts.navdir === 'vertical' && !that.fullscreen) {\n $nav.width(opts.thumbwidth + opts.thumbmargin * 2);\n }\n\n if (opts.navdir === 'horizontal' && !that.fullscreen) {\n $nav.height(opts.thumbheight + opts.thumbmargin * 2);\n }\n\n if (o_nav === 'dots') {\n $nav.width(width)\n .height('auto');\n $navWrap.show();\n }\n\n if (opts.navdir === 'vertical' && that.fullScreen) {\n $stage.css('height', $WINDOW.height());\n }\n\n if (opts.navdir === 'horizontal' && that.fullScreen) {\n $stage.css('height', $WINDOW.height() - $nav.height());\n }\n\n if (o_nav) {\n switch (opts.navdir) {\n case 'vertical':\n $navWrap.removeClass(navShafthorizontalClass);\n $navWrap.removeClass(navShaftListClass);\n $navWrap.addClass(navShaftVerticalClass);\n $nav\n .stop()\n .animate({height: measures.h, width: opts.thumbwidth}, time);\n break;\n case 'list':\n $navWrap.removeClass(navShaftVerticalClass);\n $navWrap.removeClass(navShafthorizontalClass);\n $navWrap.addClass(navShaftListClass);\n break;\n default:\n $navWrap.removeClass(navShaftVerticalClass);\n $navWrap.removeClass(navShaftListClass);\n $navWrap.addClass(navShafthorizontalClass);\n $nav\n .stop()\n .animate({width: measures.nw}, time);\n break;\n }\n\n stageShaftReposition();\n slideNavShaft({guessIndex: activeIndex, time: time, keep: true});\n if (o_navThumbs && frameAppend.nav) slideThumbBorder(time);\n }\n\n measuresSetFLAG = setFLAG || true;\n\n ready.ok = true;\n ready();\n }\n }\n\n stageLeft = $stage.offset().left;\n setStagePosition();\n\n return this;\n };\n\n that.setOptions = function (options) {\n $.extend(opts, options);\n reset();\n return this;\n };\n\n that.shuffle = function () {\n data && shuffle(data) && reset();\n return this;\n };\n\n function setShadow($el, edge) {\n if (o_shadows) {\n $el.removeClass(shadowsLeftClass + ' ' + shadowsRightClass);\n $el.removeClass(shadowsTopClass + ' ' + shadowsBottomClass);\n edge && !$videoPlaying && $el.addClass(edge.replace(/^|\\s/g, ' ' + shadowsClass + '--'));\n }\n }\n\n that.longPress = {\n threshold: 1,\n count: 0,\n thumbSlideTime: 20,\n progress: function(){\n if (!this.inProgress) {\n this.count++;\n this.inProgress = this.count > this.threshold;\n }\n },\n end: function(){\n if(this.inProgress) {\n this.isEnded = true\n }\n },\n reset: function(){\n this.count = 0;\n this.inProgress = false;\n this.isEnded = false;\n }\n };\n\n that.destroy = function () {\n that.cancelFullScreen();\n that.stopAutoplay();\n\n data = that.data = null;\n\n appendElements();\n\n activeIndexes = [];\n detachFrames(STAGE_FRAME_KEY);\n\n reset.ok = false;\n\n return this;\n };\n\n /**\n *\n * @returns {jQuery.Fotorama}\n */\n that.playVideo = function () {\n var dataFrame = activeFrame,\n video = dataFrame.video,\n _activeIndex = activeIndex;\n\n if (typeof video === 'object' && dataFrame.videoReady) {\n o_nativeFullScreen && that.fullScreen && that.cancelFullScreen();\n\n waitFor(function () {\n return !fullScreenApi.is() || _activeIndex !== activeIndex;\n }, function () {\n if (_activeIndex === activeIndex) {\n dataFrame.$video = dataFrame.$video || $(div(videoClass)).append(createVideoFrame(video));\n dataFrame.$video.appendTo(dataFrame[STAGE_FRAME_KEY]);\n\n $wrap.addClass(wrapVideoClass);\n $videoPlaying = dataFrame.$video;\n\n stageNoMove();\n\n $arrs.blur();\n $fullscreenIcon.blur();\n\n triggerEvent('loadvideo');\n }\n });\n }\n\n return this;\n };\n\n that.stopVideo = function () {\n unloadVideo($videoPlaying, true, true);\n return this;\n };\n\n that.spliceByIndex = function (index, newImgObj) {\n newImgObj.i = index + 1;\n newImgObj.img && $.ajax({\n url: newImgObj.img,\n type: 'HEAD',\n success: function () {\n data.splice(index, 1, newImgObj);\n reset();\n }\n });\n };\n\n function unloadVideo($video, unloadActiveFLAG, releaseAutoplayFLAG) {\n if (unloadActiveFLAG) {\n $wrap.removeClass(wrapVideoClass);\n $videoPlaying = false;\n\n stageNoMove();\n }\n\n if ($video && $video !== $videoPlaying) {\n $video.remove();\n triggerEvent('unloadvideo');\n }\n\n if (releaseAutoplayFLAG) {\n releaseAutoplay();\n changeAutoplay();\n }\n }\n\n function toggleControlsClass(FLAG) {\n $wrap.toggleClass(wrapNoControlsClass, FLAG);\n }\n\n function stageCursor(e) {\n if (stageShaftTouchTail.flow) return;\n\n var x = e ? e.pageX : stageCursor.x,\n pointerFLAG = x && !disableDirrection(getDirection(x)) && opts.click;\n\n if (stageCursor.p !== pointerFLAG\n && $stage.toggleClass(pointerClass, pointerFLAG)) {\n stageCursor.p = pointerFLAG;\n stageCursor.x = x;\n }\n }\n\n $stage.on('mousemove', stageCursor);\n\n function clickToShow(showOptions, e) {\n clearTimeout(clickToShow.t);\n\n if (opts.clicktransition && opts.clicktransition !== opts.transition) {\n setTimeout(function () {\n var _o_transition = opts.transition;\n\n that.setOptions({transition: opts.clicktransition});\n\n // now safe to pass base transition to o_transition, so that.show will restor it\n o_transition = _o_transition;\n // this timeout is here to prevent jerking in some browsers\n clickToShow.t = setTimeout(function () {\n that.show(showOptions);\n }, 10);\n }, 0);\n } else {\n that.show(showOptions, e);\n }\n }\n\n function onStageTap(e, toggleControlsFLAG) {\n var target = e.target,\n $target = $(target);\n if ($target.hasClass(videoPlayClass)) {\n that.playVideo();\n } else if (target === fullscreenIcon) {\n that.toggleFullScreen();\n } else if ($videoPlaying) {\n target === videoClose && unloadVideo($videoPlaying, true, true);\n } else if (!$fotorama.hasClass(fullscreenClass)) {\n that.requestFullScreen();\n }\n }\n\n function updateTouchTails(key, value) {\n stageShaftTouchTail[key] = navShaftTouchTail[key] = value;\n }\n\n stageShaftTouchTail = moveOnTouch($stageShaft, {\n onStart: onTouchStart,\n onMove: function (e, result) {\n setShadow($stage, result.edge);\n },\n onTouchEnd: onTouchEnd,\n onEnd: function (result) {\n var toggleControlsFLAG;\n\n setShadow($stage);\n toggleControlsFLAG = (MS_POINTER && !hoverFLAG || result.touch) &&\n opts.arrows;\n\n if ((result.moved || (toggleControlsFLAG && result.pos !== result.newPos && !result.control)) && result.$target[0] !== $fullscreenIcon[0]) {\n var index = getIndexByPos(result.newPos, measures.w, opts.margin, repositionIndex);\n\n that.show({\n index: index,\n time: o_fade ? o_transitionDuration : result.time,\n overPos: result.overPos,\n user: true\n });\n } else if (!result.aborted && !result.control) {\n onStageTap(result.startEvent, toggleControlsFLAG);\n }\n },\n timeLow: 1,\n timeHigh: 1,\n friction: 2,\n select: '.' + selectClass + ', .' + selectClass + ' *',\n $wrap: $stage,\n direction: 'horizontal'\n\n });\n\n navShaftTouchTail = moveOnTouch($navShaft, {\n onStart: onTouchStart,\n onMove: function (e, result) {\n setShadow($nav, result.edge);\n },\n onTouchEnd: onTouchEnd,\n onEnd: function (result) {\n\n function onEnd() {\n slideNavShaft.l = result.newPos;\n releaseAutoplay();\n changeAutoplay();\n thumbsDraw(result.newPos, true);\n thumbArrUpdate();\n }\n\n if (!result.moved) {\n var target = result.$target.closest('.' + navFrameClass, $navShaft)[0];\n target && onNavFrameClick.call(target, result.startEvent);\n } else if (result.pos !== result.newPos) {\n pausedAutoplayFLAG = true;\n slide($navShaft, {\n time: result.time,\n pos: result.newPos,\n overPos: result.overPos,\n direction: opts.navdir,\n onEnd: onEnd\n });\n thumbsDraw(result.newPos);\n o_shadows && setShadow($nav, findShadowEdge(result.newPos, navShaftTouchTail.min, navShaftTouchTail.max, result.dir));\n } else {\n onEnd();\n }\n },\n timeLow: .5,\n timeHigh: 2,\n friction: 5,\n $wrap: $nav,\n direction: opts.navdir\n });\n\n stageWheelTail = wheel($stage, {\n shift: true,\n onEnd: function (e, direction) {\n onTouchStart();\n onTouchEnd();\n that.show({index: direction, slow: e.altKey})\n }\n });\n\n navWheelTail = wheel($nav, {\n onEnd: function (e, direction) {\n onTouchStart();\n onTouchEnd();\n var newPos = stop($navShaft) + direction * .25;\n $navShaft.css(getTranslate(minMaxLimit(newPos, navShaftTouchTail.min, navShaftTouchTail.max), opts.navdir));\n o_shadows && setShadow($nav, findShadowEdge(newPos, navShaftTouchTail.min, navShaftTouchTail.max, opts.navdir));\n navWheelTail.prevent = {'<': newPos >= navShaftTouchTail.max, '>': newPos <= navShaftTouchTail.min};\n clearTimeout(navWheelTail.t);\n navWheelTail.t = setTimeout(function () {\n slideNavShaft.l = newPos;\n thumbsDraw(newPos, true)\n }, TOUCH_TIMEOUT);\n thumbsDraw(newPos);\n }\n });\n\n $wrap.hover(\n function () {\n setTimeout(function () {\n if (touchedFLAG) return;\n toggleControlsClass(!(hoverFLAG = true));\n }, 0);\n },\n function () {\n if (!hoverFLAG) return;\n toggleControlsClass(!(hoverFLAG = false));\n }\n );\n\n function onNavFrameClick(e) {\n var index = $(this).data().eq;\n\n if (opts.navtype === 'thumbs') {\n clickToShow({index: index, slow: e.altKey, user: true, coo: e._x - $nav.offset().left});\n } else {\n clickToShow({index: index, slow: e.altKey, user: true});\n }\n }\n\n function onArrClick(e) {\n clickToShow({index: $arrs.index(this) ? '>' : '<', slow: e.altKey, user: true});\n }\n\n smartClick($arrs, function (e) {\n stopEvent(e);\n onArrClick.call(this, e);\n }, {\n onStart: function () {\n onTouchStart();\n stageShaftTouchTail.control = true;\n },\n onTouchEnd: onTouchEnd\n });\n\n smartClick($thumbArrLeft, function (e) {\n stopEvent(e);\n if (opts.navtype === 'thumbs') {\n\n that.show('<');\n } else {\n that.showSlide('prev')\n }\n });\n\n smartClick($thumbArrRight, function (e) {\n stopEvent(e);\n if (opts.navtype === 'thumbs') {\n that.show('>');\n } else {\n that.showSlide('next')\n }\n\n });\n\n\n function addFocusOnControls(el) {\n addFocus(el, function () {\n setTimeout(function () {\n lockScroll($stage);\n }, 0);\n toggleControlsClass(false);\n });\n }\n\n $arrs.each(function () {\n addEnterUp(this, function (e) {\n onArrClick.call(this, e);\n });\n addFocusOnControls(this);\n });\n\n addEnterUp(fullscreenIcon, function () {\n if ($fotorama.hasClass(fullscreenClass)) {\n that.cancelFullScreen();\n $stageShaft.focus();\n } else {\n that.requestFullScreen();\n $fullscreenIcon.focus();\n }\n\n });\n addFocusOnControls(fullscreenIcon);\n\n function reset() {\n setData();\n setOptions();\n\n if (!reset.i) {\n reset.i = true;\n // Only once\n var _startindex = opts.startindex;\n activeIndex = repositionIndex = dirtyIndex = lastActiveIndex = startIndex = edgeIndex(_startindex) || 0;\n /*(o_rtl ? size - 1 : 0)*///;\n }\n\n if (size) {\n if (changeToRtl()) return;\n\n if ($videoPlaying) {\n unloadVideo($videoPlaying, true);\n }\n\n activeIndexes = [];\n\n if (!isVideo()) {\n detachFrames(STAGE_FRAME_KEY);\n }\n\n reset.ok = true;\n\n that.show({index: activeIndex, time: 0});\n that.resize();\n } else {\n that.destroy();\n }\n }\n\n function changeToRtl() {\n\n if (!changeToRtl.f === o_rtl) {\n changeToRtl.f = o_rtl;\n activeIndex = size - 1 - activeIndex;\n that.reverse();\n\n return true;\n }\n }\n\n $.each('load push pop shift unshift reverse sort splice'.split(' '), function (i, method) {\n that[method] = function () {\n data = data || [];\n if (method !== 'load') {\n Array.prototype[method].apply(data, arguments);\n } else if (arguments[0] && typeof arguments[0] === 'object' && arguments[0].length) {\n data = clone(arguments[0]);\n }\n reset();\n return that;\n }\n });\n\n function ready() {\n if (ready.ok) {\n ready.ok = false;\n triggerEvent('ready');\n }\n }\n\n reset();\n };\n $.fn.fotorama = function (opts) {\n return this.each(function () {\n var that = this,\n $fotorama = $(this),\n fotoramaData = $fotorama.data(),\n fotorama = fotoramaData.fotorama;\n\n if (!fotorama) {\n waitFor(function () {\n return !isHidden(that);\n }, function () {\n fotoramaData.urtext = $fotorama.html();\n new $.Fotorama($fotorama,\n $.extend(\n {},\n OPTIONS,\n window.fotoramaDefaults,\n opts,\n fotoramaData\n )\n );\n });\n } else {\n fotorama.setOptions(opts, true);\n }\n });\n };\n $.Fotorama.instances = [];\n\n function calculateIndexes() {\n $.each($.Fotorama.instances, function (index, instance) {\n instance.index = index;\n });\n }\n\n function addInstance(instance) {\n $.Fotorama.instances.push(instance);\n calculateIndexes();\n }\n\n function hideInstance(instance) {\n $.Fotorama.instances.splice(instance.index, 1);\n calculateIndexes();\n }\n\n $.Fotorama.cache = {};\n $.Fotorama.measures = {};\n $ = $ || {};\n $.Fotorama = $.Fotorama || {};\n $.Fotorama.jst = $.Fotorama.jst || {};\n\n $.Fotorama.jst.dots = function (v) {\n var __t, __p = '', __e = _.escape;\n __p += '<div class=\"fotorama__nav__frame fotorama__nav__frame--dot\" tabindex=\"0\" role=\"button\" data-gallery-role=\"nav-frame\" data-nav-type=\"thumb\" aria-label>\\r\\n <div class=\"fotorama__dot\"></div>\\r\\n</div>';\n return __p\n };\n\n $.Fotorama.jst.frameCaption = function (v) {\n var __t, __p = '', __e = _.escape;\n __p += '<div class=\"fotorama__caption\" aria-hidden=\"true\">\\r\\n <div class=\"fotorama__caption__wrap\" id=\"' +\n ((__t = ( v.labelledby )) == null ? '' : __t) +\n '\">' +\n ((__t = ( v.caption )) == null ? '' : __t) +\n '</div>\\r\\n</div>\\r\\n';\n return __p\n };\n\n $.Fotorama.jst.style = function (v) {\n var __t, __p = '', __e = _.escape;\n __p += '.fotorama' +\n ((__t = ( v.s )) == null ? '' : __t) +\n ' .fotorama__nav--thumbs .fotorama__nav__frame{\\r\\npadding:' +\n ((__t = ( v.m )) == null ? '' : __t) +\n 'px;\\r\\nheight:' +\n ((__t = ( v.h )) == null ? '' : __t) +\n 'px}\\r\\n.fotorama' +\n ((__t = ( v.s )) == null ? '' : __t) +\n ' .fotorama__thumb-border{\\r\\nheight:' +\n ((__t = ( v.h )) == null ? '' : __t) +\n 'px;\\r\\nborder-width:' +\n ((__t = ( v.b )) == null ? '' : __t) +\n 'px;\\r\\nmargin-top:' +\n ((__t = ( v.m )) == null ? '' : __t) +\n 'px}';\n return __p\n };\n\n $.Fotorama.jst.thumb = function (v) {\n var __t, __p = '', __e = _.escape;\n __p += '<div class=\"fotorama__nav__frame fotorama__nav__frame--thumb\" tabindex=\"0\" role=\"button\" data-gallery-role=\"nav-frame\" data-nav-type=\"thumb\" aria-label>\\r\\n <div class=\"fotorama__thumb\">\\r\\n </div>\\r\\n</div>';\n return __p\n };\n})(window, document, location, typeof jQuery !== 'undefined' && jQuery);\n","Magento_CardinalCommerce/js/cardinal-client.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'uiClass',\n 'Magento_CardinalCommerce/js/cardinal-factory',\n 'Magento_Checkout/js/model/quote',\n 'mage/translate'\n], function ($, Class, cardinalFactory, quote, $t) {\n 'use strict';\n\n return {\n /**\n * Starts Cardinal Consumer Authentication\n *\n * @param {Object} cardData\n * @return {jQuery.Deferred}\n */\n startAuthentication: function (cardData) {\n var deferred = $.Deferred();\n\n if (this.cardinalClient) {\n this._startAuthentication(deferred, cardData);\n } else {\n cardinalFactory(this.getEnvironment())\n .done(function (client) {\n this.cardinalClient = client;\n this._startAuthentication(deferred, cardData);\n }.bind(this));\n }\n\n return deferred.promise();\n },\n\n /**\n * Cardinal Consumer Authentication\n *\n * @param {jQuery.Deferred} deferred\n * @param {Object} cardData\n */\n _startAuthentication: function (deferred, cardData) {\n //this.cardinalClient.configure({ logging: { level: 'verbose' } });\n this.cardinalClient.on('payments.validated', function (data, jwt) {\n if (data.ErrorNumber !== 0) {\n deferred.reject(data.ErrorDescription);\n } else if ($.inArray(data.ActionCode, ['FAILURE', 'ERROR']) !== -1) {\n deferred.reject($t('Authentication Failed. Please try again with another form of payment.'));\n } else {\n deferred.resolve(jwt);\n }\n this.cardinalClient.off('payments.validated');\n }.bind(this));\n\n this.cardinalClient.on('payments.setupComplete', function () {\n this.cardinalClient.start('cca', this.getRequestOrderObject(cardData));\n this.cardinalClient.off('payments.setupComplete');\n }.bind(this));\n\n this.cardinalClient.setup('init', {\n jwt: this.getRequestJWT()\n });\n },\n\n /**\n * Returns request order object.\n *\n * The request order object is structured object that is used to pass data\n * to Cardinal that describes an order you'd like to process.\n *\n * If you pass a request object in both the JWT and the browser,\n * Cardinal will merge the objects together where the browser overwrites\n * the JWT object as it is considered the most recently captured data.\n *\n * @param {Object} cardData\n * @returns {Object}\n */\n getRequestOrderObject: function (cardData) {\n var totalAmount = quote.totals()['base_grand_total'],\n currencyCode = quote.totals()['base_currency_code'],\n billingAddress = quote.billingAddress(),\n requestObject;\n\n requestObject = {\n OrderDetails: {\n Amount: totalAmount * 100,\n CurrencyCode: currencyCode\n },\n Consumer: {\n Account: {\n AccountNumber: cardData.accountNumber,\n ExpirationMonth: cardData.expMonth,\n ExpirationYear: cardData.expYear,\n CardCode: cardData.cardCode\n },\n BillingAddress: {\n FirstName: billingAddress.firstname,\n LastName: billingAddress.lastname,\n Address1: billingAddress.street[0],\n Address2: billingAddress.street[1],\n City: billingAddress.city,\n State: billingAddress.region,\n PostalCode: billingAddress.postcode,\n CountryCode: billingAddress.countryId,\n Phone1: billingAddress.telephone\n }\n }\n };\n\n return requestObject;\n },\n\n /**\n * Returns request JWT\n * @returns {String}\n */\n getRequestJWT: function () {\n return window.checkoutConfig.cardinal.requestJWT;\n },\n\n /**\n * Returns type of environment\n * @returns {String}\n */\n getEnvironment: function () {\n return window.checkoutConfig.cardinal.environment;\n }\n };\n});\n","Magento_CardinalCommerce/js/cardinal-factory.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery'\n], function ($) {\n 'use strict';\n\n return function (environment) {\n var deferred = $.Deferred(),\n dependency = 'cardinaljs';\n\n if (environment === 'sandbox') {\n dependency = 'cardinaljsSandbox';\n }\n\n require(\n [dependency],\n function (Cardinal) {\n deferred.resolve(Cardinal);\n },\n deferred.reject\n );\n\n return deferred.promise();\n };\n});\n","js-storage/storage-wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'js-storage/js.storage'\n], function ($, storage) {\n 'use strict';\n\n if (window.cookieStorage) {\n var cookiesConfig = window.cookiesConfig || {};\n\n $.extend(window.cookieStorage, {\n _secure: !!cookiesConfig.secure,\n _samesite: cookiesConfig.samesite ? cookiesConfig.samesite : 'lax',\n\n /**\n * Set value under name\n * @param {String} name\n * @param {String} value\n * @param {Object} [options]\n */\n setItem: function (name, value, options) {\n var _default = {\n expires: this._expires,\n path: this._path,\n domain: this._domain,\n secure: this._secure,\n samesite: this._samesite\n };\n\n $.cookie(this._prefix + name, value, $.extend(_default, options || {}));\n },\n\n /**\n * Set default options\n * @param {Object} c\n * @returns {storage}\n */\n setConf: function (c) {\n if (c.path) {\n this._path = c.path;\n }\n\n if (c.domain) {\n this._domain = c.domain;\n }\n\n if (c.expires) {\n this._expires = c.expires;\n }\n\n if (typeof c.secure !== 'undefined') {\n this._secure = c.secure;\n }\n\n if (typeof c.samesite !== 'undefined') {\n this._samesite = c.samesite;\n }\n\n return this;\n }\n });\n }\n\n $.alwaysUseJsonInStorage = $.alwaysUseJsonInStorage || storage.alwaysUseJsonInStorage;\n $.cookieStorage = $.cookieStorage || storage.cookieStorage;\n $.initNamespaceStorage = $.initNamespaceStorage || storage.initNamespaceStorage;\n $.localStorage = $.localStorage || storage.localStorage;\n $.namespaceStorages = $.namespaceStorages || storage.namespaceStorages;\n $.removeAllStorages = $.removeAllStorages || storage.removeAllStorages;\n $.sessionStorage = $.sessionStorage || storage.sessionStorage;\n});\n","js-storage/js.storage.js":"/*\n * JS Storage Plugin\n *\n * Copyright (c) 2019 Julien Maurel\n *\n * Licensed under the MIT license:\n * http://www.opensource.org/licenses/mit-license.php\n *\n * Project home:\n * https://github.com/julien-maurel/js-storage\n *\n * Version: 1.1.0\n */\n(function (factory) {\n var registeredInModuleLoader = false;\n if (typeof define === 'function' && define.amd) {\n define(['jquery', 'jquery/jquery.cookie'], factory);\n registeredInModuleLoader = true;\n }\n if (typeof exports === 'object') {\n module.exports = factory();\n registeredInModuleLoader = true;\n }\n if (!registeredInModuleLoader) {\n var OldStorages = window.Storages;\n var api = window.Storages = factory();\n api.noConflict = function () {\n window.Storages = OldStorages;\n return api;\n };\n }\n}(function () {\n // Variables used by utilities functions (like isPlainObject...)\n var class2type = {};\n var toString = class2type.toString;\n var hasOwn = class2type.hasOwnProperty;\n var fnToString = hasOwn.toString;\n var ObjectFunctionString = fnToString.call(Object);\n var getProto = Object.getPrototypeOf;\n var apis = {};\n\n // Prefix to use with cookie fallback\n var cookie_local_prefix = \"ls_\";\n var cookie_session_prefix = \"ss_\";\n\n // Get items from a storage\n function _get() {\n var storage = this._type, l = arguments.length, s = window[storage], a = arguments, a0 = a[0], vi, ret, tmp, i, j;\n if (l < 1) {\n throw new Error('Minimum 1 argument must be given');\n } else if (Array.isArray(a0)) {\n // If second argument is an array, return an object with value of storage for each item in this array\n ret = {};\n for (i in a0) {\n if (a0.hasOwnProperty(i)) {\n vi = a0[i];\n try {\n ret[vi] = JSON.parse(s.getItem(vi));\n } catch (e) {\n ret[vi] = s.getItem(vi);\n }\n }\n }\n return ret;\n } else if (l == 1) {\n // If only 1 argument, return value directly\n try {\n return JSON.parse(s.getItem(a0));\n } catch (e) {\n return s.getItem(a0);\n }\n } else {\n // If more than 1 argument, parse storage to retrieve final value to return it\n // Get first level\n try {\n ret = JSON.parse(s.getItem(a0));\n if (!ret) {\n throw new ReferenceError(a0 + ' is not defined in this storage');\n }\n } catch (e) {\n throw new ReferenceError(a0 + ' is not defined in this storage');\n }\n // Parse next levels\n for (i = 1; i < l - 1; i++) {\n ret = ret[a[i]];\n if (ret === undefined) {\n throw new ReferenceError([].slice.call(a, 0, i + 1).join('.') + ' is not defined in this storage');\n }\n }\n // If last argument is an array, return an object with value for each item in this array\n // Else return value normally\n if (Array.isArray(a[i])) {\n tmp = ret;\n ret = {};\n for (j in a[i]) {\n if (a[i].hasOwnProperty(j)) {\n ret[a[i][j]] = tmp[a[i][j]];\n }\n }\n return ret;\n } else {\n return ret[a[i]];\n }\n }\n }\n\n // Set items of a storage\n function _set() {\n var storage = this._type, l = arguments.length, s = window[storage], a = arguments, a0 = a[0], a1 = a[1], vi, to_store = isNaN(a1) ? {} : [], type, tmp, i;\n if (l < 1 || !_isPlainObject(a0) && l < 2) {\n throw new Error('Minimum 2 arguments must be given or first parameter must be an object');\n } else if (_isPlainObject(a0)) {\n // If first argument is an object, set values of storage for each property of this object\n for (i in a0) {\n if (a0.hasOwnProperty(i)) {\n vi = a0[i];\n if (!_isPlainObject(vi) && !this.alwaysUseJson) {\n s.setItem(i, vi);\n } else {\n s.setItem(i, JSON.stringify(vi));\n }\n }\n }\n return a0;\n } else if (l == 2) {\n // If only 2 arguments, set value of storage directly\n if (typeof a1 === 'object' || this.alwaysUseJson) {\n s.setItem(a0, JSON.stringify(a1));\n } else {\n s.setItem(a0, a1);\n }\n return a1;\n } else {\n // If more than 3 arguments, parse storage to retrieve final node and set value\n // Get first level\n try {\n tmp = s.getItem(a0);\n if (tmp != null) {\n to_store = JSON.parse(tmp);\n }\n } catch (e) {\n }\n tmp = to_store;\n // Parse next levels and set value\n for (i = 1; i < l - 2; i++) {\n vi = a[i];\n type = isNaN(a[i + 1]) ? \"object\" : \"array\";\n if (!tmp[vi] || type == \"object\" && !_isPlainObject(tmp[vi]) || type == \"array\" && !Array.isArray(tmp[vi])) {\n if (type == \"array\") tmp[vi] = [];\n else tmp[vi] = {};\n }\n tmp = tmp[vi];\n }\n tmp[a[i]] = a[i + 1];\n s.setItem(a0, JSON.stringify(to_store));\n return to_store;\n }\n }\n\n // Remove items from a storage\n function _remove() {\n var storage = this._type, l = arguments.length, s = window[storage], a = arguments, a0 = a[0], to_store, tmp, i, j;\n if (l < 1) {\n throw new Error('Minimum 1 argument must be given');\n } else if (Array.isArray(a0)) {\n // If first argument is an array, remove values from storage for each item of this array\n for (i in a0) {\n if (a0.hasOwnProperty(i)) {\n s.removeItem(a0[i]);\n }\n }\n return true;\n } else if (l == 1) {\n // If only 2 arguments, remove value from storage directly\n s.removeItem(a0);\n return true;\n } else {\n // If more than 2 arguments, parse storage to retrieve final node and remove value\n // Get first level\n try {\n to_store = tmp = JSON.parse(s.getItem(a0));\n } catch (e) {\n throw new ReferenceError(a0 + ' is not defined in this storage');\n }\n // Parse next levels and remove value\n for (i = 1; i < l - 1; i++) {\n tmp = tmp[a[i]];\n if (tmp === undefined) {\n throw new ReferenceError([].slice.call(a, 1, i).join('.') + ' is not defined in this storage');\n }\n }\n // If last argument is an array,remove value for each item in this array\n // Else remove value normally\n if (Array.isArray(a[i])) {\n for (j in a[i]) {\n if (a[i].hasOwnProperty(j)) {\n delete tmp[a[i][j]];\n }\n }\n } else {\n delete tmp[a[i]];\n }\n s.setItem(a0, JSON.stringify(to_store));\n return true;\n }\n }\n\n // Remove all items from a storage\n function _removeAll(reinit_ns) {\n var keys = _keys.call(this), i;\n for (i in keys) {\n if (keys.hasOwnProperty(i)) {\n _remove.call(this, keys[i]);\n }\n }\n // Reinitialize all namespace storages\n if (reinit_ns) {\n for (i in apis.namespaceStorages) {\n if (apis.namespaceStorages.hasOwnProperty(i)) {\n _createNamespace(i);\n }\n }\n }\n }\n\n // Check if items of a storage are empty\n function _isEmpty() {\n var l = arguments.length, a = arguments, a0 = a[0], i;\n if (l == 0) {\n // If no argument, test if storage is empty\n return (_keys.call(this).length == 0);\n } else if (Array.isArray(a0)) {\n // If first argument is an array, test each item of this array and return true only if all items are empty\n for (i = 0; i < a0.length; i++) {\n if (!_isEmpty.call(this, a0[i])) {\n return false;\n }\n }\n return true;\n } else {\n // If at least 1 argument, try to get value and test it\n try {\n var v = _get.apply(this, arguments);\n // Convert result to an object (if last argument is an array, _get return already an object) and test each item\n if (!Array.isArray(a[l - 1])) {\n v = {'totest': v};\n }\n for (i in v) {\n if (v.hasOwnProperty(i) && !(\n (_isPlainObject(v[i]) && _isEmptyObject(v[i])) ||\n (Array.isArray(v[i]) && !v[i].length) ||\n (typeof v[i] !== 'boolean' && !v[i])\n )) {\n return false;\n }\n }\n return true;\n } catch (e) {\n return true;\n }\n }\n }\n\n // Check if items of a storage exist\n function _isSet() {\n var l = arguments.length, a = arguments, a0 = a[0], i;\n if (l < 1) {\n throw new Error('Minimum 1 argument must be given');\n }\n if (Array.isArray(a0)) {\n // If first argument is an array, test each item of this array and return true only if all items exist\n for (i = 0; i < a0.length; i++) {\n if (!_isSet.call(this, a0[i])) {\n return false;\n }\n }\n return true;\n } else {\n // For other case, try to get value and test it\n try {\n var v = _get.apply(this, arguments);\n // Convert result to an object (if last argument is an array, _get return already an object) and test each item\n if (!Array.isArray(a[l - 1])) {\n v = {'totest': v};\n }\n for (i in v) {\n if (v.hasOwnProperty(i) && !(v[i] !== undefined && v[i] !== null)) {\n return false;\n }\n }\n return true;\n } catch (e) {\n return false;\n }\n }\n }\n\n // Get keys of a storage or of an item of the storage\n function _keys() {\n var storage = this._type, l = arguments.length, s = window[storage], keys = [], o = {};\n // If at least 1 argument, get value from storage to retrieve keys\n // Else, use storage to retrieve keys\n if (l > 0) {\n o = _get.apply(this, arguments);\n } else {\n o = s;\n }\n if (o && o._cookie) {\n // If storage is a cookie, use js-cookie to retrieve keys\n var cookies = Cookies.get();\n for (var key in cookies) {\n if (cookies.hasOwnProperty(key) && key != '') {\n keys.push(key.replace(o._prefix, ''));\n }\n }\n } else {\n for (var i in o) {\n if (o.hasOwnProperty(i)) {\n keys.push(i);\n }\n }\n }\n return keys;\n }\n\n // Create new namespace storage\n function _createNamespace(name) {\n if (!name || typeof name != \"string\") {\n throw new Error('First parameter must be a string');\n }\n if (storage_available) {\n if (!window.localStorage.getItem(name)) {\n window.localStorage.setItem(name, '{}');\n }\n if (!window.sessionStorage.getItem(name)) {\n window.sessionStorage.setItem(name, '{}');\n }\n } else {\n if (!window.localCookieStorage.getItem(name)) {\n window.localCookieStorage.setItem(name, '{}');\n }\n if (!window.sessionCookieStorage.getItem(name)) {\n window.sessionCookieStorage.setItem(name, '{}');\n }\n }\n var ns = {\n localStorage: _extend({}, apis.localStorage, {_ns: name}),\n sessionStorage: _extend({}, apis.sessionStorage, {_ns: name})\n };\n if (cookies_available) {\n if (!window.cookieStorage.getItem(name)) {\n window.cookieStorage.setItem(name, '{}');\n }\n ns.cookieStorage = _extend({}, apis.cookieStorage, {_ns: name});\n }\n apis.namespaceStorages[name] = ns;\n return ns;\n }\n\n // Test if storage is natively available on browser\n function _testStorage(name) {\n var foo = 'jsapi';\n try {\n if (!window[name]) {\n return false;\n }\n window[name].setItem(foo, foo);\n window[name].removeItem(foo);\n return true;\n } catch (e) {\n return false;\n }\n }\n\n // Test if a variable is a plain object (from jQuery)\n function _isPlainObject(obj) {\n var proto, Ctor;\n\n // Detect obvious negatives\n // Use toString instead of jQuery.type to catch host objects\n if (!obj || toString.call(obj) !== \"[object Object]\") {\n return false;\n }\n\n proto = getProto(obj);\n\n // Objects with no prototype (e.g., `Object.create( null )`) are plain\n if (!proto) {\n return true;\n }\n\n // Objects with prototype are plain iff they were constructed by a global Object function\n Ctor = hasOwn.call(proto, \"constructor\") && proto.constructor;\n return typeof Ctor === \"function\" && fnToString.call(Ctor) === ObjectFunctionString;\n }\n\n // Test if a variable is an empty object (from jQuery)\n function _isEmptyObject(obj) {\n var name;\n\n for (name in obj) {\n return false;\n }\n return true;\n }\n\n // Merge objects\n function _extend() {\n var i = 1;\n var result = arguments[0];\n for (; i < arguments.length; i++) {\n var attributes = arguments[i];\n for (var key in attributes) {\n if (attributes.hasOwnProperty(key)) {\n result[key] = attributes[key];\n }\n }\n }\n return result;\n }\n\n // Check if storages are natively available on browser and check is js-cookie is present\n var storage_available = _testStorage('localStorage');\n var cookies_available = typeof Cookies !== 'undefined';\n\n // Namespace object\n var storage = {\n _type: '',\n _ns: '',\n _callMethod: function (f, a) {\n a = Array.prototype.slice.call(a);\n var p = [], a0 = a[0];\n if (this._ns) {\n p.push(this._ns);\n }\n if (typeof a0 === 'string' && a0.indexOf('.') !== -1) {\n a.shift();\n [].unshift.apply(a, a0.split('.'));\n }\n [].push.apply(p, a);\n return f.apply(this, p);\n },\n // Define if plugin always use JSON to store values (even to store simple values like string, int...) or not\n alwaysUseJson: false,\n // Get items. If no parameters and storage have a namespace, return all namespace\n get: function () {\n if (!storage_available && !cookies_available){\n return null;\n }\n return this._callMethod(_get, arguments);\n },\n // Set items\n set: function () {\n var l = arguments.length, a = arguments, a0 = a[0];\n if (l < 1 || !_isPlainObject(a0) && l < 2) {\n throw new Error('Minimum 2 arguments must be given or first parameter must be an object');\n }\n if (!storage_available && !cookies_available){\n return null;\n }\n // If first argument is an object and storage is a namespace storage, set values individually\n if (_isPlainObject(a0) && this._ns) {\n for (var i in a0) {\n if (a0.hasOwnProperty(i)) {\n this._callMethod(_set, [i, a0[i]]);\n }\n }\n return a0;\n } else {\n var r = this._callMethod(_set, a);\n if (this._ns) {\n return r[a0.split('.')[0]];\n } else {\n return r;\n }\n }\n },\n // Delete items\n remove: function () {\n if (arguments.length < 1) {\n throw new Error('Minimum 1 argument must be given');\n }\n if (!storage_available && !cookies_available){\n return null;\n }\n return this._callMethod(_remove, arguments);\n },\n // Delete all items\n removeAll: function (reinit_ns) {\n if (!storage_available && !cookies_available){\n return null;\n }\n if (this._ns) {\n this._callMethod(_set, [{}]);\n return true;\n } else {\n return this._callMethod(_removeAll, [reinit_ns]);\n }\n },\n // Items empty\n isEmpty: function () {\n if (!storage_available && !cookies_available){\n return null;\n }\n return this._callMethod(_isEmpty, arguments);\n },\n // Items exists\n isSet: function () {\n if (arguments.length < 1) {\n throw new Error('Minimum 1 argument must be given');\n }\n if (!storage_available && !cookies_available){\n return null;\n }\n return this._callMethod(_isSet, arguments);\n },\n // Get keys of items\n keys: function () {\n if (!storage_available && !cookies_available){\n return null;\n }\n return this._callMethod(_keys, arguments);\n }\n };\n\n // Use js-cookie for compatibility with old browsers and give access to cookieStorage\n if (cookies_available) {\n // sessionStorage is valid for one window/tab. To simulate that with cookie, we set a name for the window and use it for the name of the cookie\n if (!window.name) {\n window.name = Math.floor(Math.random() * 100000000);\n }\n var cookie_storage = {\n _cookie: true,\n _prefix: '',\n _expires: null,\n _path: null,\n _domain: null,\n _secure: false,\n setItem: function (n, v) {\n Cookies.set(this._prefix + n, v, {expires: this._expires, path: this._path, domain: this._domain, secure: this._secure});\n },\n getItem: function (n) {\n return Cookies.get(this._prefix + n);\n },\n removeItem: function (n) {\n return Cookies.remove(this._prefix + n, {path: this._path});\n },\n clear: function () {\n var cookies = Cookies.get();\n for (var key in cookies) {\n if (cookies.hasOwnProperty(key) && key != '') {\n if (!this._prefix && key.indexOf(cookie_local_prefix) === -1 && key.indexOf(cookie_session_prefix) === -1 || this._prefix && key.indexOf(this._prefix) === 0) {\n Cookies.remove(key);\n }\n }\n }\n },\n setExpires: function (e) {\n this._expires = e;\n return this;\n },\n setPath: function (p) {\n this._path = p;\n return this;\n },\n setDomain: function (d) {\n this._domain = d;\n return this;\n },\n setSecure: function (s) {\n this._secure = s;\n return this;\n },\n setConf: function (c) {\n if (c.path) {\n this._path = c.path;\n }\n if (c.domain) {\n this._domain = c.domain;\n }\n if (c.secure) {\n this._secure = c.secure;\n }\n if (c.expires) {\n this._expires = c.expires;\n }\n return this;\n },\n setDefaultConf: function () {\n this._path = this._domain = this._expires = null;\n this._secure = false;\n }\n };\n if (!storage_available) {\n window.localCookieStorage = _extend({}, cookie_storage, {\n _prefix: cookie_local_prefix,\n _expires: 365 * 10,\n _secure: true\n });\n window.sessionCookieStorage = _extend({}, cookie_storage, {\n _prefix: cookie_session_prefix + window.name + '_',\n _secure: true\n });\n }\n window.cookieStorage = _extend({}, cookie_storage);\n // cookieStorage API\n apis.cookieStorage = _extend({}, storage, {\n _type: 'cookieStorage',\n setExpires: function (e) {\n window.cookieStorage.setExpires(e);\n return this;\n },\n setPath: function (p) {\n window.cookieStorage.setPath(p);\n return this;\n },\n setDomain: function (d) {\n window.cookieStorage.setDomain(d);\n return this;\n },\n setSecure: function (s) {\n window.cookieStorage.setSecure(s);\n return this;\n },\n setConf: function (c) {\n window.cookieStorage.setConf(c);\n return this;\n },\n setDefaultConf: function () {\n window.cookieStorage.setDefaultConf();\n return this;\n }\n });\n }\n\n // Get a new API on a namespace\n apis.initNamespaceStorage = function (ns) {\n return _createNamespace(ns);\n };\n if (storage_available) {\n // localStorage API\n apis.localStorage = _extend({}, storage, {_type: 'localStorage'});\n // sessionStorage API\n apis.sessionStorage = _extend({}, storage, {_type: 'sessionStorage'});\n } else {\n // localStorage API\n apis.localStorage = _extend({}, storage, {_type: 'localCookieStorage'});\n // sessionStorage API\n apis.sessionStorage = _extend({}, storage, {_type: 'sessionCookieStorage'});\n }\n // List of all namespace storage\n apis.namespaceStorages = {};\n // Remove all items in all storages\n apis.removeAllStorages = function (reinit_ns) {\n apis.localStorage.removeAll(reinit_ns);\n apis.sessionStorage.removeAll(reinit_ns);\n if (apis.cookieStorage) {\n apis.cookieStorage.removeAll(reinit_ns);\n }\n if (!reinit_ns) {\n apis.namespaceStorages = {};\n }\n };\n // About alwaysUseJson\n // By default, all values are string on html storages and the plugin don't use json to store simple values (strings, int, float...)\n // So by default, if you do storage.setItem('test',2), value in storage will be \"2\", not 2\n // If you set this property to true, all values set with the plugin will be stored as json to have typed values in any cases\n apis.alwaysUseJsonInStorage = function (value) {\n storage.alwaysUseJson = value;\n apis.localStorage.alwaysUseJson = value;\n apis.sessionStorage.alwaysUseJson = value;\n if (apis.cookieStorage) {\n apis.cookieStorage.alwaysUseJson = value;\n }\n };\n\n return apis;\n}));\n","Magento_Security/js/escaper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * A loose JavaScript version of Magento\\Framework\\Escaper\n *\n * Due to differences in how XML/HTML is processed in PHP vs JS there are a couple of minor differences in behavior\n * from the PHP counterpart.\n *\n * The first difference is that the default invocation of escapeHtml without allowedTags will double-escape existing\n * entities as the intention of such an invocation is that the input isn't supposed to contain any HTML.\n *\n * The second difference is that escapeHtml will not escape quotes. Since the input is actually being processed by the\n * DOM there is no chance of quotes being mixed with HTML syntax. And, since escapeHtml is not\n * intended to be used with raw injection into a HTML attribute, this is acceptable.\n *\n * @api\n */\ndefine([], function () {\n 'use strict';\n\n return {\n neverAllowedElements: ['script', 'img', 'embed', 'iframe', 'video', 'source', 'object', 'audio'],\n generallyAllowedAttributes: ['id', 'class', 'href', 'title', 'style'],\n forbiddenAttributesByElement: {\n a: ['style']\n },\n\n /**\n * Escape a string for safe injection into HTML\n *\n * @param {String} data\n * @param {Array|null} allowedTags\n * @returns {String}\n */\n escapeHtml: function (data, allowedTags) {\n var domParser = new DOMParser(),\n fragment = domParser.parseFromString('<div></div>', 'text/html');\n\n fragment = fragment.body.childNodes[0];\n allowedTags = typeof allowedTags === 'object' && allowedTags.length ? allowedTags : null;\n\n if (allowedTags) {\n fragment.innerHTML = data || '';\n allowedTags = this._filterProhibitedTags(allowedTags);\n\n this._removeComments(fragment);\n this._removeNotAllowedElements(fragment, allowedTags);\n this._removeNotAllowedAttributes(fragment);\n\n return fragment.innerHTML;\n }\n\n fragment.textContent = data || '';\n\n return fragment.innerHTML;\n },\n\n /**\n * Remove the always forbidden tags from a list of provided tags\n *\n * @param {Array} tags\n * @returns {Array}\n * @private\n */\n _filterProhibitedTags: function (tags) {\n return tags.filter(function (n) {\n return this.neverAllowedElements.indexOf(n) === -1;\n }.bind(this));\n },\n\n /**\n * Remove comment nodes from the given node\n *\n * @param {Node} node\n * @private\n */\n _removeComments: function (node) {\n var treeWalker = node.ownerDocument.createTreeWalker(\n node,\n NodeFilter.SHOW_COMMENT,\n function () {\n return NodeFilter.FILTER_ACCEPT;\n },\n false\n ),\n nodesToRemove = [];\n\n while (treeWalker.nextNode()) {\n nodesToRemove.push(treeWalker.currentNode);\n }\n\n nodesToRemove.forEach(function (nodeToRemove) {\n nodeToRemove.parentNode.removeChild(nodeToRemove);\n });\n },\n\n /**\n * Strip the given node of all disallowed tags while permitting any nested text nodes\n *\n * @param {Node} node\n * @param {Array|null} allowedTags\n * @private\n */\n _removeNotAllowedElements: function (node, allowedTags) {\n var treeWalker = node.ownerDocument.createTreeWalker(\n node,\n NodeFilter.SHOW_ELEMENT,\n function (currentNode) {\n return allowedTags.indexOf(currentNode.nodeName.toLowerCase()) === -1 ?\n NodeFilter.FILTER_ACCEPT\n // SKIP instead of REJECT because REJECT also rejects child nodes\n : NodeFilter.FILTER_SKIP;\n },\n false\n ),\n nodesToRemove = [];\n\n while (treeWalker.nextNode()) {\n if (allowedTags.indexOf(treeWalker.currentNode.nodeName.toLowerCase()) === -1) {\n nodesToRemove.push(treeWalker.currentNode);\n }\n }\n\n nodesToRemove.forEach(function (nodeToRemove) {\n nodeToRemove.parentNode.replaceChild(\n node.ownerDocument.createTextNode(nodeToRemove.textContent),\n nodeToRemove\n );\n });\n },\n\n /**\n * Remove any invalid attributes from the given node\n *\n * @param {Node} node\n * @private\n */\n _removeNotAllowedAttributes: function (node) {\n var treeWalker = node.ownerDocument.createTreeWalker(\n node,\n NodeFilter.SHOW_ELEMENT,\n function () {\n return NodeFilter.FILTER_ACCEPT;\n },\n false\n ),\n i,\n attribute,\n nodeName,\n attributesToRemove = [];\n\n while (treeWalker.nextNode()) {\n for (i = 0; i < treeWalker.currentNode.attributes.length; i++) {\n attribute = treeWalker.currentNode.attributes[i];\n nodeName = treeWalker.currentNode.nodeName.toLowerCase();\n\n if (this.generallyAllowedAttributes.indexOf(attribute.name) === -1 || // eslint-disable-line max-depth,max-len\n this._checkHrefValue(attribute) ||\n this.forbiddenAttributesByElement[nodeName] &&\n this.forbiddenAttributesByElement[nodeName].indexOf(attribute.name) !== -1\n ) {\n attributesToRemove.push(attribute);\n }\n }\n }\n\n attributesToRemove.forEach(function (attributeToRemove) {\n attributeToRemove.ownerElement.removeAttribute(attributeToRemove.name);\n });\n },\n\n /**\n * Check that attribute contains script content\n *\n * @param {Object} attribute\n * @private\n */\n _checkHrefValue: function (attribute) {\n return attribute.nodeName === 'href' && attribute.nodeValue.startsWith('javascript');\n }\n };\n});\n","Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n 'use strict';\n\n var scriptTagAdded = false;\n\n return {\n /**\n * Add script tag. Script tag should be added once\n */\n addReCaptchaScriptTag: function () {\n var element, scriptTag;\n\n if (!scriptTagAdded) {\n element = document.createElement('script');\n scriptTag = document.getElementsByTagName('script')[0];\n\n element.async = true;\n element.src = 'https://www.google.com/recaptcha/api.js' +\n '?onload=globalOnRecaptchaOnLoadCallback&render=explicit';\n\n scriptTag.parentNode.insertBefore(element, scriptTag);\n scriptTagAdded = true;\n }\n }\n };\n});\n","Magento_ReCaptchaFrontendUi/js/registry.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['ko'], function (ko) {\n 'use strict';\n\n return {\n ids: ko.observableArray([]),\n captchaList: ko.observableArray([]),\n tokenFields: ko.observableArray([])\n };\n});\n","Magento_ReCaptchaFrontendUi/js/reCaptcha.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global grecaptcha */\ndefine(\n [\n 'uiComponent',\n 'jquery',\n 'ko',\n 'underscore',\n 'Magento_ReCaptchaFrontendUi/js/registry',\n 'Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader',\n 'Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer'\n ], function (Component, $, ko, _, registry, reCaptchaLoader, nonInlineReCaptchaRenderer) {\n 'use strict';\n\n return Component.extend({\n\n defaults: {\n template: 'Magento_ReCaptchaFrontendUi/reCaptcha',\n reCaptchaId: 'recaptcha'\n },\n\n /**\n * @inheritdoc\n */\n initialize: function () {\n this._super();\n this._loadApi();\n },\n\n /**\n * Loads recaptchaapi API and triggers event, when loaded\n * @private\n */\n _loadApi: function () {\n if (this._isApiRegistered !== undefined) {\n if (this._isApiRegistered === true) {\n $(window).trigger('recaptchaapiready');\n }\n\n return;\n }\n this._isApiRegistered = false;\n\n // global function\n window.globalOnRecaptchaOnLoadCallback = function () {\n this._isApiRegistered = true;\n $(window).trigger('recaptchaapiready');\n }.bind(this);\n\n reCaptchaLoader.addReCaptchaScriptTag();\n },\n\n /**\n * Checking that reCAPTCHA is invisible type\n * @returns {Boolean}\n */\n getIsInvisibleRecaptcha: function () {\n if (this.settings ===\n\n void 0) {\n return false;\n }\n\n return this.settings.invisible;\n },\n\n /**\n * reCAPTCHA callback\n * @param {String} token\n */\n reCaptchaCallback: function (token) {\n if (this.getIsInvisibleRecaptcha()) {\n this.tokenField.value = token;\n this.$parentForm.submit();\n }\n },\n\n /**\n * Initialize reCAPTCHA after first rendering\n */\n initCaptcha: function () {\n var $parentForm,\n $wrapper,\n $reCaptcha,\n widgetId,\n parameters;\n\n if (this.captchaInitialized || this.settings ===\n\n void 0) {\n return;\n }\n\n this.captchaInitialized = true;\n\n /*\n * Workaround for data-bind issue:\n * We cannot use data-bind to link a dynamic id to our component\n * See:\n * https://stackoverflow.com/questions/46657573/recaptcha-the-bind-parameter-must-be-an-element-or-id\n *\n * We create a wrapper element with a wrapping id and we inject the real ID with jQuery.\n * In this way we have no data-bind attribute at all in our reCAPTCHA div\n */\n $wrapper = $('#' + this.getReCaptchaId() + '-wrapper');\n $reCaptcha = $wrapper.find('.g-recaptcha');\n $reCaptcha.attr('id', this.getReCaptchaId());\n\n $parentForm = $wrapper.parents('form');\n\n if (this.settings === undefined) {\n\n return;\n }\n\n parameters = _.extend(\n {\n 'callback': function (token) { // jscs:ignore jsDoc\n this.reCaptchaCallback(token);\n this.validateReCaptcha(true);\n }.bind(this),\n 'expired-callback': function () {\n this.validateReCaptcha(false);\n }.bind(this)\n },\n this.settings.rendering\n );\n\n if (parameters.size === 'invisible' && parameters.badge !== 'inline') {\n nonInlineReCaptchaRenderer.add($reCaptcha, parameters);\n }\n\n // eslint-disable-next-line no-undef\n widgetId = grecaptcha.render(this.getReCaptchaId(), parameters);\n this.initParentForm($parentForm, widgetId);\n\n registry.ids.push(this.getReCaptchaId());\n registry.captchaList.push(widgetId);\n registry.tokenFields.push(this.tokenField);\n\n },\n\n /**\n * Initialize parent form.\n *\n * @param {Object} parentForm\n * @param {String} widgetId\n */\n initParentForm: function (parentForm, widgetId) {\n var listeners;\n\n if (this.getIsInvisibleRecaptcha() && parentForm.length > 0) {\n parentForm.submit(function (event) {\n if (!this.tokenField.value) {\n // eslint-disable-next-line no-undef\n grecaptcha.execute(widgetId);\n event.preventDefault(event);\n event.stopImmediatePropagation();\n }\n }.bind(this));\n\n // Move our (last) handler topmost. We need this to avoid submit bindings with ko.\n listeners = $._data(parentForm[0], 'events').submit;\n listeners.unshift(listeners.pop());\n\n // Create a virtual token field\n this.tokenField = $('<input type=\"text\" name=\"token\" style=\"display: none\" />')[0];\n this.$parentForm = parentForm;\n parentForm.append(this.tokenField);\n } else {\n this.tokenField = null;\n }\n if ($('#send2').length > 0) {$('#send2').prop('disabled', false);}\n },\n\n /**\n * Validates reCAPTCHA\n * @param {*} state\n * @returns {jQuery}\n */\n validateReCaptcha: function (state) {\n if (!this.getIsInvisibleRecaptcha()) {\n return $(document).find('input[type=checkbox].required-captcha').prop('checked', state);\n }\n },\n\n /**\n * Render reCAPTCHA\n */\n renderReCaptcha: function () {\n if (window.grecaptcha && window.grecaptcha.render) { // Check if reCAPTCHA is already loaded\n this.initCaptcha();\n } else { // Wait for reCAPTCHA to be loaded\n $(window).on('recaptchaapiready', function () {\n this.initCaptcha();\n }.bind(this));\n }\n },\n\n /**\n * Get reCAPTCHA ID\n * @returns {String}\n */\n getReCaptchaId: function () {\n return this.reCaptchaId;\n }\n });\n });\n","Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global grecaptcha */\ndefine([\n 'jquery',\n 'jquery/z-index'\n], function ($) {\n 'use strict';\n\n var reCaptchaEntities = [],\n initialized = false,\n rendererRecaptchaId = 'recaptcha-invisible',\n rendererReCaptcha = null;\n\n return {\n /**\n * Add reCaptcha entity to checklist.\n *\n * @param {jQuery} reCaptchaEntity\n * @param {Object} parameters\n */\n add: function (reCaptchaEntity, parameters) {\n if (!initialized) {\n this.init();\n grecaptcha.render(rendererRecaptchaId, parameters);\n setInterval(this.resolveVisibility, 100);\n initialized = true;\n }\n\n reCaptchaEntities.push(reCaptchaEntity);\n },\n\n /**\n * Show additional reCaptcha instance if any other should be visible, otherwise hide it.\n */\n resolveVisibility: function () {\n reCaptchaEntities.some(function (entity) {\n return entity.is(':visible') &&\n // 900 is some magic z-index value of modal popups.\n (entity.closest('[data-role=\\'modal\\']').length === 0 || entity.zIndex() > 900);\n }) ? rendererReCaptcha.show() : rendererReCaptcha.hide();\n },\n\n /**\n * Initialize additional reCaptcha instance.\n */\n init: function () {\n rendererReCaptcha = $('<div/>', {\n 'id': rendererRecaptchaId\n });\n rendererReCaptcha.hide();\n $('body').append(rendererReCaptcha);\n }\n };\n});\n","Magento_ReCaptchaFrontendUi/js/ui-messages-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['Magento_ReCaptchaFrontendUi/js/registry'], function (registry) {\n 'use strict';\n\n return function (originalComponent) {\n return originalComponent.extend({\n /**\n * Initialize reset on messages\n * @returns {initialize}\n */\n initialize: function () {\n this._super();\n\n this.messageContainer.errorMessages.subscribe(function () {\n var\n i,\n captchaList = registry.captchaList(),\n tokenFieldsList = registry.tokenFields();\n\n for (i = 0; i < captchaList.length; i++) {\n // eslint-disable-next-line no-undef\n grecaptcha.reset(captchaList[i]);\n\n if (tokenFieldsList[i]) {\n tokenFieldsList[i].value = '';\n }\n }\n }, null, 'arrayChange');\n\n return this;\n }\n });\n };\n});\n"}
}});