| Current Path : /proc/thread-self/cwd/static/frontend/Magento/blank/it_IT/js/bundle/ |
| Current File : //proc/thread-self/cwd/static/frontend/Magento/blank/it_IT/js/bundle/bundle1.js |
require.config({"config": {
"jsbuild":{"StripeIntegration_Payments/js/view/payment/method-renderer/stripe_payments_multishipping.js":"define(\n [\n 'ko',\n 'Magento_Checkout/js/view/payment/default',\n 'Magento_Ui/js/model/messageList',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Customer/js/model/customer',\n 'StripeIntegration_Payments/js/action/post-update-cart',\n 'StripeIntegration_Payments/js/action/post-restore-quote',\n 'StripeIntegration_Payments/js/action/get-requires-action',\n 'StripeIntegration_Payments/js/view/checkout/trialing_subscriptions',\n 'StripeIntegration_Payments/js/stripe',\n 'stripe_payments_express',\n 'mage/translate',\n 'mage/url',\n 'jquery',\n 'Magento_Checkout/js/action/place-order',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_Checkout/js/action/redirect-on-success',\n 'mage/storage',\n 'mage/url',\n 'Magento_CheckoutAgreements/js/model/agreement-validator',\n 'Magento_Customer/js/customer-data',\n 'Magento_Checkout/js/model/payment-service'\n ],\n function (\n ko,\n Component,\n globalMessageList,\n quote,\n customer,\n updateCartAction,\n restoreQuoteAction,\n getRequiresAction,\n trialingSubscriptions,\n stripe,\n stripeExpress,\n $t,\n url,\n $,\n placeOrderAction,\n additionalValidators,\n redirectOnSuccessAction,\n storage,\n urlBuilder,\n agreementValidator,\n customerData,\n paymentService\n ) {\n 'use strict';\n\n return Component.extend({\n externalRedirectUrl: null,\n defaults: {\n template: 'StripeIntegration_Payments/payment/element',\n stripePaymentsShowApplePaySection: false\n },\n redirectAfterPlaceOrder: false,\n elements: null,\n initParams: null,\n paymentElement: null,\n zeroDecimalCurrencies: ['BIF','CLP','DJF','GNF','JPY','KMF','KRW','MGA','PYG','RWF','UGX','VND','VUV','XAF','XOF','XPF'],\n\n initObservable: function ()\n {\n this._super()\n .observe([\n 'paymentElement',\n 'isPaymentFormComplete',\n 'isPaymentFormVisible',\n 'isLoading',\n 'stripePaymentsError',\n 'permanentError',\n 'isOrderPlaced',\n 'isInitializing',\n 'isInitialized',\n 'useQuoteBillingAddress',\n 'cvcToken',\n 'paymentElementPaymentMethod',\n\n // Saved payment methods dropdown\n 'dropdownOptions',\n 'selection',\n 'isDropdownOpen'\n ]);\n\n var self = this;\n\n this.isPaymentFormVisible(false);\n this.isOrderPlaced(false);\n this.isInitializing(true);\n this.isInitialized(false);\n this.useQuoteBillingAddress(false);\n this.cvcToken(null);\n this.collectCvc = ko.computed(this.shouldCollectCvc.bind(this));\n this.isAmex = ko.computed(this.isAmexSelected.bind(this));\n this.cardCvcElement = null;\n\n var currentTotals = quote.totals();\n var currentShippingAddress = quote.shippingAddress();\n var currentBillingAddress = quote.billingAddress();\n\n quote.totals.subscribe(function (totals)\n {\n if (!totals || !totals.grand_total || !totals.quote_currency_code)\n {\n return;\n }\n\n if (!currentTotals || !currentTotals.grand_total || !currentTotals.quote_currency_code)\n {\n currentTotals = totals;\n return;\n }\n\n var amount1 = totals.grand_total;\n var amount2 = currentTotals.grand_total;\n var currency1 = totals.quote_currency_code;\n var currency2 = currentTotals.quote_currency_code;\n\n if (amount1 === amount2 && currency1 === currency2)\n {\n return;\n }\n\n currentTotals = totals;\n\n self.onQuoteTotalsChanged.bind(self)();\n self.isOrderPlaced(false);\n }, this);\n\n quote.paymentMethod.subscribe(function (method)\n {\n if (method.method == this.getCode() && !this.isInitializing())\n {\n // We intentionally re-create the element because its container element may have changed\n this.initPaymentForm();\n }\n }, this);\n\n quote.billingAddress.subscribe(function(address)\n {\n if (address && self.paymentElement && self.paymentElement.update && !self.isPaymentFormComplete())\n {\n // Remove the postcode & country fields if a billing address has been specified\n self.paymentElement.update(self.getPaymentElementUpdateOptions());\n }\n });\n\n return this;\n },\n\n initSavedPaymentMethods: function()\n {\n // If it is already initialized, do not re-initialize\n if (this.dropdownOptions())\n {\n return;\n }\n\n var options = [];\n var methods = this.getStripeParam(\"savedMethods\");\n if (methods)\n {\n for (var i in methods)\n {\n if (methods.hasOwnProperty(i))\n {\n // We do this because some themes and libraries extend all objects with their own methods\n options.push(methods[i]);\n }\n }\n }\n\n if (options.length > 0)\n {\n this.isPaymentFormVisible(false);\n this.selection(options[0]);\n }\n else\n {\n this.isPaymentFormVisible(true);\n this.selection(false);\n }\n\n this.dropdownOptions(options);\n },\n\n shouldCollectCvc: function()\n {\n var selection = this.selection();\n\n if (!selection)\n return false;\n\n if (selection.type != 'card')\n return false;\n\n return !!selection.cvc;\n },\n\n isAmexSelected: function()\n {\n var selection = this.selection();\n\n if (!selection)\n return false;\n\n if (selection.type != 'card')\n return false;\n\n return (selection.brand == \"amex\");\n },\n\n newPaymentMethod: function()\n {\n this.messageContainer.clear();\n\n this.selection({\n type: 'new',\n value: 'new',\n icon: false,\n label: $t('New payment method')\n });\n this.isDropdownOpen(false);\n this.isPaymentFormVisible(true);\n if (!this.isInitialized())\n {\n this.onContainerRendered();\n this.isInitialized(true);\n }\n },\n\n getPaymentMethodId: function()\n {\n var selection = this.selection();\n\n if (selection && typeof selection.value != \"undefined\" && selection.value != \"new\")\n {\n return selection.value;\n }\n\n var paymentMethod = this.paymentElementPaymentMethod();\n if (paymentMethod && paymentMethod.id)\n {\n return paymentMethod.id;\n }\n\n return null;\n },\n\n toggleDropdown: function()\n {\n this.isDropdownOpen(!this.isDropdownOpen());\n },\n\n getStripeParam: function(param)\n {\n var params = this.getInitParams();\n\n if (!params)\n {\n return null;\n }\n\n if (typeof params[param] != \"undefined\")\n {\n return params[param];\n }\n\n return null;\n },\n\n onQuoteTotalsChanged: function()\n {\n if (!this.elements || !this.elements.update)\n {\n return;\n }\n\n try\n {\n this.elements.update(this.getElementsOptions(true));\n }\n catch (e)\n {\n this.elements.update(this.getElementsOptions(false));\n }\n },\n\n getInitParams: function()\n {\n return window.checkoutConfig.payment.stripe_payments.initParams;\n },\n\n onPaymentElementContainerRendered: function()\n {\n var self = this;\n this.isLoading(true);\n stripe.initStripe(this.getInitParams(), function(err)\n {\n if (err)\n return self.crash(err);\n\n self.initSavedPaymentMethods();\n self.initPaymentForm();\n });\n },\n\n onContainerRendered: function()\n {\n this.onPaymentElementContainerRendered();\n },\n\n getCardCVCOptions: function()\n {\n return {\n style: {\n base: {\n // iconColor: '#c4f0ff',\n // color: '#fff',\n // fontWeight: '500',\n // fontFamily: 'Roboto, Open Sans, Segoe UI, sans-serif',\n fontSize: '16px',\n // fontSmoothing: 'antialiased',\n // ':-webkit-autofill': {\n // color: '#fce883',\n // },\n // '::placeholder': {\n // color: '#87BBFD',\n // },\n // },\n // invalid: {\n // iconColor: '#FFC7EE',\n // color: '#FFC7EE',\n },\n },\n };\n },\n\n onCvcContainerRendered: function()\n {\n var self = this;\n var params = this.getInitParams();\n\n stripe.initStripe(params, function(err)\n {\n if (err)\n return self.crash(err);\n\n var options = {};\n if (params && params.locale)\n {\n options.locale = params.locale;\n }\n\n try\n {\n var elements = stripe.stripeJs.elements(options);\n self.cardCvcElement = elements.create('cardCvc', self.getCardCVCOptions());\n self.cardCvcElement.mount('#stripe-card-cvc-element');\n self.cardCvcElement.on('change', self.onCvcChange.bind(self));\n }\n catch (e)\n {\n this.crash(e.message);\n }\n });\n },\n\n onCvcChange: function(event)\n {\n if (event.error)\n this.selection().cvcError = event.error.message;\n else\n this.selection().cvcError = null;\n },\n\n crash: function(message)\n {\n this.isLoading(false);\n var userError = this.getStripeParam(\"userError\");\n if (userError)\n this.permanentError(userError);\n else\n this.permanentError($t(\"Sorry, this payment method is not available. Please contact us for assistance.\"));\n\n console.error(\"Error: \" + message);\n },\n\n softCrash: function(message)\n {\n var userError = this.getStripeParam(\"userError\");\n if (userError)\n this.showError(userError);\n else\n this.showError($t(\"Sorry, this payment method is not available. Please contact us for assistance.\"));\n\n console.error(\"Error: \" + message);\n },\n\n isCollapsed: function()\n {\n if (this.isChecked() == this.getCode())\n {\n return false;\n }\n else\n {\n return true;\n }\n },\n\n initPaymentForm: function()\n {\n this.isInitializing(false);\n this.isLoading(false);\n\n if (this.isCollapsed()) // Don't render PE with a height of 0\n return;\n\n if (document.getElementById('stripe-payment-element') === null)\n return this.crash(\"Cannot initialize Payment Element on a DOM that does not contain a div.stripe-payment-element.\");\n\n if (!stripe.stripeJs)\n return this.crash(\"Stripe.js could not be initialized.\");\n\n if (this.getStripeParam(\"isOrderPlaced\"))\n this.isOrderPlaced(true);\n\n try\n {\n try\n {\n this.elements = stripe.stripeJs.elements(this.getElementsOptions(true));\n }\n catch (e)\n {\n console.warn(\"Could not filter Stripe payment method types: \" + e.message);\n this.elements = stripe.stripeJs.elements(this.getElementsOptions(false));\n }\n this.paymentElement = this.elements.create('payment', this.getPaymentElementOptions());\n this.paymentElement.mount('#stripe-payment-element');\n this.paymentElement.on('change', this.onChange.bind(this));\n }\n catch (e)\n {\n this.crash(e.message);\n }\n },\n\n getElementsOptions: function(filterPaymentMethods)\n {\n var options = window.checkoutConfig.payment.stripe_payments.elementOptions;\n\n if (!filterPaymentMethods && options.payment_method_types)\n delete options.payment_method_types;\n\n if (options.mode != \"setup\")\n {\n options.amount = this.getElementsAmount();\n options.currency = this.getElementsCurrency();\n }\n\n return options;\n },\n\n getPaymentElementOptions: function()\n {\n var options = {};\n\n var params = this.getInitParams();\n if (params && typeof params.wallets != \"undefined\" && params.wallets)\n options.wallets = params.wallets;\n\n var billingAddress = quote.billingAddress();\n\n if (billingAddress)\n {\n try\n {\n this.useQuoteBillingAddress(true);\n\n var hasState = (billingAddress.region || billingAddress.regionCode || billingAddress.regionId);\n\n options.fields = {\n billingDetails: {\n name: 'never',\n email: 'never',\n phone: (billingAddress.telephone ? 'never' : 'auto'),\n address: {\n line1: ((billingAddress.street.length > 0) ? 'never' : 'auto'),\n line2: ((billingAddress.street.length > 0) ? 'never' : 'auto'),\n city: billingAddress.city ? 'never' : 'auto',\n state: hasState ? 'never' : 'auto',\n country: billingAddress.countryId ? 'never' : 'auto',\n postalCode: billingAddress.postcode ? 'never' : 'auto'\n }\n }\n };\n }\n catch (e)\n {\n this.useQuoteBillingAddress(false);\n\n options.fields = {};\n console.warn('Could not retrieve billing address: ' + e.message);\n }\n\n // Set the default billing address in order to enable the Link payment method\n var billingDetails = this.getBillingDetails();\n\n if (billingDetails)\n {\n options.defaultValues = {\n billingDetails: billingDetails\n };\n }\n }\n else\n {\n this.useQuoteBillingAddress(false);\n }\n\n if (params.layout)\n {\n options.layout = params.layout;\n }\n\n return options;\n },\n\n getPaymentElementUpdateOptions: function()\n {\n var options = this.getPaymentElementOptions();\n\n if (options.wallets)\n {\n delete options.wallets;\n }\n\n return options;\n },\n\n onChange: function(event)\n {\n this.isLoading(false);\n this.isPaymentFormComplete(event.complete);\n },\n\n getElementsAmount: function()\n {\n var totals = quote.totals();\n\n if (totals && totals.grand_total)\n {\n var amount = totals.grand_total;\n return this.convertToStripeAmount(amount, this.getElementsCurrency());\n }\n\n return 0;\n },\n\n getElementsCurrency: function()\n {\n var totals = quote.totals();\n if (totals && totals.quote_currency_code)\n {\n var currency = totals.quote_currency_code;\n return currency.toLowerCase();\n }\n\n return 'USD';\n },\n\n isBillingAddressSet: function()\n {\n return quote.billingAddress() && quote.billingAddress().canUseForBilling();\n },\n\n convertToStripeAmount: function(amount, currencyCode)\n {\n var code = currencyCode.toUpperCase();\n\n if (this.zeroDecimalCurrencies.indexOf(code) >= 0)\n {\n return Math.round(amount);\n }\n else\n {\n return Math.round(amount * 100);\n }\n },\n\n isPlaceOrderEnabled: function()\n {\n if (this.stripePaymentsError())\n return false;\n\n if (this.permanentError())\n return false;\n\n return this.isBillingAddressSet();\n },\n\n getAddressField: function(field)\n {\n if (!quote.billingAddress())\n return null;\n\n var address = quote.billingAddress();\n\n if (!address[field] || address[field].length == 0)\n return null;\n\n return address[field];\n },\n\n getBillingDetails: function()\n {\n var details = {};\n var address = {};\n\n if (this.getAddressField('city'))\n address.city = this.getAddressField('city');\n\n if (this.getAddressField('countryId'))\n address.country = this.getAddressField('countryId');\n\n if (this.getAddressField('postcode'))\n address.postal_code = this.getAddressField('postcode');\n\n if (this.getAddressField('region'))\n address.state = this.getAddressField('region');\n\n if (this.getAddressField('street'))\n {\n var street = this.getAddressField('street');\n address.line1 = street[0];\n\n if (street.length > 1)\n address.line2 = street[1];\n }\n\n if (Object.keys(address).length > 0)\n details.address = address;\n\n if (this.getAddressField('telephone'))\n details.phone = this.getAddressField('telephone');\n\n if (this.getAddressField('firstname'))\n details.name = this.getAddressField('firstname') + ' ' + this.getAddressField('lastname');\n\n if (quote.guestEmail)\n details.email = quote.guestEmail;\n else if (customerData.email)\n details.email = customerData.email;\n\n if (Object.keys(details).length > 0)\n return details;\n\n return null;\n },\n\n config: function()\n {\n return window.checkoutConfig.payment[this.getCode()];\n },\n\n isActive: function(parents)\n {\n return true;\n },\n\n placeOrder: function()\n {\n this.messageContainer.clear();\n\n if (!this.isPaymentFormComplete() && !this.getPaymentMethodId())\n return this.showError($t('Please complete your payment details.'));\n\n if (!this.validate())\n return;\n\n this.clearErrors();\n this.isPlaceOrderActionAllowed(false);\n this.isLoading(true);\n this.cvcToken(null);\n\n var params = { };\n\n if (this.useQuoteBillingAddress())\n {\n params.payment_method_data = {\n billing_details: {\n address: this.getStripeFormattedAddress(quote.billingAddress()),\n email: this.getBillingEmail(),\n name: this.getNameFromAddress(quote.billingAddress()),\n phone: this.getBillingPhone()\n }\n };\n }\n\n if (this.hasShipping())\n {\n params.shipping = {\n address: this.getStripeFormattedAddress(quote.shippingAddress()),\n name: this.getNameFromAddress(quote.shippingAddress())\n };\n }\n\n var self = this;\n\n if (this.isSavedCardSelected() && this.selection().cvc)\n {\n stripe.stripeJs.createToken('cvc_update', this.cardCvcElement).then(function(result)\n {\n if (result.error)\n {\n self.showError(result.error.message);\n }\n else if (result.token)\n {\n self.cvcToken(result.token.id);\n self.placeOrderWithSavedPaymentMethod.bind(self)();\n }\n else\n {\n self.showError('Could not perform CVC check.');\n }\n });\n }\n else if (this.isSavedPaymentMethodSelected())\n {\n this.placeOrderWithSavedPaymentMethod();\n }\n else\n {\n this.createPaymentMethod(this.onPaymentMethodCreatedForOrderPlacement.bind(this));\n }\n\n return false;\n },\n\n hasShipping: function()\n {\n return (quote && quote.shippingMethod() && quote.shippingMethod().method_code);\n },\n\n createPaymentMethod: function(callback)\n {\n this.paymentElementPaymentMethod(null);\n\n var self = this;\n\n var paymentMethodData = {\n elements: this.elements,\n params: {}\n };\n\n var confirmParams = this.getConfirmParams();\n var billingDetails = null;\n if (confirmParams &&\n confirmParams.confirmParams &&\n confirmParams.confirmParams.payment_method_data &&\n confirmParams.confirmParams.payment_method_data.billing_details\n )\n {\n billingDetails = confirmParams.confirmParams.payment_method_data.billing_details;\n }\n\n if (billingDetails)\n {\n paymentMethodData.params.billing_details = confirmParams.confirmParams.payment_method_data.billing_details;\n }\n else\n {\n return this.showError($t(\"Please specify a billing address.\"));\n }\n\n this.elements.submit().then(function()\n {\n stripe.stripeJs.createPaymentMethod(paymentMethodData).then(function(result)\n {\n if (result.error)\n {\n self.showError(result.error.message);\n console.error(result.error.message);\n }\n else\n {\n self.paymentElementPaymentMethod(result.paymentMethod);\n callback(result.paymentMethod);\n }\n });\n },\n function(result)\n {\n if (result.error)\n {\n self.showError(result.error.message);\n console.error(result.error.message);\n }\n else\n {\n self.showError(\"A payment submission error has occurred.\");\n console.error(result);\n }\n });\n },\n\n isSavedPaymentMethodSelected: function()\n {\n var selectedMethodType = this.getSelectedMethod(\"type\");\n\n if (!selectedMethodType) // There is no saved PMs dropdown\n return false;\n\n if (selectedMethodType != 'new') // A saved PMs is selected\n return true;\n\n return false; // New PM is selected\n },\n\n isSavedCardSelected: function()\n {\n var selectedMethodType = this.getSelectedMethod(\"type\");\n\n if (!selectedMethodType) // There is no saved PMs dropdown\n return false;\n\n if (selectedMethodType == 'card') // A saved PMs is selected\n return true;\n\n return false; // New PM is selected\n },\n\n placeOrderWithSavedPaymentMethod: function()\n {\n var self = this;\n var placeNewOrder = this.placeNewOrder.bind(this);\n\n if (this.isOrderPlaced()) // The order was already placed but either 3D Secure failed or the customer pressed the back button from an external payment page\n {\n updateCartAction(this.getData(), this.onCartUpdated.bind(this));\n }\n else\n {\n try\n {\n placeNewOrder();\n }\n catch (e)\n {\n this.showError($t(\"The order could not be placed. Please contact us for assistance.\"));\n console.error(e.message);\n }\n }\n },\n\n onPaymentMethodCreatedForOrderPlacement: function(paymentMethod)\n {\n var placeNewOrder = this.placeNewOrder.bind(this);\n var self = this;\n\n if (self.isOrderPlaced()) // The order was already placed but either 3D Secure failed or the customer pressed the back button from an external payment page\n {\n updateCartAction(this.getData(), this.onCartUpdated.bind(this));\n }\n else\n {\n try\n {\n placeNewOrder();\n }\n catch (e)\n {\n self.showError($t(\"The order could not be placed. Please contact us for assistance.\"));\n console.error(e.message);\n }\n }\n },\n\n onCartUpdated: function(result, outcome, response)\n {\n var placeNewOrder = this.placeNewOrder.bind(this);\n var onOrderPlaced = this.onOrderPlaced.bind(this);\n try\n {\n var data = JSON.parse(result);\n if (data.error)\n {\n this.showError(data.error);\n }\n else if (data.redirect)\n {\n $.mage.redirect(data.redirect);\n }\n else if (data.placeNewOrder)\n {\n placeNewOrder();\n }\n else\n {\n onOrderPlaced();\n }\n }\n catch (e)\n {\n this.showError($t(\"The order could not be placed. Please contact us for assistance.\"));\n console.error(e.message);\n }\n },\n\n placeNewOrder: function()\n {\n var self = this;\n\n this.isLoading(false); // Needed for the terms and conditions checkbox\n this.getPlaceOrderDeferredObject()\n .fail(this.handlePlaceOrderErrors.bind(this))\n .done(this.onOrderPlaced.bind(this))\n .always(function(response, status, xhr)\n {\n if (status != \"success\")\n {\n self.isLoading(false);\n self.isPlaceOrderEnabled(true);\n }\n });\n },\n\n getSelectedMethod: function(param)\n {\n var selection = this.selection();\n if (!selection)\n return null;\n\n if (typeof selection[param] == \"undefined\")\n return null;\n\n return selection[param];\n },\n\n // Called when:\n // - A brand new order has just been placed\n // - After updateCartAction() with placeNewOrder == false\n onOrderPlaced: function(result, outcome, response)\n {\n if (!this.isOrderPlaced() && isNaN(result))\n {\n return this.softCrash(\"The order was placed but the response from the server did not include a numeric order ID.\");\n }\n else\n {\n this.isOrderPlaced(true);\n }\n\n this.isLoading(true);\n var self = this;\n var handleNextActions = this.handleNextActions.bind(this);\n getRequiresAction(function(clientSecret)\n {\n try\n {\n if (clientSecret && clientSecret.length)\n {\n stripe.stripeJs.handleNextAction({\n clientSecret: clientSecret\n }).then(self.onConfirm.bind(self));\n }\n else\n {\n // No further actions are needed\n self.onConfirm(null);\n }\n }\n catch (e)\n {\n restoreQuoteAction();\n self.showError(\"The order was placed but we could not confirm if the payment was successful.\");\n console.error(e);\n }\n\n });\n },\n\n isSuccessful: function(stripeObject)\n {\n\n if (stripeObject.status == \"requires_action\" &&\n stripeObject.next_action &&\n stripeObject.next_action.type &&\n stripeObject.next_action.type != \"use_stripe_sdk\"\n )\n {\n // This is the case for vouchers, where an offline payment is required\n return true;\n }\n\n\n return (['processing', 'requires_capture', 'succeeded'].indexOf(stripeObject.status) >= 0);\n },\n\n // Called when:\n // - A brand new order has just been placed\n // - After updateCartAction() with placeNewOrder == false\n handleNextActions: function(stripeObject)\n {\n if (!this.isOrderPlaced())\n {\n return this.softCrash(\"Cannot handleNextActions without placing the order first\");\n }\n\n var self = this;\n\n if (this.isSuccessful(stripeObject))\n {\n this.onConfirm(null);\n }\n else if (stripeObject.status == \"requires_action\")\n {\n // Non-card based confirms may redirect the customer externally. We restore the quote just before it in case the\n // customer clicks the back button on the browser before authenticating the payment.\n restoreQuoteAction(function()\n {\n stripe.stripeJs.handleNextAction({\n clientSecret: stripeObject.client_secret\n }).then(self.onConfirm.bind(self));\n });\n }\n else if (stripeObject.status == \"requires_confirmation\")\n {\n // This should only hit when a payment failed with a saved PM, and then the customer switched to PaymentElement to enter a new payment method\n restoreQuoteAction(function()\n {\n // We pass null because we do not want to update the PM. It has already been updated with stripe.updatePaymentIntent\n updateCartAction(self.getData(), self.onCartUpdated.bind(self));\n });\n }\n else if (stripeObject.status == \"requires_payment_method\")\n {\n restoreQuoteAction(function()\n {\n updateCartAction(self.getData(), self.onCartUpdated.bind(self));\n });\n }\n else\n {\n restoreQuoteAction(function()\n {\n self.showError($t(\"The order could not be placed. Please contact us for assistance.\"));\n console.error(\"Could not finalize order bacause the payment intent is in status \" + stripeObject.status);\n });\n }\n },\n\n getConfirmParams: function()\n {\n var params = {\n elements: this.elements,\n confirmParams: {\n return_url: this.getStripeParam(\"successUrl\")\n }\n };\n\n this.getPaymentElementOptions();\n if (this.useQuoteBillingAddress())\n {\n params.confirmParams.payment_method_data = {\n billing_details: {\n address: this.getStripeFormattedAddress(quote.billingAddress()),\n email: this.getBillingEmail(),\n name: this.getNameFromAddress(quote.billingAddress()),\n phone: this.getBillingPhone()\n }\n };\n }\n\n return params;\n },\n\n getStripeFormattedAddress: function(address)\n {\n var stripeAddress = {};\n\n stripeAddress.state = address.region ? address.region : null;\n stripeAddress.postal_code = address.postcode ? address.postcode : null;\n stripeAddress.country = address.countryId ? address.countryId : null;\n stripeAddress.city = address.city ? address.city : null;\n\n if (address.street && address.street.length > 0)\n {\n stripeAddress.line1 = address.street[0];\n\n if (address.street.length > 1)\n {\n stripeAddress.line2 = address.street[1];\n }\n else\n {\n stripeAddress.line2 = null;\n }\n }\n else\n {\n stripeAddress.line1 = null;\n stripeAddress.line2 = null;\n }\n\n return stripeAddress;\n },\n\n getBillingEmail: function()\n {\n if (quote.guestEmail)\n {\n return quote.guestEmail;\n }\n else if (window.checkoutConfig.customerData && window.checkoutConfig.customerData.email)\n {\n return window.checkoutConfig.customerData.email;\n }\n\n return null;\n },\n\n getNameFromAddress: function(address)\n {\n if (!address)\n return null;\n\n var parts = [];\n if (address.firstname)\n parts.push(address.firstname);\n\n if (address.middlename)\n parts.push(address.middlename);\n\n if (address.lastname)\n parts.push(address.lastname);\n\n return parts.join(\" \");\n },\n\n getBillingPhone: function()\n {\n var billingAddress = quote.billingAddress();\n if (!billingAddress)\n return null;\n\n if (billingAddress.telephone)\n return billingAddress.telephone;\n\n return null;\n },\n\n onConfirm: function(result)\n {\n this.isLoading(false);\n if (result && result.error)\n {\n this.showError(result.error.message);\n }\n else\n {\n customerData.invalidate(['cart']);\n var successUrl = this.getStripeParam(\"successUrl\");\n $.mage.redirect(successUrl);\n }\n },\n\n /**\n * @return {*}\n */\n getPlaceOrderDeferredObject: function()\n {\n return placeOrderAction(this.getData(), this.messageContainer);\n },\n\n getClientSecretFromResponse: function(response)\n {\n if (typeof response != \"string\")\n {\n return null;\n }\n\n if (response.indexOf(\"Authentication Required: \") >= 0)\n {\n return response.substring(\"Authentication Required: \".length);\n }\n\n return null;\n },\n\n handleCardPayment: function(paymentIntent, done)\n {\n try\n {\n stripe.stripeJs.handleCardPayment(paymentIntent.client_secret).then(function(result)\n {\n if (result.error)\n return done(result.error.message);\n\n return done();\n });\n }\n catch (e)\n {\n done(e.message);\n }\n },\n handleCardAction: function(paymentIntent, done)\n {\n try\n {\n stripe.stripeJs.handleCardAction(paymentIntent.client_secret).then(function(result)\n {\n if (result.error)\n return done(result.error.message);\n\n return done();\n });\n }\n catch (e)\n {\n done(e.message);\n }\n },\n\n authenticateCustomer: function(clientSecret, done)\n {\n try\n {\n stripe.stripeJs.handleNextAction({\n clientSecret: clientSecret\n }).then(function(result)\n {\n if (result.error)\n return done(result.error.message);\n\n done();\n });\n }\n catch (e)\n {\n done(e.message);\n }\n },\n\n handlePlaceOrderErrors: function (result)\n {\n if (result && result.responseJSON && result.responseJSON.message)\n {\n var clientSecret = this.getClientSecretFromResponse(result.responseJSON.message);\n\n if (clientSecret)\n {\n var self = this;\n return this.authenticateCustomer(clientSecret, function(err)\n {\n if (err)\n return self.showError(err);\n\n self.placeNewOrder.bind(self)();\n });\n }\n else\n {\n this.showError(result.responseJSON.message);\n }\n }\n else\n {\n this.showError($t(\"The order could not be placed. Please contact us for assistance.\"));\n\n if (result && result.responseText)\n console.error(result.responseText);\n else\n console.error(result);\n }\n },\n\n showError: function(message)\n {\n this.isLoading(false);\n this.isPlaceOrderEnabled(true);\n this.messageContainer.addErrorMessage({ \"message\": message });\n },\n\n validate: function(elm)\n {\n return this.validateCvc() && agreementValidator.validate() && additionalValidators.validate();\n },\n\n validateCvc: function()\n {\n if (!this.selection())\n return true;\n\n if (this.selection().type != \"card\")\n return true;\n\n if (this.selection().cvc != 1)\n return true;\n\n if (typeof this.selection().cvcError == \"undefined\")\n {\n this.showError($t(\"Please enter your card's security code.\"));\n return false;\n }\n else if (!this.selection().cvcError)\n {\n return true;\n }\n else\n {\n this.showError(this.selection().cvcError);\n return false;\n }\n\n return true;\n },\n\n getCode: function()\n {\n return 'stripe_payments';\n },\n\n getData: function()\n {\n var data = {\n 'method': this.item.method,\n 'additional_data': {\n 'payment_element': true,\n 'payment_method': this.getPaymentMethodId(),\n 'manual_authentication': 'card'\n }\n };\n\n if (this.cvcToken())\n {\n data.additional_data.cvc_token = this.cvcToken();\n }\n\n return data;\n },\n\n clearErrors: function()\n {\n this.stripePaymentsError(null);\n }\n\n });\n }\n);\n","StripeIntegration_Payments/js/view/ui_components/setup_element.js":"define(\n [\n 'ko',\n 'uiComponent',\n 'StripeIntegration_Payments/js/action/list-payment-methods',\n 'StripeIntegration_Payments/js/action/add-payment-method',\n 'StripeIntegration_Payments/js/action/delete-payment-method',\n 'StripeIntegration_Payments/js/stripe',\n 'Magento_Ui/js/model/messageList',\n 'Magento_Customer/js/model/customer',\n 'mage/translate',\n 'jquery',\n 'mage/storage',\n 'Magento_Customer/js/customer-data',\n 'Magento_Ui/js/model/messages',\n 'uiLayout'\n ],\n function (\n ko,\n Component,\n listPaymentMethodsAction,\n addPaymentMethodAction,\n deletePaymentMethodAction,\n stripe,\n globalMessageList,\n customer,\n $t,\n $,\n storage,\n customerData,\n messagesModel,\n layout\n ) {\n 'use strict';\n\n return Component.extend({\n externalRedirectUrl: null,\n defaults: {\n template: 'StripeIntegration_Payments/setup_element',\n },\n elements: null,\n initParams: null,\n\n initObservable: function ()\n {\n this._super()\n .observe([\n 'paymentElement',\n 'isPaymentFormComplete',\n 'isPaymentFormVisible',\n 'isLoading',\n 'stripePaymentsError',\n 'permanentError',\n 'isOrderPlaced',\n 'isInitialized',\n 'savedPaymentMethods',\n 'processingSavedPaymentMethods'\n ]);\n\n var self = this;\n\n this.isPaymentFormVisible(false);\n this.isOrderPlaced(false);\n this.isInitialized(false);\n this.processingSavedPaymentMethods(false);\n\n this.hasPaymentMethods = ko.computed(this.hasPaymentMethodsComputed.bind(this));\n\n this.messageContainer = new messagesModel();\n\n var messagesComponent = {\n parent: this.name,\n name: this.name + '.messages',\n displayArea: 'messages',\n component: 'Magento_Ui/js/view/messages',\n config: {\n messageContainer: this.messageContainer,\n autoHideTimeOut: -1\n }\n };\n\n layout([messagesComponent]);\n\n return this;\n },\n\n getStripeParam: function(param)\n {\n if (typeof window.initParams == \"undefined\")\n return null;\n\n if (typeof window.initParams[param] == \"undefined\")\n return null;\n\n return window.initParams[param];\n },\n\n onPaymentElementContainerRendered: function()\n {\n var self = this;\n this.isLoading(true);\n this.listPaymentMethods();\n var initParams = window.initParams;\n\n stripe.initStripe(initParams, function(err)\n {\n if (err)\n return self.crash(err);\n\n self.initSetupElement(initParams);\n });\n },\n\n onContainerRendered: function()\n {\n this.onPaymentElementContainerRendered();\n },\n\n crash: function(message)\n {\n this.isLoading(false);\n this.permanentError($t(\"Sorry, an error has occurred. Please contact us for assistance.\"));\n console.error(\"Error: \" + message);\n },\n\n softCrash: function(message)\n {\n this.showError($t(\"Sorry, an error has occurred. Please contact us for assistance.\"));\n this.stripePaymentsError(message);\n console.error(\"Error: \" + message);\n },\n\n initSetupElement: function(params)\n {\n if (document.getElementById('stripe-setup-element') === null)\n return this.crash(\"Cannot initialize Payment Element on a DOM that does not contain a div.stripe-setup-element.\");\n\n if (!stripe.stripeJs)\n return this.crash(\"Stripe.js could not be initialized.\");\n\n var elements = this.elements = stripe.stripeJs.elements({\n mode: \"setup\",\n setup_future_usage: \"on_session\",\n locale: params.locale,\n currency: params.currency,\n appearance: this.getStripePaymentElementOptions(),\n paymentMethodCreation: \"manual\"\n });\n\n this.paymentElement = elements.create('payment');\n this.paymentElement.mount('#stripe-setup-element');\n this.paymentElement.on('change', this.onChange.bind(this));\n this.isLoading(false);\n },\n\n onChange: function(event)\n {\n this.isLoading(false);\n this.isPaymentFormComplete(event.complete);\n },\n\n getStripePaymentElementOptions: function()\n {\n return {\n theme: 'stripe',\n variables: {\n colorText: '#32325d',\n fontFamily: '\"Open Sans\",\"Helvetica Neue\", Helvetica, Arial, sans-serif',\n },\n };\n },\n\n getAddressField: function(field)\n {\n var address = [];\n\n if (typeof address[field] == \"undefined\")\n return null;\n\n if (typeof address[field] !== \"string\" && typeof address[field] !== \"object\")\n return null;\n\n if (address[field].length == 0)\n return null;\n\n return address[field];\n },\n\n getBillingDetails: function()\n {\n var details = {};\n var address = {};\n\n if (this.getAddressField('city'))\n address.city = this.getAddressField('city');\n\n if (this.getAddressField('countryId'))\n address.country = this.getAddressField('countryId');\n\n if (this.getAddressField('postcode'))\n address.postal_code = this.getAddressField('postcode');\n\n if (this.getAddressField('region'))\n address.state = this.getAddressField('region');\n\n if (this.getAddressField('street'))\n {\n var street = this.getAddressField('street');\n address.line1 = street[0];\n\n if (street.length > 1)\n address.line2 = street[1];\n }\n\n if (Object.keys(address).length > 0)\n details.address = address;\n\n if (this.getAddressField('telephone'))\n details.phone = this.getAddressField('telephone');\n\n if (this.getAddressField('firstname'))\n details.name = this.getAddressField('firstname') + ' ' + this.getAddressField('lastname');\n\n if (customerData.email)\n details.email = customerData.email;\n\n if (Object.keys(details).length > 0)\n return details;\n\n return null;\n },\n\n config: function()\n {\n return self.initParams;\n },\n\n onClick: function(result, outcome, response)\n {\n if (!this.isPaymentFormComplete())\n return this.showError($t('Please complete the payment method details.'));\n\n this.clearErrors();\n\n this.isLoading(true);\n var onPaymentMethodCreated = this.onPaymentMethodCreated.bind(this);\n var onFail = this.onFail.bind(this);\n\n this.createPaymentMethod(onPaymentMethodCreated, onFail);\n },\n\n createPaymentMethod: function(onPaymentMethodCreated, onFail)\n {\n var paymentMethodData = {\n elements: this.elements,\n params: {}\n };\n\n this.elements.submit().then(function()\n {\n stripe.stripeJs.createPaymentMethod(paymentMethodData).then(onPaymentMethodCreated, onFail);\n }, onFail);\n\n },\n\n onPaymentMethodCreated: function(result)\n {\n var self = this;\n\n if (result.error)\n {\n this.showError(result.error.message);\n }\n else\n {\n addPaymentMethodAction(result.paymentMethod.id, function(response, status, xhr)\n {\n self.isLoading(false);\n if (status == \"success\")\n {\n try\n {\n var data = JSON.parse(response);\n\n var methods = self.savedPaymentMethods();\n if (!methods)\n {\n methods = [];\n }\n\n var isDuplicate = false;\n var newMethods = [];\n\n for (var i in methods)\n {\n if (methods[i].fingerprint != data.fingerprint)\n {\n newMethods.push(methods[i]);\n }\n else\n {\n isDuplicate = true;\n }\n }\n\n newMethods.push(data);\n\n self.savedPaymentMethods(newMethods);\n\n if (isDuplicate)\n {\n self.showSuccessMessage($t(\"An existing payment method has been updated.\"));\n }\n else\n {\n self.showSuccessMessage($t(\"The payment method has been saved.\"));\n }\n self.clearFormData();\n }\n catch (e)\n {\n console.warn(e);\n self.showError($t(\"The payment method could not be saved: %1\").replace(\"%1\", e.message));\n }\n }\n else if (response && response.responseJSON && response.responseJSON.message)\n {\n self.showError(response.responseJSON.message);\n }\n else\n {\n self.showError(\"Sorry, the payment methods could not be added.\");\n console.warn(response);\n }\n });\n }\n },\n\n clearFormData: function()\n {\n this.paymentElement.clear();\n $('html, body').animate({ scrollTop: $(\"#my-saved-payment-methods-table\").offset().top - 100}, 500);\n },\n\n onFail: function(result)\n {\n this.showError(\"Could not set up the payment method. Please try again.\");\n console.error(result);\n },\n\n showError: function(message)\n {\n this.isLoading(false);\n this.messageContainer.addErrorMessage({ \"message\": message });\n },\n\n showSuccessMessage: function(message)\n {\n this.isLoading(false);\n this.messageContainer.addSuccessMessage({ \"message\": message });\n },\n\n validate: function(elm)\n {\n return true;\n },\n\n getCode: function()\n {\n return 'stripe_payments';\n },\n\n clearErrors: function()\n {\n this.messageContainer.clear();\n this.stripePaymentsError(null);\n },\n\n hasPaymentMethodsComputed: function()\n {\n return this.savedPaymentMethods() && this.savedPaymentMethods().length > 0;\n },\n\n removePaymentMethod: function(fingerprint)\n {\n var methods = this.savedPaymentMethods();\n if (!methods)\n {\n methods = [];\n }\n\n var newMethods = [];\n\n for (var i in methods)\n {\n if (methods[i].fingerprint != fingerprint)\n {\n newMethods.push(methods[i]);\n }\n }\n\n return newMethods;\n },\n\n deletePaymentMethod: function(paymentMethod)\n {\n var sure = confirm($t(\"Are you sure you want to delete this payment method?\"));\n\n if (!sure)\n return;\n\n var self = this;\n this.processingSavedPaymentMethods(true);\n deletePaymentMethodAction(paymentMethod.id, paymentMethod.fingerprint, function(response, status, xhr)\n {\n self.processingSavedPaymentMethods(false);\n if (status == \"success\")\n {\n try\n {\n var data = JSON.parse(response);\n self.showSuccessMessage(data);\n\n var newMethods = self.removePaymentMethod(paymentMethod.fingerprint);\n self.savedPaymentMethods(newMethods);\n }\n catch (e)\n {\n self.showError($t(\"The payment methods could not be deleted: %1\").replace(\"%1\", e.message));\n }\n }\n else\n {\n self.showError($t(\"The payment methods could not be deleted: %1\").replace(\"%1\", response));\n }\n });\n },\n\n listPaymentMethods: function()\n {\n var self = this;\n this.processingSavedPaymentMethods(true);\n\n listPaymentMethodsAction(function(response, status, xhr)\n {\n self.processingSavedPaymentMethods(false);\n if (status == \"success\")\n {\n try\n {\n var data = JSON.parse(response);\n var methods = [];\n\n for (var fingerprint in data)\n {\n methods.push(data[fingerprint]);\n }\n\n self.savedPaymentMethods(methods);\n }\n catch (e)\n {\n console.warn(e);\n console.warn(response);\n }\n }\n });\n }\n\n });\n }\n);\n","StripeIntegration_Payments/js/view/multishipping/method-renderer/payment_element.js":"define(\n [\n 'ko',\n 'StripeIntegration_Payments/js/view/payment/method-renderer/stripe_payments_multishipping',\n 'StripeIntegration_Payments/js/stripe',\n 'Magento_Ui/js/model/messageList',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Customer/js/model/customer',\n 'Magento_Checkout/js/action/set-payment-information',\n 'mage/translate',\n 'mage/url',\n 'jquery',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'mage/storage',\n 'mage/url',\n 'Magento_CheckoutAgreements/js/model/agreement-validator',\n 'Magento_Customer/js/customer-data',\n 'Magento_Ui/js/modal/alert',\n 'domReady!'\n ],\n function (\n ko,\n Component,\n stripe,\n globalMessageList,\n quote,\n customer,\n setPaymentInformationAction,\n $t,\n url,\n $,\n additionalValidators,\n storage,\n urlBuilder,\n agreementValidator,\n customerData,\n alert\n ) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'StripeIntegration_Payments/multishipping/payment_element',\n continueSelector: '#payment-continue',\n cardElement: null,\n token: ko.observable(null),\n params: null,\n captureMethod: 'automatic'\n },\n\n initObservable: function ()\n {\n this._super();\n\n $(this.continueSelector).click(this.onContinue.bind(this));\n\n return this;\n },\n\n onPaymentElementContainerRendered: function()\n {\n var self = this;\n this.isLoading(true);\n\n this.params = window.initParams;\n\n stripe.initStripe(this.params, function(err)\n {\n if (err)\n return self.crash(err);\n\n self.initSavedPaymentMethods.bind(self)();\n self.initPaymentForm.bind(self)();\n });\n },\n\n onContainerRendered: function()\n {\n this.onPaymentElementContainerRendered();\n this.isInitialized(true);\n },\n\n initPaymentForm: function()\n {\n this.isInitializing(false);\n this.isLoading(false);\n\n if (this.isCollapsed()) // Don't render PE with a height of 0\n return;\n\n if (document.getElementById('stripe-payment-element') === null)\n return this.crash(\"Cannot initialize Card Element on a DOM that does not contain a div.stripe-card-element.\");\n\n if (!stripe.stripeJs)\n return this.crash(\"Stripe.js could not be initialized.\");\n\n try\n {\n var elementOptions = this.getElementsOptions(true);\n elementOptions.setupFutureUsage = 'on_session';\n elementOptions.captureMethod = this.captureMethod;\n this.elements = stripe.stripeJs.elements(this.getElementsOptions(true));\n }\n catch (e)\n {\n console.warn(\"Could not filter Stripe payment method types: \" + e.message);\n this.elements = stripe.stripeJs.elements(this.getElementsOptions(false));\n }\n\n this.paymentElement = this.elements.create('payment', this.getPaymentElementOptions());\n this.paymentElement.mount('#stripe-payment-element');\n this.paymentElement.on('change', this.onChange.bind(this));\n\n },\n\n onSetPaymentMethodFail: function(result)\n {\n this.token(null);\n this.isLoading(false);\n console.error(result);\n },\n\n onContinue: function(e)\n {\n // If we already have a tokenized payment method, don't do anything\n if (this.token())\n return;\n\n var self = this;\n\n if (!this.isStripeMethodSelected())\n return;\n\n e.preventDefault();\n e.stopPropagation();\n\n if (!this.validatePaymentMethod())\n return;\n\n this.isLoading(true);\n\n if (this.getSelectedMethod(\"type\") && this.getSelectedMethod(\"type\") != \"new\")\n {\n self.token(this.getSelectedMethod(\"value\"));\n setPaymentInformationAction(this.messageContainer, this.getData()).then(function(){\n $(self.continueSelector).click();\n }).fail(self.onSetPaymentMethodFail.bind(self));\n }\n else\n {\n this.createPaymentMethod(function(err)\n {\n if (err)\n return self.showError(err);\n\n $(self.continueSelector).click();\n });\n }\n },\n\n createPaymentMethod: function(done)\n {\n var self = this;\n\n var paymentMethodData = {\n elements: this.elements,\n params: {}\n };\n\n var confirmParams = this.getConfirmParams();\n var billingDetails = null;\n if (confirmParams &&\n confirmParams.confirmParams &&\n confirmParams.confirmParams.payment_method_data &&\n confirmParams.confirmParams.payment_method_data.billing_details\n )\n {\n billingDetails = confirmParams.confirmParams.payment_method_data.billing_details;\n }\n\n if (billingDetails)\n {\n paymentMethodData.params.billing_details = confirmParams.confirmParams.payment_method_data.billing_details;\n }\n else\n {\n return this.showError($t(\"Please specify a billing address.\"));\n }\n\n this.elements.submit().then(function() {\n stripe.stripeJs.createPaymentMethod(paymentMethodData).then(function(result)\n {\n if (result.error)\n {\n self.showError(result.error.message);\n console.error(result.error.message);\n }\n else\n {\n self.token(result.paymentMethod.id);\n\n setPaymentInformationAction(self.messageContainer, self.getData()).then(function()\n {\n done();\n }).fail(self.onSetPaymentMethodFail.bind(self));\n }\n });\n });\n\n },\n\n getData: function()\n {\n var data = {\n 'method': this.item.method,\n 'additional_data': {\n 'payment_element': true,\n 'cc_stripejs_token': this.token(),\n 'manual_authentication': 'card'\n }\n };\n\n return data;\n },\n\n showError: function(message)\n {\n this.isLoading(false);\n alert({ content: message });\n },\n\n validatePaymentMethod: function ()\n {\n var methods = $('[name^=\"payment[\"]'), isValid = false;\n\n if (methods.length === 0)\n this.showError( $.mage.__('We can\\'t complete your order because you don\\'t have a payment method set up.') );\n else if (methods.filter('input:radio:checked').length)\n return true;\n else\n this.showError( $.mage.__('Please choose a payment method.') );\n\n return isValid;\n },\n\n isStripeMethodSelected: function()\n {\n var methods = $('[name^=\"payment[\"]');\n\n if (methods.length === 0)\n return false;\n\n var stripe = methods.filter(function(index, value)\n {\n if (value.id == \"p_method_stripe_payments\")\n return value;\n });\n\n if (stripe.length == 0)\n return false;\n\n return stripe[0].checked;\n }\n });\n }\n);\n","StripeIntegration_Payments/js/view/subscription_update/review.js":"define(\n [\n 'ko',\n 'Magento_Checkout/js/view/payment/default',\n 'Magento_Ui/js/model/messageList',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Customer/js/model/customer',\n 'StripeIntegration_Payments/js/helper/subscriptions',\n 'StripeIntegration_Payments/js/model/upcomingInvoice',\n 'mage/translate',\n 'jquery',\n 'Magento_Checkout/js/action/place-order',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_CheckoutAgreements/js/model/agreement-validator',\n 'Magento_CheckoutAgreements/js/model/agreements-assigner'\n ],\n function (\n ko,\n Component,\n globalMessageList,\n quote,\n customer,\n subscriptions,\n upcomingInvoice,\n $t,\n $,\n placeOrderAction,\n additionalValidators,\n agreementValidator,\n agreementsAssigner\n ) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'StripeIntegration_Payments/subscription_update/review',\n },\n currentTotals: null,\n newPrice: ko.observable(\"--\"),\n prorationFee: ko.observable(\"--\"),\n unusedTime: ko.observable(\"--\"),\n isPlaceOrderEnabled: ko.observable(false),\n credit: ko.observable(null),\n\n initObservable: function ()\n {\n this._super()\n .observe([\n 'isLoading',\n 'stripePaymentsError',\n 'permanentError',\n 'userError'\n ]);\n\n var self = this;\n\n this.initParams = window.checkoutConfig.payment.stripe_payments.initParams;\n\n upcomingInvoice.initialize();\n var onUpcomingInvoiceChanged = this.onUpcomingInvoiceChanged.bind(this);\n upcomingInvoice.onChange(onUpcomingInvoiceChanged);\n\n this.hasProrationFee = ko.computed(function(){\n return self.prorationFee() && self.prorationFee() != \"--\";\n });\n\n return this;\n },\n\n getConfig: function(key)\n {\n return subscriptions.getConfig(key);\n },\n\n crash: function(message)\n {\n this.isLoading(false);\n if (this.userError())\n this.showError(this.userError());\n else\n this.permanentError($t(\"Sorry, this payment method is not available. Please contact us for assistance.\"));\n\n console.error(\"Error: \" + message);\n },\n\n softCrash: function(message)\n {\n this.isLoading(false);\n if (this.userError())\n this.showError(this.userError());\n else\n this.showError($t(\"Sorry, this payment method is not available. Please contact us for assistance.\"));\n\n console.error(\"Error: \" + message);\n },\n\n onChange: function(event)\n {\n this.isLoading(false);\n },\n\n placeOrder: function()\n {\n if (!this.validate())\n return;\n\n var self = this;\n this.isPlaceOrderEnabled(false);\n this.isLoading(true);\n\n this.getPlaceOrderDeferredObject()\n .fail(this.handlePlaceOrderErrors.bind(this))\n .done(this.onOrderPlaced.bind(this))\n .always(function(){\n self.isLoading(false);\n self.isPlaceOrderEnabled(true);\n });\n },\n\n getPlaceOrderDeferredObject: function()\n {\n return placeOrderAction(this.getData(), this.messageContainer);\n },\n\n handlePlaceOrderErrors: function (result)\n {\n if (result && result.responseJSON && result.responseJSON.message)\n this.showError(result.responseJSON.message);\n else\n {\n this.showError($t(\"Sorry, the subscription could not be updated. Please contact us for assistance.\"));\n\n if (result && result.responseText)\n console.error(result.responseText);\n else\n console.error(result);\n }\n },\n\n onOrderPlaced: function(result, outcome, response)\n {\n if (result && !isNaN(result))\n {\n $.mage.redirect(subscriptions.getSuccessUrl());\n return;\n }\n\n try\n {\n var jsonResponse = JSON.parse(result);\n if (jsonResponse && jsonResponse.error)\n {\n return this.showError(jsonResponse.error);\n }\n else\n {\n console.warn(\"The order could not be placed. The server response was: \" + result);\n return this.showError($t(\"Sorry, the subscription could not be updated. Please contact us for assistance.\"));\n }\n }\n catch (e)\n {\n console.warn(\"The order could not be placed. The error was: \" + e);\n return this.showError($t(\"Sorry, the subscription could not be updated. Please contact us for assistance.\"));\n }\n },\n\n getData: function()\n {\n var data = {\n 'method': \"stripe_payments\",\n 'additional_data': {\n 'is_subscription_update': true\n }\n };\n\n agreementsAssigner(data);\n\n return data;\n },\n\n showError: function(message)\n {\n this.isLoading(false);\n this.messageContainer.addErrorMessage({ \"message\": message });\n },\n\n validate: function(elm)\n {\n return agreementValidator.validate() && additionalValidators.validate();\n },\n\n getCode: function()\n {\n return 'stripe_payments';\n },\n\n clearErrors: function()\n {\n this.stripePaymentsError(null);\n },\n\n onUpcomingInvoiceChanged: function(result, outcome, response)\n {\n try\n {\n var params = JSON.parse(result);\n\n this.resetTotals();\n\n if (params && params.error)\n {\n this.userError(params.error);\n return this.softCrash(params.error);\n }\n\n if (!params || !params.upcomingInvoice)\n return this.softCrash(\"Could not retrieve upcoming invoice\");\n\n if (params.upcomingInvoice.new_price &&\n params.upcomingInvoice.new_price.label &&\n params.upcomingInvoice.new_price.label.length > 0)\n {\n this.newPrice(params.upcomingInvoice.new_price.label);\n }\n\n if (params.upcomingInvoice.proration_fee &&\n params.upcomingInvoice.proration_fee.label &&\n params.upcomingInvoice.proration_fee.label.length > 0)\n {\n this.prorationFee(params.upcomingInvoice.proration_fee.label);\n }\n\n if (params.upcomingInvoice.unused_time &&\n params.upcomingInvoice.unused_time.label &&\n params.upcomingInvoice.unused_time.label.length > 0)\n {\n this.unusedTime(params.upcomingInvoice.unused_time.label);\n }\n\n if (params.upcomingInvoice.credit)\n {\n this.credit(params.upcomingInvoice.credit);\n }\n\n this.isPlaceOrderEnabled(true);\n }\n catch (e)\n {\n console.warn(\"Could not calculate subscription update prices\");\n console.warn(e);\n }\n },\n\n resetTotals: function()\n {\n this.newPrice(\"--\");\n this.prorationFee(\"--\");\n this.unusedTime(\"--\");\n },\n\n getCancelUrl: function()\n {\n return subscriptions.getCancelUrl();\n }\n\n });\n }\n);\n","StripeIntegration_Payments/js/view/subscription_update/sidebar.js":"define([\n 'ko',\n 'uiComponent',\n 'Magento_Checkout/js/model/totals',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Customer/js/customer-data',\n 'StripeIntegration_Payments/js/helper/subscriptions',\n 'mage/translate',\n 'jquery'\n],\nfunction (\n ko,\n Component,\n totals,\n quote,\n customerData,\n subscriptions,\n $t,\n $\n)\n{\n 'use strict';\n\n return Component.extend({\n isDisplayed: ko.observable(false),\n isLoading: totals.isLoading,\n\n initialize: function()\n {\n this._super();\n\n this.isDisplayed(subscriptions.displaySidebar());\n\n // var self = this;\n\n // window.addEventListener('hashchange', function()\n // {\n // self.isDisplayed(subscriptions.displaySidebar());\n // });\n },\n\n getConfig: function(key)\n {\n return subscriptions.getConfig(key);\n },\n\n cancelUpdate: function()\n {\n var cancelUrl = subscriptions.getCancelUrl();\n var yes = confirm($t(\"Are you sure you want to cancel the subscription update?\"));\n if (yes)\n {\n $.mage.redirect(cancelUrl);\n }\n },\n\n });\n});\n","StripeIntegration_Payments/js/view/checkout/trialing_subscriptions.js":"define(\n [\n 'ko',\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 'mage/translate',\n 'StripeIntegration_Payments/js/action/get-trialing-subscriptions',\n 'Magento_Customer/js/customer-data'\n ],\n function (ko, Component, quote, priceUtils, totals, $t, getTrialingSubscriptions, customerData) {\n \"use strict\";\n return Component.extend({\n defaults: {\n isFullTaxSummaryDisplayed: window.checkoutConfig.isFullTaxSummaryDisplayed || false,\n template: 'StripeIntegration_Payments/checkout/trialing_subscriptions',\n trialingSubscriptions: ko.observable(window.checkoutConfig.payment.stripe_payments.trialingSubscriptions),\n fetching: ko.observable(false)\n },\n totals: quote.getTotals(),\n isTaxDisplayedInGrandTotal: window.checkoutConfig.includeTaxInGrandTotal || false,\n\n initialize: function ()\n {\n this._super();\n\n this.observe(['trialingSubscriptions']);\n this.trialingSubscriptions(window.checkoutConfig.payment.stripe_payments.trialingSubscriptions);\n\n this.getFormattedSubscriptionsPrice = ko.computed(function()\n {\n var price = -this.getAmount('subscriptions_total');\n return this.getFormattedPrice(price);\n }, this);\n\n this.getFormattedShipping = ko.computed(function()\n {\n var price = -this.getAmount('shipping_total');\n return this.getFormattedPrice(price);\n }, this);\n\n this.getFormattedTax = ko.computed(function()\n {\n var price = -this.getAmount('tax_total');\n return this.getFormattedPrice(price);\n }, this);\n\n this.getFormattedDiscount = ko.computed(function()\n {\n var price = this.getAmount('discount_total');\n return this.getFormattedPrice(price);\n }, this);\n\n this.hasTrialingSubscriptions = ko.computed(function()\n {\n return this.getAmount('subscriptions_total') !== 0;\n }, this);\n\n this.hasShipping = ko.computed(function()\n {\n return this.getAmount('shipping_total') !== 0;\n }, this);\n\n this.hasTax = ko.computed(function()\n {\n return this.getAmount('tax_total') !== 0;\n }, this);\n\n this.hasDiscount = ko.computed(function()\n {\n return this.getAmount('discount_total') !== 0;\n }, this);\n\n this.trialingSubscriptions(this.getTrialSubscriptions());\n\n var grandTotal = quote.totals().grand_total;\n\n quote.totals.subscribe(function (totals)\n {\n if (grandTotal == quote.totals().grand_total)\n return;\n\n grandTotal = quote.totals().grand_total;\n\n this.refresh(quote);\n }, this);\n },\n\n isDisplayed: function()\n {\n return this.isFullMode() && this.getPureValue() !== 0;\n },\n\n getTrialSubscriptions: function()\n {\n if (\n window.checkoutConfig &&\n window.checkoutConfig.payment &&\n window.checkoutConfig.payment.stripe_payments &&\n window.checkoutConfig.payment.stripe_payments.hasTrialSubscriptions &&\n window.checkoutConfig.payment.stripe_payments.trialingSubscriptions\n )\n {\n return window.checkoutConfig.payment.stripe_payments.trialingSubscriptions;\n }\n\n return null;\n },\n\n refresh: function(quote)\n {\n if (!this.getTrialSubscriptions())\n return;\n\n if (this.fetching())\n return;\n\n var self = this;\n this.fetching(true);\n\n getTrialingSubscriptions(quote)\n .always(function()\n {\n self.fetching(false);\n })\n .done(function (subscriptions)\n {\n try {\n var data = JSON.parse(subscriptions);\n window.checkoutConfig.payment.stripe_payments.trialingSubscriptions = data;\n self.trialingSubscriptions(data);\n } catch (e) {\n console.warn('Could not retrieve trial subscriptions: ' + e.message);\n self.trialingSubscriptions(window.checkoutConfig.payment.stripe_payments.trialingSubscriptions);\n }\n })\n .fail(function (xhr, textStatus, errorThrown)\n {\n console.warn(console.warn('Could not retrieve trial subscriptions: ' + xhr.responseText));\n });\n },\n\n discountTitle: function()\n {\n return $t('Trial Discount');\n },\n\n shippingTitle: function()\n {\n return $t('Trial Shipping');\n },\n\n taxTitle: function()\n {\n return $t('Trial Tax');\n },\n\n getAmount: function(key)\n {\n var config = this.trialingSubscriptions();\n\n if (config == null)\n return 0;\n\n if ((key in config) && !isNaN(config[key]))\n return config[key];\n\n return 0;\n },\n\n getPureValue: function()\n {\n var price = this.getAmount('discount_total') -\n this.getAmount('subscriptions_total') -\n this.getAmount('shipping_total') -\n this.getAmount('tax_total') +\n this.getAmount('tax_inclusive');\n\n return Math.round(price * 10000) / 10000;\n },\n\n getBasePureValue: function()\n {\n var price = this.getAmount('base_discount_total') -\n this.getAmount('base_subscriptions_total') -\n this.getAmount('base_shipping_total') -\n this.getAmount('base_tax_total') +\n this.getAmount('base_tax_inclusive');\n\n return Math.round(price * 10000) / 10000;\n },\n\n getTaxAmount: function()\n {\n return this.getAmount('tax_total');\n },\n\n config: function()\n {\n return window.checkoutConfig.payment.stripe_payments;\n }\n });\n }\n);\n","StripeIntegration_Payments/js/view/checkout/cart/totals/initial_fee.js":"define(\n [\n 'StripeIntegration_Payments/js/view/checkout/summary/initial_fee'\n ],\n function (Component) {\n 'use strict';\n\n return Component.extend(\n {\n isDisplayed: function ()\n {\n return this.getPureValue() !== 0;\n }\n });\n }\n);\n","StripeIntegration_Payments/js/view/checkout/summary/initial_fee.js":"define(\n [\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 ],\n function (Component, quote, priceUtils, totals) {\n \"use strict\";\n return Component.extend({\n defaults: {\n isFullTaxSummaryDisplayed: window.checkoutConfig.isFullTaxSummaryDisplayed || false,\n template: 'StripeIntegration_Payments/checkout/summary/initial_fee'\n },\n totals: quote.getTotals(),\n isTaxDisplayedInGrandTotal: window.checkoutConfig.includeTaxInGrandTotal || false,\n\n isDisplayed: function() {\n return this.isFullMode() && this.getPureValue() !== 0;\n },\n\n getValue: function() {\n var price = 0;\n if (this.totals() && totals.getSegment('initial_fee')) {\n price = totals.getSegment('initial_fee').value;\n }\n return this.getFormattedPrice(price);\n },\n getPureValue: function() {\n var price = 0;\n if (this.totals() && totals.getSegment('initial_fee')) {\n price = totals.getSegment('initial_fee').value;\n }\n return price;\n }\n });\n }\n);\n","StripeIntegration_Payments/js/view/checkout/summary/prorations.js":"define(\n [\n 'ko',\n 'mage/translate',\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 'StripeIntegration_Payments/js/helper/subscriptions',\n 'StripeIntegration_Payments/js/model/upcomingInvoice'\n ],\n function (\n ko,\n $t,\n Component,\n quote,\n priceUtils,\n totals,\n subscriptions,\n upcomingInvoice\n ) {\n \"use strict\";\n\n return Component.extend({\n defaults: {\n template: 'StripeIntegration_Payments/checkout/summary/prorations'\n },\n totals: quote.getTotals(),\n prorationAdjustment: ko.observable(0),\n baseProrationAdjustment: ko.observable(0),\n\n initialize: function()\n {\n this._super();\n upcomingInvoice.initialize();\n upcomingInvoice.onChange(this.onUpcomingInvoiceChanged.bind(this));\n },\n\n isDisplayed: function()\n {\n return subscriptions.isSubscriptionUpdate() && this.isFullMode() && this.getPureValue() !== 0;\n },\n\n getValue: function()\n {\n var price = this.getPureValue();\n return this.getFormattedPrice(price);\n },\n\n getPureValue: function()\n {\n var price = 0;\n if (subscriptions.isSubscriptionUpdate() && this.prorationAdjustment()) {\n price = this.prorationAdjustment();\n }\n return price;\n },\n\n getBasePureValue: function()\n {\n var price = 0;\n if (subscriptions.isSubscriptionUpdate() && this.baseProrationAdjustment()) {\n price = this.baseProrationAdjustment();\n }\n return price;\n },\n\n onUpcomingInvoiceChanged: function(result, outcome, response)\n {\n try\n {\n var params = JSON.parse(result);\n\n if (params && params.error)\n {\n return;\n }\n\n if (!params || !params.upcomingInvoice)\n return;\n\n if (!isNaN(params.upcomingInvoice.proration_adjustment))\n {\n this.prorationAdjustment(params.upcomingInvoice.proration_adjustment);\n }\n\n if (!isNaN(params.upcomingInvoice.base_proration_adjustment))\n {\n this.baseProrationAdjustment(params.upcomingInvoice.base_proration_adjustment);\n }\n }\n catch (e)\n {\n console.warn(\"Could not calculate sidebar proration amount\");\n console.warn(e);\n }\n },\n });\n }\n);\n","StripeIntegration_Payments/js/model/upcomingInvoice.js":"define(\n [\n 'ko',\n 'Magento_Checkout/js/model/quote',\n 'StripeIntegration_Payments/js/action/get-upcoming-invoice',\n ],\n function (\n ko,\n quote,\n getUpcomingInvoiceAction\n ) {\n 'use strict';\n\n return {\n upcomingInvoiceRequest: null,\n initialized: false,\n currentTotals: null,\n callbacks: [],\n\n initialize: function()\n {\n if (this.initialized)\n return;\n\n this.initialized = true;\n\n this.watchTotals();\n getUpcomingInvoiceAction(this.upcomingInvoiceChanged.bind(this));\n },\n\n watchTotals: function()\n {\n this.currentTotals = quote.totals();\n var upcomingInvoiceChanged = this.upcomingInvoiceChanged.bind(this);\n var self = this;\n\n quote.totals.subscribe(function (totals)\n {\n if (JSON.stringify(totals.total_segments) == JSON.stringify(self.currentTotals.total_segments))\n return;\n\n self.currentTotals = totals;\n\n getUpcomingInvoiceAction(upcomingInvoiceChanged);\n }, self);\n },\n\n upcomingInvoiceChanged: function(result, outcome, response)\n {\n this.upcomingInvoiceRequest = {\n result: result,\n outcome: outcome,\n response: response\n };\n\n for (var i = 0; i < this.callbacks.length; i++)\n {\n this.callbacks[i](result, outcome, response);\n }\n },\n\n onChange: function(callback)\n {\n this.callbacks.push(callback);\n\n if (this.upcominInvoiceRequest)\n {\n callback(this.upcominInvoiceRequest.result, this.upcominInvoiceRequest.outcome, this.upcominInvoiceRequest.response);\n }\n }\n };\n }\n);\n","Magento_ProductVideo/js/load-player.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n @version 0.0.1\n @requires jQuery & jQuery UI\n */\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget',\n 'vimeoWrapper'\n], function ($) {\n 'use strict';\n\n var videoRegister = {\n _register: {},\n\n /**\n * Checks, if api is already registered\n *\n * @param {String} api\n * @returns {bool}\n */\n isRegistered: function (api) {\n return this._register[api] !== undefined;\n },\n\n /**\n * Checks, if api is loaded\n *\n * @param {String} api\n * @returns {bool}\n */\n isLoaded: function (api) {\n return this._register[api] !== undefined && this._register[api] === true;\n },\n\n /**\n * Register new video api\n * @param {String} api\n * @param {bool} loaded\n */\n register: function (api, loaded) {\n loaded = loaded || false;\n this._register[api] = loaded;\n }\n };\n\n $.widget('mage.productVideoLoader', {\n\n /**\n * @private\n */\n _create: function () {\n switch (this.element.data('type')) {\n case 'youtube':\n this.element.videoYoutube();\n this._player = this.element.data('mageVideoYoutube');\n break;\n\n case 'vimeo':\n this.element.videoVimeo();\n this._player = this.element.data('mageVideoVimeo');\n break;\n default:\n throw {\n name: 'Video Error',\n message: 'Unknown video type',\n\n /**\n * join name with message\n */\n toString: function () {\n return this.name + ': ' + this.message;\n }\n };\n }\n },\n\n /**\n * Initializes variables\n * @private\n */\n _initialize: function () {\n this._params = this.element.data('params') || {};\n this._code = this.element.data('code');\n this._width = this.element.data('width');\n this._height = this.element.data('height');\n this._autoplay = !!this.element.data('autoplay');\n this._playing = this._autoplay || false;\n this._loop = this.element.data('loop');\n this._rel = this.element.data('related');\n this.useYoutubeNocookie = this.element.data('youtubenocookie') || false;\n\n this._responsive = this.element.data('responsive') !== false;\n\n if (this._responsive === true) {\n this.element.addClass('responsive');\n }\n\n this._calculateRatio();\n },\n\n /**\n * Abstract play command\n */\n play: function () {\n this._player.play();\n },\n\n /**\n * Abstract pause command\n */\n pause: function () {\n this._player.pause();\n },\n\n /**\n * Abstract stop command\n */\n stop: function () {\n this._player.stop();\n },\n\n /**\n * Abstract playing command\n */\n playing: function () {\n return this._player.playing();\n },\n\n /**\n * Calculates ratio for responsive videos\n * @private\n */\n _calculateRatio: function () {\n if (!this._responsive) {\n return;\n }\n this.element.css('paddingBottom', this._height / this._width * 100 + '%');\n }\n });\n\n $.widget('mage.videoYoutube', $.mage.productVideoLoader, {\n\n /**\n * Initialization of the Youtube widget\n * @private\n */\n _create: function () {\n var self = this;\n\n this._initialize();\n\n this.element.append('<div></div>');\n\n this._on(window, {\n\n /**\n * Handle event\n */\n 'youtubeapiready': function () {\n var host = 'https://www.youtube.com';\n\n if (self.useYoutubeNocookie) {\n host = 'https://www.youtube-nocookie.com';\n }\n\n if (self._player !== undefined) {\n return;\n }\n self._autoplay = true;\n\n if (self._autoplay) {\n self._params.autoplay = 1;\n }\n\n if (!self._rel) {\n self._params.rel = 0;\n }\n\n self._player = new window.YT.Player(self.element.children(':first')[0], {\n height: self._height,\n width: self._width,\n videoId: self._code,\n playerVars: self._params,\n host: host,\n events: {\n\n /**\n * Get duration\n */\n 'onReady': function onPlayerReady() {\n self._player.getDuration();\n self.element.closest('.fotorama__stage__frame')\n .addClass('fotorama__product-video--loaded');\n },\n\n /**\n * Event observer\n */\n onStateChange: function (data) {\n switch (window.parseInt(data.data, 10)) {\n case 1:\n self._playing = true;\n break;\n default:\n self._playing = false;\n break;\n }\n\n self._trigger('statechange', {}, data);\n\n if (data.data === window.YT.PlayerState.ENDED && self._loop) {\n self._player.playVideo();\n }\n }\n }\n\n });\n }\n });\n\n this._loadApi();\n },\n\n /**\n * Loads Youtube API and triggers event, when loaded\n * @private\n */\n _loadApi: function () {\n var element,\n scriptTag;\n\n if (videoRegister.isRegistered('youtube')) {\n if (videoRegister.isLoaded('youtube')) {\n $(window).trigger('youtubeapiready');\n }\n\n return;\n }\n\n // if script already loaded by other library\n if (window.YT) {\n videoRegister.register('youtube', true);\n $(window).trigger('youtubeapiready');\n\n return;\n }\n videoRegister.register('youtube');\n\n element = document.createElement('script');\n scriptTag = document.getElementsByTagName('script')[0];\n\n element.async = true;\n element.src = 'https://www.youtube.com/iframe_api';\n scriptTag.parentNode.insertBefore(element, scriptTag);\n\n /**\n * Event observe and handle\n */\n window.onYouTubeIframeAPIReady = function () {\n $(window).trigger('youtubeapiready');\n videoRegister.register('youtube', true);\n };\n },\n\n /**\n * Play command for Youtube\n */\n play: function () {\n this._player.playVideo();\n this._playing = true;\n },\n\n /**\n * Pause command for Youtube\n */\n pause: function () {\n this._player.pauseVideo();\n this._playing = false;\n },\n\n /**\n * Stop command for Youtube\n */\n stop: function () {\n this._player.stopVideo();\n this._playing = false;\n },\n\n /**\n * Playing command for Youtube\n */\n playing: function () {\n return this._playing;\n },\n\n /**\n * stops and unloads player\n * @private\n */\n _destroy: function () {\n this.stop();\n }\n });\n\n $.widget('mage.videoVimeo', $.mage.productVideoLoader, {\n\n /**\n * Initialize the Vimeo widget\n * @private\n */\n _create: function () {\n var timestamp,\n additionalParams = '',\n src,\n id;\n\n this._initialize();\n timestamp = new Date().getTime();\n this._autoplay = true;\n\n if (this._autoplay) {\n additionalParams += '&autoplay=1';\n }\n\n if (this._loop) {\n additionalParams += '&loop=1';\n }\n src = 'https://player.vimeo.com/video/' +\n this._code + '?api=1&player_id=vimeo' +\n this._code +\n timestamp +\n additionalParams;\n id = 'vimeo' + this._code + timestamp;\n this.element.append(\n $('<iframe></iframe>')\n .attr('frameborder', 0)\n .attr('id', id)\n .attr('width', this._width)\n .attr('height', this._height)\n .attr('src', src)\n .attr('webkitallowfullscreen', '')\n .attr('mozallowfullscreen', '')\n .attr('allowfullscreen', '')\n .attr('referrerPolicy', 'origin')\n .attr('allow', 'autoplay')\n );\n\n /* eslint-disable no-undef */\n this._player = new Vimeo.Player(this.element.children(':first')[0]);\n\n this._player.ready().then(function () {\n $('#' + id).closest('.fotorama__stage__frame').addClass('fotorama__product-video--loaded');\n });\n },\n\n /**\n * Play command for Vimeo\n */\n play: function () {\n this._player.play();\n this._playing = true;\n },\n\n /**\n * Pause command for Vimeo\n */\n pause: function () {\n this._player.pause();\n this._playing = false;\n },\n\n /**\n * Stop command for Vimeo\n */\n stop: function () {\n this._player.unload();\n this._playing = false;\n },\n\n /**\n * Playing command for Vimeo\n */\n playing: function () {\n return this._playing;\n }\n });\n});\n","Magento_ProductVideo/js/fotorama-add-video-events.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget',\n 'catalogGallery',\n 'loadPlayer'\n], function ($) {\n 'use strict';\n\n /**\n * @private\n */\n var allowBase = true; //global var is needed because fotorama always fully reloads events in case of fullscreen\n\n /**\n * @private\n */\n function parseHref(href) {\n var a = document.createElement('a');\n\n a.href = href;\n\n return a;\n }\n\n /**\n * @private\n */\n function parseURL(href, forceVideo) {\n var id,\n type,\n ampersandPosition,\n vimeoRegex,\n useYoutubeNocookie = false;\n\n /**\n * Get youtube ID\n * @param {String} srcid\n * @returns {{}}\n */\n function _getYoutubeId(srcid) {\n if (srcid) {\n ampersandPosition = srcid.indexOf('&');\n\n if (ampersandPosition === -1) {\n return srcid;\n }\n\n srcid = srcid.substring(0, ampersandPosition);\n }\n\n return srcid;\n }\n\n if (typeof href !== 'string') {\n return href;\n }\n\n href = parseHref(href);\n\n if (href.host.match(/youtube\\.com/) && href.search) {\n id = href.search.split('v=')[1];\n\n if (id) {\n id = _getYoutubeId(id);\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\n if (href.host.match(/youtube-nocookie.com/)) {\n useYoutubeNocookie = true;\n }\n } else if (href.host.match(/vimeo\\.com/)) {\n type = 'vimeo';\n vimeoRegex = new RegExp(['https?:\\\\/\\\\/(?:www\\\\.|player\\\\.)?vimeo.com\\\\/(?:channels\\\\/(?:\\\\w+\\\\/)',\n '?|groups\\\\/([^\\\\/]*)\\\\/videos\\\\/|album\\\\/(\\\\d+)\\\\/video\\\\/|video\\\\/|)(\\\\d+)(?:$|\\\\/|\\\\?)'\n ].join(''));\n id = href.href.match(vimeoRegex)[3];\n }\n\n if ((!id || !type) && forceVideo) {\n id = href.href;\n type = 'custom';\n }\n\n return id ? {\n id: id, type: type, s: href.search.replace(/^\\?/, ''), useYoutubeNocookie: useYoutubeNocookie\n } : false;\n }\n\n //create AddFotoramaVideoEvents widget\n $.widget('mage.AddFotoramaVideoEvents', {\n options: {\n videoData: '',\n videoSettings: '',\n optionsVideoData: '',\n dataMergeStrategy: 'replace'\n },\n\n /**\n * @private\n */\n onVimeoJSFramework: function () {},\n defaultVideoData: [],\n PV: 'product-video', // [CONST]\n VU: 'video-unplayed',\n PVLOADED: 'fotorama__product-video--loaded', // [CONST]\n PVLOADING: 'fotorama__product-video--loading', // [CONST]\n VID: 'video', // [CONST]\n VI: 'vimeo', // [CONST]\n FTVC: 'fotorama__video-close',\n FTAR: 'fotorama__arr',\n fotoramaSpinner: 'fotorama__spinner',\n fotoramaSpinnerShow: 'fotorama__spinner--show',\n TI: 'video-thumb-icon',\n isFullscreen: false,\n FTCF: '[data-gallery-role=\"fotorama__fullscreen-icon\"]',\n Base: 0, //on check for video is base this setting become true if there is any video with base role\n MobileMaxWidth: 768,\n GP: 'gallery-placeholder', //gallery placeholder class is needed to find and erase <script> tag\n videoData: null,\n videoDataPlaceholder: [{\n id: '',\n isBase: true,\n mediaType: 'image',\n provider: ''\n }],\n\n /**\n * Creates widget\n * @private\n */\n _create: function () {\n $(this.element).data('gallery') ?\n this._onGalleryLoaded() :\n $(this.element).on('gallery:loaded', this._onGalleryLoaded.bind(this));\n },\n\n /**\n *\n * @private\n */\n _initialize: function () {\n if (!this.defaultVideoData.length) {\n this.defaultVideoData = this.options.videoData;\n }\n\n // If product does not have images, no video data generated,\n // but for configurable product we still need a video data, in case of 'prepend' gallery strategy.\n if (!this.defaultVideoData.length && !this.options.videoData.length) {\n this.defaultVideoData = this.options.videoData = this.videoDataPlaceholder;\n }\n\n this.clearEvents();\n\n if (this._checkForVideoExist()) {\n this._checkFullscreen();\n this._listenForFullscreen();\n this._isVideoBase();\n this._initFotoramaVideo();\n this._attachFotoramaEvents();\n }\n },\n\n /**\n * Callback which fired after gallery gets initialized.\n */\n _onGalleryLoaded: function () {\n this.fotoramaItem = $(this.element).find('.fotorama-item');\n this._initialize();\n },\n\n /**\n * Clear gallery events to prevent duplicated calls.\n *\n * @private\n */\n clearEvents: function () {\n if (this.fotoramaItem !== undefined) {\n this.fotoramaItem.off(\n 'fotorama:show.' + this.PV +\n ' fotorama:showend.' + this.PV +\n ' fotorama:fullscreenenter.' + this.PV +\n ' fotorama:fullscreenexit.' + this.PV\n );\n }\n },\n\n /**\n *\n * @param {Object} options\n * @private\n */\n _setOptions: function (options) {\n if (options.videoData && options.videoData.length) {\n this.options.videoData = options.videoData;\n }\n\n this._loadVideoData(options);\n this._initialize();\n },\n\n /**\n * Set video data for configurable product.\n *\n * @param {Object} options\n * @private\n */\n _loadVideoData: function (options) {\n if (options.selectedOption) {\n if (options.dataMergeStrategy === 'prepend') {\n this.options.videoData = [].concat(\n this.options.optionsVideoData[options.selectedOption],\n this.defaultVideoData\n );\n } else {\n this.options.videoData = this.options.optionsVideoData[options.selectedOption];\n }\n } else {\n this.options.videoData = this.defaultVideoData;\n }\n },\n\n /**\n *\n * @private\n */\n _checkFullscreen: function () {\n if (this.fotoramaItem.data('fotorama').fullScreen || false) {\n this.isFullscreen = true;\n }\n },\n\n /**\n *\n * @private\n */\n _listenForFullscreen: function () {\n this.fotoramaItem.on('fotorama:fullscreenenter.' + this.PV, $.proxy(function () {\n this.isFullscreen = true;\n }, this));\n\n this.fotoramaItem.on('fotorama:fullscreenexit.' + this.PV, $.proxy(function () {\n this.isFullscreen = false;\n this._hideVideoArrows();\n }, this));\n },\n\n /**\n *\n * @param {Object} inputData\n * @param {bool} isJSON\n * @returns {{}}\n * @private\n */\n _createVideoData: function (inputData, isJSON) {\n var videoData = [],\n dataUrl,\n tmpVideoData,\n tmpInputData,\n i;\n\n if (isJSON) {\n inputData = JSON.parse(inputData);\n }\n\n for (i = 0; i < inputData.length; i++) {\n tmpInputData = inputData[i];\n dataUrl = '';\n tmpVideoData = {\n mediaType: '',\n isBase: '',\n id: '',\n provider: ''\n };\n tmpVideoData.mediaType = this.VID;\n\n if (tmpInputData.mediaType !== 'external-video') {\n tmpVideoData.mediaType = tmpInputData.mediaType;\n }\n\n tmpVideoData.isBase = tmpInputData.isBase;\n\n if (tmpInputData.videoUrl && tmpInputData.videoUrl !== null) {\n dataUrl = tmpInputData.videoUrl;\n dataUrl = parseURL(dataUrl);\n tmpVideoData.id = dataUrl.id;\n tmpVideoData.provider = dataUrl.type;\n tmpVideoData.videoUrl = tmpInputData.videoUrl;\n tmpVideoData.useYoutubeNocookie = dataUrl.useYoutubeNocookie;\n }\n\n videoData.push(tmpVideoData);\n }\n\n return videoData;\n },\n\n /**\n *\n * @param {Object} fotorama\n * @param {bool} isBase\n * @private\n */\n _createCloseVideo: function (fotorama, isBase) {\n var closeVideo;\n\n this.fotoramaItem.find('.' + this.FTVC).remove();\n this.fotoramaItem.append('<div class=\"' + this.FTVC + '\"></div>');\n this.fotoramaItem.css('position', 'relative');\n closeVideo = this.fotoramaItem.find('.' + this.FTVC);\n this._closeVideoSetEvents(closeVideo, fotorama);\n\n if (\n isBase &&\n this.options.videoData[fotorama.activeIndex].isBase &&\n $(window).width() > this.MobileMaxWidth) {\n this._showCloseVideo();\n }\n },\n\n /**\n *\n * @private\n */\n _hideCloseVideo: function () {\n this.fotoramaItem\n .find('.' + this.FTVC)\n .removeClass('fotorama-show-control');\n },\n\n /**\n *\n * @private\n */\n _showCloseVideo: function () {\n this.fotoramaItem\n .find('.' + this.FTVC)\n .addClass('fotorama-show-control');\n },\n\n /**\n *\n * @param {jQuery} $closeVideo\n * @param {jQuery} fotorama\n * @private\n */\n _closeVideoSetEvents: function ($closeVideo, fotorama) {\n $closeVideo.on('click', $.proxy(function () {\n this._unloadVideoPlayer(fotorama.activeFrame.$stageFrame.parent(), fotorama, true);\n this._hideCloseVideo();\n }, this));\n },\n\n /**\n *\n * @returns {Boolean}\n * @private\n */\n _checkForVideoExist: function () {\n var key, result, checker, videoSettings;\n\n if (!this.options.videoData) {\n return false;\n }\n\n if (!this.options.videoSettings) {\n return false;\n }\n\n result = this._createVideoData(this.options.videoData, false);\n checker = false;\n videoSettings = this.options.videoSettings[0];\n videoSettings.playIfBase = parseInt(videoSettings.playIfBase, 10);\n videoSettings.showRelated = parseInt(videoSettings.showRelated, 10);\n videoSettings.videoAutoRestart = parseInt(videoSettings.videoAutoRestart, 10);\n\n for (key in result) {\n if (result[key].mediaType === this.VID) {\n checker = true;\n }\n }\n\n if (checker) {\n this.options.videoData = result;\n }\n\n return checker;\n },\n\n /**\n *\n * @private\n */\n _isVideoBase: function () {\n var allVideoData = this.options.videoData,\n videoItem,\n allVideoDataKeys,\n key,\n i;\n\n allVideoDataKeys = Object.keys(allVideoData);\n\n for (i = 0; i < allVideoDataKeys.length; i++) {\n key = allVideoDataKeys[i];\n videoItem = allVideoData[key];\n\n if (\n videoItem.mediaType === this.VID && videoItem.isBase &&\n this.options.videoSettings[0].playIfBase && allowBase\n ) {\n this.Base = true;\n allowBase = false;\n }\n }\n\n if (!this.isFullscreen) {\n this._createCloseVideo(this.fotoramaItem.data('fotorama'), this.Base);\n }\n },\n\n /**\n *\n * @param {Event} e\n * @private\n */\n _initFotoramaVideo: function (e) {\n var fotorama = this.fotoramaItem.data('fotorama'),\n thumbsParent,\n thumbs,\n t;\n\n if (!fotorama.activeFrame.$navThumbFrame) {\n this.fotoramaItem.on('fotorama:showend.' + this.PV, $.proxy(function (evt, fotoramaData) {\n $(fotoramaData.activeFrame.$stageFrame).removeAttr('href');\n }, this));\n\n this._startPrepareForPlayer(e, fotorama);\n\n return null;\n }\n\n fotorama.data.map($.proxy(this._setItemType, this));\n thumbsParent = fotorama.activeFrame.$navThumbFrame.parent();\n thumbs = thumbsParent.find('.fotorama__nav__frame:visible');\n\n for (t = 0; t < thumbs.length; t++) {\n this._setThumbsIcon(thumbs.eq(t), t);\n this._checkForVideo(e, fotorama, t + 1);\n }\n\n this.fotoramaItem.on('fotorama:showend.' + this.PV, $.proxy(function (evt, fotoramaData) {\n $(fotoramaData.activeFrame.$stageFrame).removeAttr('href');\n }, this));\n },\n\n /**\n *\n * @param {Object} elem\n * @param {Number} i\n * @private\n */\n _setThumbsIcon: function (elem, i) {\n var fotorama = this.fotoramaItem.data('fotorama');\n\n if (fotorama.options.nav === 'dots' && elem.hasClass(this.TI)) {\n elem.removeClass(this.TI);\n }\n\n if (this.options.videoData[i].mediaType === this.VID &&\n fotorama.data[i].type === this.VID &&\n fotorama.options.nav === 'thumbs') {\n elem.addClass(this.TI);\n }\n },\n\n /**\n * Temporary solution with adding types for configurable product items\n *\n * @param {Object} item\n * @param {Number} i\n * @private\n */\n _setItemType: function (item, i) {\n !item.type && (item.type = this.options.videoData[i].mediaType);\n },\n\n /**\n * Attach\n *\n * @private\n */\n _attachFotoramaEvents: function () {\n this.fotoramaItem.on('fotorama:showend.' + this.PV, $.proxy(function (e, fotorama) {\n this._startPrepareForPlayer(e, fotorama);\n }, this));\n\n this.fotoramaItem.on('fotorama:show.' + this.PV, $.proxy(function (e, fotorama) {\n this._unloadVideoPlayer(fotorama.activeFrame.$stageFrame.parent(), fotorama, true);\n }, this));\n\n this.fotoramaItem.on('fotorama:fullscreenexit.' + this.PV, $.proxy(function (e, fotorama) {\n fotorama.activeFrame.$stageFrame.find('.' + this.PV).remove();\n this._startPrepareForPlayer(e, fotorama);\n }, this));\n },\n\n /**\n * Start prepare for player\n *\n * @param {Event} e\n * @param {jQuery} fotorama\n * @private\n */\n _startPrepareForPlayer: function (e, fotorama) {\n this._unloadVideoPlayer(fotorama.activeFrame.$stageFrame.parent(), fotorama, false);\n this._checkForVideo(e, fotorama, fotorama.activeFrame.i);\n this._checkForVideo(e, fotorama, fotorama.activeFrame.i - 1);\n this._checkForVideo(e, fotorama, fotorama.activeFrame.i + 1);\n },\n\n /**\n * Check for video\n *\n * @param {Event} e\n * @param {jQuery} fotorama\n * @param {Number} number\n * @private\n */\n _checkForVideo: function (e, fotorama, number) {\n var videoData = this.options.videoData[number - 1],\n $image = fotorama.data[number - 1];\n\n if ($image) {\n !$image.type && this._setItemType($image, number - 1);\n\n if ($image.type === 'image') {\n $image.$navThumbFrame && $image.$navThumbFrame.removeClass(this.TI);\n this._hideCloseVideo();\n\n return;\n } else if ($image.$navThumbFrame && $image.type === 'video') {\n !$image.$navThumbFrame.hasClass(this.TI) && $image.$navThumbFrame.addClass(this.TI);\n }\n\n $image = $image.$stageFrame;\n }\n\n if ($image && videoData && videoData.mediaType === this.VID) {\n $(fotorama.activeFrame.$stageFrame).removeAttr('href');\n this._prepareForVideoContainer($image, videoData, fotorama, number);\n }\n\n if (this.isFullscreen && this.fotoramaItem.data('fotorama').activeFrame.i === number) {\n this.fotoramaItem.data('fotorama').activeFrame.$stageFrame.trigger('click');\n }\n },\n\n /**\n * Prepare for video container\n *\n * @param {jQuery} $image\n * @param {Object} videoData\n * @param {Object} fotorama\n * @param {Number} number\n * @private\n */\n _prepareForVideoContainer: function ($image, videoData, fotorama, number) {\n $image.addClass('fotorama-video-container').addClass(this.VU);\n this._createVideoContainer(videoData, $image);\n this._setVideoEvent($image, this.PV, fotorama, number);\n },\n\n /**\n * Create video container\n *\n * @param {Object} videoData\n * @param {jQuery} $image\n * @private\n */\n _createVideoContainer: function (videoData, $image) {\n var videoSettings;\n\n videoSettings = this.options.videoSettings[0];\n $image.find('.' + this.PV).remove();\n $image.append(\n '<div class=\"' +\n this.PV +\n '\" data-related=\"' +\n videoSettings.showRelated +\n '\" data-loop=\"' +\n videoSettings.videoAutoRestart +\n '\" data-type=\"' +\n videoData.provider +\n '\" data-code=\"' +\n videoData.id +\n '\" data-youtubenocookie=\"' +\n videoData.useYoutubeNocookie +\n '\" data-width=\"100%\" data-height=\"100%\"></div>'\n );\n },\n\n /**\n *\n * @param {Object} $image\n * @param {Object} PV\n * @param {Object} fotorama\n * @param {Number} number\n * @private\n */\n _setVideoEvent: function ($image, PV, fotorama, number) {\n $image.find('.magnify-lens').remove();\n $image\n .off('click tap', $.proxy(this._clickHandler, this))\n .on('click tap', $.proxy(this._clickHandler, this));\n this._handleBaseVideo(fotorama, number); //check for video is it base and handle it if it's base\n },\n\n /**\n * Hides preview arrows above video player.\n * @private\n */\n _hideVideoArrows: function () {\n var arrows = $('.' + this.FTAR);\n\n arrows.removeClass('fotorama__arr--shown');\n arrows.removeClass('fotorama__arr--hidden');\n },\n\n /**\n * @private\n */\n _showLoader: function () {\n var spinner = this.fotoramaItem.find('.' + this.fotoramaSpinner);\n\n spinner.addClass(this.fotoramaSpinnerShow);\n this.fotoramaItem.data('fotorama').activeFrame.$stageFrame.addClass(this.PVLOADING);\n },\n\n /**\n * @private\n */\n _hideLoader: function () {\n var spinner = this.fotoramaItem.find('.' + this.fotoramaSpinner);\n\n spinner.removeClass(this.fotoramaSpinnerShow);\n this.fotoramaItem.data('fotorama').activeFrame.$stageFrame.removeClass(this.PVLOADING);\n },\n\n /**\n * @param {Event} event\n * @private\n */\n _clickHandler: function (event) {\n var type;\n\n if ($(event.target).hasClass(this.VU) && $(event.target).find('iframe').length === 0) {\n $(event.target).removeClass(this.VU);\n type = $(event.target).find('.' + this.PV).data('type');\n\n if (type === this.VI) {\n $(event.target).find('.' + this.PV).productVideoLoader();\n } else if (type === this.VI) {\n this._showLoader();\n this.onVimeoJSFramework = function () {\n $(event.target).find('.' + this.PV).productVideoLoader();\n this._hideLoader();\n }.bind(this);\n } else {\n $(event.target).find('.' + this.PV).productVideoLoader();\n }\n\n $('.' + this.FTAR).addClass(this.isFullscreen ? 'fotorama__arr--shown' : 'fotorama__arr--hidden');\n $('.' + this.FTVC).addClass('fotorama-show-control');\n }\n },\n\n /**\n * Handle base video\n * @param {Object} fotorama\n * @param {Number} srcNumber\n * @private\n */\n _handleBaseVideo: function (fotorama, srcNumber) {\n var videoData = this.options.videoData,\n activeIndex = fotorama.activeIndex,\n number = parseInt(srcNumber, 10),\n activeIndexIsBase = videoData[activeIndex];\n\n if (!this.Base) {\n return;\n }\n\n if (activeIndexIsBase && number === 1 && $(window).width() > this.MobileMaxWidth) {\n setTimeout($.proxy(function () {\n fotorama.requestFullScreen();\n this.fotoramaItem.data('fotorama').activeFrame.$stageFrame.trigger('click');\n this.Base = false;\n }, this), 50);\n }\n },\n\n /**\n * Destroy video player\n * @param {jQuery} $wrapper\n * @param {jQuery} current\n * @param {bool} close\n * @private\n */\n _unloadVideoPlayer: function ($wrapper, current, close) {\n var self = this;\n\n if (!$wrapper) {\n return;\n }\n\n $wrapper.find('.' + this.PVLOADED).removeClass(this.PVLOADED);\n this._hideLoader();\n\n $wrapper.find('.' + this.PV).each(function () {\n var $item = $(this).parent(),\n cloneVideoDiv,\n iframeElement = $(this).find('iframe'),\n currentIndex,\n itemIndex;\n\n if (iframeElement.length === 0) {\n return;\n }\n\n currentIndex = current.activeFrame.$stageFrame.index();\n itemIndex = $item.index();\n\n if (currentIndex === itemIndex && !close) {\n return;\n }\n\n if (currentIndex !== itemIndex && close) {\n return;\n }\n\n iframeElement.remove();\n cloneVideoDiv = $(this).clone();\n $(this).remove();\n $item.append(cloneVideoDiv);\n $item.addClass(self.VU);\n\n self._hideCloseVideo();\n self._hideVideoArrows();\n\n if (self.isFullscreen && !self.fotoramaItem.data('fotorama').options.fullscreen.arrows) {\n if ($('.' + self.FTAR + '--prev').is(':focus') || $('.' + self.FTAR + '--next').is(':focus')) {\n $(self.FTCF).trigger('focus');\n }\n }\n });\n }\n });\n\n return $.mage.AddFotoramaVideoEvents;\n});\n","Magento_Checkout/js/empty-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['Magento_Customer/js/customer-data'], function (customerData) {\n 'use strict';\n\n return function () {\n var cartData = customerData.get('cart');\n\n customerData.getInitCustomerData().done(function () {\n if (cartData().items && cartData().items.length !== 0) {\n customerData.reload(['cart'], false);\n }\n });\n };\n});\n","Magento_Checkout/js/proceed-to-checkout.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'Magento_Customer/js/model/authentication-popup',\n 'Magento_Customer/js/customer-data'\n], function ($, authenticationPopup, customerData) {\n 'use strict';\n\n return function (config, element) {\n $(element).on('click', function (event) {\n var cart = customerData.get('cart'),\n customer = customerData.get('customer');\n\n event.preventDefault();\n\n if (!customer().firstname && cart().isGuestCheckoutAllowed === false) {\n authenticationPopup.showModal();\n\n return false;\n }\n $(element).attr('disabled', true);\n location.href = config.checkoutUrl;\n });\n\n };\n});\n","Magento_Checkout/js/shopping-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'Magento_Ui/js/modal/confirm',\n 'jquery-ui-modules/widget',\n 'mage/translate'\n], function ($, confirm) {\n 'use strict';\n\n $.widget('mage.shoppingCart', {\n /** @inheritdoc */\n _create: function () {\n var items, i, reload;\n\n $(this.options.emptyCartButton).on('click', $.proxy(function () {\n this._confirmClearCart();\n }, this));\n items = $.find('[data-role=\"cart-item-qty\"]');\n\n for (i = 0; i < items.length; i++) {\n $(items[i]).on('keypress', $.proxy(function (event) { //eslint-disable-line no-loop-func\n var keyCode = event.keyCode ? event.keyCode : event.which;\n\n if (keyCode == 13) { //eslint-disable-line eqeqeq\n $(this.options.emptyCartButton).attr('name', 'update_cart_action_temp');\n $(this.options.updateCartActionContainer)\n .attr('name', 'update_cart_action').attr('value', 'update_qty');\n\n }\n }, this));\n }\n $(this.options.continueShoppingButton).on('click', $.proxy(function () {\n location.href = this.options.continueShoppingUrl;\n }, this));\n\n $(document).on('ajax:removeFromCart', $.proxy(function () {\n reload = true;\n $('div.block.block-minicart').on('dropdowndialogclose', $.proxy(function () {\n if (reload === true) {\n location.reload();\n reload = false;\n }\n $('div.block.block-minicart').off('dropdowndialogclose');\n }));\n }, this));\n $(document).on('ajax:updateItemQty', $.proxy(function () {\n reload = true;\n $('div.block.block-minicart').on('dropdowndialogclose', $.proxy(function () {\n if (reload === true) {\n location.reload();\n reload = false;\n }\n $('div.block.block-minicart').off('dropdowndialogclose');\n }));\n }, this));\n },\n\n /**\n * Display confirmation modal for clearing the cart\n * @private\n */\n _confirmClearCart: function () {\n var self = this;\n\n confirm({\n content: $.mage.__('Are you sure you want to remove all items from your shopping cart?'),\n actions: {\n /**\n * Confirmation modal handler to execute clear cart action\n */\n confirm: function () {\n self.clearCart();\n }\n }\n });\n },\n\n /**\n * Prepares the form and submit to clear the cart\n * @public\n */\n clearCart: function () {\n $(this.options.emptyCartButton).attr('name', 'update_cart_action_temp');\n $(this.options.updateCartActionContainer)\n .attr('name', 'update_cart_action').attr('value', 'empty_cart');\n\n if ($(this.options.emptyCartButton).parents('form').length > 0) {\n $(this.options.emptyCartButton).parents('form').trigger('submit');\n }\n }\n });\n\n return $.mage.shoppingCart;\n});\n","Magento_Checkout/js/checkout-data.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Checkout adapter for customer data storage\n *\n * @api\n */\ndefine([\n 'jquery',\n 'Magento_Customer/js/customer-data',\n 'mageUtils',\n 'jquery/jquery-storageapi'\n], function ($, storage, utils) {\n 'use strict';\n\n var cacheKey = 'checkout-data',\n\n /**\n * @param {Object} data\n */\n saveData = function (data) {\n storage.set(cacheKey, data);\n },\n\n /**\n * @return {*}\n */\n initData = function () {\n return {\n 'selectedShippingAddress': null, //Selected shipping address pulled from persistence storage\n 'shippingAddressFromData': null, //Shipping address pulled from persistence storage\n 'newCustomerShippingAddress': null, //Shipping address pulled from persistence storage for customer\n 'selectedShippingRate': null, //Shipping rate pulled from persistence storage\n 'selectedPaymentMethod': null, //Payment method pulled from persistence storage\n 'selectedBillingAddress': null, //Selected billing address pulled from persistence storage\n 'billingAddressFromData': null, //Billing address pulled from persistence storage\n 'newCustomerBillingAddress': null //Billing address pulled from persistence storage for new customer\n };\n },\n\n /**\n * @return {*}\n */\n getData = function () {\n var data = storage.get(cacheKey)();\n\n if ($.isEmptyObject(data)) {\n data = $.initNamespaceStorage('mage-cache-storage').localStorage.get(cacheKey);\n\n if ($.isEmptyObject(data)) {\n data = initData();\n saveData(data);\n }\n }\n\n return data;\n };\n\n return {\n /**\n * Setting the selected shipping address pulled from persistence storage\n *\n * @param {Object} data\n */\n setSelectedShippingAddress: function (data) {\n var obj = getData();\n\n obj.selectedShippingAddress = data;\n saveData(obj);\n },\n\n /**\n * Pulling the selected shipping address from persistence storage\n *\n * @return {*}\n */\n getSelectedShippingAddress: function () {\n return getData().selectedShippingAddress;\n },\n\n /**\n * Setting the shipping address pulled from persistence storage\n *\n * @param {Object} data\n */\n setShippingAddressFromData: function (data) {\n var obj = getData();\n\n obj.shippingAddressFromData = utils.filterFormData(data);\n saveData(obj);\n },\n\n /**\n * Pulling the shipping address from persistence storage\n *\n * @return {*}\n */\n getShippingAddressFromData: function () {\n return getData().shippingAddressFromData;\n },\n\n /**\n * Setting the shipping address pulled from persistence storage for new customer\n *\n * @param {Object} data\n */\n setNewCustomerShippingAddress: function (data) {\n var obj = getData();\n\n obj.newCustomerShippingAddress = data;\n saveData(obj);\n },\n\n /**\n * Pulling the shipping address from persistence storage for new customer\n *\n * @return {*}\n */\n getNewCustomerShippingAddress: function () {\n return getData().newCustomerShippingAddress;\n },\n\n /**\n * Setting the selected shipping rate pulled from persistence storage\n *\n * @param {Object} data\n */\n setSelectedShippingRate: function (data) {\n var obj = getData();\n\n obj.selectedShippingRate = data;\n saveData(obj);\n },\n\n /**\n * Pulling the selected shipping rate from local storage\n *\n * @return {*}\n */\n getSelectedShippingRate: function () {\n return getData().selectedShippingRate;\n },\n\n /**\n * Setting the selected payment method pulled from persistence storage\n *\n * @param {Object} data\n */\n setSelectedPaymentMethod: function (data) {\n var obj = getData();\n\n obj.selectedPaymentMethod = data;\n saveData(obj);\n },\n\n /**\n * Pulling the payment method from persistence storage\n *\n * @return {*}\n */\n getSelectedPaymentMethod: function () {\n return getData().selectedPaymentMethod;\n },\n\n /**\n * Setting the selected billing address pulled from persistence storage\n *\n * @param {Object} data\n */\n setSelectedBillingAddress: function (data) {\n var obj = getData();\n\n obj.selectedBillingAddress = data;\n saveData(obj);\n },\n\n /**\n * Pulling the selected billing address from persistence storage\n *\n * @return {*}\n */\n getSelectedBillingAddress: function () {\n return getData().selectedBillingAddress;\n },\n\n /**\n * Setting the billing address pulled from persistence storage\n *\n * @param {Object} data\n */\n setBillingAddressFromData: function (data) {\n var obj = getData();\n\n obj.billingAddressFromData = utils.filterFormData(data);\n saveData(obj);\n },\n\n /**\n * Pulling the billing address from persistence storage\n *\n * @return {*}\n */\n getBillingAddressFromData: function () {\n return getData().billingAddressFromData;\n },\n\n /**\n * Setting the billing address pulled from persistence storage for new customer\n *\n * @param {Object} data\n */\n setNewCustomerBillingAddress: function (data) {\n var obj = getData();\n\n obj.newCustomerBillingAddress = data;\n saveData(obj);\n },\n\n /**\n * Pulling the billing address from persistence storage for new customer\n *\n * @return {*}\n */\n getNewCustomerBillingAddress: function () {\n return getData().newCustomerBillingAddress;\n },\n\n /**\n * Pulling the email address from persistence storage\n *\n * @return {*}\n */\n getValidatedEmailValue: function () {\n var obj = getData();\n\n return obj.validatedEmailValue ? obj.validatedEmailValue : '';\n },\n\n /**\n * Setting the email address pulled from persistence storage\n *\n * @param {String} email\n */\n setValidatedEmailValue: function (email) {\n var obj = getData();\n\n obj.validatedEmailValue = email;\n saveData(obj);\n },\n\n /**\n * Pulling the email input field value from persistence storage\n *\n * @return {*}\n */\n getInputFieldEmailValue: function () {\n var obj = getData();\n\n return obj.inputFieldEmailValue ? obj.inputFieldEmailValue : '';\n },\n\n /**\n * Setting the email input field value pulled from persistence storage\n *\n * @param {String} email\n */\n setInputFieldEmailValue: function (email) {\n var obj = getData();\n\n obj.inputFieldEmailValue = email;\n saveData(obj);\n },\n\n /**\n * Pulling the checked email value from persistence storage\n *\n * @return {*}\n */\n getCheckedEmailValue: function () {\n var obj = getData();\n\n return obj.checkedEmailValue ? obj.checkedEmailValue : '';\n },\n\n /**\n * Setting the checked email value pulled from persistence storage\n *\n * @param {String} email\n */\n setCheckedEmailValue: function (email) {\n var obj = getData();\n\n obj.checkedEmailValue = email;\n saveData(obj);\n }\n };\n});\n","Magento_Checkout/js/checkout-loader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'rjsResolver'\n], function (resolver) {\n 'use strict';\n\n /**\n * Removes provided loader element from DOM.\n *\n * @param {HTMLElement} $loader - Loader DOM element.\n */\n function hideLoader($loader) {\n $loader.parentNode.removeChild($loader);\n }\n\n /**\n * Initializes assets loading process listener.\n *\n * @param {Object} config - Optional configuration\n * @param {HTMLElement} $loader - Loader DOM element.\n */\n function init(config, $loader) {\n resolver(hideLoader.bind(null, $loader));\n }\n\n return init;\n});\n","Magento_Checkout/js/discount-codes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'jquery-ui-modules/widget'\n], function ($) {\n 'use strict';\n\n $.widget('mage.discountCode', {\n options: {\n },\n\n /** @inheritdoc */\n _create: function () {\n this.couponCode = $(this.options.couponCodeSelector);\n this.removeCoupon = $(this.options.removeCouponSelector);\n\n $(this.options.applyButton).on('click', $.proxy(function () {\n this.couponCode.attr('data-validate', '{required:true}');\n this.removeCoupon.attr('value', '0');\n $(this.element).validation().trigger('submit');\n }, this));\n\n $(this.options.cancelButton).on('click', $.proxy(function () {\n this.couponCode.removeAttr('data-validate');\n this.removeCoupon.attr('value', '1');\n this.element.trigger('submit');\n }, this));\n }\n });\n\n return $.mage.discountCode;\n});\n","Magento_Checkout/js/region-updater.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mage/template',\n 'underscore',\n 'jquery-ui-modules/widget',\n 'mage/validation'\n], function ($, mageTemplate, _) {\n 'use strict';\n\n $.widget('mage.regionUpdater', {\n options: {\n regionTemplate:\n '<option value=\"<%- data.value %>\" <% if (data.isSelected) { %>selected=\"selected\"<% } %>>' +\n '<%- data.title %>' +\n '</option>',\n isRegionRequired: true,\n isZipRequired: true,\n isCountryRequired: true,\n currentRegion: null,\n isMultipleCountriesAllowed: true\n },\n\n /**\n *\n * @private\n */\n _create: function () {\n this._initCountryElement();\n\n this.currentRegionOption = this.options.currentRegion;\n this.regionTmpl = mageTemplate(this.options.regionTemplate);\n\n this._updateRegion(this.element.find('option:selected').val());\n\n $(this.options.regionListId).on('change', $.proxy(function (e) {\n this.setOption = false;\n this.currentRegionOption = $(e.target).val();\n }, this));\n\n $(this.options.regionInputId).on('focusout', $.proxy(function () {\n this.setOption = true;\n }, this));\n },\n\n /**\n *\n * @private\n */\n _initCountryElement: function () {\n\n if (this.options.isMultipleCountriesAllowed) {\n this.element.parents('div.field').show();\n this.element.on('change', $.proxy(function (e) {\n // clear region inputs on country change\n $(this.options.regionListId).val('');\n $(this.options.regionInputId).val('');\n this._updateRegion($(e.target).val());\n }, this));\n\n if (this.options.isCountryRequired) {\n this.element.addClass('required-entry');\n this.element.parents('div.field').addClass('required');\n }\n } else {\n this.element.parents('div.field').hide();\n }\n },\n\n /**\n * Remove options from dropdown list\n *\n * @param {Object} selectElement - jQuery object for dropdown list\n * @private\n */\n _removeSelectOptions: function (selectElement) {\n selectElement.find('option').each(function (index) {\n if (index) {\n $(this).remove();\n }\n });\n },\n\n /**\n * Render dropdown list\n * @param {Object} selectElement - jQuery object for dropdown list\n * @param {String} key - region code\n * @param {Object} value - region object\n * @private\n */\n _renderSelectOption: function (selectElement, key, value) {\n selectElement.append($.proxy(function () {\n var name = value.name.replace(/[!\"#$%&'()*+,.\\/:;<=>?@[\\\\\\]^`{|}~]/g, '\\\\$&'),\n tmplData,\n tmpl;\n\n if (value.code && $(name).is('span')) {\n key = value.code;\n value.name = $(name).text();\n }\n\n tmplData = {\n value: key,\n title: value.name,\n isSelected: false\n };\n\n if (this.options.defaultRegion === key) {\n tmplData.isSelected = true;\n }\n\n tmpl = this.regionTmpl({\n data: tmplData\n });\n\n return $(tmpl);\n }, this));\n },\n\n /**\n * Takes clearError callback function as first option\n * If no form is passed as option, look up the closest form and call clearError method.\n * @private\n */\n _clearError: function () {\n var args = ['clearError', this.options.regionListId, this.options.regionInputId, this.options.postcodeId];\n\n if (this.options.clearError && typeof this.options.clearError === 'function') {\n this.options.clearError.call(this);\n } else {\n if (!this.options.form) {\n this.options.form = this.element.closest('form').length ? $(this.element.closest('form')[0]) : null;\n }\n\n this.options.form = $(this.options.form);\n\n this.options.form && this.options.form.data('validator') &&\n this.options.form.validation.apply(this.options.form, _.compact(args));\n\n // Clean up errors on region & zip fix\n $(this.options.regionInputId).removeClass('mage-error').parent().find('.mage-error').remove();\n $(this.options.regionListId).removeClass('mage-error').parent().find('.mage-error').remove();\n $(this.options.postcodeId).removeClass('mage-error').parent().find('.mage-error').remove();\n }\n },\n\n /**\n * Update dropdown list based on the country selected\n *\n * @param {String} country - 2 uppercase letter for country code\n * @private\n */\n _updateRegion: function (country) {\n // Clear validation error messages\n var regionList = $(this.options.regionListId),\n regionInput = $(this.options.regionInputId),\n postcode = $(this.options.postcodeId),\n label = regionList.parent().siblings('label'),\n container = regionList.parents('div.field'),\n regionsEntries,\n regionId,\n regionData;\n\n this._clearError();\n this._checkRegionRequired(country);\n\n // Populate state/province dropdown list if available or use input box\n if (this.options.regionJson[country]) {\n this._removeSelectOptions(regionList);\n regionsEntries = _.pairs(this.options.regionJson[country]);\n regionsEntries.sort(function (a, b) {\n return a[1].name > b[1].name ? 1 : -1;\n });\n $.each(regionsEntries, $.proxy(function (key, value) {\n regionId = value[0];\n regionData = value[1];\n this._renderSelectOption(regionList, regionId, regionData);\n }, this));\n\n if (this.currentRegionOption) {\n regionList.val(this.currentRegionOption);\n }\n\n if (this.setOption) {\n regionList.find('option').filter(function () {\n return this.text === regionInput.val();\n }).attr('selected', true);\n }\n\n if (this.options.isRegionRequired) {\n regionList.addClass('required-entry').prop('disabled', false);\n container.addClass('required').show();\n } else {\n regionList.removeClass('required-entry validate-select').removeAttr('data-validate');\n container.removeClass('required');\n\n if (!this.options.optionalRegionAllowed) { //eslint-disable-line max-depth\n regionList.hide();\n container.hide();\n } else {\n regionList.prop('disabled', false).show();\n }\n }\n\n regionList.show();\n regionInput.hide();\n label.attr('for', regionList.attr('id'));\n } else {\n this._removeSelectOptions(regionList);\n\n if (this.options.isRegionRequired) {\n regionInput.addClass('required-entry').prop('disabled', false);\n container.addClass('required').show();\n } else {\n if (!this.options.optionalRegionAllowed) { //eslint-disable-line max-depth\n regionInput.attr('disabled', 'disabled');\n container.hide();\n }\n container.removeClass('required');\n regionInput.removeClass('required-entry');\n }\n\n regionList.removeClass('required-entry').prop('disabled', 'disabled').hide();\n regionInput.show();\n label.attr('for', regionInput.attr('id'));\n }\n\n // If country is in optionalzip list, make postcode input not required\n if (this.options.isZipRequired) {\n $.inArray(country, this.options.countriesWithOptionalZip) >= 0 ?\n postcode.removeClass('required-entry').closest('.field').removeClass('required') :\n postcode.addClass('required-entry').closest('.field').addClass('required');\n }\n\n // Add defaultvalue attribute to state/province select element\n regionList.attr('defaultvalue', this.options.defaultRegion);\n this.options.form.find('[type=\"submit\"]').prop('disabled', false).show();\n },\n\n /**\n * Check if the selected country has a mandatory region selection\n *\n * @param {String} country - Code of the country - 2 uppercase letter for country code\n * @private\n */\n _checkRegionRequired: function (country) {\n var self = this;\n\n this.options.isRegionRequired = false;\n $.each(this.options.regionJson.config['regions_required'], function (index, elem) {\n if (elem === country) {\n self.options.isRegionRequired = true;\n }\n });\n }\n });\n\n return $.mage.regionUpdater;\n});\n","Magento_Checkout/js/sidebar.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'Magento_Customer/js/model/authentication-popup',\n 'Magento_Customer/js/customer-data',\n 'Magento_Ui/js/modal/alert',\n 'Magento_Ui/js/modal/confirm',\n 'underscore',\n 'jquery-ui-modules/widget',\n 'mage/decorate',\n 'mage/collapsible',\n 'mage/cookies',\n 'jquery-ui-modules/effect-fade'\n], function ($, authenticationPopup, customerData, alert, confirm, _) {\n 'use strict';\n\n $.widget('mage.sidebar', {\n options: {\n isRecursive: true,\n minicart: {\n maxItemsVisible: 3\n }\n },\n scrollHeight: 0,\n shoppingCartUrl: window.checkout.shoppingCartUrl,\n\n /**\n * Create sidebar.\n * @private\n */\n _create: function () {\n this._initContent();\n },\n\n /**\n * Update sidebar block.\n */\n update: function () {\n $(this.options.targetElement).trigger('contentUpdated');\n this._calcHeight();\n },\n\n /**\n * @private\n */\n _initContent: function () {\n var self = this,\n events = {};\n\n this.element.decorate('list', this.options.isRecursive);\n\n /**\n * @param {jQuery.Event} event\n */\n events['click ' + this.options.button.close] = function (event) {\n event.stopPropagation();\n $(self.options.targetElement).dropdownDialog('close');\n };\n events['click ' + this.options.button.checkout] = $.proxy(function () {\n var cart = customerData.get('cart'),\n customer = customerData.get('customer'),\n element = $(this.options.button.checkout);\n\n if (!customer().firstname && cart().isGuestCheckoutAllowed === false) {\n // set URL for redirect on successful login/registration. It's postprocessed on backend.\n $.cookie('login_redirect', this.options.url.checkout);\n\n if (this.options.url.isRedirectRequired) {\n element.prop('disabled', true);\n location.href = this.options.url.loginUrl;\n } else {\n authenticationPopup.showModal();\n }\n\n return false;\n }\n element.prop('disabled', true);\n location.href = this.options.url.checkout;\n }, this);\n\n /**\n * @param {jQuery.Event} event\n */\n events['click ' + this.options.button.remove] = function (event) {\n event.stopPropagation();\n confirm({\n content: self.options.confirmMessage,\n actions: {\n /** @inheritdoc */\n confirm: function () {\n self._removeItem($(event.currentTarget));\n },\n\n /** @inheritdoc */\n always: function (e) {\n e.stopImmediatePropagation();\n }\n }\n });\n };\n\n /**\n * @param {jQuery.Event} event\n */\n events['keyup ' + this.options.item.qty] = function (event) {\n self._showItemButton($(event.target));\n };\n\n /**\n * @param {jQuery.Event} event\n */\n events['change ' + this.options.item.qty] = function (event) {\n self._showItemButton($(event.target));\n };\n\n /**\n * @param {jQuery.Event} event\n */\n events['click ' + this.options.item.button] = function (event) {\n event.stopPropagation();\n self._updateItemQty($(event.currentTarget));\n };\n\n /**\n * @param {jQuery.Event} event\n */\n events['focusout ' + this.options.item.qty] = function (event) {\n self._validateQty($(event.currentTarget));\n };\n\n this._on(this.element, events);\n this._calcHeight();\n },\n\n /**\n * @param {HTMLElement} elem\n * @private\n */\n _showItemButton: function (elem) {\n var itemId = elem.data('cart-item'),\n itemQty = elem.data('item-qty');\n\n if (this._isValidQty(itemQty, elem.val())) {\n $('#update-cart-item-' + itemId).show('fade', 300);\n } else if (elem.val() == 0) { //eslint-disable-line eqeqeq\n this._hideItemButton(elem);\n } else {\n this._hideItemButton(elem);\n }\n },\n\n /**\n * @param {*} origin - origin qty. 'data-item-qty' attribute.\n * @param {*} changed - new qty.\n * @returns {Boolean}\n * @private\n */\n _isValidQty: function (origin, changed) {\n return origin != changed && //eslint-disable-line eqeqeq\n changed.length > 0 &&\n changed - 0 == changed && //eslint-disable-line eqeqeq\n changed - 0 > 0;\n },\n\n /**\n * @param {Object} elem\n * @private\n */\n _validateQty: function (elem) {\n var itemQty = elem.data('item-qty');\n\n if (!this._isValidQty(itemQty, elem.val())) {\n elem.val(itemQty);\n }\n },\n\n /**\n * @param {HTMLElement} elem\n * @private\n */\n _hideItemButton: function (elem) {\n var itemId = elem.data('cart-item');\n\n $('#update-cart-item-' + itemId).hide('fade', 300);\n },\n\n /**\n * @param {HTMLElement} elem\n * @private\n */\n _updateItemQty: function (elem) {\n var itemId = elem.data('cart-item');\n\n this._ajax(this.options.url.update, {\n 'item_id': itemId,\n 'item_qty': $('#cart-item-' + itemId + '-qty').val()\n }, elem, this._updateItemQtyAfter);\n },\n\n /**\n * Update content after update qty\n *\n * @param {HTMLElement} elem\n */\n _updateItemQtyAfter: function (elem) {\n var productData = this._getProductById(Number(elem.data('cart-item')));\n\n if (!_.isUndefined(productData)) {\n $(document).trigger('ajax:updateCartItemQty');\n\n if (window.location.href === this.shoppingCartUrl) {\n window.location.reload(false);\n }\n }\n this._hideItemButton(elem);\n },\n\n /**\n * @param {HTMLElement} elem\n * @private\n */\n _removeItem: function (elem) {\n var itemId = elem.data('cart-item');\n\n this._ajax(this.options.url.remove, {\n 'item_id': itemId\n }, elem, this._removeItemAfter);\n },\n\n /**\n * Update content after item remove\n *\n * @param {Object} elem\n * @private\n */\n _removeItemAfter: function (elem) {\n var productData = this._getProductById(Number(elem.data('cart-item')));\n\n if (!_.isUndefined(productData)) {\n $(document).trigger('ajax:removeFromCart', {\n productIds: [productData['product_id']],\n productInfo: [\n {\n 'id': productData['product_id']\n }\n ]\n });\n\n if (window.location.href.indexOf(this.shoppingCartUrl) === 0) {\n window.location.reload();\n }\n }\n },\n\n /**\n * Retrieves product data by Id.\n *\n * @param {Number} productId - product Id\n * @returns {Object|undefined}\n * @private\n */\n _getProductById: function (productId) {\n return _.find(customerData.get('cart')().items, function (item) {\n return productId === Number(item['item_id']);\n });\n },\n\n /**\n * @param {String} url - ajax url\n * @param {Object} data - post data for ajax call\n * @param {Object} elem - element that initiated the event\n * @param {Function} callback - callback method to execute after AJAX success\n */\n _ajax: function (url, data, elem, callback) {\n $.extend(data, {\n 'form_key': $.mage.cookies.get('form_key')\n });\n\n $.ajax({\n url: url,\n data: data,\n type: 'post',\n dataType: 'json',\n context: this,\n\n /** @inheritdoc */\n beforeSend: function () {\n elem.attr('disabled', 'disabled');\n },\n\n /** @inheritdoc */\n complete: function () {\n elem.attr('disabled', null);\n }\n })\n .done(function (response) {\n var msg;\n\n if (response.success) {\n callback.call(this, elem, response);\n } else {\n msg = response['error_message'];\n\n if (msg) {\n alert({\n content: msg\n });\n }\n }\n })\n .fail(function (error) {\n console.log(JSON.stringify(error));\n });\n },\n\n /**\n * Calculate height of minicart list\n *\n * @private\n */\n _calcHeight: function () {\n var self = this,\n height = 0,\n counter = this.options.minicart.maxItemsVisible,\n target = $(this.options.minicart.list),\n outerHeight;\n\n self.scrollHeight = 0;\n target.children().each(function () {\n\n if ($(this).find('.options').length > 0) {\n $(this).collapsible();\n }\n outerHeight = $(this).outerHeight(true);\n\n if (counter-- > 0) {\n height += outerHeight;\n }\n self.scrollHeight += outerHeight;\n });\n\n target.parent().height(height);\n }\n });\n\n return $.mage.sidebar;\n});\n","Magento_Checkout/js/action/set-payment-information.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_Checkout/js/action/set-payment-information-extended'\n\n], function (setPaymentInformationExtended) {\n 'use strict';\n\n return function (messageContainer, paymentData) {\n\n return setPaymentInformationExtended(messageContainer, paymentData, false);\n };\n});\n","Magento_Checkout/js/action/update-shopping-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Ui/js/modal/alert',\n 'Magento_Ui/js/modal/confirm',\n 'jquery',\n 'mage/translate',\n 'jquery-ui-modules/widget',\n 'mage/validation'\n], function (alert, confirm, $, $t) {\n 'use strict';\n\n $.widget('mage.updateShoppingCart', {\n options: {\n validationURL: '',\n eventName: 'updateCartItemQty',\n updateCartActionContainer: '',\n isCartHasUpdatedContent: false\n },\n\n /** @inheritdoc */\n _create: function () {\n this._on(this.element, {\n 'submit': this.onSubmit\n });\n this._on('[data-role=cart-item-qty]', {\n 'change': function () {\n this.isCartHasUpdatedContent = true;\n }\n });\n this._on('ul.pages-items', {\n 'click a': function (event) {\n if (this.isCartHasUpdatedContent) {\n event.preventDefault();\n this.changePageConfirm($(event.currentTarget).attr('href'));\n }\n }\n });\n },\n\n /**\n * Show the confirmation popup\n * @param nextPageUrl\n */\n changePageConfirm: function (nextPageUrl) {\n confirm({\n title: $t('Are you sure you want to leave the page?'),\n content: $t('Changes you made to the cart will not be saved.'),\n actions: {\n confirm: function () {\n window.location.href = nextPageUrl;\n }\n },\n buttons: [{\n text: $t('Cancel'),\n class: 'action-secondary action-dismiss',\n click: function (event) {\n this.closeModal(event);\n }\n }, {\n text: $t('Leave'),\n class: 'action-primary action-accept',\n click: function (event) {\n this.closeModal(event, true);\n }\n }]\n });\n },\n\n /**\n * Prevents default submit action and calls form validator.\n *\n * @param {Event} event\n * @return {Boolean}\n */\n onSubmit: function (event) {\n var action = this.element.find(this.options.updateCartActionContainer).val();\n\n if (!this.options.validationURL || action === 'empty_cart') {\n return true;\n }\n\n if (this.isValid()) {\n event.preventDefault();\n this.validateItems(this.options.validationURL, this.element.serialize());\n }\n\n return false;\n },\n\n /**\n * Validates requested form.\n *\n * @return {Boolean}\n */\n isValid: function () {\n return this.element.validation() && this.element.validation('isValid');\n },\n\n /**\n * Validates updated shopping cart data.\n *\n * @param {String} url - request url\n * @param {Object} data - post data for ajax call\n */\n validateItems: function (url, data) {\n $.extend(data, {\n 'form_key': $.mage.cookies.get('form_key')\n });\n\n $.ajax({\n url: url,\n data: data,\n type: 'post',\n dataType: 'json',\n context: this,\n\n /** @inheritdoc */\n beforeSend: function () {\n $(document.body).trigger('processStart');\n },\n\n /** @inheritdoc */\n complete: function () {\n $(document.body).trigger('processStop');\n }\n })\n .done(function (response) {\n if (response.success) {\n this.onSuccess();\n } else {\n this.onError(response);\n }\n })\n .fail(function () {\n this.submitForm();\n });\n },\n\n /**\n * Form validation succeed.\n */\n onSuccess: function () {\n $(document).trigger('ajax:' + this.options.eventName);\n this.submitForm();\n },\n\n /**\n * Form validation failed.\n */\n onError: function (response) {\n var that = this,\n elm,\n responseData = [];\n\n try {\n responseData = JSON.parse(response['error_message']);\n } catch (error) {\n }\n\n if (response['error_message']) {\n try {\n $.each(responseData, function (index, data) {\n\n if (data.itemId !== undefined) {\n elm = $('#cart-' + data.itemId + '-qty');\n elm.val(elm.attr('data-item-qty'));\n }\n response['error_message'] = data.error;\n });\n } catch (e) {}\n alert({\n content: response['error_message'],\n actions: {\n /** @inheritdoc */\n always: function () {\n that.submitForm();\n }\n }\n });\n } else {\n this.submitForm();\n }\n },\n\n /**\n * Real submit of validated form.\n */\n submitForm: function () {\n this.element\n .off('submit', this.onSubmit)\n .on('submit', function () {\n $(document.body).trigger('processStart');\n })\n .trigger('submit');\n }\n });\n\n return $.mage.updateShoppingCart;\n});\n","Magento_Checkout/js/action/get-payment-information.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_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/url-builder',\n 'mage/storage',\n 'Magento_Checkout/js/model/error-processor',\n 'Magento_Customer/js/model/customer',\n 'Magento_Checkout/js/model/payment/method-converter',\n 'Magento_Checkout/js/model/payment-service'\n], function ($, quote, urlBuilder, storage, errorProcessor, customer, methodConverter, paymentService) {\n 'use strict';\n\n return function (deferred, messageContainer) {\n var serviceUrl;\n\n deferred = deferred || $.Deferred();\n\n /**\n * Checkout for guest and registered customer.\n */\n if (!customer.isLoggedIn()) {\n serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/payment-information', {\n cartId: quote.getQuoteId()\n });\n } else {\n serviceUrl = urlBuilder.createUrl('/carts/mine/payment-information', {});\n }\n\n return storage.get(\n serviceUrl, false\n ).done(function (response) {\n quote.setTotals(response.totals);\n paymentService.setPaymentMethods(methodConverter(response['payment_methods']));\n deferred.resolve();\n }).fail(function (response) {\n errorProcessor.process(response, messageContainer);\n deferred.reject();\n });\n };\n});\n","Magento_Checkout/js/action/recollect-shipping-rates.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_Checkout/js/model/quote',\n 'Magento_Checkout/js/action/select-shipping-address',\n 'Magento_Checkout/js/model/shipping-rate-registry'\n], function (quote, selectShippingAddress, rateRegistry) {\n 'use strict';\n\n return function () {\n var shippingAddress = null;\n\n if (!quote.isVirtual()) {\n shippingAddress = quote.shippingAddress();\n\n rateRegistry.set(shippingAddress.getCacheKey(), null);\n selectShippingAddress(shippingAddress);\n }\n };\n});\n","Magento_Checkout/js/action/select-shipping-method.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n '../model/quote'\n], function (quote) {\n 'use strict';\n\n return function (shippingMethod) {\n quote.shippingMethod(shippingMethod);\n };\n});\n","Magento_Checkout/js/action/set-shipping-information.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n '../model/quote',\n 'Magento_Checkout/js/model/shipping-save-processor'\n], function (quote, shippingSaveProcessor) {\n 'use strict';\n\n return function () {\n return shippingSaveProcessor.saveShippingInformation(quote.shippingAddress().getType());\n };\n});\n","Magento_Checkout/js/action/select-payment-method.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_Checkout/js/model/quote'\n], function (quote) {\n 'use strict';\n\n return function (paymentMethod) {\n if (paymentMethod) {\n paymentMethod.__disableTmpl = {\n title: true\n };\n }\n quote.paymentMethod(paymentMethod);\n };\n});\n","Magento_Checkout/js/action/create-shipping-address.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_Customer/js/model/address-list',\n 'Magento_Checkout/js/model/address-converter'\n], function (addressList, addressConverter) {\n 'use strict';\n\n return function (addressData) {\n var address = addressConverter.formAddressDataToQuoteAddress(addressData),\n isAddressUpdated = addressList().some(function (currentAddress, index, addresses) {\n if (currentAddress.getKey() == address.getKey()) { //eslint-disable-line eqeqeq\n addresses[index] = address;\n\n return true;\n }\n\n return false;\n });\n\n if (!isAddressUpdated) {\n addressList.push(address);\n } else {\n addressList.valueHasMutated();\n }\n\n return address;\n };\n});\n","Magento_Checkout/js/action/redirect-on-success.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine(\n [\n 'mage/url',\n 'Magento_Checkout/js/model/full-screen-loader'\n ],\n function (url, fullScreenLoader) {\n 'use strict';\n\n return {\n redirectUrl: window.checkoutConfig.defaultSuccessPageUrl,\n\n /**\n * Provide redirect to page\n */\n execute: function () {\n fullScreenLoader.startLoader();\n this.redirectToSuccessPage();\n },\n\n /**\n * Redirect to success page.\n */\n redirectToSuccessPage: function () {\n window.location.replace(url.build(this.redirectUrl));\n }\n };\n }\n);\n","Magento_Checkout/js/action/select-billing-address.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 '../model/quote'\n], function ($, quote) {\n 'use strict';\n\n return function (billingAddress) {\n var address = null;\n\n if (quote.shippingAddress() && billingAddress.getCacheKey() == //eslint-disable-line eqeqeq\n quote.shippingAddress().getCacheKey()\n ) {\n address = $.extend(true, {}, billingAddress);\n address.saveInAddressBook = null;\n } else {\n address = billingAddress;\n }\n quote.billingAddress(address);\n };\n});\n","Magento_Checkout/js/action/place-order.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_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/url-builder',\n 'Magento_Customer/js/model/customer',\n 'Magento_Checkout/js/model/place-order'\n], function (quote, urlBuilder, customer, placeOrderService) {\n 'use strict';\n\n return function (paymentData, messageContainer) {\n var serviceUrl, payload;\n\n payload = {\n cartId: quote.getQuoteId(),\n billingAddress: quote.billingAddress(),\n paymentMethod: paymentData\n };\n\n if (customer.isLoggedIn()) {\n serviceUrl = urlBuilder.createUrl('/carts/mine/payment-information', {});\n } else {\n serviceUrl = urlBuilder.createUrl('/guest-carts/:quoteId/payment-information', {\n quoteId: quote.getQuoteId()\n });\n payload.email = quote.guestEmail;\n }\n\n return placeOrderService(serviceUrl, payload, messageContainer);\n };\n});\n","Magento_Checkout/js/action/set-billing-address.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine(\n [\n 'jquery',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/url-builder',\n 'mage/storage',\n 'Magento_Checkout/js/model/error-processor',\n 'Magento_Customer/js/model/customer',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'Magento_Checkout/js/action/get-payment-information'\n ],\n function ($,\n quote,\n urlBuilder,\n storage,\n errorProcessor,\n customer,\n fullScreenLoader,\n getPaymentInformationAction\n ) {\n 'use strict';\n\n return function (messageContainer) {\n var serviceUrl,\n payload;\n\n /**\n * Checkout for guest and registered customer.\n */\n if (!customer.isLoggedIn()) {\n serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/billing-address', {\n cartId: quote.getQuoteId()\n });\n payload = {\n cartId: quote.getQuoteId(),\n address: quote.billingAddress()\n };\n } else {\n serviceUrl = urlBuilder.createUrl('/carts/mine/billing-address', {});\n payload = {\n cartId: quote.getQuoteId(),\n address: quote.billingAddress()\n };\n }\n\n fullScreenLoader.startLoader();\n\n return storage.post(\n serviceUrl, JSON.stringify(payload)\n ).done(\n function () {\n var deferred = $.Deferred();\n\n getPaymentInformationAction(deferred);\n $.when(deferred).done(function () {\n fullScreenLoader.stopLoader();\n });\n }\n ).fail(\n function (response) {\n errorProcessor.process(response, messageContainer);\n fullScreenLoader.stopLoader();\n }\n );\n };\n }\n);\n","Magento_Checkout/js/action/set-payment-information-extended.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_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/url-builder',\n 'mage/storage',\n 'Magento_Checkout/js/model/error-processor',\n 'Magento_Customer/js/model/customer',\n 'Magento_Checkout/js/action/get-totals',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'underscore',\n 'Magento_Checkout/js/model/payment/place-order-hooks'\n], function (quote, urlBuilder, storage, errorProcessor, customer, getTotalsAction, fullScreenLoader, _, hooks) {\n 'use strict';\n\n /**\n * Filter template data.\n *\n * @param {Object|Array} data\n */\n var filterTemplateData = function (data) {\n return _.each(data, function (value, key, list) {\n if (_.isArray(value) || _.isObject(value)) {\n list[key] = filterTemplateData(value);\n }\n\n if (key === '__disableTmpl' || key === 'title') {\n delete list[key];\n }\n });\n };\n\n return function (messageContainer, paymentData, skipBilling) {\n var serviceUrl,\n payload,\n headers = {};\n\n paymentData = filterTemplateData(paymentData);\n skipBilling = skipBilling || false;\n payload = {\n cartId: quote.getQuoteId(),\n paymentMethod: paymentData\n };\n\n /**\n * Checkout for guest and registered customer.\n */\n if (!customer.isLoggedIn()) {\n serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/set-payment-information', {\n cartId: quote.getQuoteId()\n });\n payload.email = quote.guestEmail;\n } else {\n serviceUrl = urlBuilder.createUrl('/carts/mine/set-payment-information', {});\n }\n\n if (skipBilling === false) {\n payload.billingAddress = quote.billingAddress();\n }\n\n fullScreenLoader.startLoader();\n\n _.each(hooks.requestModifiers, function (modifier) {\n modifier(headers, payload);\n });\n\n return storage.post(\n serviceUrl, JSON.stringify(payload), true, 'application/json', headers\n ).fail(\n function (response) {\n errorProcessor.process(response, messageContainer);\n }\n ).always(\n function () {\n fullScreenLoader.stopLoader();\n _.each(hooks.afterRequestListeners, function (listener) {\n listener();\n });\n }\n );\n };\n});\n","Magento_Checkout/js/action/select-shipping-address.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_Checkout/js/model/quote'\n], function (quote) {\n 'use strict';\n\n return function (shippingAddress) {\n quote.shippingAddress(shippingAddress);\n };\n});\n","Magento_Checkout/js/action/create-billing-address.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_Checkout/js/model/address-converter'\n], function (addressConverter) {\n 'use strict';\n\n return function (addressData) {\n var address = addressConverter.formAddressDataToQuoteAddress(addressData);\n\n /**\n * Returns new customer billing address type.\n *\n * @returns {String}\n */\n address.getType = function () {\n return 'new-customer-billing-address';\n };\n\n return address;\n };\n});\n","Magento_Checkout/js/action/get-totals.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 '../model/quote',\n 'Magento_Checkout/js/model/resource-url-manager',\n 'Magento_Checkout/js/model/error-processor',\n 'mage/storage',\n 'Magento_Checkout/js/model/totals'\n], function ($, quote, resourceUrlManager, errorProcessor, storage, totals) {\n 'use strict';\n\n return function (callbacks, deferred) {\n deferred = deferred || $.Deferred();\n totals.isLoading(true);\n\n return storage.get(\n resourceUrlManager.getUrlForCartTotals(quote),\n false\n ).done(function (response) {\n var proceed = true;\n\n totals.isLoading(false);\n\n if (callbacks.length > 0) {\n $.each(callbacks, function (index, callback) {\n proceed = proceed && callback();\n });\n }\n\n if (proceed) {\n quote.setTotals(response);\n deferred.resolve();\n }\n }).fail(function (response) {\n totals.isLoading(false);\n deferred.reject();\n errorProcessor.process(response);\n }).always(function () {\n totals.isLoading(false);\n });\n };\n});\n","Magento_Checkout/js/view/cart-item-renderer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent'\n], function (Component) {\n 'use strict';\n\n return Component.extend({\n /**\n * Prepare the product name value to be rendered as HTML\n *\n * @param {String} productName\n * @return {String}\n */\n getProductNameUnsanitizedHtml: function (productName) {\n // product name has already escaped on backend\n return productName;\n },\n\n /**\n * Prepare the given option value to be rendered as HTML\n *\n * @param {String} optionValue\n * @return {String}\n */\n getOptionValueUnsanitizedHtml: function (optionValue) {\n // option value has already escaped on backend\n return optionValue;\n }\n });\n});\n","Magento_Checkout/js/view/progress-bar.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'underscore',\n 'ko',\n 'uiComponent',\n 'Magento_Checkout/js/model/step-navigator',\n 'Magento_Checkout/js/view/billing-address'\n], function ($, _, ko, Component, stepNavigator, billingAddress) {\n 'use strict';\n\n var steps = stepNavigator.steps;\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/progress-bar',\n visible: true\n },\n steps: steps,\n\n /** @inheritdoc */\n initialize: function () {\n var stepsValue;\n\n this._super();\n window.addEventListener('hashchange', _.bind(stepNavigator.handleHash, stepNavigator));\n\n if (!window.location.hash) {\n stepsValue = stepNavigator.steps();\n\n if (stepsValue.length) {\n stepNavigator.setHash(stepsValue.sort(stepNavigator.sortItems)[0].code);\n }\n }\n\n stepNavigator.handleHash();\n },\n\n /**\n * @param {*} itemOne\n * @param {*} itemTwo\n * @return {*|Number}\n */\n sortItems: function (itemOne, itemTwo) {\n return stepNavigator.sortItems(itemOne, itemTwo);\n },\n\n /**\n * @param {Object} step\n */\n navigateTo: function (step) {\n if (step.code === 'shipping') {\n billingAddress().needCancelBillingAddressChanges();\n }\n stepNavigator.navigateTo(step.code);\n },\n\n /**\n * @param {Object} item\n * @return {*|Boolean}\n */\n isProcessed: function (item) {\n return stepNavigator.isProcessed(item.code);\n }\n });\n});\n","Magento_Checkout/js/view/registration.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'uiComponent',\n 'Magento_Ui/js/model/messageList'\n], function ($, Component, messageList) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/registration',\n accountCreated: false,\n creationStarted: false,\n isFormVisible: true\n },\n\n /**\n * @inheritdoc\n */\n initObservable: function () {\n this._super()\n .observe('accountCreated')\n .observe('isFormVisible')\n .observe('creationStarted');\n\n return this;\n },\n\n /**\n * @return {*}\n */\n getEmailAddress: function () {\n return this.email;\n },\n\n /**\n * @return String\n */\n getUrl: function () {\n return this.registrationUrl;\n },\n\n /**\n * Create new user account.\n *\n * @deprecated\n */\n createAccount: function () {\n this.creationStarted(true);\n $.post(\n this.registrationUrl\n ).done(\n function (response) {\n\n if (response.errors == false) { //eslint-disable-line eqeqeq\n this.accountCreated(true);\n } else {\n messageList.addErrorMessage(response);\n }\n this.isFormVisible(false);\n }.bind(this)\n ).fail(\n function (response) {\n this.accountCreated(false);\n this.isFormVisible(false);\n messageList.addErrorMessage(response);\n }.bind(this)\n );\n }\n });\n});\n","Magento_Checkout/js/view/summary.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'Magento_Checkout/js/model/totals'\n], function (Component, totals) {\n 'use strict';\n\n return Component.extend({\n isLoading: totals.isLoading\n });\n});\n","Magento_Checkout/js/view/authentication-messages.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Ui/js/view/messages',\n 'Magento_Checkout/js/model/authentication-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});\n","Magento_Checkout/js/view/authentication.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'Magento_Ui/js/form/form',\n 'Magento_Customer/js/action/login',\n 'Magento_Customer/js/model/customer',\n 'mage/validation',\n 'Magento_Checkout/js/model/authentication-messages',\n 'Magento_Checkout/js/model/full-screen-loader'\n], function ($, Component, loginAction, customer, validation, messageContainer, fullScreenLoader) {\n 'use strict';\n\n var checkoutConfig = window.checkoutConfig;\n\n return Component.extend({\n isGuestCheckoutAllowed: checkoutConfig.isGuestCheckoutAllowed,\n isCustomerLoginRequired: checkoutConfig.isCustomerLoginRequired,\n registerUrl: checkoutConfig.registerUrl,\n forgotPasswordUrl: checkoutConfig.forgotPasswordUrl,\n autocomplete: checkoutConfig.autocomplete,\n defaults: {\n template: 'Magento_Checkout/authentication'\n },\n\n /**\n * Is login form enabled for current customer.\n *\n * @return {Boolean}\n */\n isActive: function () {\n return !customer.isLoggedIn();\n },\n\n /**\n * Provide login action.\n *\n * @param {HTMLElement} loginForm\n */\n login: function (loginForm) {\n var loginData = {},\n formDataArray = $(loginForm).serializeArray();\n\n formDataArray.forEach(function (entry) {\n loginData[entry.name] = entry.value;\n });\n\n if ($(loginForm).validation() &&\n $(loginForm).validation('isValid')\n ) {\n fullScreenLoader.startLoader();\n loginAction(loginData, checkoutConfig.checkoutUrl, undefined, messageContainer).always(function () {\n fullScreenLoader.stopLoader();\n });\n }\n }\n });\n});\n","Magento_Checkout/js/view/minicart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'Magento_Customer/js/customer-data',\n 'jquery',\n 'ko',\n 'underscore',\n 'sidebar',\n 'mage/translate',\n 'mage/dropdown'\n], function (Component, customerData, $, ko, _) {\n 'use strict';\n\n var sidebarInitialized = false,\n addToCartCalls = 0,\n miniCart;\n\n miniCart = $('[data-block=\\'minicart\\']');\n\n /**\n * @return {Boolean}\n */\n function initSidebar() {\n if (miniCart.data('mageSidebar')) {\n miniCart.sidebar('update');\n }\n\n if (!$('[data-role=product-item]').length) {\n return false;\n }\n miniCart.trigger('contentUpdated');\n\n if (sidebarInitialized) {\n return false;\n }\n sidebarInitialized = true;\n miniCart.sidebar({\n 'targetElement': 'div.block.block-minicart',\n 'url': {\n 'checkout': window.checkout.checkoutUrl,\n 'update': window.checkout.updateItemQtyUrl,\n 'remove': window.checkout.removeItemUrl,\n 'loginUrl': window.checkout.customerLoginUrl,\n 'isRedirectRequired': window.checkout.isRedirectRequired\n },\n 'button': {\n 'checkout': '#top-cart-btn-checkout',\n 'remove': '#mini-cart a.action.delete',\n 'close': '#btn-minicart-close'\n },\n 'showcart': {\n 'parent': 'span.counter',\n 'qty': 'span.counter-number',\n 'label': 'span.counter-label'\n },\n 'minicart': {\n 'list': '#mini-cart',\n 'content': '#minicart-content-wrapper',\n 'qty': 'div.items-total',\n 'subtotal': 'div.subtotal span.price',\n 'maxItemsVisible': window.checkout.minicartMaxItemsVisible\n },\n 'item': {\n 'qty': ':input.cart-item-qty',\n 'button': ':button.update-cart-item'\n },\n 'confirmMessage': $.mage.__('Are you sure you would like to remove this item from the shopping cart?')\n });\n }\n\n miniCart.on('dropdowndialogopen', function () {\n initSidebar();\n });\n\n return Component.extend({\n shoppingCartUrl: window.checkout.shoppingCartUrl,\n maxItemsToDisplay: window.checkout.maxItemsToDisplay,\n cart: {},\n\n // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n /**\n * @override\n */\n initialize: function () {\n var self = this,\n cartData = customerData.get('cart');\n\n this.update(cartData());\n cartData.subscribe(function (updatedCart) {\n addToCartCalls--;\n this.isLoading(addToCartCalls > 0);\n sidebarInitialized = false;\n this.update(updatedCart);\n initSidebar();\n }, this);\n $('[data-block=\"minicart\"]').on('contentLoading', function () {\n addToCartCalls++;\n self.isLoading(true);\n });\n\n if (\n cartData().website_id !== window.checkout.websiteId && cartData().website_id !== undefined ||\n cartData().storeId !== window.checkout.storeId && cartData().storeId !== undefined\n ) {\n customerData.reload(['cart'], false);\n }\n\n return this._super();\n },\n //jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n\n isLoading: ko.observable(false),\n initSidebar: initSidebar,\n\n /**\n * Close mini shopping cart.\n */\n closeMinicart: function () {\n $('[data-block=\"minicart\"]').find('[data-role=\"dropdownDialog\"]').dropdownDialog('close');\n },\n\n /**\n * @param {String} productType\n * @return {*|String}\n */\n getItemRenderer: function (productType) {\n return this.itemRenderer[productType] || 'defaultRenderer';\n },\n\n /**\n * Update mini shopping cart content.\n *\n * @param {Object} updatedCart\n * @returns void\n */\n update: function (updatedCart) {\n _.each(updatedCart, function (value, key) {\n if (!this.cart.hasOwnProperty(key)) {\n this.cart[key] = ko.observable();\n }\n this.cart[key](value);\n }, this);\n },\n\n /**\n * Get cart param by name.\n *\n * @param {String} name\n * @returns {*}\n */\n getCartParamUnsanitizedHtml: function (name) {\n if (!_.isUndefined(name)) {\n if (!this.cart.hasOwnProperty(name)) {\n this.cart[name] = ko.observable();\n }\n }\n\n return this.cart[name]();\n },\n\n /**\n * @deprecated please use getCartParamUnsanitizedHtml.\n * @param {String} name\n * @returns {*}\n */\n getCartParam: function (name) {\n return this.getCartParamUnsanitizedHtml(name);\n },\n\n /**\n * Returns array of cart items, limited by 'maxItemsToDisplay' setting\n * @returns []\n */\n getCartItems: function () {\n var items = this.getCartParamUnsanitizedHtml('items') || [];\n\n items = items.slice(parseInt(-this.maxItemsToDisplay, 10));\n\n return items;\n },\n\n /**\n * Returns count of cart line items\n * @returns {Number}\n */\n getCartLineItemsCount: function () {\n var items = this.getCartParamUnsanitizedHtml('items') || [];\n\n return parseInt(items.length, 10);\n }\n });\n});\n","Magento_Checkout/js/view/shipping-information.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'uiComponent',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/step-navigator',\n 'Magento_Checkout/js/model/sidebar'\n], function ($, Component, quote, stepNavigator, sidebarModel) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/shipping-information'\n },\n\n /**\n * @return {Boolean}\n */\n isVisible: function () {\n return !quote.isVirtual() && stepNavigator.isProcessed('shipping');\n },\n\n /**\n * @return {String}\n */\n getShippingMethodTitle: function () {\n var shippingMethod = quote.shippingMethod(),\n shippingMethodTitle = '';\n\n if (!shippingMethod) {\n return '';\n }\n\n shippingMethodTitle = shippingMethod['carrier_title'];\n\n if (typeof shippingMethod['method_title'] !== 'undefined') {\n shippingMethodTitle += ' - ' + shippingMethod['method_title'];\n }\n\n return shippingMethodTitle;\n },\n\n /**\n * Back step.\n */\n back: function () {\n sidebarModel.hide();\n stepNavigator.navigateTo('shipping');\n },\n\n /**\n * Back to shipping method.\n */\n backToShippingMethod: function () {\n sidebarModel.hide();\n stepNavigator.navigateTo('shipping', 'opc-shipping_method');\n }\n });\n});\n","Magento_Checkout/js/view/billing-address.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\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 'Magento_Checkout/js/model/address-converter'\n],\nfunction (\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 addressConverter\n) {\n 'use strict';\n\n var lastSelectedBillingAddress = null,\n addressUpdated = false,\n addressEdited = false,\n countryData = customerData.get('directory-data'),\n addressOptions = addressList().filter(function (address) {\n return address.getType() === 'customer-address';\n });\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/billing-address',\n actionsTemplate: 'Magento_Checkout/billing-address/actions',\n formTemplate: 'Magento_Checkout/billing-address/form',\n detailsTemplate: 'Magento_Checkout/billing-address/details',\n links: {\n isAddressFormVisible: '${$.billingAddressListProvider}:isNewAddressSelected'\n }\n },\n currentBillingAddress: quote.billingAddress,\n customerHasAddresses: addressOptions.length > 0,\n\n /**\n * Init component\n */\n initialize: function () {\n this._super();\n quote.paymentMethod.subscribe(function () {\n checkoutDataResolver.resolveBillingAddress();\n }, this);\n billingAddressPostcodeValidator.initFields(this.get('name') + '.form-fields');\n },\n\n /**\n * @return {exports.initObservable}\n */\n initObservable: function () {\n this._super()\n .observe({\n selectedAddress: null,\n isAddressDetailsVisible: quote.billingAddress() != null,\n isAddressFormVisible: !customer.isLoggedIn() || !addressOptions.length,\n isAddressSameAsShipping: false,\n saveInAddressBook: 1\n });\n\n quote.billingAddress.subscribe(function (newAddress) {\n if (quote.isVirtual()) {\n this.isAddressSameAsShipping(false);\n } else {\n this.isAddressSameAsShipping(\n newAddress != null &&\n newAddress.getCacheKey() == quote.shippingAddress().getCacheKey() //eslint-disable-line eqeqeq\n );\n }\n\n if (newAddress != null && newAddress.saveInAddressBook !== undefined) {\n this.saveInAddressBook(newAddress.saveInAddressBook);\n } else {\n this.saveInAddressBook(1);\n }\n this.isAddressDetailsVisible(true);\n }, this);\n\n return this;\n },\n\n canUseShippingAddress: ko.computed(function () {\n return !quote.isVirtual() && quote.shippingAddress() && quote.shippingAddress().canUseForBilling();\n }),\n\n /**\n * @param {Object} address\n * @return {*}\n */\n addressOptionsText: function (address) {\n return address.getAddressInline();\n },\n\n /**\n * @return {Boolean}\n */\n useShippingAddress: function () {\n if (this.isAddressSameAsShipping()) {\n selectBillingAddress(quote.shippingAddress());\n this.updateAddresses(true);\n this.isAddressDetailsVisible(true);\n } else {\n lastSelectedBillingAddress = quote.billingAddress();\n quote.billingAddress(null);\n this.isAddressDetailsVisible(false);\n }\n checkoutData.setSelectedBillingAddress(null);\n\n return true;\n },\n\n /**\n * Update address action\n */\n updateAddress: function () {\n var addressData, newBillingAddress;\n\n addressUpdated = true;\n\n if (this.selectedAddress() && !this.isAddressFormVisible()) {\n selectBillingAddress(this.selectedAddress());\n checkoutData.setSelectedBillingAddress(this.selectedAddress().getKey());\n } else {\n this.source.set('params.invalid', false);\n this.source.trigger(this.dataScopePrefix + '.data.validate');\n\n if (this.source.get(this.dataScopePrefix + '.custom_attributes')) {\n this.source.trigger(this.dataScopePrefix + '.custom_attributes.data.validate');\n }\n\n if (!this.source.get('params.invalid')) {\n addressData = this.source.get(this.dataScopePrefix);\n\n if (customer.isLoggedIn() && !this.customerHasAddresses) { //eslint-disable-line max-depth\n this.saveInAddressBook(1);\n }\n addressData['save_in_address_book'] = this.saveInAddressBook() ? 1 : 0;\n newBillingAddress = createBillingAddress(addressData);\n // New address must be selected as a billing address\n selectBillingAddress(newBillingAddress);\n checkoutData.setSelectedBillingAddress(newBillingAddress.getKey());\n checkoutData.setNewCustomerBillingAddress(addressData);\n }\n }\n this.updateAddresses(true);\n },\n\n /**\n * Edit address action\n */\n editAddress: function () {\n addressUpdated = false;\n addressEdited = true;\n lastSelectedBillingAddress = quote.billingAddress();\n quote.billingAddress(null);\n this.isAddressDetailsVisible(false);\n },\n\n /**\n * Cancel address edit action\n */\n cancelAddressEdit: function () {\n addressUpdated = true;\n this.restoreBillingAddress();\n\n if (quote.billingAddress()) {\n // restore 'Same As Shipping' checkbox state\n this.isAddressSameAsShipping(\n quote.billingAddress() != null &&\n quote.billingAddress().getCacheKey() == quote.shippingAddress().getCacheKey() && //eslint-disable-line\n !quote.isVirtual()\n );\n this.isAddressDetailsVisible(true);\n }\n },\n\n /**\n * Manage cancel button visibility\n */\n canUseCancelBillingAddress: ko.computed(function () {\n return quote.billingAddress() || lastSelectedBillingAddress;\n }),\n\n /**\n * Check if Billing Address Changes should be canceled\n */\n needCancelBillingAddressChanges: function () {\n if (addressEdited && !addressUpdated) {\n this.cancelAddressEdit();\n }\n },\n\n /**\n * Restore billing address\n */\n restoreBillingAddress: function () {\n var lastBillingAddress;\n\n if (lastSelectedBillingAddress != null) {\n selectBillingAddress(lastSelectedBillingAddress);\n lastBillingAddress = addressConverter.quoteAddressToFormAddressData(lastSelectedBillingAddress);\n\n checkoutData.setNewCustomerBillingAddress(lastBillingAddress);\n }\n },\n\n /**\n * @param {Number} countryId\n * @return {*}\n */\n getCountryName: function (countryId) {\n return countryData()[countryId] != undefined ? countryData()[countryId].name : ''; //eslint-disable-line\n },\n\n /**\n * Trigger action to update shipping and billing addresses\n *\n * @param {Boolean} force\n */\n updateAddresses: function (force) {\n force = !(typeof force === 'undefined' || force !== true);\n\n if (force\n || window.checkoutConfig.reloadOnBillingAddress\n || !window.checkoutConfig.displayBillingOnPaymentMethod) {\n setBillingAddressAction(globalMessageList);\n }\n },\n\n /**\n * Get code\n * @param {Object} parent\n * @returns {String}\n */\n getCode: function (parent) {\n return _.isFunction(parent.getCode) ? parent.getCode() : 'shared';\n },\n\n /**\n * Get customer attribute label\n *\n * @param {*} attribute\n * @returns {*}\n */\n getCustomAttributeLabel: function (attribute) {\n var label;\n\n if (typeof attribute === 'string') {\n return attribute;\n }\n\n if (attribute.label) {\n return attribute.label;\n }\n\n if (_.isArray(attribute.value)) {\n label = _.map(attribute.value, function (value) {\n return this.getCustomAttributeOptionLabel(attribute['attribute_code'], value) || value;\n }, this).join(', ');\n } else if (typeof attribute.value === 'object') {\n label = _.map(Object.values(attribute.value)).join(', ');\n } else {\n label = this.getCustomAttributeOptionLabel(attribute['attribute_code'], attribute.value);\n }\n\n return label || attribute.value;\n },\n\n /**\n * Get option label for given attribute code and option ID\n *\n * @param {String} attributeCode\n * @param {String} value\n * @returns {String|null}\n */\n getCustomAttributeOptionLabel: function (attributeCode, value) {\n var option,\n label,\n options = this.source.get('customAttributes') || {};\n\n if (options[attributeCode]) {\n option = _.findWhere(options[attributeCode], {\n value: value\n });\n\n if (option) {\n label = option.label;\n }\n } else if (value.file !== null) {\n label = value.file;\n }\n\n return label;\n }\n });\n});\n","Magento_Checkout/js/view/payment.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'underscore',\n 'uiComponent',\n 'ko',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/step-navigator',\n 'Magento_Checkout/js/model/payment-service',\n 'Magento_Checkout/js/model/payment/method-converter',\n 'Magento_Checkout/js/action/get-payment-information',\n 'Magento_Checkout/js/model/checkout-data-resolver',\n 'mage/translate'\n], function (\n $,\n _,\n Component,\n ko,\n quote,\n stepNavigator,\n paymentService,\n methodConverter,\n getPaymentInformation,\n checkoutDataResolver,\n $t\n) {\n 'use strict';\n\n /** Set payment methods to collection */\n paymentService.setPaymentMethods(methodConverter(window.checkoutConfig.paymentMethods));\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/payment',\n activeMethod: ''\n },\n isVisible: ko.observable(quote.isVirtual()),\n quoteIsVirtual: quote.isVirtual(),\n isPaymentMethodsAvailable: ko.computed(function () {\n return paymentService.getAvailablePaymentMethods().length > 0;\n }),\n\n /** @inheritdoc */\n initialize: function () {\n this._super();\n checkoutDataResolver.resolvePaymentMethod();\n stepNavigator.registerStep(\n 'payment',\n null,\n $t('Review & Payments'),\n this.isVisible,\n _.bind(this.navigate, this),\n this.sortOrder\n );\n\n return this;\n },\n\n /**\n * Navigate method.\n */\n navigate: function () {\n var self = this;\n\n if (!self.hasShippingMethod()) {\n this.isVisible(false);\n stepNavigator.setHash('shipping');\n } else {\n getPaymentInformation().done(function () {\n self.isVisible(true);\n });\n }\n },\n\n /**\n * @return {Boolean}\n */\n hasShippingMethod: function () {\n return window.checkoutConfig.selectedShippingMethod !== null;\n },\n\n /**\n * @return {*}\n */\n getFormKey: function () {\n return window.checkoutConfig.formKey;\n }\n });\n});\n","Magento_Checkout/js/view/shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\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], 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) {\n 'use strict';\n\n var popUp = null;\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/shipping',\n shippingFormTemplate: 'Magento_Checkout/shipping-address/form',\n shippingMethodListTemplate: 'Magento_Checkout/shipping-address/shipping-method-list',\n shippingMethodItemTemplate: 'Magento_Checkout/shipping-address/shipping-method-item',\n imports: {\n countryOptions: '${ $.parentName }.shippingAddress.shipping-address-fieldset.country_id:indexedOptions'\n }\n },\n visible: ko.observable(!quote.isVirtual()),\n errorValidationMessage: ko.observable(false),\n isCustomerLoggedIn: customer.isLoggedIn,\n isFormPopUpVisible: formPopUpState.isVisible,\n isFormInline: addressList().length === 0,\n isNewAddressAdded: ko.observable(false),\n saveInAddressBook: 1,\n quoteIsVirtual: quote.isVirtual(),\n\n /**\n * @return {exports}\n */\n initialize: function () {\n var self = this,\n hasNewAddress,\n fieldsetName = 'checkout.steps.shipping-step.shippingAddress.shipping-address-fieldset';\n\n this._super();\n\n if (!quote.isVirtual()) {\n stepNavigator.registerStep(\n 'shipping',\n '',\n $t('Shipping'),\n this.visible, _.bind(this.navigate, this),\n this.sortOrder\n );\n }\n checkoutDataResolver.resolveShippingAddress();\n\n hasNewAddress = addressList.some(function (address) {\n return address.getType() == 'new-customer-address'; //eslint-disable-line eqeqeq\n });\n\n this.isNewAddressAdded(hasNewAddress);\n\n this.isFormPopUpVisible.subscribe(function (value) {\n if (value) {\n self.getPopUp().openModal();\n }\n });\n\n quote.shippingMethod.subscribe(function () {\n self.errorValidationMessage(false);\n });\n\n registry.async('checkoutProvider')(function (checkoutProvider) {\n var shippingAddressData = checkoutData.getShippingAddressFromData();\n\n if (shippingAddressData) {\n checkoutProvider.set(\n 'shippingAddress',\n $.extend(true, {}, checkoutProvider.get('shippingAddress'), shippingAddressData)\n );\n }\n checkoutProvider.on('shippingAddress', function (shippingAddrsData, changes) {\n var isStreetAddressDeleted, isStreetAddressNotEmpty;\n\n /**\n * In last modifying operation street address was deleted.\n * @return {Boolean}\n */\n isStreetAddressDeleted = function () {\n var change;\n\n if (!changes || changes.length === 0) {\n return false;\n }\n\n change = changes.pop();\n\n if (_.isUndefined(change.value) || _.isUndefined(change.oldValue)) {\n return false;\n }\n\n if (!change.path.startsWith('shippingAddress.street')) {\n return false;\n }\n\n return change.value.length === 0 && change.oldValue.length > 0;\n };\n\n isStreetAddressNotEmpty = shippingAddrsData.street && !_.isEmpty(shippingAddrsData.street[0]);\n\n if (isStreetAddressNotEmpty || isStreetAddressDeleted()) {\n checkoutData.setShippingAddressFromData(shippingAddrsData);\n }\n });\n shippingRatesValidator.initFields(fieldsetName);\n });\n\n return this;\n },\n\n /**\n * Navigator change hash handler.\n *\n * @param {Object} step - navigation step\n */\n navigate: function (step) {\n step && step.isVisible(true);\n },\n\n /**\n * @return {*}\n */\n getPopUp: function () {\n var self = this,\n buttons;\n\n if (!popUp) {\n buttons = this.popUpForm.options.buttons;\n this.popUpForm.options.buttons = [\n {\n text: buttons.save.text ? buttons.save.text : $t('Save Address'),\n class: buttons.save.class ? buttons.save.class : 'action primary action-save-address',\n click: self.saveNewAddress.bind(self)\n },\n {\n text: buttons.cancel.text ? buttons.cancel.text : $t('Cancel'),\n class: buttons.cancel.class ? buttons.cancel.class : 'action secondary action-hide-popup',\n\n /** @inheritdoc */\n click: this.onClosePopUp.bind(this)\n }\n ];\n\n /** @inheritdoc */\n this.popUpForm.options.closed = function () {\n self.isFormPopUpVisible(false);\n };\n\n this.popUpForm.options.modalCloseBtnHandler = this.onClosePopUp.bind(this);\n this.popUpForm.options.keyEventHandlers = {\n escapeKey: this.onClosePopUp.bind(this)\n };\n\n /** @inheritdoc */\n this.popUpForm.options.opened = function () {\n // Store temporary address for revert action in case when user click cancel action\n self.temporaryAddress = $.extend(true, {}, checkoutData.getShippingAddressFromData());\n };\n popUp = modal(this.popUpForm.options, $(this.popUpForm.element));\n }\n\n return popUp;\n },\n\n /**\n * Revert address and close modal.\n */\n onClosePopUp: function () {\n checkoutData.setShippingAddressFromData($.extend(true, {}, this.temporaryAddress));\n this.getPopUp().closeModal();\n },\n\n /**\n * Show address form popup\n */\n showFormPopUp: function () {\n this.isFormPopUpVisible(true);\n },\n\n /**\n * Save new shipping address\n */\n saveNewAddress: function () {\n var addressData,\n newShippingAddress;\n\n this.source.set('params.invalid', false);\n this.triggerShippingDataValidateEvent();\n\n if (!this.source.get('params.invalid')) {\n addressData = this.source.get('shippingAddress');\n // if user clicked the checkbox, its value is true or false. Need to convert.\n addressData['save_in_address_book'] = this.saveInAddressBook ? 1 : 0;\n\n // New address must be selected as a shipping address\n newShippingAddress = createShippingAddress(addressData);\n selectShippingAddress(newShippingAddress);\n checkoutData.setSelectedShippingAddress(newShippingAddress.getKey());\n checkoutData.setNewCustomerShippingAddress($.extend(true, {}, addressData));\n this.getPopUp().closeModal();\n this.isNewAddressAdded(true);\n }\n },\n\n /**\n * Shipping Method View\n */\n rates: shippingService.getShippingRates(),\n isLoading: shippingService.isLoading,\n isSelected: ko.computed(function () {\n return checkoutData.getSelectedShippingRate() ? checkoutData.getSelectedShippingRate() :\n quote.shippingMethod() ?\n quote.shippingMethod()['carrier_code'] + '_' + quote.shippingMethod()['method_code'] :\n null;\n }),\n\n /**\n * @param {Object} shippingMethod\n * @return {Boolean}\n */\n selectShippingMethod: function (shippingMethod) {\n selectShippingMethodAction(shippingMethod);\n checkoutData.setSelectedShippingRate(shippingMethod['carrier_code'] + '_' + shippingMethod['method_code']);\n\n return true;\n },\n\n /**\n * Set shipping information handler\n */\n setShippingInformation: function () {\n if (this.validateShippingInformation()) {\n quote.billingAddress(null);\n checkoutDataResolver.resolveBillingAddress();\n registry.async('checkoutProvider')(function (checkoutProvider) {\n var shippingAddressData = checkoutData.getShippingAddressFromData();\n\n if (shippingAddressData) {\n checkoutProvider.set(\n 'shippingAddress',\n $.extend(true, {}, checkoutProvider.get('shippingAddress'), shippingAddressData)\n );\n }\n });\n setShippingInformationAction().done(\n function () {\n stepNavigator.next();\n }\n );\n }\n },\n\n /**\n * @return {Boolean}\n */\n validateShippingInformation: function () {\n var shippingAddress,\n addressData,\n loginFormSelector = 'form[data-role=email-with-possible-login]',\n emailValidationResult = customer.isLoggedIn(),\n field,\n option = _.isObject(this.countryOptions) && this.countryOptions[quote.shippingAddress().countryId],\n messageContainer = registry.get('checkout.errors').messageContainer;\n\n if (!quote.shippingMethod()) {\n this.errorValidationMessage(\n $t('The shipping method is missing. Select the shipping method and try again.')\n );\n\n return false;\n }\n\n if (!customer.isLoggedIn()) {\n $(loginFormSelector).validation();\n emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid());\n }\n\n if (this.isFormInline) {\n this.source.set('params.invalid', false);\n this.triggerShippingDataValidateEvent();\n\n if (!quote.shippingMethod()['method_code']) {\n this.errorValidationMessage(\n $t('The shipping method is missing. Select the shipping method and try again.')\n );\n }\n\n if (emailValidationResult &&\n this.source.get('params.invalid') ||\n !quote.shippingMethod()['method_code'] ||\n !quote.shippingMethod()['carrier_code']\n ) {\n this.focusInvalid();\n\n return false;\n }\n\n shippingAddress = quote.shippingAddress();\n addressData = addressConverter.formAddressDataToQuoteAddress(\n this.source.get('shippingAddress')\n );\n\n //Copy form data to quote shipping address object\n for (field in addressData) {\n if (addressData.hasOwnProperty(field) && //eslint-disable-line max-depth\n shippingAddress.hasOwnProperty(field) &&\n typeof addressData[field] != 'function' &&\n _.isEqual(shippingAddress[field], addressData[field])\n ) {\n shippingAddress[field] = addressData[field];\n } else if (typeof addressData[field] != 'function' &&\n !_.isEqual(shippingAddress[field], addressData[field])) {\n shippingAddress = addressData;\n break;\n }\n }\n\n if (customer.isLoggedIn()) {\n shippingAddress['save_in_address_book'] = 1;\n }\n selectShippingAddress(shippingAddress);\n } else if (customer.isLoggedIn() &&\n option &&\n option['is_region_required'] &&\n !quote.shippingAddress().region\n ) {\n messageContainer.addErrorMessage({\n message: $t('Please specify a regionId in shipping address.')\n });\n\n return false;\n }\n\n if (!emailValidationResult) {\n $(loginFormSelector + ' input[name=username]').trigger('focus');\n\n return false;\n }\n\n return true;\n },\n\n /**\n * Trigger Shipping data Validate Event.\n */\n triggerShippingDataValidateEvent: function () {\n this.source.trigger('shippingAddress.data.validate');\n\n if (this.source.get('shippingAddress.custom_attributes')) {\n this.source.trigger('shippingAddress.custom_attributes.data.validate');\n }\n }\n });\n});\n","Magento_Checkout/js/view/estimation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Catalog/js/price-utils',\n 'Magento_Checkout/js/model/totals',\n 'Magento_Checkout/js/model/sidebar'\n], function (Component, quote, priceUtils, totals, sidebarModel) {\n 'use strict';\n\n return Component.extend({\n isLoading: totals.isLoading,\n\n /**\n * @return {Number}\n */\n getQuantity: function () {\n if (totals.totals()) {\n return parseFloat(totals.totals()['items_qty']);\n }\n\n return 0;\n },\n\n /**\n * @return {Number}\n */\n getPureValue: function () {\n if (totals.totals()) {\n return parseFloat(totals.getSegment('grand_total').value);\n }\n\n return 0;\n },\n\n /**\n * Show sidebar.\n */\n showSidebar: function () {\n sidebarModel.show();\n },\n\n /**\n * @param {*} price\n * @return {*|String}\n */\n getFormattedPrice: function (price) {\n return priceUtils.formatPriceLocale(price, quote.getPriceFormat());\n },\n\n /**\n * @return {*|String}\n */\n getValue: function () {\n return this.getFormattedPrice(this.getPureValue());\n }\n });\n});\n","Magento_Checkout/js/view/sidebar.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'ko',\n 'jquery',\n 'Magento_Checkout/js/model/sidebar'\n], function (Component, ko, $, sidebarModel) {\n 'use strict';\n\n return Component.extend({\n /**\n * @param {HTMLElement} element\n */\n setModalElement: function (element) {\n sidebarModel.setPopup($(element));\n }\n });\n});\n","Magento_Checkout/js/view/form/element/email.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'uiComponent',\n 'ko',\n 'Magento_Customer/js/model/customer',\n 'Magento_Customer/js/action/check-email-availability',\n 'Magento_Customer/js/action/login',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/checkout-data',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'mage/validation'\n], function ($, Component, ko, customer, checkEmailAvailability, loginAction, quote, checkoutData, fullScreenLoader) {\n 'use strict';\n\n var validatedEmail;\n\n if (!checkoutData.getValidatedEmailValue() &&\n window.checkoutConfig.validatedEmailValue\n ) {\n checkoutData.setInputFieldEmailValue(window.checkoutConfig.validatedEmailValue);\n checkoutData.setValidatedEmailValue(window.checkoutConfig.validatedEmailValue);\n }\n\n validatedEmail = checkoutData.getValidatedEmailValue();\n\n if (validatedEmail && !customer.isLoggedIn()) {\n quote.guestEmail = validatedEmail;\n }\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/form/element/email',\n email: checkoutData.getInputFieldEmailValue(),\n emailFocused: false,\n isLoading: false,\n isPasswordVisible: false,\n listens: {\n email: 'emailHasChanged',\n emailFocused: 'validateEmail'\n },\n ignoreTmpls: {\n email: true\n }\n },\n checkDelay: 2000,\n checkRequest: null,\n isEmailCheckComplete: null,\n isCustomerLoggedIn: customer.isLoggedIn,\n forgotPasswordUrl: window.checkoutConfig.forgotPasswordUrl,\n emailCheckTimeout: 0,\n emailInputId: '#customer-email',\n\n /**\n * Initializes regular properties of instance.\n *\n * @returns {Object} Chainable.\n */\n initConfig: function () {\n this._super();\n\n this.isPasswordVisible = this.resolveInitialPasswordVisibility();\n\n return this;\n },\n\n /**\n * Initializes observable properties of instance\n *\n * @returns {Object} Chainable.\n */\n initObservable: function () {\n this._super()\n .observe(['email', 'emailFocused', 'isLoading', 'isPasswordVisible']);\n\n return this;\n },\n\n /**\n * Callback on changing email property\n */\n emailHasChanged: function () {\n var self = this;\n\n clearTimeout(this.emailCheckTimeout);\n\n if (self.validateEmail()) {\n quote.guestEmail = self.email();\n checkoutData.setValidatedEmailValue(self.email());\n }\n this.emailCheckTimeout = setTimeout(function () {\n if (self.validateEmail()) {\n self.checkEmailAvailability();\n } else {\n self.isPasswordVisible(false);\n }\n }, self.checkDelay);\n\n checkoutData.setInputFieldEmailValue(self.email());\n },\n\n /**\n * Check email existing.\n */\n checkEmailAvailability: function () {\n this.validateRequest();\n this.isEmailCheckComplete = $.Deferred();\n // Clean up errors on email\n $(this.emailInputId).removeClass('mage-error').parent().find('.mage-error').remove();\n this.isLoading(true);\n this.checkRequest = checkEmailAvailability(this.isEmailCheckComplete, this.email());\n\n $.when(this.isEmailCheckComplete).done(function () {\n this.isPasswordVisible(false);\n checkoutData.setCheckedEmailValue('');\n }.bind(this)).fail(function () {\n this.isPasswordVisible(true);\n checkoutData.setCheckedEmailValue(this.email());\n }.bind(this)).always(function () {\n this.isLoading(false);\n }.bind(this));\n },\n\n /**\n * If request has been sent -> abort it.\n * ReadyStates for request aborting:\n * 1 - The request has been set up\n * 2 - The request has been sent\n * 3 - The request is in process\n */\n validateRequest: function () {\n if (this.checkRequest != null && $.inArray(this.checkRequest.readyState, [1, 2, 3])) {\n this.checkRequest.abort();\n this.checkRequest = null;\n }\n },\n\n /**\n * Local email validation.\n *\n * @param {Boolean} focused - input focus.\n * @returns {Boolean} - validation result.\n */\n validateEmail: function (focused) {\n var loginFormSelector = 'form[data-role=email-with-possible-login]',\n usernameSelector = loginFormSelector + ' input[name=username]',\n loginForm = $(loginFormSelector),\n validator,\n valid;\n\n loginForm.validation();\n\n if (focused === false && !!this.email()) {\n valid = !!$(usernameSelector).valid();\n\n if (valid) {\n $(usernameSelector).removeAttr('aria-invalid aria-describedby');\n }\n\n return valid;\n }\n\n if (loginForm.is(':visible')) {\n validator = loginForm.validate();\n\n return validator.check(usernameSelector);\n }\n\n return true;\n },\n\n /**\n * Log in form submitting callback.\n *\n * @param {HTMLElement} loginForm - form element.\n */\n login: function (loginForm) {\n var loginData = {},\n formDataArray = $(loginForm).serializeArray();\n\n formDataArray.forEach(function (entry) {\n loginData[entry.name] = entry.value;\n });\n\n if (this.isPasswordVisible() && $(loginForm).validation() && $(loginForm).validation('isValid')) {\n fullScreenLoader.startLoader();\n loginAction(loginData).always(function () {\n fullScreenLoader.stopLoader();\n });\n }\n },\n\n /**\n * Resolves an initial state of a login form.\n *\n * @returns {Boolean} - initial visibility state.\n */\n resolveInitialPasswordVisibility: function () {\n if (checkoutData.getInputFieldEmailValue() !== '' && checkoutData.getCheckedEmailValue() !== '') {\n return true;\n }\n\n if (checkoutData.getInputFieldEmailValue() !== '') {\n return checkoutData.getInputFieldEmailValue() === checkoutData.getCheckedEmailValue();\n }\n\n return false;\n }\n });\n});\n","Magento_Checkout/js/view/cart/shipping-estimation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(\n [\n 'jquery',\n 'Magento_Ui/js/form/form',\n 'Magento_Checkout/js/action/select-shipping-address',\n 'Magento_Checkout/js/model/address-converter',\n 'Magento_Checkout/js/model/cart/estimate-service',\n 'Magento_Checkout/js/checkout-data',\n 'Magento_Checkout/js/model/shipping-rates-validator',\n 'uiRegistry',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/checkout-data-resolver',\n 'Magento_Checkout/js/model/shipping-service',\n 'mage/validation'\n ],\n function (\n $,\n Component,\n selectShippingAddress,\n addressConverter,\n estimateService,\n checkoutData,\n shippingRatesValidator,\n registry,\n quote,\n checkoutDataResolver,\n shippingService\n ) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/cart/shipping-estimation'\n },\n isVirtual: quote.isVirtual(),\n\n /**\n * @override\n */\n initialize: function () {\n this._super();\n\n // Prevent shipping methods showing none available whilst we resolve\n shippingService.isLoading(true);\n\n registry.async('checkoutProvider')(function (checkoutProvider) {\n var address, estimatedAddress;\n\n shippingService.isLoading(false);\n\n checkoutDataResolver.resolveEstimationAddress();\n address = quote.isVirtual() ? quote.billingAddress() : quote.shippingAddress();\n\n if (!address && quote.isVirtual()) {\n address = addressConverter.formAddressDataToQuoteAddress(\n checkoutData.getSelectedBillingAddress()\n );\n }\n\n if (address) {\n estimatedAddress = address.isEditable() ?\n addressConverter.quoteAddressToFormAddressData(address) :\n {\n // only the following fields must be used by estimation form data provider\n 'country_id': address.countryId,\n region: address.region,\n 'region_id': address.regionId,\n postcode: address.postcode\n };\n checkoutProvider.set(\n 'shippingAddress',\n $.extend({}, checkoutProvider.get('shippingAddress'), estimatedAddress)\n );\n }\n\n if (!quote.isVirtual()) {\n checkoutProvider.on('shippingAddress', function (shippingAddressData) {\n //jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n if (quote.shippingAddress().countryId !== shippingAddressData.country_id ||\n (shippingAddressData.postcode || shippingAddressData.region_id)\n ) {\n checkoutData.setShippingAddressFromData(shippingAddressData);\n }\n //jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n });\n } else {\n checkoutProvider.on('shippingAddress', function (shippingAddressData) {\n checkoutData.setBillingAddressFromData(shippingAddressData);\n });\n }\n });\n\n return this;\n },\n\n /**\n * @override\n */\n initElement: function (element) {\n this._super();\n\n if (element.index === 'address-fieldsets') {\n shippingRatesValidator.bindChangeHandlers(element.elems(), true, 500);\n element.elems.subscribe(function (elems) {\n shippingRatesValidator.doElementBinding(elems[elems.length - 1], true, 500);\n });\n }\n\n return this;\n },\n\n /**\n * Returns shipping rates for address\n * @returns void\n */\n getEstimationInfo: function () {\n var addressData = null;\n\n this.source.set('params.invalid', false);\n this.source.trigger('shippingAddress.data.validate');\n\n if (!this.source.get('params.invalid')) {\n addressData = this.source.get('shippingAddress');\n selectShippingAddress(addressConverter.formAddressDataToQuoteAddress(addressData));\n }\n }\n });\n }\n);\n","Magento_Checkout/js/view/cart/shipping-rates.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'underscore',\n 'uiComponent',\n 'Magento_Checkout/js/model/shipping-service',\n 'Magento_Catalog/js/price-utils',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/action/select-shipping-method',\n 'Magento_Checkout/js/checkout-data'\n], function (ko, _, Component, shippingService, priceUtils, quote, selectShippingMethodAction, checkoutData) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/cart/shipping-rates'\n },\n isVisible: ko.observable(!quote.isVirtual()),\n isLoading: shippingService.isLoading,\n shippingRates: shippingService.getShippingRates(),\n shippingRateGroups: ko.observableArray([]),\n selectedShippingMethod: ko.computed(function () {\n return quote.shippingMethod() ?\n quote.shippingMethod()['carrier_code'] + '_' + quote.shippingMethod()['method_code'] :\n null;\n }),\n\n /**\n * @override\n */\n initObservable: function () {\n var self = this;\n\n this._super();\n\n this.shippingRates.subscribe(function (rates) {\n self.shippingRateGroups([]);\n _.each(rates, function (rate) {\n var carrierTitle = rate['carrier_title'];\n\n if (self.shippingRateGroups.indexOf(carrierTitle) === -1) {\n self.shippingRateGroups.push(carrierTitle);\n }\n });\n });\n\n return this;\n },\n\n /**\n * Get shipping rates for specific group based on title.\n * @returns Array\n */\n getRatesForGroup: function (shippingRateGroupTitle) {\n return _.filter(this.shippingRates(), function (rate) {\n return shippingRateGroupTitle === rate['carrier_title'];\n });\n },\n\n /**\n * Format shipping price.\n * @returns {String}\n */\n getFormattedPrice: function (price) {\n return priceUtils.formatPriceLocale(price, quote.getPriceFormat());\n },\n\n /**\n * Set shipping method.\n * @param {String} methodData\n * @returns bool\n */\n selectShippingMethod: function (methodData) {\n selectShippingMethodAction(methodData);\n checkoutData.setSelectedShippingRate(methodData['carrier_code'] + '_' + methodData['method_code']);\n\n return true;\n }\n });\n});\n","Magento_Checkout/js/view/cart/totals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'jquery',\n 'uiComponent',\n 'Magento_Checkout/js/model/totals',\n 'Magento_Checkout/js/model/shipping-service'\n], function ($, Component, totalsService, shippingService) {\n 'use strict';\n\n return Component.extend({\n isLoading: totalsService.isLoading,\n\n /**\n * @override\n */\n initialize: function () {\n this._super();\n totalsService.totals.subscribe(function () {\n $(window).trigger('resize');\n });\n shippingService.getShippingRates().subscribe(function () {\n $(window).trigger('resize');\n });\n }\n });\n});\n","Magento_Checkout/js/view/cart/totals/shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Checkout/js/view/summary/shipping',\n 'Magento_Checkout/js/model/quote'\n], function (Component, quote) {\n 'use strict';\n\n return Component.extend({\n\n /**\n * @override\n */\n isCalculated: function () {\n return !!quote.shippingMethod();\n }\n });\n});\n","Magento_Checkout/js/view/payment/default.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'jquery',\n 'uiComponent',\n 'Magento_Checkout/js/action/place-order',\n 'Magento_Checkout/js/action/select-payment-method',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Customer/js/model/customer',\n 'Magento_Checkout/js/model/payment-service',\n 'Magento_Checkout/js/checkout-data',\n 'Magento_Checkout/js/model/checkout-data-resolver',\n 'uiRegistry',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_Ui/js/model/messages',\n 'uiLayout',\n 'Magento_Checkout/js/action/redirect-on-success'\n], function (\n ko,\n $,\n Component,\n placeOrderAction,\n selectPaymentMethodAction,\n quote,\n customer,\n paymentService,\n checkoutData,\n checkoutDataResolver,\n registry,\n additionalValidators,\n Messages,\n layout,\n redirectOnSuccessAction\n) {\n 'use strict';\n\n return Component.extend({\n redirectAfterPlaceOrder: true,\n isPlaceOrderActionAllowed: ko.observable(quote.billingAddress() != null),\n\n /**\n * After place order callback\n */\n afterPlaceOrder: function () {\n // Override this function and put after place order logic here\n },\n\n /**\n * Initialize view.\n *\n * @return {exports}\n */\n initialize: function () {\n var billingAddressCode,\n billingAddressData,\n defaultAddressData;\n\n this._super().initChildren();\n quote.billingAddress.subscribe(function (address) {\n this.isPlaceOrderActionAllowed(address !== null);\n }, this);\n checkoutDataResolver.resolveBillingAddress();\n\n billingAddressCode = 'billingAddress' + this.getCode();\n registry.async('checkoutProvider')(function (checkoutProvider) {\n defaultAddressData = checkoutProvider.get(billingAddressCode);\n\n if (defaultAddressData === undefined) {\n // Skip if payment does not have a billing address form\n return;\n }\n billingAddressData = checkoutData.getBillingAddressFromData();\n\n if (billingAddressData) {\n checkoutProvider.set(\n billingAddressCode,\n $.extend(true, {}, defaultAddressData, billingAddressData)\n );\n }\n checkoutProvider.on(billingAddressCode, function (providerBillingAddressData) {\n checkoutData.setBillingAddressFromData(providerBillingAddressData);\n }, billingAddressCode);\n });\n\n return this;\n },\n\n /**\n * Initialize child elements\n *\n * @returns {Component} Chainable.\n */\n initChildren: function () {\n this.messageContainer = new Messages();\n this.createMessagesComponent();\n\n return this;\n },\n\n /**\n * Create child message renderer component\n *\n * @returns {Component} Chainable.\n */\n createMessagesComponent: function () {\n\n var messagesComponent = {\n parent: this.name,\n name: this.name + '.messages',\n displayArea: 'messages',\n component: 'Magento_Ui/js/view/messages',\n config: {\n messageContainer: this.messageContainer\n }\n };\n\n layout([messagesComponent]);\n\n return this;\n },\n\n /**\n * Place order.\n */\n placeOrder: function (data, event) {\n var self = this;\n\n if (event) {\n event.preventDefault();\n }\n\n if (this.validate() &&\n additionalValidators.validate() &&\n this.isPlaceOrderActionAllowed() === true\n ) {\n this.isPlaceOrderActionAllowed(false);\n\n this.getPlaceOrderDeferredObject()\n .done(\n function () {\n self.afterPlaceOrder();\n\n if (self.redirectAfterPlaceOrder) {\n redirectOnSuccessAction.execute();\n }\n }\n ).always(\n function () {\n self.isPlaceOrderActionAllowed(true);\n }\n );\n\n return true;\n }\n\n return false;\n },\n\n /**\n * @return {*}\n */\n getPlaceOrderDeferredObject: function () {\n return $.when(\n placeOrderAction(this.getData(), this.messageContainer)\n );\n },\n\n /**\n * @return {Boolean}\n */\n selectPaymentMethod: function () {\n selectPaymentMethodAction(this.getData());\n checkoutData.setSelectedPaymentMethod(this.item.method);\n\n return true;\n },\n\n isChecked: ko.computed(function () {\n return quote.paymentMethod() ? quote.paymentMethod().method : null;\n }),\n\n isRadioButtonVisible: ko.computed(function () {\n return paymentService.getAvailablePaymentMethods().length !== 1;\n }),\n\n /**\n * Get payment method data\n */\n getData: function () {\n return {\n 'method': this.item.method,\n 'po_number': null,\n 'additional_data': null\n };\n },\n\n /**\n * Get payment method type.\n */\n getTitle: function () {\n return this.item.title;\n },\n\n /**\n * Get payment method code.\n */\n getCode: function () {\n return this.item.method;\n },\n\n /**\n * @return {Boolean}\n */\n validate: function () {\n return true;\n },\n\n /**\n * @return {String}\n */\n getBillingAddressFormName: function () {\n return 'billing-address-form-' + this.item.method;\n },\n\n /**\n * Dispose billing address subscriptions\n */\n disposeSubscriptions: function () {\n // dispose all active subscriptions\n var billingAddressCode = 'billingAddress' + this.getCode();\n\n registry.async('checkoutProvider')(function (checkoutProvider) {\n checkoutProvider.off(billingAddressCode);\n });\n }\n });\n});\n","Magento_Checkout/js/view/payment/email-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(\n [\n 'uiComponent',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_Checkout/js/model/customer-email-validator'\n ],\n function (Component, additionalValidators, agreementValidator) {\n 'use strict';\n\n additionalValidators.registerValidator(agreementValidator);\n\n return Component.extend({});\n }\n);\n","Magento_Checkout/js/view/payment/list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'ko',\n 'mageUtils',\n 'uiComponent',\n 'Magento_Checkout/js/model/payment/method-list',\n 'Magento_Checkout/js/model/payment/renderer-list',\n 'uiLayout',\n 'Magento_Checkout/js/model/checkout-data-resolver',\n 'mage/translate',\n 'uiRegistry'\n], function (_, ko, utils, Component, paymentMethods, rendererList, layout, checkoutDataResolver, $t, registry) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/payment-methods/list',\n visible: paymentMethods().length > 0,\n configDefaultGroup: {\n name: 'methodGroup',\n component: 'Magento_Checkout/js/model/payment/method-group'\n },\n paymentGroupsList: [],\n defaultGroupTitle: $t('Select a new payment method')\n },\n\n /**\n * Initialize view.\n *\n * @returns {Component} Chainable.\n */\n initialize: function () {\n this._super().initDefaulGroup().initChildren();\n paymentMethods.subscribe(\n function (changes) {\n checkoutDataResolver.resolvePaymentMethod();\n //remove renderer for \"deleted\" payment methods\n _.each(changes, function (change) {\n if (change.status === 'deleted') {\n this.removeRenderer(change.value.method);\n }\n }, this);\n //add renderer for \"added\" payment methods\n _.each(changes, function (change) {\n if (change.status === 'added') {\n this.createRenderer(change.value);\n }\n }, this);\n }, this, 'arrayChange');\n\n return this;\n },\n\n /** @inheritdoc */\n initObservable: function () {\n this._super().\n observe(['paymentGroupsList']);\n\n return this;\n },\n\n /**\n * Creates default group\n *\n * @returns {Component} Chainable.\n */\n initDefaulGroup: function () {\n layout([\n this.configDefaultGroup\n ]);\n\n return this;\n },\n\n /**\n * Create renders for child payment methods.\n *\n * @returns {Component} Chainable.\n */\n initChildren: function () {\n var self = this;\n\n _.each(paymentMethods(), function (paymentMethodData) {\n self.createRenderer(paymentMethodData);\n });\n\n return this;\n },\n\n /**\n * @returns\n */\n createComponent: function (payment) {\n var rendererTemplate,\n rendererComponent,\n templateData;\n\n templateData = {\n parentName: this.name,\n name: payment.name\n };\n rendererTemplate = {\n parent: '${ $.$data.parentName }',\n name: '${ $.$data.name }',\n displayArea: payment.displayArea,\n component: payment.component\n };\n rendererComponent = utils.template(rendererTemplate, templateData);\n utils.extend(rendererComponent, {\n item: payment.item,\n config: payment.config\n });\n\n return rendererComponent;\n },\n\n /**\n * Create renderer.\n *\n * @param {Object} paymentMethodData\n */\n createRenderer: function (paymentMethodData) {\n var isRendererForMethod = false,\n currentGroup;\n\n registry.get(this.configDefaultGroup.name, function (defaultGroup) {\n _.each(rendererList(), function (renderer) {\n\n if (renderer.hasOwnProperty('typeComparatorCallback') &&\n typeof renderer.typeComparatorCallback == 'function'\n ) {\n isRendererForMethod = renderer.typeComparatorCallback(renderer.type, paymentMethodData.method);\n } else {\n isRendererForMethod = renderer.type === paymentMethodData.method;\n }\n\n if (isRendererForMethod) {\n currentGroup = renderer.group ? renderer.group : defaultGroup;\n\n this.collectPaymentGroups(currentGroup);\n\n layout([\n this.createComponent(\n {\n config: renderer.config,\n component: renderer.component,\n name: renderer.type,\n method: paymentMethodData.method,\n item: paymentMethodData,\n displayArea: currentGroup.displayArea\n }\n )]);\n }\n }.bind(this));\n }.bind(this));\n },\n\n /**\n * Collects unique groups of available payment methods\n *\n * @param {Object} group\n */\n collectPaymentGroups: function (group) {\n var groupsList = this.paymentGroupsList(),\n isGroupExists = _.some(groupsList, function (existsGroup) {\n return existsGroup.alias === group.alias;\n });\n\n if (!isGroupExists) {\n groupsList.push(group);\n groupsList = _.sortBy(groupsList, function (existsGroup) {\n return existsGroup.sortOrder;\n });\n this.paymentGroupsList(groupsList);\n }\n },\n\n /**\n * Returns payment group title\n *\n * @param {Object} group\n * @returns {String}\n */\n getGroupTitle: function (group) {\n var title = group().title;\n\n if (group().isDefault() && this.paymentGroupsList().length > 1) {\n title = this.defaultGroupTitle;\n }\n\n return title;\n },\n\n /**\n * Checks if at least one payment method available\n *\n * @returns {String}\n */\n isPaymentMethodsAvailable: function () {\n return _.some(this.paymentGroupsList(), function (group) {\n return this.regionHasElements(group.displayArea);\n }, this);\n },\n\n /**\n * Remove view renderer.\n *\n * @param {String} paymentMethodCode\n */\n removeRenderer: function (paymentMethodCode) {\n var items;\n\n _.each(this.paymentGroupsList(), function (group) {\n items = this.getRegion(group.displayArea);\n\n _.find(items(), function (value) {\n if (value.item.method.indexOf(paymentMethodCode) === 0) {\n value.disposeSubscriptions();\n value.destroy();\n }\n });\n }, this);\n }\n });\n});\n","Magento_Checkout/js/view/configure/product-customer-data.js":"require([\n 'jquery',\n 'Magento_Customer/js/customer-data',\n 'underscore',\n 'domReady!'\n], function ($, customerData, _) {\n 'use strict';\n\n var selectors = {\n qtySelector: '#product_addtocart_form [name=\"qty\"]',\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 productQty,\n productQtyInput,\n\n /**\n * Updates product's qty input value according to actual data\n */\n updateQty = function () {\n\n if (productQty || productQty === 0) {\n productQtyInput = productQtyInput || $(selectors.qtySelector);\n\n if (productQtyInput && productQty.toString() !== productQtyInput.val()) {\n productQtyInput.val(productQty);\n }\n }\n },\n\n /**\n * Sets productQty according to cart data from customer-data\n *\n * @param {Object} data - cart data from customer-data\n */\n setProductQty = function (data) {\n var product;\n\n if (!(data && data.items && data.items.length && productId)) {\n return;\n }\n product = _.find(data.items, function (item) {\n if (item['item_id'] === itemId) {\n return item['product_id'] === productId ||\n item['item_id'] === productId;\n }\n });\n\n if (!product) {\n return;\n }\n productQty = product.qty;\n };\n\n cartData.subscribe(function (updateCartData) {\n setProductQty(updateCartData);\n updateQty();\n });\n\n setProductQty(cartData());\n updateQty();\n});\n","Magento_Checkout/js/view/shipping-address/list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'ko',\n 'mageUtils',\n 'uiComponent',\n 'uiLayout',\n 'Magento_Customer/js/model/address-list'\n], function (_, ko, utils, Component, layout, addressList) {\n 'use strict';\n\n var defaultRendererTemplate = {\n parent: '${ $.$data.parentName }',\n name: '${ $.$data.name }',\n component: 'Magento_Checkout/js/view/shipping-address/address-renderer/default',\n provider: 'checkoutProvider'\n };\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/shipping-address/list',\n visible: addressList().length > 0,\n rendererTemplates: []\n },\n\n /** @inheritdoc */\n initialize: function () {\n this._super()\n .initChildren();\n\n addressList.subscribe(function (changes) {\n var self = this;\n\n changes.forEach(function (change) {\n if (change.status === 'added') {\n self.createRendererComponent(change.value, change.index);\n }\n });\n },\n this,\n 'arrayChange'\n );\n\n return this;\n },\n\n /** @inheritdoc */\n initConfig: function () {\n this._super();\n // the list of child components that are responsible for address rendering\n this.rendererComponents = [];\n\n return this;\n },\n\n /** @inheritdoc */\n initChildren: function () {\n _.each(addressList(), this.createRendererComponent, this);\n\n return this;\n },\n\n /**\n * Create new component that will render given address in the address list\n *\n * @param {Object} address\n * @param {*} index\n */\n createRendererComponent: function (address, index) {\n var rendererTemplate, templateData, rendererComponent;\n\n if (index in this.rendererComponents) {\n this.rendererComponents[index].address(address);\n } else {\n // rendererTemplates are provided via layout\n rendererTemplate = address.getType() != undefined && this.rendererTemplates[address.getType()] != undefined ? //eslint-disable-line\n utils.extend({}, defaultRendererTemplate, this.rendererTemplates[address.getType()]) :\n defaultRendererTemplate;\n templateData = {\n parentName: this.name,\n name: index\n };\n rendererComponent = utils.template(rendererTemplate, templateData);\n utils.extend(rendererComponent, {\n address: ko.observable(address)\n });\n layout([rendererComponent]);\n this.rendererComponents[index] = rendererComponent;\n }\n }\n });\n});\n","Magento_Checkout/js/view/shipping-address/address-renderer/default.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'ko',\n 'uiComponent',\n 'underscore',\n 'Magento_Checkout/js/action/select-shipping-address',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/shipping-address/form-popup-state',\n 'Magento_Checkout/js/checkout-data',\n 'Magento_Customer/js/customer-data'\n], function ($, ko, Component, _, selectShippingAddressAction, quote, formPopUpState, checkoutData, customerData) {\n 'use strict';\n\n var countryData = customerData.get('directory-data');\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/shipping-address/address-renderer/default'\n },\n\n /** @inheritdoc */\n initObservable: function () {\n this._super();\n this.isSelected = ko.computed(function () {\n var isSelected = false,\n shippingAddress = quote.shippingAddress();\n\n if (shippingAddress) {\n isSelected = shippingAddress.getKey() == this.address().getKey(); //eslint-disable-line eqeqeq\n }\n\n return isSelected;\n }, this);\n\n return this;\n },\n\n /**\n * @param {String} countryId\n * @return {String}\n */\n getCountryName: function (countryId) {\n return countryData()[countryId] != undefined ? countryData()[countryId].name : ''; //eslint-disable-line\n },\n\n /**\n * Get customer attribute label\n *\n * @param {*} attribute\n * @returns {*}\n */\n getCustomAttributeLabel: function (attribute) {\n var label;\n\n if (typeof attribute === 'string') {\n return attribute;\n }\n\n if (attribute.label) {\n return attribute.label;\n }\n\n if (_.isArray(attribute.value)) {\n label = _.map(attribute.value, function (value) {\n return this.getCustomAttributeOptionLabel(attribute['attribute_code'], value) || value;\n }, this).join(', ');\n } else if (typeof attribute.value === 'object') {\n label = _.map(Object.values(attribute.value)).join(', ');\n } else {\n label = this.getCustomAttributeOptionLabel(attribute['attribute_code'], attribute.value);\n }\n\n return label || attribute.value;\n },\n\n /**\n * Get option label for given attribute code and option ID\n *\n * @param {String} attributeCode\n * @param {String} value\n * @returns {String|null}\n */\n getCustomAttributeOptionLabel: function (attributeCode, value) {\n var option,\n label,\n options = this.source.get('customAttributes') || {};\n\n if (options[attributeCode]) {\n option = _.findWhere(options[attributeCode], {\n value: value\n });\n\n if (option) {\n label = option.label;\n }\n } else if (value.file !== null) {\n label = value.file;\n }\n\n return label;\n },\n\n /** Set selected customer shipping address */\n selectAddress: function () {\n selectShippingAddressAction(this.address());\n checkoutData.setSelectedShippingAddress(this.address().getKey());\n },\n\n /**\n * Edit address.\n */\n editAddress: function () {\n formPopUpState.isVisible(true);\n this.showPopup();\n\n },\n\n /**\n * Show popup.\n */\n showPopup: function () {\n $('[data-open-modal=\"opc-new-shipping-address\"]').trigger('click');\n }\n });\n});\n","Magento_Checkout/js/view/shipping-information/list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'ko',\n 'mageUtils',\n 'uiComponent',\n 'uiLayout',\n 'Magento_Checkout/js/model/quote'\n], function ($, ko, utils, Component, layout, quote) {\n 'use strict';\n\n var defaultRendererTemplate = {\n parent: '${ $.$data.parentName }',\n name: '${ $.$data.name }',\n component: 'Magento_Checkout/js/view/shipping-information/address-renderer/default',\n provider: 'checkoutProvider'\n };\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/shipping-information/list',\n rendererTemplates: {}\n },\n\n /** @inheritdoc */\n initialize: function () {\n var self = this;\n\n this._super()\n .initChildren();\n\n quote.shippingAddress.subscribe(function (address) {\n self.createRendererComponent(address);\n });\n\n return this;\n },\n\n /** @inheritdoc */\n initConfig: function () {\n this._super();\n // the list of child components that are responsible for address rendering\n this.rendererComponents = {};\n\n return this;\n },\n\n /** @inheritdoc */\n initChildren: function () {\n return this;\n },\n\n /**\n * Create new component that will render given address in the address list\n *\n * @param {Object} address\n */\n createRendererComponent: function (address) {\n var rendererTemplate, templateData, rendererComponent;\n\n $.each(this.rendererComponents, function (index, component) {\n component.visible(false);\n });\n\n if (this.rendererComponents[address.getType()]) {\n this.rendererComponents[address.getType()].address(address);\n this.rendererComponents[address.getType()].visible(true);\n } else {\n // rendererTemplates are provided via layout\n rendererTemplate = address.getType() != undefined && this.rendererTemplates[address.getType()] != undefined ? //eslint-disable-line\n utils.extend({}, defaultRendererTemplate, this.rendererTemplates[address.getType()]) :\n defaultRendererTemplate;\n templateData = {\n parentName: this.name,\n name: address.getType()\n };\n\n rendererComponent = utils.template(rendererTemplate, templateData);\n utils.extend(\n rendererComponent,\n {\n address: ko.observable(address),\n visible: ko.observable(true)\n }\n );\n layout([rendererComponent]);\n this.rendererComponents[address.getType()] = rendererComponent;\n }\n }\n });\n});\n","Magento_Checkout/js/view/shipping-information/address-renderer/default.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'underscore',\n 'Magento_Customer/js/customer-data'\n], function (Component, _, customerData) {\n 'use strict';\n\n var countryData = customerData.get('directory-data');\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/shipping-information/address-renderer/default'\n },\n\n /**\n * @param {*} countryId\n * @return {String}\n */\n getCountryName: function (countryId) {\n return countryData()[countryId] != undefined ? countryData()[countryId].name : ''; //eslint-disable-line\n },\n\n /**\n * Get customer attribute label\n *\n * @param {*} attribute\n * @returns {*}\n */\n getCustomAttributeLabel: function (attribute) {\n var label;\n\n if (typeof attribute === 'string') {\n return attribute;\n }\n\n if (attribute.label) {\n return attribute.label;\n }\n\n if (_.isArray(attribute.value)) {\n label = _.map(attribute.value, function (value) {\n return this.getCustomAttributeOptionLabel(attribute['attribute_code'], value) || value;\n }, this).join(', ');\n } else if (typeof attribute.value === 'object') {\n label = _.map(Object.values(attribute.value)).join(', ');\n } else {\n label = this.getCustomAttributeOptionLabel(attribute['attribute_code'], attribute.value);\n }\n\n return label || attribute.value;\n },\n\n /**\n * Get option label for given attribute code and option ID\n *\n * @param {String} attributeCode\n * @param {String} value\n * @returns {String|null}\n */\n getCustomAttributeOptionLabel: function (attributeCode, value) {\n var option,\n label,\n options = this.source.get('customAttributes') || {};\n\n if (options[attributeCode]) {\n option = _.findWhere(options[attributeCode], {\n value: value\n });\n\n if (option) {\n label = option.label;\n }\n } else if (value.file !== null) {\n label = value.file;\n }\n\n return label;\n }\n });\n});\n","Magento_Checkout/js/view/summary/cart-items.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'Magento_Checkout/js/model/totals',\n 'uiComponent',\n 'Magento_Checkout/js/model/step-navigator',\n 'Magento_Checkout/js/model/quote'\n], function (ko, totals, Component, stepNavigator, quote) {\n 'use strict';\n\n var useQty = window.checkoutConfig.useQty;\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/summary/cart-items'\n },\n totals: totals.totals(),\n items: ko.observable([]),\n maxCartItemsToDisplay: window.checkoutConfig.maxCartItemsToDisplay,\n cartUrl: window.checkoutConfig.cartUrl,\n\n /**\n * @deprecated Please use observable property (this.items())\n */\n getItems: totals.getItems(),\n\n /**\n * Returns cart items qty\n *\n * @returns {Number}\n */\n getItemsQty: function () {\n return parseFloat(this.totals['items_qty']);\n },\n\n /**\n * Returns count of cart line items\n *\n * @returns {Number}\n */\n getCartLineItemsCount: function () {\n return parseInt(totals.getItems()().length, 10);\n },\n\n /**\n * Returns shopping cart items summary (includes config settings)\n *\n * @returns {Number}\n */\n getCartSummaryItemsCount: function () {\n return useQty ? this.getItemsQty() : this.getCartLineItemsCount();\n },\n\n /**\n * @inheritdoc\n */\n initialize: function () {\n this._super();\n // Set initial items to observable field\n this.setItems(totals.getItems()());\n // Subscribe for items data changes and refresh items in view\n totals.getItems().subscribe(function (items) {\n this.setItems(items);\n }.bind(this));\n },\n\n /**\n * Set items to observable field\n *\n * @param {Object} items\n */\n setItems: function (items) {\n if (items && items.length > 0) {\n items = items.slice(parseInt(-this.maxCartItemsToDisplay, 10));\n }\n this.items(items);\n },\n\n /**\n * Returns bool value for items block state (expanded or not)\n *\n * @returns {*|Boolean}\n */\n isItemsBlockExpanded: function () {\n return quote.isVirtual() || stepNavigator.isProcessed('shipping');\n }\n });\n});\n","Magento_Checkout/js/view/summary/abstract-total.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Catalog/js/price-utils',\n 'Magento_Checkout/js/model/totals',\n 'Magento_Checkout/js/model/step-navigator'\n], function (Component, quote, priceUtils, totals, stepNavigator) {\n 'use strict';\n\n return Component.extend({\n /**\n * @param {*} price\n * @return {*|String}\n */\n getFormattedPrice: function (price) {\n return priceUtils.formatPriceLocale(price, quote.getPriceFormat());\n },\n\n /**\n * @return {*}\n */\n getTotals: function () {\n return totals.totals();\n },\n\n /**\n * @return {*}\n */\n isFullMode: function () {\n if (!this.getTotals()) {\n return false;\n }\n\n return stepNavigator.isProcessed('shipping');\n }\n });\n});\n","Magento_Checkout/js/view/summary/subtotal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\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 return Component.extend({\n defaults: {\n template: 'Magento_Checkout/summary/subtotal'\n },\n\n /**\n * Get pure value.\n *\n * @return {*}\n */\n getPureValue: function () {\n var totals = quote.getTotals()();\n\n if (totals) {\n return totals.subtotal;\n }\n\n return quote.subtotal;\n },\n\n /**\n * @return {*|String}\n */\n getValue: function () {\n return this.getFormattedPrice(this.getPureValue());\n }\n\n });\n});\n","Magento_Checkout/js/view/summary/totals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Checkout/js/view/summary/abstract-total'\n], function (Component) {\n 'use strict';\n\n return Component.extend({\n /**\n * @return {*}\n */\n isDisplayed: function () {\n return this.isFullMode();\n }\n });\n});\n","Magento_Checkout/js/view/summary/shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'underscore',\n 'Magento_Checkout/js/view/summary/abstract-total',\n 'Magento_Checkout/js/model/quote',\n 'Magento_SalesRule/js/view/summary/discount'\n], function ($, _, Component, quote, discountView) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/summary/shipping'\n },\n quoteIsVirtual: quote.isVirtual(),\n totals: quote.getTotals(),\n\n /**\n * @return {*}\n */\n getShippingMethodTitle: function () {\n var shippingMethod,\n shippingMethodTitle = '';\n\n if (!this.isCalculated()) {\n return '';\n }\n shippingMethod = quote.shippingMethod();\n\n if (!_.isArray(shippingMethod) && !_.isObject(shippingMethod)) {\n return '';\n }\n\n if (typeof shippingMethod['method_title'] !== 'undefined') {\n shippingMethodTitle = ' - ' + shippingMethod['method_title'];\n }\n\n return shippingMethodTitle ?\n shippingMethod['carrier_title'] + shippingMethodTitle :\n shippingMethod['carrier_title'];\n },\n\n /**\n * @return {*|Boolean}\n */\n isCalculated: function () {\n return this.totals() && this.isFullMode() && quote.shippingMethod() != null; //eslint-disable-line eqeqeq\n },\n\n /**\n * @return {*}\n */\n getValue: 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 * If is set coupon code, but there wasn't displayed discount view.\n *\n * @return {Boolean}\n */\n haveToShowCoupon: function () {\n var couponCode = this.totals()['coupon_code'];\n\n if (typeof couponCode === 'undefined') {\n couponCode = false;\n }\n\n return couponCode && !discountView().isDisplayed();\n },\n\n /**\n * Returns coupon code description.\n *\n * @return {String}\n */\n getCouponDescription: function () {\n if (!this.haveToShowCoupon()) {\n return '';\n }\n\n return '(' + this.totals()['coupon_code'] + ')';\n }\n });\n});\n","Magento_Checkout/js/view/summary/grand-total.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\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 return Component.extend({\n defaults: {\n template: 'Magento_Checkout/summary/grand-total'\n },\n\n /**\n * @return {*}\n */\n isDisplayed: function () {\n return this.isFullMode();\n },\n\n /**\n * Get pure value.\n */\n getPureValue: function () {\n var totals = quote.getTotals()();\n\n if (totals) {\n return totals['grand_total'];\n }\n\n return quote['grand_total'];\n },\n\n /**\n * @return {*|String}\n */\n getValue: function () {\n return this.getFormattedPrice(this.getPureValue());\n }\n });\n});\n","Magento_Checkout/js/view/summary/item/details.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'escaper'\n], function (Component, escaper) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/summary/item/details',\n allowedTags: ['b', 'strong', 'i', 'em', 'u']\n },\n\n /**\n * @param {Object} quoteItem\n * @return {String}\n */\n getNameUnsanitizedHtml: function (quoteItem) {\n var txt = document.createElement('textarea');\n\n txt.innerHTML = quoteItem.name;\n\n return escaper.escapeHtml(txt.value, this.allowedTags);\n },\n\n /**\n * @param {Object} quoteItem\n * @return {String}Magento_Checkout/js/region-updater\n */\n getValue: function (quoteItem) {\n return quoteItem.name;\n }\n });\n});\n","Magento_Checkout/js/view/summary/item/details/message.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['uiComponent'], function (Component) {\n 'use strict';\n\n var quoteMessages = window.checkoutConfig.quoteMessages;\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/summary/item/details/message'\n },\n displayArea: 'item_message',\n quoteMessages: quoteMessages,\n\n /**\n * @param {Object} item\n * @return {null}\n */\n getMessage: function (item) {\n if (this.quoteMessages[item['item_id']]) {\n return this.quoteMessages[item['item_id']];\n }\n\n return null;\n }\n });\n});\n","Magento_Checkout/js/view/summary/item/details/thumbnail.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['uiComponent'], function (Component) {\n 'use strict';\n\n var imageData = window.checkoutConfig.imageData;\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/summary/item/details/thumbnail'\n },\n displayArea: 'before_details',\n imageData: imageData,\n\n /**\n * @param {Object} item\n * @return {Array}\n */\n getImageItem: function (item) {\n if (this.imageData[item['item_id']]) {\n return this.imageData[item['item_id']];\n }\n\n return [];\n },\n\n /**\n * @param {Object} item\n * @return {null}\n */\n getSrc: function (item) {\n if (this.imageData[item['item_id']]) {\n return this.imageData[item['item_id']].src;\n }\n\n return null;\n },\n\n /**\n * @param {Object} item\n * @return {null}\n */\n getWidth: function (item) {\n if (this.imageData[item['item_id']]) {\n return this.imageData[item['item_id']].width;\n }\n\n return null;\n },\n\n /**\n * @param {Object} item\n * @return {null}\n */\n getHeight: function (item) {\n if (this.imageData[item['item_id']]) {\n return this.imageData[item['item_id']].height;\n }\n\n return null;\n },\n\n /**\n * @param {Object} item\n * @return {null}\n */\n getAlt: function (item) {\n if (this.imageData[item['item_id']]) {\n return this.imageData[item['item_id']].alt;\n }\n\n return null;\n }\n });\n});\n","Magento_Checkout/js/view/summary/item/details/subtotal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Checkout/js/view/summary/abstract-total'\n], function (viewModel) {\n 'use strict';\n\n return viewModel.extend({\n defaults: {\n displayArea: 'after_details',\n template: 'Magento_Checkout/summary/item/details/subtotal'\n },\n\n /**\n * @param {Object} quoteItem\n * @return {*|String}\n */\n getValue: function (quoteItem) {\n return this.getFormattedPrice(quoteItem['row_total']);\n }\n });\n});\n","Magento_Checkout/js/view/checkout/placeOrderCaptcha.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Captcha/js/view/checkout/defaultCaptcha',\n 'Magento_Captcha/js/model/captchaList',\n 'underscore',\n 'Magento_Checkout/js/model/payment/place-order-hooks'\n],\nfunction (defaultCaptcha, captchaList, _, placeOrderHooks) {\n 'use strict';\n\n return defaultCaptcha.extend({\n /** @inheritdoc */\n initialize: function () {\n var self = this,\n currentCaptcha;\n\n this._super();\n currentCaptcha = captchaList.getCaptchaByFormId(this.formId);\n if (currentCaptcha != null) {\n currentCaptcha.setIsVisible(true);\n this.setCurrentCaptcha(currentCaptcha);\n placeOrderHooks.requestModifiers.push(function (headers) {\n if (self.isRequired()) {\n headers['X-Captcha'] = self.captchaValue()();\n }\n });\n if (self.isRequired()) {\n placeOrderHooks.afterRequestListeners.push(function () {\n self.refresh();\n });\n }\n }\n }\n });\n});\n","Magento_Checkout/js/view/checkout/minicart/subtotal/totals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\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_Checkout/js/view/billing-address/list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiComponent',\n 'Magento_Customer/js/model/address-list',\n 'mage/translate',\n 'Magento_Customer/js/model/customer'\n], function (Component, addressList, $t, customer) {\n 'use strict';\n\n var newAddressOption = {\n /**\n * Get new address label\n * @returns {String}\n */\n getAddressInline: function () {\n return $t('New Address');\n },\n customerAddressId: null\n },\n addressOptions = addressList().filter(function (address) {\n return address.getType() === 'customer-address';\n }),\n addressDefaultIndex = addressOptions.findIndex(function (address) {\n return address.isDefaultBilling();\n });\n\n return Component.extend({\n defaults: {\n template: 'Magento_Checkout/billing-address',\n selectedAddress: null,\n isNewAddressSelected: false,\n addressOptions: addressOptions,\n exports: {\n selectedAddress: '${ $.parentName }:selectedAddress'\n }\n },\n\n /**\n * @returns {Object} Chainable.\n */\n initConfig: function () {\n this._super();\n this.addressOptions.push(newAddressOption);\n\n return this;\n },\n\n /**\n * @return {exports.initObservable}\n */\n initObservable: function () {\n this._super()\n .observe('selectedAddress isNewAddressSelected')\n .observe({\n isNewAddressSelected: !customer.isLoggedIn() || !addressOptions.length,\n selectedAddress: this.addressOptions[addressDefaultIndex]\n });\n\n return this;\n },\n\n /**\n * @param {Object} address\n * @return {*}\n */\n addressOptionsText: function (address) {\n return address.getAddressInline();\n },\n\n /**\n * @param {Object} address\n */\n onAddressChange: function (address) {\n this.isNewAddressSelected(address === newAddressOption);\n }\n });\n});\n","Magento_Checkout/js/model/shipping-rates-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 'jquery',\n 'ko',\n './shipping-rates-validation-rules',\n '../model/address-converter',\n '../action/select-shipping-address',\n './postcode-validator',\n './default-validator',\n 'mage/translate',\n 'uiRegistry',\n 'Magento_Checkout/js/model/shipping-address/form-popup-state',\n 'Magento_Checkout/js/model/shipping-service',\n 'Magento_Checkout/js/model/quote'\n], function (\n $,\n ko,\n shippingRatesValidationRules,\n addressConverter,\n selectShippingAddress,\n postcodeValidator,\n defaultValidator,\n $t,\n uiRegistry,\n formPopUpState,\n shippingService\n) {\n 'use strict';\n\n var checkoutConfig = window.checkoutConfig,\n validators = [],\n observedElements = [],\n postcodeElements = [],\n postcodeElementName = 'postcode';\n\n validators.push(defaultValidator);\n\n return {\n validateAddressTimeout: 0,\n validateZipCodeTimeout: 0,\n validateDelay: 2000,\n\n /**\n * @param {String} carrier\n * @param {Object} validator\n */\n registerValidator: function (carrier, validator) {\n if (checkoutConfig.activeCarriers.indexOf(carrier) !== -1) {\n validators.push(validator);\n }\n },\n\n /**\n * @param {Object} address\n * @return {Boolean}\n */\n validateAddressData: function (address) {\n return validators.some(function (validator) {\n return validator.validate(address);\n });\n },\n\n /**\n * Perform postponed binding for fieldset elements\n *\n * @param {String} formPath\n */\n initFields: function (formPath) {\n var self = this,\n elements = shippingRatesValidationRules.getObservableFields();\n\n if ($.inArray(postcodeElementName, elements) === -1) {\n // Add postcode field to observables if not exist for zip code validation support\n elements.push(postcodeElementName);\n }\n\n $.each(elements, function (index, field) {\n uiRegistry.async(formPath + '.' + field)(self.doElementBinding.bind(self));\n });\n },\n\n /**\n * Bind shipping rates request to form element\n *\n * @param {Object} element\n * @param {Boolean} force\n * @param {Number} delay\n */\n doElementBinding: function (element, force, delay) {\n var observableFields = shippingRatesValidationRules.getObservableFields();\n\n if (element && (observableFields.indexOf(element.index) !== -1 || force)) {\n if (element.index !== postcodeElementName) {\n this.bindHandler(element, delay);\n }\n }\n\n if (element.index === postcodeElementName) {\n this.bindHandler(element, delay);\n postcodeElements.push(element);\n }\n },\n\n /**\n * @param {*} elements\n * @param {Boolean} force\n * @param {Number} delay\n */\n bindChangeHandlers: function (elements, force, delay) {\n var self = this;\n\n $.each(elements, function (index, elem) {\n self.doElementBinding(elem, force, delay);\n });\n },\n\n /**\n * @param {Object} element\n * @param {Number} delay\n */\n bindHandler: 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 self.bindHandler(elem);\n });\n } else {\n element.on('value', function () {\n clearTimeout(self.validateZipCodeTimeout);\n self.validateZipCodeTimeout = setTimeout(function () {\n if (element.index === postcodeElementName) {\n self.postcodeValidation(element);\n } else {\n $.each(postcodeElements, function (index, elem) {\n self.postcodeValidation(elem);\n });\n }\n }, delay);\n\n if (!formPopUpState.isVisible()) {\n // Prevent shipping methods showing none available whilst we resolve\n shippingService.isLoading(true);\n clearTimeout(self.validateAddressTimeout);\n self.validateAddressTimeout = setTimeout(function () {\n self.validateFields();\n }, delay);\n }\n });\n observedElements.push(element);\n }\n },\n\n /**\n * @return {*}\n */\n postcodeValidation: function (postcodeElement) {\n var countryId = $('select[name=\"country_id\"]:visible').val(),\n validationResult,\n warnMessage;\n\n if (postcodeElement == null || postcodeElement.value() == null) {\n return true;\n }\n\n postcodeElement.warn(null);\n validationResult = postcodeValidator.validate(postcodeElement.value(), countryId);\n\n if (!validationResult) {\n warnMessage = $t('Provided Zip/Postal Code seems to be invalid.');\n\n if (postcodeValidator.validatedPostCodeExample.length) {\n warnMessage += $t(' Example: ') + postcodeValidator.validatedPostCodeExample.join('; ') + '. ';\n }\n warnMessage += $t('If you believe it is the right one you can ignore this notice.');\n postcodeElement.warn(warnMessage);\n }\n\n return validationResult;\n },\n\n /**\n * Convert form data to quote address and validate fields for shipping rates\n */\n validateFields: function () {\n var addressFlat = addressConverter.formDataProviderToFlatData(\n this.collectObservedData(),\n 'shippingAddress'\n ),\n address;\n\n if (this.validateAddressData(addressFlat)) {\n addressFlat = uiRegistry.get('checkoutProvider').shippingAddress;\n address = addressConverter.formAddressDataToQuoteAddress(addressFlat);\n selectShippingAddress(address);\n }\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 observedValues[field.dataScope] = field.value();\n });\n\n return observedValues;\n }\n };\n});\n","Magento_Checkout/js/model/shipping-rate-service.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/shipping-rate-processor/new-address',\n 'Magento_Checkout/js/model/shipping-rate-processor/customer-address'\n], function (quote, defaultProcessor, customerAddressProcessor) {\n 'use strict';\n\n var processors = {};\n\n processors.default = defaultProcessor;\n processors['customer-address'] = customerAddressProcessor;\n\n quote.shippingAddress.subscribe(function () {\n var type = quote.shippingAddress().getType();\n\n if (processors[type]) {\n processors[type].getRates(quote.shippingAddress());\n } else {\n processors.default.getRates(quote.shippingAddress());\n }\n });\n\n return {\n /**\n * @param {String} type\n * @param {*} processor\n */\n registerProcessor: function (type, processor) {\n processors[type] = processor;\n }\n };\n});\n","Magento_Checkout/js/model/payment-service.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/payment/method-list',\n 'Magento_Checkout/js/action/select-payment-method'\n], function (_, quote, methodList, selectPaymentMethod) {\n 'use strict';\n\n /**\n * Free method filter\n * @param {Object} paymentMethod\n * @return {Boolean}\n */\n var isFreePaymentMethod = function (paymentMethod) {\n return paymentMethod.method === 'free';\n },\n\n /**\n * Grabs the grand total from quote\n * @return {Number}\n */\n getGrandTotal = function () {\n return quote.totals()['grand_total'];\n };\n\n return {\n isFreeAvailable: false,\n\n /**\n * Populate the list of payment methods\n * @param {Array} methods\n */\n setPaymentMethods: function (methods) {\n var freeMethod,\n filteredMethods,\n methodIsAvailable,\n methodNames;\n\n freeMethod = _.find(methods, isFreePaymentMethod);\n this.isFreeAvailable = !!freeMethod;\n\n if (freeMethod && getGrandTotal() <= 0) {\n methods.splice(0, methods.length, freeMethod);\n selectPaymentMethod(freeMethod);\n }\n\n filteredMethods = _.without(methods, freeMethod);\n if (filteredMethods.length === 1) {\n selectPaymentMethod(filteredMethods[0]);\n } else if (quote.paymentMethod()) {\n methodIsAvailable = methods.some(function (item) {\n return item.method === quote.paymentMethod().method;\n });\n\n if (!methodIsAvailable && !_.isEmpty(window.checkoutConfig.vault)) {\n methodIsAvailable = Object.keys(window.checkoutConfig.payment.vault)\n .findIndex((vaultPayment) => vaultPayment === quote.paymentMethod().method) !== -1;\n }\n\n //Unset selected payment method if not available\n if (!methodIsAvailable) {\n selectPaymentMethod(null);\n }\n }\n\n /**\n * Overwrite methods with existing methods to preserve ko array references.\n * This prevent ko from re-rendering those methods.\n */\n methodNames = _.pluck(methods, 'method');\n _.map(methodList(), function (existingMethod) {\n var existingMethodIndex = methodNames.indexOf(existingMethod.method);\n\n if (existingMethodIndex !== -1) {\n methods[existingMethodIndex] = existingMethod;\n }\n });\n\n methodList(methods);\n },\n\n /**\n * Get the list of available payment methods.\n * @return {Array}\n */\n getAvailablePaymentMethods: function () {\n var allMethods = methodList().slice(),\n grandTotalOverZero = getGrandTotal() > 0;\n\n if (!this.isFreeAvailable) {\n return allMethods;\n }\n\n if (grandTotalOverZero) {\n return _.reject(allMethods, isFreePaymentMethod);\n }\n\n return _.filter(allMethods, isFreePaymentMethod);\n }\n };\n});\n","Magento_Checkout/js/model/shipping-rates-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(['jquery'], function ($) {\n 'use strict';\n\n var ratesRules = {},\n checkoutConfig = window.checkoutConfig;\n\n return {\n /**\n * @param {String} carrier\n * @param {Object} rules\n */\n registerRules: function (carrier, rules) {\n if (checkoutConfig.activeCarriers.indexOf(carrier) !== -1) {\n ratesRules[carrier] = rules.getRules();\n }\n },\n\n /**\n * @return {Object}\n */\n getRules: function () {\n return ratesRules;\n },\n\n /**\n * @return {Array}\n */\n getObservableFields: function () {\n var self = this,\n observableFields = [];\n\n $.each(self.getRules(), function (carrier, fields) {\n $.each(fields, function (field) {\n if (observableFields.indexOf(field) === -1) {\n observableFields.push(field);\n }\n });\n });\n\n return observableFields;\n }\n };\n});\n","Magento_Checkout/js/model/full-screen-loader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'rjsResolver'\n], function ($, resolver) {\n 'use strict';\n\n var containerId = '#checkout';\n\n return {\n\n /**\n * Start full page loader action\n */\n startLoader: function () {\n $(containerId).trigger('processStart');\n },\n\n /**\n * Stop full page loader action\n *\n * @param {Boolean} [forceStop]\n */\n stopLoader: function (forceStop) {\n var $elem = $(containerId),\n stop = $elem.trigger.bind($elem, 'processStop'); //eslint-disable-line jquery-no-bind-unbind\n\n forceStop ? stop() : resolver(stop);\n }\n };\n});\n","Magento_Checkout/js/model/checkout-data-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Checkout adapter for customer data storage\n */\ndefine([\n 'Magento_Customer/js/model/address-list',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/checkout-data',\n 'Magento_Checkout/js/action/create-shipping-address',\n 'Magento_Checkout/js/action/select-shipping-address',\n 'Magento_Checkout/js/action/select-shipping-method',\n 'Magento_Checkout/js/model/payment-service',\n 'Magento_Checkout/js/action/select-payment-method',\n 'Magento_Checkout/js/model/address-converter',\n 'Magento_Checkout/js/action/select-billing-address',\n 'Magento_Checkout/js/action/create-billing-address',\n 'underscore'\n], function (\n addressList,\n quote,\n checkoutData,\n createShippingAddress,\n selectShippingAddress,\n selectShippingMethodAction,\n paymentService,\n selectPaymentMethodAction,\n addressConverter,\n selectBillingAddress,\n createBillingAddress,\n _\n) {\n 'use strict';\n\n var isBillingAddressResolvedFromBackend = false;\n\n return {\n\n /**\n * Resolve estimation address. Used local storage\n */\n resolveEstimationAddress: function () {\n var address;\n\n if (quote.isVirtual()) {\n if (checkoutData.getBillingAddressFromData()) {\n address = addressConverter.formAddressDataToQuoteAddress(\n checkoutData.getBillingAddressFromData()\n );\n selectBillingAddress(address);\n } else {\n this.resolveBillingAddress();\n }\n } else if (checkoutData.getShippingAddressFromData()) {\n address = addressConverter.formAddressDataToQuoteAddress(checkoutData.getShippingAddressFromData());\n selectShippingAddress(address);\n } else {\n this.resolveShippingAddress();\n }\n },\n\n /**\n * Resolve shipping address. Used local storage\n */\n resolveShippingAddress: function () {\n var newCustomerShippingAddress;\n\n if (!checkoutData.getShippingAddressFromData() &&\n window.checkoutConfig.shippingAddressFromData\n ) {\n checkoutData.setShippingAddressFromData(window.checkoutConfig.shippingAddressFromData);\n }\n\n newCustomerShippingAddress = checkoutData.getNewCustomerShippingAddress();\n\n if (newCustomerShippingAddress) {\n createShippingAddress(newCustomerShippingAddress);\n }\n this.applyShippingAddress();\n },\n\n /**\n * Apply resolved estimated address to quote\n *\n * @param {Object} isEstimatedAddress\n */\n applyShippingAddress: function (isEstimatedAddress) {\n var address,\n shippingAddress,\n isConvertAddress;\n\n if (addressList().length === 0) {\n address = addressConverter.formAddressDataToQuoteAddress(\n checkoutData.getShippingAddressFromData()\n );\n selectShippingAddress(address);\n }\n shippingAddress = quote.shippingAddress();\n isConvertAddress = isEstimatedAddress || false;\n\n if (!shippingAddress) {\n shippingAddress = this.getShippingAddressFromCustomerAddressList();\n\n if (shippingAddress) {\n selectShippingAddress(\n isConvertAddress ?\n addressConverter.addressToEstimationAddress(shippingAddress)\n : shippingAddress\n );\n }\n }\n },\n\n /**\n * @param {Object} ratesData\n */\n resolveShippingRates: function (ratesData) {\n var selectedShippingRate = checkoutData.getSelectedShippingRate(),\n availableRate = false;\n\n if (ratesData.length === 1 && !quote.shippingMethod()) {\n //set shipping rate if we have only one available shipping rate\n selectShippingMethodAction(ratesData[0]);\n\n return;\n }\n\n if (quote.shippingMethod()) {\n availableRate = _.find(ratesData, function (rate) {\n return rate['carrier_code'] == quote.shippingMethod()['carrier_code'] && //eslint-disable-line\n rate['method_code'] == quote.shippingMethod()['method_code']; //eslint-disable-line eqeqeq\n });\n }\n\n if (!availableRate && selectedShippingRate) {\n availableRate = _.find(ratesData, function (rate) {\n return rate['carrier_code'] + '_' + rate['method_code'] === selectedShippingRate;\n });\n }\n\n if (!availableRate && window.checkoutConfig.selectedShippingMethod) {\n availableRate = _.find(ratesData, function (rate) {\n var selectedShippingMethod = window.checkoutConfig.selectedShippingMethod;\n\n return rate['carrier_code'] == selectedShippingMethod['carrier_code'] && //eslint-disable-line\n rate['method_code'] == selectedShippingMethod['method_code']; //eslint-disable-line eqeqeq\n });\n }\n\n //Unset selected shipping method if not available\n if (!availableRate) {\n selectShippingMethodAction(null);\n } else {\n selectShippingMethodAction(availableRate);\n }\n },\n\n /**\n * Resolve payment method. Used local storage\n */\n resolvePaymentMethod: function () {\n var availablePaymentMethods = paymentService.getAvailablePaymentMethods(),\n selectedPaymentMethod = checkoutData.getSelectedPaymentMethod();\n\n if (selectedPaymentMethod) {\n availablePaymentMethods.some(function (payment) {\n if (payment.method == selectedPaymentMethod) { //eslint-disable-line eqeqeq\n selectPaymentMethodAction(payment);\n }\n });\n }\n },\n\n /**\n * Resolve billing address. Used local storage\n */\n resolveBillingAddress: function () {\n var selectedBillingAddress,\n newCustomerBillingAddressData;\n\n selectedBillingAddress = checkoutData.getSelectedBillingAddress();\n newCustomerBillingAddressData = checkoutData.getNewCustomerBillingAddress();\n\n if (selectedBillingAddress) {\n if (selectedBillingAddress === 'new-customer-billing-address' && newCustomerBillingAddressData) {\n selectBillingAddress(createBillingAddress(newCustomerBillingAddressData));\n } else {\n addressList.some(function (address) {\n if (selectedBillingAddress === address.getKey()) {\n selectBillingAddress(address);\n }\n });\n }\n } else {\n this.applyBillingAddress();\n }\n\n if (!isBillingAddressResolvedFromBackend &&\n !checkoutData.getBillingAddressFromData() &&\n !_.isEmpty(window.checkoutConfig.billingAddressFromData) &&\n !quote.billingAddress()\n ) {\n if (window.checkoutConfig.isBillingAddressFromDataValid === true) {\n selectBillingAddress(createBillingAddress(window.checkoutConfig.billingAddressFromData));\n } else {\n checkoutData.setBillingAddressFromData(window.checkoutConfig.billingAddressFromData);\n }\n isBillingAddressResolvedFromBackend = true;\n }\n },\n\n /**\n * Apply resolved billing address to quote\n */\n applyBillingAddress: function () {\n var shippingAddress,\n isBillingAddressInitialized;\n\n if (quote.billingAddress()) {\n selectBillingAddress(quote.billingAddress());\n\n return;\n }\n\n if (quote.isVirtual() || !quote.billingAddress()) {\n isBillingAddressInitialized = addressList.some(function (addrs) {\n if (addrs.isDefaultBilling()) {\n selectBillingAddress(addrs);\n\n return true;\n }\n\n return false;\n });\n }\n\n shippingAddress = quote.shippingAddress();\n\n if (!isBillingAddressInitialized &&\n shippingAddress &&\n shippingAddress.canUseForBilling() &&\n (shippingAddress.isDefaultShipping() || !quote.isVirtual())\n ) {\n //set billing address same as shipping by default if it is not empty\n selectBillingAddress(quote.shippingAddress());\n }\n },\n\n /**\n * Get shipping address from address list\n *\n * @return {Object|null}\n */\n getShippingAddressFromCustomerAddressList: function () {\n var shippingAddress = _.find(\n addressList(),\n function (address) {\n return checkoutData.getSelectedShippingAddress() == address.getKey() //eslint-disable-line\n }\n );\n\n if (!shippingAddress) {\n shippingAddress = _.find(\n addressList(),\n function (address) {\n return address.isDefaultShipping();\n }\n );\n }\n\n if (!shippingAddress && addressList().length === 1) {\n shippingAddress = addressList()[0];\n }\n\n return shippingAddress;\n }\n };\n});\n","Magento_Checkout/js/model/default-validation-rules.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 {\n /**\n * @return {Object}\n */\n getRules: function () {\n return {\n 'country_id': {\n 'required': true\n }\n };\n }\n };\n});\n","Magento_Checkout/js/model/shipping-save-processor.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_Checkout/js/model/shipping-save-processor/default'\n], function (defaultProcessor) {\n 'use strict';\n\n var processors = {};\n\n processors['default'] = defaultProcessor;\n\n return {\n /**\n * @param {String} type\n * @param {*} processor\n */\n registerProcessor: function (type, processor) {\n processors[type] = processor;\n },\n\n /**\n * @param {String} type\n * @return {Array}\n */\n saveShippingInformation: function (type) {\n var rates = [];\n\n if (processors[type]) {\n rates = processors[type].saveShippingInformation();\n } else {\n rates = processors['default'].saveShippingInformation();\n }\n\n return rates;\n }\n };\n});\n","Magento_Checkout/js/model/authentication-messages.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'Magento_Ui/js/model/messages'\n], function (ko, Messages) {\n 'use strict';\n\n return new Messages();\n});\n","Magento_Checkout/js/model/step-navigator.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], function ($, ko) {\n 'use strict';\n\n var steps = ko.observableArray();\n\n return {\n steps: steps,\n stepCodes: [],\n validCodes: [],\n\n /**\n * @return {Boolean}\n */\n handleHash: function () {\n var hashString = window.location.hash.replace('#', ''),\n isRequestedStepVisible;\n\n if (hashString === '') {\n return false;\n }\n\n if ($.inArray(hashString, this.validCodes) === -1) {\n window.location.href = window.checkoutConfig.pageNotFoundUrl;\n\n return false;\n }\n\n isRequestedStepVisible = steps.sort(this.sortItems).some(function (element) {\n return (element.code == hashString || element.alias == hashString) && element.isVisible(); //eslint-disable-line\n });\n\n //if requested step is visible, then we don't need to load step data from server\n if (isRequestedStepVisible) {\n return false;\n }\n\n steps().sort(this.sortItems).forEach(function (element) {\n if (element.code == hashString || element.alias == hashString) { //eslint-disable-line eqeqeq\n element.navigate(element);\n } else {\n element.isVisible(false);\n }\n\n });\n\n return false;\n },\n\n /**\n * @param {String} code\n * @param {*} alias\n * @param {*} title\n * @param {Function} isVisible\n * @param {*} navigate\n * @param {*} sortOrder\n */\n registerStep: function (code, alias, title, isVisible, navigate, sortOrder) {\n var hash, active;\n\n if ($.inArray(code, this.validCodes) !== -1) {\n throw new DOMException('Step code [' + code + '] already registered in step navigator');\n }\n\n if (alias != null) {\n if ($.inArray(alias, this.validCodes) !== -1) {\n throw new DOMException('Step code [' + alias + '] already registered in step navigator');\n }\n this.validCodes.push(alias);\n }\n this.validCodes.push(code);\n steps.push({\n code: code,\n alias: alias != null ? alias : code,\n title: title,\n isVisible: isVisible,\n navigate: navigate,\n sortOrder: sortOrder\n });\n active = this.getActiveItemIndex();\n steps.each(function (elem, index) {\n if (active !== index) {\n elem.isVisible(false);\n }\n });\n this.stepCodes.push(code);\n hash = window.location.hash.replace('#', '');\n\n if (hash != '' && hash != code) { //eslint-disable-line eqeqeq\n //Force hiding of not active step\n isVisible(false);\n }\n },\n\n /**\n * @param {Object} itemOne\n * @param {Object} itemTwo\n * @return {Number}\n */\n sortItems: function (itemOne, itemTwo) {\n return itemOne.sortOrder > itemTwo.sortOrder ? 1 : -1;\n },\n\n /**\n * @return {Number}\n */\n getActiveItemIndex: function () {\n var activeIndex = 0;\n\n steps().sort(this.sortItems).some(function (element, index) {\n if (element.isVisible()) {\n activeIndex = index;\n\n return true;\n }\n\n return false;\n });\n\n return activeIndex;\n },\n\n /**\n * @param {*} code\n * @return {Boolean}\n */\n isProcessed: function (code) {\n var activeItemIndex = this.getActiveItemIndex(),\n sortedItems = steps().sort(this.sortItems),\n requestedItemIndex = -1;\n\n sortedItems.forEach(function (element, index) {\n if (element.code == code) { //eslint-disable-line eqeqeq\n requestedItemIndex = index;\n }\n });\n\n return activeItemIndex > requestedItemIndex;\n },\n\n /**\n * @param {*} code\n * @param {*} scrollToElementId\n */\n navigateTo: function (code, scrollToElementId) {\n var sortedItems = steps().sort(this.sortItems),\n bodyElem = $('body');\n\n scrollToElementId = scrollToElementId || null;\n\n if (!this.isProcessed(code)) {\n return;\n }\n sortedItems.forEach(function (element) {\n if (element.code == code) { //eslint-disable-line eqeqeq\n element.isVisible(true);\n bodyElem.animate({\n scrollTop: $('#' + code).offset().top\n }, 0, function () {\n window.location = window.checkoutConfig.checkoutUrl + '#' + code;\n });\n\n if (scrollToElementId && $('#' + scrollToElementId).length) {\n bodyElem.animate({\n scrollTop: $('#' + scrollToElementId).offset().top\n }, 0);\n }\n } else {\n element.isVisible(false);\n }\n\n });\n },\n\n /**\n * Sets window location hash.\n *\n * @param {String} hash\n */\n setHash: function (hash) {\n window.location.hash = hash;\n },\n\n /**\n * Next step.\n */\n next: function () {\n var activeIndex = 0,\n code;\n\n steps().sort(this.sortItems).forEach(function (element, index) {\n if (element.isVisible()) {\n element.isVisible(false);\n activeIndex = index;\n }\n });\n\n if (steps().length > activeIndex + 1) {\n code = steps()[activeIndex + 1].code;\n steps()[activeIndex + 1].isVisible(true);\n this.setHash(code);\n document.body.scrollTop = document.documentElement.scrollTop = 0;\n }\n }\n };\n});\n","Magento_Checkout/js/model/place-order.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine(\n [\n 'mage/storage',\n 'Magento_Checkout/js/model/error-processor',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'Magento_Customer/js/customer-data',\n 'Magento_Checkout/js/model/payment/place-order-hooks',\n 'underscore'\n ],\n function (storage, errorProcessor, fullScreenLoader, customerData, hooks, _) {\n 'use strict';\n\n return function (serviceUrl, payload, messageContainer) {\n var headers = {}, redirectURL = '';\n\n fullScreenLoader.startLoader();\n _.each(hooks.requestModifiers, function (modifier) {\n modifier(headers, payload);\n });\n\n return storage.post(\n serviceUrl, JSON.stringify(payload), true, 'application/json', headers\n ).fail(\n function (response) {\n errorProcessor.process(response, messageContainer);\n redirectURL = response.getResponseHeader('errorRedirectAction');\n\n if (redirectURL) {\n setTimeout(function () {\n errorProcessor.redirectTo(redirectURL);\n }, 3000);\n }\n }\n ).done(\n function (response) {\n var clearData = {\n 'selectedShippingAddress': null,\n 'shippingAddressFromData': null,\n 'newCustomerShippingAddress': null,\n 'selectedShippingRate': null,\n 'selectedPaymentMethod': null,\n 'selectedBillingAddress': null,\n 'billingAddressFromData': null,\n 'newCustomerBillingAddress': null\n };\n\n if (response.responseType !== 'error') {\n customerData.set('checkout-data', clearData);\n }\n }\n ).always(\n function () {\n fullScreenLoader.stopLoader();\n _.each(hooks.afterRequestListeners, function (listener) {\n listener();\n });\n }\n );\n };\n }\n);\n","Magento_Checkout/js/model/new-customer-address.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([\n 'underscore',\n 'Magento_Checkout/js/model/default-post-code-resolver'\n], function (_, DefaultPostCodeResolver) {\n 'use strict';\n\n /**\n * @param {Object} addressData\n * Returns new address object\n */\n return function (addressData) {\n var identifier = Date.now(),\n countryId = addressData['country_id'] || addressData.countryId || window.checkoutConfig.defaultCountryId,\n regionId;\n\n if (addressData.region && addressData.region['region_id']) {\n regionId = addressData.region['region_id'];\n } else if (\n /* eslint-disable */\n addressData['country_id'] && addressData['country_id'] == window.checkoutConfig.defaultCountryId ||\n !addressData['country_id'] && countryId == window.checkoutConfig.defaultCountryId\n /* eslint-enable */\n ) {\n regionId = window.checkoutConfig.defaultRegionId || undefined;\n }\n\n return {\n email: addressData.email,\n countryId: countryId,\n regionId: regionId || addressData.regionId,\n regionCode: addressData.region ? addressData.region['region_code'] : null,\n region: addressData.region ? addressData.region.region : null,\n customerId: addressData['customer_id'] || addressData.customerId,\n street: addressData.street,\n company: addressData.company,\n telephone: addressData.telephone,\n fax: addressData.fax,\n postcode: addressData.postcode ? addressData.postcode : DefaultPostCodeResolver.resolve(),\n city: addressData.city,\n firstname: addressData.firstname,\n lastname: addressData.lastname,\n middlename: addressData.middlename,\n prefix: addressData.prefix,\n suffix: addressData.suffix,\n vatId: addressData['vat_id'],\n saveInAddressBook: addressData['save_in_address_book'],\n customAttributes: addressData['custom_attributes'],\n extensionAttributes: addressData['extension_attributes'],\n\n /**\n * @return {*}\n */\n isDefaultShipping: function () {\n return addressData['default_shipping'];\n },\n\n /**\n * @return {*}\n */\n isDefaultBilling: function () {\n return addressData['default_billing'];\n },\n\n /**\n * @return {String}\n */\n getType: function () {\n return 'new-customer-address';\n },\n\n /**\n * @return {String}\n */\n getKey: function () {\n return this.getType();\n },\n\n /**\n * @return {String}\n */\n getCacheKey: function () {\n return this.getType() + identifier;\n },\n\n /**\n * @return {Boolean}\n */\n isEditable: function () {\n return true;\n },\n\n /**\n * @return {Boolean}\n */\n canUseForBilling: function () {\n return true;\n }\n };\n };\n});\n","Magento_Checkout/js/model/shipping-service.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'Magento_Checkout/js/model/checkout-data-resolver'\n], function (ko, checkoutDataResolver) {\n 'use strict';\n\n var shippingRates = ko.observableArray([]);\n\n return {\n isLoading: ko.observable(false),\n\n /**\n * Set shipping rates\n *\n * @param {*} ratesData\n */\n setShippingRates: function (ratesData) {\n shippingRates(ratesData);\n shippingRates.valueHasMutated();\n checkoutDataResolver.resolveShippingRates(ratesData);\n },\n\n /**\n * Get shipping rates\n *\n * @returns {*}\n */\n getShippingRates: function () {\n return shippingRates;\n }\n };\n});\n","Magento_Checkout/js/model/resource-url-manager.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_Customer/js/model/customer',\n 'Magento_Checkout/js/model/url-builder',\n 'mageUtils'\n], function (customer, urlBuilder, utils) {\n 'use strict';\n\n return {\n /**\n * @param {Object} quote\n * @return {*}\n */\n getUrlForTotalsEstimationForNewAddress: function (quote) {\n var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n {\n cartId: quote.getQuoteId()\n } : {},\n urls = {\n 'guest': '/guest-carts/:cartId/totals-information',\n 'customer': '/carts/mine/totals-information'\n };\n\n return this.getUrl(urls, params);\n },\n\n /**\n * @param {Object} quote\n * @return {*}\n */\n getUrlForEstimationShippingMethodsForNewAddress: function (quote) {\n var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n {\n quoteId: quote.getQuoteId()\n } : {},\n urls = {\n 'guest': '/guest-carts/:quoteId/estimate-shipping-methods',\n 'customer': '/carts/mine/estimate-shipping-methods'\n };\n\n return this.getUrl(urls, params);\n },\n\n /**\n * @param {Object} quote\n * @return {*}\n */\n getUrlForEstimationShippingMethodsByAddressId: function (quote) {\n var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n {\n quoteId: quote.getQuoteId()\n } : {},\n urls = {\n 'default': '/carts/mine/estimate-shipping-methods-by-address-id'\n };\n\n return this.getUrl(urls, params);\n },\n\n /**\n * @param {String} couponCode\n * @param {String} quoteId\n * @return {*}\n */\n getApplyCouponUrl: function (couponCode, quoteId) {\n var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n {\n quoteId: quoteId\n } : {},\n urls = {\n 'guest': '/guest-carts/' + quoteId + '/coupons/' + encodeURIComponent(couponCode),\n 'customer': '/carts/mine/coupons/' + encodeURIComponent(couponCode)\n };\n\n return this.getUrl(urls, params);\n },\n\n /**\n * @param {String} quoteId\n * @return {*}\n */\n getCancelCouponUrl: function (quoteId) {\n var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n {\n quoteId: quoteId\n } : {},\n urls = {\n 'guest': '/guest-carts/' + quoteId + '/coupons/',\n 'customer': '/carts/mine/coupons/'\n };\n\n return this.getUrl(urls, params);\n },\n\n /**\n * @param {Object} quote\n * @return {*}\n */\n getUrlForCartTotals: function (quote) {\n var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n {\n quoteId: quote.getQuoteId()\n } : {},\n urls = {\n 'guest': '/guest-carts/:quoteId/totals',\n 'customer': '/carts/mine/totals'\n };\n\n return this.getUrl(urls, params);\n },\n\n /**\n * @param {Object} quote\n * @return {*}\n */\n getUrlForSetShippingInformation: function (quote) {\n var params = this.getCheckoutMethod() == 'guest' ? //eslint-disable-line eqeqeq\n {\n cartId: quote.getQuoteId()\n } : {},\n urls = {\n 'guest': '/guest-carts/:cartId/shipping-information',\n 'customer': '/carts/mine/shipping-information'\n };\n\n return this.getUrl(urls, params);\n },\n\n /**\n * Get url for service.\n *\n * @param {*} urls\n * @param {*} urlParams\n * @return {String|*}\n */\n getUrl: function (urls, urlParams) {\n var url;\n\n if (utils.isEmpty(urls)) {\n return 'Provided service call does not exist.';\n }\n\n if (!utils.isEmpty(urls['default'])) {\n url = urls['default'];\n } else {\n url = urls[this.getCheckoutMethod()];\n }\n\n return urlBuilder.createUrl(url, urlParams);\n },\n\n /**\n * @return {String}\n */\n getCheckoutMethod: function () {\n return customer.isLoggedIn() ? 'customer' : 'guest';\n }\n };\n }\n);\n","Magento_Checkout/js/model/billing-address-postcode-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'Magento_Checkout/js/model/postcode-validator',\n 'mage/translate',\n 'uiRegistry'\n ], function (\n $,\n postcodeValidator,\n $t,\n uiRegistry\n) {\n 'use strict';\n\n var postcodeElementName = 'postcode';\n\n return {\n validateZipCodeTimeout: 0,\n validateDelay: 2000,\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 uiRegistry.async(formPath + '.' + postcodeElementName)(self.bindHandler.bind(self));\n },\n\n /**\n * @param {Object} element\n * @param {Number} delay\n */\n bindHandler: function (element, delay) {\n var self = this;\n\n delay = typeof delay === 'undefined' ? self.validateDelay : delay;\n\n element.on('value', function () {\n clearTimeout(self.validateZipCodeTimeout);\n self.validateZipCodeTimeout = setTimeout(function () {\n self.postcodeValidation(element);\n }, delay);\n });\n },\n\n /**\n * @param {Object} postcodeElement\n * @return {*}\n */\n postcodeValidation: function (postcodeElement) {\n var countryId = $('select[name=\"country_id\"]:visible').val(),\n validationResult,\n warnMessage;\n\n if (postcodeElement == null || postcodeElement.value() == null) {\n return true;\n }\n\n postcodeElement.warn(null);\n validationResult = postcodeValidator.validate(postcodeElement.value(), countryId);\n\n if (!validationResult) {\n warnMessage = $t('Provided Zip/Postal Code seems to be invalid.');\n\n if (postcodeValidator.validatedPostCodeExample.length) {\n warnMessage += $t(' Example: ') + postcodeValidator.validatedPostCodeExample.join('; ') + '. ';\n }\n warnMessage += $t('If you believe it is the right one you can ignore this notice.');\n postcodeElement.warn(warnMessage);\n }\n\n return validationResult;\n }\n };\n});\n","Magento_Checkout/js/model/default-post-code-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([], function () {\n 'use strict';\n\n /**\n * Define necessity of using default post code value\n */\n var useDefaultPostCode;\n\n return {\n /**\n * Resolve default post code\n *\n * @returns {String|null}\n */\n resolve: function () {\n return useDefaultPostCode ? window.checkoutConfig.defaultPostcode : null;\n },\n\n /**\n * Set state to useDefaultPostCode variable\n *\n * @param {Boolean} shouldUseDefaultPostCode\n * @returns {underscore}\n */\n setUseDefaultPostCode: function (shouldUseDefaultPostCode) {\n useDefaultPostCode = shouldUseDefaultPostCode;\n\n return this;\n }\n };\n});\n","Magento_Checkout/js/model/address-converter.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 'Magento_Checkout/js/model/new-customer-address',\n 'Magento_Customer/js/customer-data',\n 'mage/utils/objects',\n 'underscore'\n], function ($, address, customerData, mageUtils, _) {\n 'use strict';\n\n var countryData = customerData.get('directory-data');\n\n return {\n /**\n * Convert address form data to Address object\n *\n * @param {Object} formData\n * @returns {Object}\n */\n formAddressDataToQuoteAddress: function (formData) {\n // clone address form data to new object\n var addressData = $.extend(true, {}, formData),\n region,\n regionName = addressData.region,\n customAttributes;\n\n if (mageUtils.isObject(addressData.street)) {\n addressData.street = this.objectToArray(addressData.street);\n }\n\n addressData.region = {\n 'region_id': addressData['region_id'],\n 'region_code': addressData['region_code'],\n region: regionName\n };\n\n if (addressData['region_id'] &&\n countryData()[addressData['country_id']] &&\n countryData()[addressData['country_id']].regions\n ) {\n region = countryData()[addressData['country_id']].regions[addressData['region_id']];\n\n if (region) {\n addressData.region['region_id'] = addressData['region_id'];\n addressData.region['region_code'] = region.code;\n addressData.region.region = region.name;\n }\n } else if (\n !addressData['region_id'] &&\n countryData()[addressData['country_id']] &&\n countryData()[addressData['country_id']].regions\n ) {\n addressData.region['region_code'] = '';\n addressData.region.region = '';\n }\n delete addressData['region_id'];\n\n if (addressData['custom_attributes']) {\n addressData['custom_attributes'] = _.map(\n addressData['custom_attributes'],\n function (value, key) {\n customAttributes = {\n 'attribute_code': key,\n 'value': value\n };\n\n if (typeof value === 'boolean') {\n customAttributes = {\n 'attribute_code': key,\n 'value': value,\n 'label': value === true ? 'Yes' : 'No'\n };\n }\n\n return customAttributes;\n }\n );\n }\n\n return address(addressData);\n },\n\n /**\n * Convert Address object to address form data.\n *\n * @param {Object} addrs\n * @returns {Object}\n */\n quoteAddressToFormAddressData: function (addrs) {\n var self = this,\n output = {},\n streetObject,\n customAttributesObject;\n\n $.each(addrs, function (key) {\n if (addrs.hasOwnProperty(key) && typeof addrs[key] !== 'function') {\n output[self.toUnderscore(key)] = addrs[key];\n }\n });\n\n if (Array.isArray(addrs.street)) {\n streetObject = {};\n addrs.street.forEach(function (value, index) {\n streetObject[index] = value;\n });\n output.street = streetObject;\n }\n\n //jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n if (Array.isArray(addrs.customAttributes)) {\n customAttributesObject = {};\n addrs.customAttributes.forEach(function (value) {\n customAttributesObject[value.attribute_code] = value.value;\n });\n output.custom_attributes = customAttributesObject;\n }\n //jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n\n return output;\n },\n\n /**\n * @param {String} string\n */\n toUnderscore: function (string) {\n return string.replace(/([A-Z])/g, function ($1) {\n return '_' + $1.toLowerCase();\n });\n },\n\n /**\n * @param {Object} formProviderData\n * @param {String} formIndex\n * @return {Object}\n */\n formDataProviderToFlatData: function (formProviderData, formIndex) {\n var addressData = {};\n\n $.each(formProviderData, function (path, value) {\n var pathComponents = path.split('.'),\n dataObject = {};\n\n pathComponents.splice(pathComponents.indexOf(formIndex), 1);\n pathComponents.reverse();\n $.each(pathComponents, function (index, pathPart) {\n var parent = {};\n\n if (index == 0) { //eslint-disable-line eqeqeq\n dataObject[pathPart] = value;\n } else {\n parent[pathPart] = dataObject;\n dataObject = parent;\n }\n });\n $.extend(true, addressData, dataObject);\n });\n\n return addressData;\n },\n\n /**\n * Convert object to array\n * @param {Object} object\n * @returns {Array}\n */\n objectToArray: function (object) {\n var convertedArray = [];\n\n $.each(object, function (key) {\n return typeof object[key] === 'string' ? convertedArray.push(object[key]) : false;\n });\n\n return convertedArray.slice(0);\n },\n\n /**\n * @param {Object} addrs\n * @return {*|Object}\n */\n addressToEstimationAddress: function (addrs) {\n var self = this,\n estimatedAddressData = {};\n\n $.each(addrs, function (key) {\n estimatedAddressData[self.toUnderscore(key)] = addrs[key];\n });\n\n return this.formAddressDataToQuoteAddress(estimatedAddressData);\n }\n };\n});\n","Magento_Checkout/js/model/totals.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 'Magento_Checkout/js/model/quote',\n 'Magento_Customer/js/customer-data'\n], function (ko, quote, customerData) {\n 'use strict';\n\n var quoteItems = ko.observable(quote.totals().items),\n cartData = customerData.get('cart'),\n quoteSubtotal = parseFloat(quote.totals().subtotal),\n subtotalAmount = parseFloat(cartData().subtotalAmount);\n\n quote.totals.subscribe(function (newValue) {\n quoteItems(newValue.items);\n });\n\n if (!isNaN(subtotalAmount) && quoteSubtotal !== subtotalAmount && quoteSubtotal !== 0) {\n customerData.reload(['cart'], false);\n }\n\n return {\n totals: quote.totals,\n isLoading: ko.observable(false),\n\n /**\n * @return {Function}\n */\n getItems: function () {\n return quoteItems;\n },\n\n /**\n * @param {*} code\n * @return {*}\n */\n getSegment: function (code) {\n var i, total;\n\n if (!this.totals()) {\n return null;\n }\n\n for (i in this.totals()['total_segments']) { //eslint-disable-line guard-for-in\n total = this.totals()['total_segments'][i];\n\n if (total.code == code) { //eslint-disable-line eqeqeq\n return total;\n }\n }\n\n return null;\n }\n };\n});\n","Magento_Checkout/js/model/customer-email-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'Magento_Customer/js/model/customer',\n 'mage/validation'\n], function ($, customer) {\n 'use strict';\n\n return {\n /**\n * Validate checkout agreements\n *\n * @returns {Boolean}\n */\n validate: function () {\n var emailValidationResult = customer.isLoggedIn(),\n loginFormSelector = 'form[data-role=email-with-possible-login]';\n\n if (!customer.isLoggedIn()) {\n $(loginFormSelector).validation();\n emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid());\n }\n\n return emailValidationResult;\n }\n };\n});\n","Magento_Checkout/js/model/quote.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([\n 'ko',\n 'underscore',\n 'domReady!'\n], function (ko, _) {\n 'use strict';\n\n /**\n * Get totals data from the extension attributes.\n * @param {*} data\n * @returns {*}\n */\n var proceedTotalsData = function (data) {\n if (_.isObject(data) && _.isObject(data['extension_attributes'])) {\n _.each(data['extension_attributes'], function (element, index) {\n data[index] = element;\n });\n }\n\n return data;\n },\n billingAddress = ko.observable(null),\n shippingAddress = ko.observable(null),\n shippingMethod = ko.observable(null),\n paymentMethod = ko.observable(null),\n quoteData = window.checkoutConfig.quoteData,\n basePriceFormat = window.checkoutConfig.basePriceFormat,\n priceFormat = window.checkoutConfig.priceFormat,\n storeCode = window.checkoutConfig.storeCode,\n totalsData = proceedTotalsData(window.checkoutConfig.totalsData),\n totals = ko.observable(totalsData),\n collectedTotals = ko.observable({});\n\n return {\n totals: totals,\n shippingAddress: shippingAddress,\n shippingMethod: shippingMethod,\n billingAddress: billingAddress,\n paymentMethod: paymentMethod,\n guestEmail: null,\n\n /**\n * @return {*}\n */\n getQuoteId: function () {\n return quoteData['entity_id'];\n },\n\n /**\n * @return {Boolean}\n */\n isVirtual: function () {\n return !!Number(quoteData['is_virtual']);\n },\n\n /**\n * @return {*}\n */\n getPriceFormat: function () {\n return priceFormat;\n },\n\n /**\n * @return {*}\n */\n getBasePriceFormat: function () {\n return basePriceFormat;\n },\n\n /**\n * @return {*}\n */\n getItems: function () {\n return window.checkoutConfig.quoteItemData;\n },\n\n /**\n *\n * @return {*}\n */\n getTotals: function () {\n return totals;\n },\n\n /**\n * @param {Object} data\n */\n setTotals: function (data) {\n data = proceedTotalsData(data);\n totals(data);\n this.setCollectedTotals('subtotal_with_discount', parseFloat(data['subtotal_with_discount']));\n },\n\n /**\n * @param {*} paymentMethodCode\n */\n setPaymentMethod: function (paymentMethodCode) {\n paymentMethod(paymentMethodCode);\n },\n\n /**\n * @return {*}\n */\n getPaymentMethod: function () {\n return paymentMethod;\n },\n\n /**\n * @return {*}\n */\n getStoreCode: function () {\n return storeCode;\n },\n\n /**\n * @param {String} code\n * @param {*} value\n */\n setCollectedTotals: function (code, value) {\n var colTotals = collectedTotals();\n\n colTotals[code] = value;\n collectedTotals(colTotals);\n },\n\n /**\n * @return {Number}\n */\n getCalculatedTotal: function () {\n var total = 0.; //eslint-disable-line no-floating-decimal\n\n _.each(collectedTotals(), function (value) {\n total += value;\n });\n\n return total;\n },\n\n /**\n * @return {Boolean}\n */\n isPersistent: function () {\n return !!Number(quoteData['is_persistent']);\n }\n };\n});\n","Magento_Checkout/js/model/postcode-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'mageUtils'\n], function (utils) {\n 'use strict';\n\n return {\n validatedPostCodeExample: [],\n\n /**\n * @param {*} postCode\n * @param {*} countryId\n * @param {Array} postCodesPatterns\n * @return {Boolean}\n */\n validate: function (postCode, countryId, postCodesPatterns) {\n var pattern, regex,\n patterns = postCodesPatterns ? postCodesPatterns[countryId] :\n window.checkoutConfig.postCodes[countryId];\n\n this.validatedPostCodeExample = [];\n\n if (!utils.isEmpty(postCode) && !utils.isEmpty(patterns)) {\n for (pattern in patterns) {\n if (patterns.hasOwnProperty(pattern)) { //eslint-disable-line max-depth\n this.validatedPostCodeExample.push(patterns[pattern].example);\n regex = new RegExp(patterns[pattern].pattern);\n\n if (regex.test(postCode)) { //eslint-disable-line max-depth\n return true;\n }\n }\n }\n\n return false;\n }\n\n return true;\n }\n };\n});\n","Magento_Checkout/js/model/error-processor.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/url',\n 'Magento_Ui/js/model/messageList',\n 'mage/translate'\n], function (url, globalMessageList, $t) {\n 'use strict';\n\n return {\n /**\n * @param {Object} response\n * @param {Object} messageContainer\n */\n process: function (response, messageContainer) {\n var error;\n\n messageContainer = messageContainer || globalMessageList;\n\n if (response.status == 401) { //eslint-disable-line eqeqeq\n this.redirectTo(url.build('customer/account/login/'));\n } else {\n try {\n error = JSON.parse(response.responseText);\n } catch (exception) {\n error = {\n message: $t('Something went wrong with your request. Please try again later.')\n };\n }\n messageContainer.addErrorMessage(error);\n }\n },\n\n /**\n * Method to redirect by requested URL.\n */\n redirectTo: function (redirectUrl) {\n window.location.replace(redirectUrl);\n }\n };\n});\n","Magento_Checkout/js/model/default-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'jquery',\n 'mageUtils',\n './default-validation-rules',\n 'mage/translate'\n], function ($, utils, validationRules, $t) {\n 'use strict';\n\n return {\n validationErrors: [],\n\n /**\n * @param {Object} address\n * @return {Boolean}\n */\n validate: function (address) {\n var self = this;\n\n this.validationErrors = [];\n $.each(validationRules.getRules(), function (field, rule) {\n var message;\n\n if (rule.required && utils.isEmpty(address[field])) {\n message = $t('Field ') + field + $t(' is required.');\n\n self.validationErrors.push(message);\n }\n });\n\n return !this.validationErrors.length;\n }\n };\n});\n","Magento_Checkout/js/model/sidebar.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 {\n popUp: false,\n\n /**\n * @param {Object} popUp\n */\n setPopup: function (popUp) {\n this.popUp = popUp;\n },\n\n /**\n * Show popup.\n */\n show: function () {\n if (this.popUp) {\n this.popUp.modal('openModal');\n }\n },\n\n /**\n * Hide popup.\n */\n hide: function () {\n if (this.popUp) {\n this.popUp.modal('closeModal');\n }\n }\n };\n});\n","Magento_Checkout/js/model/url-builder.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 {\n method: 'rest',\n storeCode: window.checkoutConfig.storeCode,\n version: 'V1',\n serviceUrl: ':method/:storeCode/:version',\n\n /**\n * @param {String} url\n * @param {Object} params\n * @return {*}\n */\n createUrl: function (url, params) {\n var completeUrl = this.serviceUrl + url;\n\n return this.bindParams(completeUrl, params);\n },\n\n /**\n * @param {String} url\n * @param {Object} params\n * @return {*}\n */\n bindParams: function (url, params) {\n var urlParts;\n\n params.method = this.method;\n params.storeCode = this.storeCode;\n params.version = this.version;\n\n urlParts = url.split('/');\n urlParts = urlParts.filter(Boolean);\n\n $.each(urlParts, function (key, part) {\n part = part.replace(':', '');\n\n if (params[part] != undefined) { //eslint-disable-line eqeqeq\n urlParts[key] = params[part];\n }\n });\n\n return urlParts.join('/');\n }\n };\n});\n","Magento_Checkout/js/model/shipping-rate-registry.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 cache = [];\n\n return {\n /**\n * @param {String} addressKey\n * @return {*}\n */\n get: function (addressKey) {\n if (cache[addressKey]) {\n return cache[addressKey];\n }\n\n return false;\n },\n\n /**\n * @param {String} addressKey\n * @param {*} data\n */\n set: function (addressKey, data) {\n cache[addressKey] = data;\n }\n };\n});\n","Magento_Checkout/js/model/shipping-save-processor/default.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/resource-url-manager',\n 'mage/storage',\n 'Magento_Checkout/js/model/payment-service',\n 'Magento_Checkout/js/model/payment/method-converter',\n 'Magento_Checkout/js/model/error-processor',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'Magento_Checkout/js/action/select-billing-address',\n 'Magento_Checkout/js/model/shipping-save-processor/payload-extender'\n], function (\n ko,\n quote,\n resourceUrlManager,\n storage,\n paymentService,\n methodConverter,\n errorProcessor,\n fullScreenLoader,\n selectBillingAddressAction,\n payloadExtender\n) {\n 'use strict';\n\n return {\n /**\n * @return {jQuery.Deferred}\n */\n saveShippingInformation: function () {\n var payload;\n\n if (!quote.billingAddress() && quote.shippingAddress().canUseForBilling()) {\n selectBillingAddressAction(quote.shippingAddress());\n }\n\n payload = {\n addressInformation: {\n 'shipping_address': quote.shippingAddress(),\n 'billing_address': quote.billingAddress(),\n 'shipping_method_code': quote.shippingMethod()['method_code'],\n 'shipping_carrier_code': quote.shippingMethod()['carrier_code']\n }\n };\n\n payloadExtender(payload);\n\n fullScreenLoader.startLoader();\n\n return storage.post(\n resourceUrlManager.getUrlForSetShippingInformation(quote),\n JSON.stringify(payload)\n ).done(\n function (response) {\n quote.setTotals(response.totals);\n paymentService.setPaymentMethods(methodConverter(response['payment_methods']));\n fullScreenLoader.stopLoader();\n }\n ).fail(\n function (response) {\n errorProcessor.process(response);\n fullScreenLoader.stopLoader();\n }\n );\n }\n };\n});\n","Magento_Checkout/js/model/shipping-save-processor/payload-extender.js":"define([], function () {\n 'use strict';\n\n return function (payload) {\n payload.addressInformation['extension_attributes'] = {};\n\n return payload;\n };\n});\n","Magento_Checkout/js/model/cart/estimate-service.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/shipping-rate-processor/new-address',\n 'Magento_Checkout/js/model/cart/totals-processor/default',\n 'Magento_Checkout/js/model/shipping-service',\n 'Magento_Checkout/js/model/cart/cache',\n 'Magento_Customer/js/customer-data'\n], function (_, quote, defaultProcessor, totalsDefaultProvider, shippingService, cartCache, customerData) {\n 'use strict';\n\n var rateProcessors = {},\n totalsProcessors = {},\n\n /**\n * Cache shipping address until changed\n */\n setShippingAddress = function () {\n var shippingAddress = _.pick(quote.shippingAddress(), cartCache.requiredFields);\n\n cartCache.set('shipping-address', shippingAddress);\n },\n\n /**\n * Estimate totals for shipping address and update shipping rates.\n */\n estimateTotalsAndUpdateRates = function () {\n var type = quote.shippingAddress().getType();\n\n if (\n quote.isVirtual() ||\n window.checkoutConfig.activeCarriers && window.checkoutConfig.activeCarriers.length === 0\n ) {\n // update totals block when estimated address was set\n totalsProcessors['default'] = totalsDefaultProvider;\n totalsProcessors[type] ?\n totalsProcessors[type].estimateTotals(quote.shippingAddress()) :\n totalsProcessors['default'].estimateTotals(quote.shippingAddress());\n } else {\n // check if user data not changed -> load rates from cache\n if (!cartCache.isChanged('address', quote.shippingAddress()) &&\n !cartCache.isChanged('cartVersion', customerData.get('cart')()['data_id']) &&\n cartCache.get('rates') && !cartCache.isChanged('totals', quote.getTotals())\n ) {\n shippingService.setShippingRates(cartCache.get('rates'));\n quote.setTotals(cartCache.get('totals'));\n return;\n }\n\n // update rates list when estimated address was set\n rateProcessors['default'] = defaultProcessor;\n rateProcessors[type] ?\n rateProcessors[type].getRates(quote.shippingAddress()) :\n rateProcessors['default'].getRates(quote.shippingAddress());\n\n // save rates to cache after load\n shippingService.getShippingRates().subscribe(function (rates) {\n cartCache.set('rates', rates);\n setShippingAddress();\n });\n\n // update totals based on updated shipping address / rates changes\n if (cartCache.get('shipping-address') && cartCache.get('shipping-address').countryId &&\n cartCache.isChanged('shipping-address', quote.shippingAddress()) &&\n (!quote.shippingMethod() || !quote.shippingMethod()['method_code'])) {\n totalsDefaultProvider.estimateTotals(quote.shippingAddress());\n cartCache.set('totals', quote.getTotals());\n }\n }\n // unset loader on shipping rates list\n shippingService.isLoading(false);\n },\n\n /**\n * Estimate totals for shipping address.\n */\n estimateTotalsShipping = function () {\n totalsDefaultProvider.estimateTotals(quote.shippingAddress());\n },\n\n /**\n * Estimate totals for billing address.\n */\n estimateTotalsBilling = function () {\n var type = quote.billingAddress().getType();\n\n if (quote.isVirtual()) {\n // update totals block when estimated address was set\n totalsProcessors['default'] = totalsDefaultProvider;\n totalsProcessors[type] ?\n totalsProcessors[type].estimateTotals(quote.billingAddress()) :\n totalsProcessors['default'].estimateTotals(quote.billingAddress());\n }\n };\n\n quote.shippingAddress.subscribe(estimateTotalsAndUpdateRates);\n quote.shippingMethod.subscribe(estimateTotalsShipping);\n quote.billingAddress.subscribe(estimateTotalsBilling);\n});\n","Magento_Checkout/js/model/cart/cache.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Cart adapter for customer data storage.\n * It stores cart data in customer data(localStorage) without saving on server.\n * Adapter is created for shipping rates and totals data caching. It eliminates unneeded calculations requests.\n */\ndefine([\n 'underscore',\n 'Magento_Customer/js/customer-data',\n 'mageUtils'\n], function (_, storage, utils) {\n 'use strict';\n\n var cacheKey = 'cart-data',\n cartData = {\n totals: null,\n address: null,\n cartVersion: null,\n shippingMethodCode: null,\n shippingCarrierCode: null,\n rates: null\n },\n\n /**\n * Set data to local storage.\n *\n * @param {Object} checkoutData\n */\n setData = function (checkoutData) {\n storage.set(cacheKey, checkoutData);\n },\n\n /**\n * Get data from local storage.\n *\n * @param {String} [key]\n * @returns {*}\n */\n getData = function (key) {\n var data = key ? storage.get(cacheKey)()[key] : storage.get(cacheKey)();\n\n if (_.isEmpty(storage.get(cacheKey)())) {\n setData(utils.copy(cartData));\n }\n\n return data;\n },\n\n /**\n * Build method name base on name, prefix and suffix.\n *\n * @param {String} name\n * @param {String} prefix\n * @param {String} suffix\n * @return {String}\n */\n getMethodName = function (name, prefix, suffix) {\n prefix = prefix || '';\n suffix = suffix || '';\n\n return prefix + name.charAt(0).toUpperCase() + name.slice(1) + suffix;\n };\n\n /**\n * Provides get/set/isChanged/clear methods for work with cart data.\n * Can be customized via mixin functionality.\n */\n return {\n cartData: cartData,\n\n /**\n * Array of required address fields\n */\n requiredFields: ['countryId', 'region', 'regionId', 'postcode'],\n\n /**\n * Get data from customer data.\n * Concatenate provided key with method name and call method if it exist or makes get by key.\n *\n * @param {String} key\n * @return {*}\n */\n get: function (key) {\n var methodName = getMethodName(key, '_get');\n\n if (key === cacheKey) {\n return getData();\n }\n\n if (this[methodName]) {\n return this[methodName]();\n }\n\n return getData(key);\n },\n\n /**\n * Set data to customer data.\n * Concatenate provided key with method name and call method if it exist or makes set by key.\n * @example _setCustomAddress method will be called, if it exists.\n * set('address', customAddressValue)\n * @example Will set value by provided key.\n * set('rates', ratesToCompare)\n *\n * @param {String} key\n * @param {*} value\n */\n set: function (key, value) {\n var methodName = getMethodName(key, '_set'),\n obj;\n\n if (key === cacheKey) {\n _.each(value, function (val, k) {\n this.set(k, val);\n }, this);\n\n return;\n }\n\n if (this[methodName]) {\n this[methodName](value);\n } else {\n obj = getData();\n obj[key] = value;\n setData(obj);\n }\n },\n\n /**\n * Clear data in cache.\n * Concatenate provided key with method name and call method if it exist or clear by key.\n * @example _clearCustomAddress method will be called, if it exist.\n * clear('customAddress')\n * @example Will clear data by provided key.\n * clear('rates')\n *\n * @param {String} key\n */\n clear: function (key) {\n var methodName = getMethodName(key, '_clear');\n\n if (key === cacheKey) {\n setData(this.cartData);\n\n return;\n }\n\n if (this[methodName]) {\n this[methodName]();\n } else {\n this.set(key, null);\n }\n },\n\n /**\n * Check if provided data has difference with cached data.\n * Concatenate provided key with method name and call method if it exist or makes strict equality.\n * @example Will call existing _isAddressChanged.\n * isChanged('address', addressToCompare)\n * @example Will get data by provided key and make strict equality with provided value.\n * isChanged('rates', ratesToCompare)\n *\n * @param {String} key\n * @param {*} value\n * @return {Boolean}\n */\n isChanged: function (key, value) {\n var methodName = getMethodName(key, '_is', 'Changed');\n\n if (this[methodName]) {\n return this[methodName](value);\n }\n\n return this.get(key) !== value;\n },\n\n /**\n * Compare cached address with provided.\n * Custom method for check object equality.\n *\n * @param {Object} address\n * @returns {Boolean}\n */\n _isAddressChanged: function (address) {\n return JSON.stringify(_.pick(this.get('address'), this.requiredFields)) !==\n JSON.stringify(_.pick(address, this.requiredFields));\n },\n\n /**\n * Compare cached subtotal with provided.\n * Custom method for check object equality.\n *\n * @param {float} subtotal\n * @returns {Boolean}\n */\n _isSubtotalChanged: function (subtotal) {\n var cached = parseFloat(this.get('totals').subtotal);\n\n return subtotal !== cached;\n }\n };\n});\n","Magento_Checkout/js/model/cart/totals-processor/default.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'underscore',\n 'Magento_Checkout/js/model/resource-url-manager',\n 'Magento_Checkout/js/model/quote',\n 'mage/storage',\n 'Magento_Checkout/js/model/totals',\n 'Magento_Checkout/js/model/error-processor',\n 'Magento_Checkout/js/model/cart/cache',\n 'Magento_Customer/js/customer-data'\n], function (_, resourceUrlManager, quote, storage, totalsService, errorProcessor, cartCache, customerData) {\n 'use strict';\n\n /**\n * Load data from server.\n *\n * @param {Object} address\n */\n var loadFromServer = function (address) {\n var serviceUrl,\n payload;\n\n // Start loader for totals block\n totalsService.isLoading(true);\n serviceUrl = resourceUrlManager.getUrlForTotalsEstimationForNewAddress(quote);\n payload = {\n addressInformation: {\n address: _.pick(address, cartCache.requiredFields)\n }\n };\n\n if (quote.shippingMethod() && quote.shippingMethod()['method_code']) {\n payload.addressInformation['shipping_method_code'] = quote.shippingMethod()['method_code'];\n payload.addressInformation['shipping_carrier_code'] = quote.shippingMethod()['carrier_code'];\n }\n\n return storage.post(\n serviceUrl, JSON.stringify(payload), false\n ).done(function (result) {\n var data = {\n totals: result,\n address: address,\n cartVersion: customerData.get('cart')()['data_id'],\n shippingMethodCode: null,\n shippingCarrierCode: null\n };\n\n if (quote.shippingMethod() && quote.shippingMethod()['method_code']) {\n data.shippingMethodCode = quote.shippingMethod()['method_code'];\n data.shippingCarrierCode = quote.shippingMethod()['carrier_code'];\n }\n\n quote.setTotals(result);\n cartCache.set('cart-data', data);\n }).fail(function (response) {\n errorProcessor.process(response);\n }).always(function () {\n // Stop loader for totals block\n totalsService.isLoading(false);\n });\n };\n\n return {\n /**\n * Array of required address fields.\n * @property {Array.String} requiredFields\n * @deprecated Use cart cache.\n */\n requiredFields: cartCache.requiredFields,\n\n /**\n * Get shipping rates for specified address.\n * @param {Object} address\n */\n estimateTotals: function (address) {\n return loadFromServer(address);\n }\n };\n});\n","Magento_Checkout/js/model/payment/method-list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko'\n], function (ko) {\n 'use strict';\n\n return ko.observableArray([]);\n});\n","Magento_Checkout/js/model/payment/method-group.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'uiElement',\n 'mage/translate'\n], function (Element, $t) {\n 'use strict';\n\n var DEFAULT_GROUP_ALIAS = 'default';\n\n return Element.extend({\n defaults: {\n alias: DEFAULT_GROUP_ALIAS,\n title: $t('Payment Method'),\n sortOrder: 100,\n displayArea: 'payment-methods-items-${ $.alias }'\n },\n\n /**\n * Checks if group instance is default\n *\n * @returns {Boolean}\n */\n isDefault: function () {\n return this.alias === DEFAULT_GROUP_ALIAS;\n }\n });\n});\n","Magento_Checkout/js/model/payment/place-order-hooks.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 {\n requestModifiers: [],\n afterRequestListeners: []\n };\n});\n","Magento_Checkout/js/model/payment/method-converter.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 return function (methods) {\n _.each(methods, function (method) {\n if (method.hasOwnProperty('code')) {\n method.method = method.code;\n delete method.code;\n }\n });\n\n return methods;\n };\n});\n","Magento_Checkout/js/model/payment/additional-validators.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 validators = [];\n\n return {\n /**\n * Register unique validator\n *\n * @param {*} validator\n */\n registerValidator: function (validator) {\n validators.push(validator);\n },\n\n /**\n * Returns array of registered validators\n *\n * @returns {Array}\n */\n getValidators: function () {\n return validators;\n },\n\n /**\n * Process validators\n *\n * @returns {Boolean}\n */\n validate: function (hideError) {\n var validationResult = true;\n\n hideError = hideError || false;\n\n if (validators.length <= 0) {\n return validationResult;\n }\n\n validators.forEach(function (item) {\n if (item.validate(hideError) == false) { //eslint-disable-line eqeqeq\n validationResult = false;\n\n return false;\n }\n });\n\n return validationResult;\n }\n };\n});\n","Magento_Checkout/js/model/payment/renderer-list.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko'\n], function (ko) {\n 'use strict';\n\n return ko.observableArray([]);\n});\n","Magento_Checkout/js/model/shipping-rate-processor/new-address.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'Magento_Checkout/js/model/resource-url-manager',\n 'Magento_Checkout/js/model/quote',\n 'mage/storage',\n 'Magento_Checkout/js/model/shipping-service',\n 'Magento_Checkout/js/model/shipping-rate-registry',\n 'Magento_Checkout/js/model/error-processor'\n], function (resourceUrlManager, quote, storage, shippingService, rateRegistry, errorProcessor) {\n 'use strict';\n\n return {\n /**\n * Get shipping rates for specified address.\n * @param {Object} address\n */\n getRates: function (address) {\n var cache, serviceUrl, payload;\n\n shippingService.isLoading(true);\n cache = rateRegistry.get(address.getCacheKey());\n serviceUrl = resourceUrlManager.getUrlForEstimationShippingMethodsForNewAddress(quote);\n payload = JSON.stringify({\n address: {\n 'street': address.street,\n 'city': address.city,\n 'region_id': address.regionId,\n 'region': address.region,\n 'country_id': address.countryId,\n 'postcode': address.postcode,\n 'email': address.email,\n 'customer_id': address.customerId,\n 'firstname': address.firstname,\n 'lastname': address.lastname,\n 'middlename': address.middlename,\n 'prefix': address.prefix,\n 'suffix': address.suffix,\n 'vat_id': address.vatId,\n 'company': address.company,\n 'telephone': address.telephone,\n 'fax': address.fax,\n 'custom_attributes': address.customAttributes,\n 'save_in_address_book': address.saveInAddressBook\n }\n }\n );\n\n if (cache) {\n shippingService.setShippingRates(cache);\n shippingService.isLoading(false);\n } else {\n let async = quote.isPersistent() ? false : true;\n\n storage.post(\n serviceUrl, payload, false, 'application/json', {}, async\n ).done(function (result) {\n rateRegistry.set(address.getCacheKey(), result);\n shippingService.setShippingRates(result);\n }).fail(function (response) {\n shippingService.setShippingRates([]);\n errorProcessor.process(response);\n }).always(function () {\n shippingService.isLoading(false);\n });\n }\n }\n };\n});\n","Magento_Checkout/js/model/shipping-rate-processor/customer-address.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'Magento_Checkout/js/model/resource-url-manager',\n 'Magento_Checkout/js/model/quote',\n 'mage/storage',\n 'Magento_Checkout/js/model/shipping-service',\n 'Magento_Checkout/js/model/shipping-rate-registry',\n 'Magento_Checkout/js/model/error-processor'\n], function (resourceUrlManager, quote, storage, shippingService, rateRegistry, errorProcessor) {\n 'use strict';\n\n return {\n /**\n * @param {Object} address\n */\n getRates: function (address) {\n var cache;\n\n shippingService.isLoading(true);\n cache = rateRegistry.get(address.getKey());\n\n if (cache) {\n shippingService.setShippingRates(cache);\n shippingService.isLoading(false);\n } else {\n storage.post(\n resourceUrlManager.getUrlForEstimationShippingMethodsByAddressId(),\n JSON.stringify({\n addressId: address.customerAddressId\n }),\n false\n ).done(function (result) {\n rateRegistry.set(address.getKey(), result);\n shippingService.setShippingRates(result);\n }).fail(function (response) {\n shippingService.setShippingRates([]);\n errorProcessor.process(response);\n }).always(function () {\n shippingService.isLoading(false);\n }\n );\n }\n }\n };\n});\n","Magento_Checkout/js/model/shipping-address/form-popup-state.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n 'ko'\n], function (ko) {\n 'use strict';\n\n return {\n isVisible: ko.observable(false)\n };\n});\n","PayPal_Braintree/js/validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'underscore'\n], function (_) {\n 'use strict';\n\n return {\n config: {},\n\n /**\n * Set configuration\n * @param {Object} config\n */\n setConfig: function (config) {\n this.config = config;\n },\n\n /**\n * Get List of available card types\n * @returns {*|exports.defaults.availableCardTypes|{}}\n */\n getAvailableCardTypes: function () {\n return this.config.availableCardTypes;\n },\n\n /**\n * Get list of card types\n * @returns {Object}\n */\n getCcTypesMapper: function () {\n return this.config.ccTypesMapper;\n },\n\n /**\n * Find mage card type by Braintree type\n * @param {String} type\n * @param {Object} availableTypes\n * @returns {*}\n */\n getMageCardType: function (type, availableTypes) {\n var storedCardType = null,\n mapper = this.getCcTypesMapper();\n\n if (type && typeof mapper[type] !== 'undefined') {\n storedCardType = mapper[type];\n\n if (_.indexOf(availableTypes, storedCardType) !== -1) {\n return storedCardType;\n }\n }\n\n return null;\n },\n\n /**\n * Filter list of available card types\n * @param {Object} availableTypes\n * @param {Object} countrySpecificCardTypes\n * @returns {Object}\n */\n collectTypes: function (availableTypes, countrySpecificCardTypes) {\n var key,\n filteredTypes = [];\n\n for (key in availableTypes) {\n if (_.indexOf(countrySpecificCardTypes, availableTypes[key]) !== -1) {\n filteredTypes.push(availableTypes[key]);\n }\n }\n\n return filteredTypes;\n },\n\n /**\n * Get list of card types for country\n * @param {String} countryId\n * @returns {*}\n */\n getCountrySpecificCardTypes: function (countryId) {\n if (typeof this.config.countrySpecificCardTypes[countryId] !== 'undefined') {\n return this.config.countrySpecificCardTypes[countryId];\n }\n\n return false;\n }\n };\n});\n","PayPal_Braintree/js/form-builder.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(\n [\n 'jquery',\n 'underscore',\n 'mage/template'\n ],\n function ($, _, mageTemplate) {\n 'use strict';\n\n return {\n\n /**\n * @param {Object} formData\n * @returns {*|jQuery}\n */\n build: function (formData) {\n var formTmpl = mageTemplate('<form action=\"<%= data.action %>\"' +\n ' method=\"POST\" hidden enctype=\"application/x-www-form-urlencoded\">' +\n '<% _.each(data.fields, function(val, key){ %>' +\n '<input value=\\'<%= val %>\\' name=\"<%= key %>\" type=\"hidden\">' +\n '<% }); %>' +\n '</form>');\n\n return $(formTmpl({\n data: {\n action: formData.action,\n fields: formData.fields\n }\n })).appendTo($('[data-container=\"body\"]'));\n }\n };\n }\n);\n","PayPal_Braintree/js/helper/format-amount.js":"define(function () {\n 'use strict';\n\n /**\n * Format amount (string) to two decimals.\n *\n * @param {string} str\n * @return {string}\n */\n return function (amount) {\n return parseFloat(amount).toFixed(2);\n };\n});\n","PayPal_Braintree/js/helper/remove-non-digit-characters.js":"define([\n 'underscore'\n], function (_) {\n 'use strict';\n\n /**\n * Remove any non-digit characters from string.\n *\n * @param {string} value\n * @return {string}\n */\n return function (value) {\n return _.isString(value) ? value.replace(/\\D/g, '') : '';\n };\n});\n","PayPal_Braintree/js/helper/create-client-token.js":"define(['jquery'], function ($) {\n 'use strict';\n\n return function () {\n return $.ajax({\n method: 'POST',\n url: '/graphql',\n contentType: 'application/json',\n data: JSON.stringify({\n query: `\n mutation {\n createBraintreeClientToken\n }`\n })\n });\n };\n});\n","PayPal_Braintree/js/helper/escape-non-ascii-characters.js":"define(function () {\n 'use strict';\n\n /**\n * Convert Non-ASCII characters into unicode.\n *\n * @param {string} value\n * @return {string}\n */\n return function (value) {\n return value.split('').map(function (c) {\n return /^[\\x00-\\x7F]$/.test(c) ? c : c.split('').map(function (a) {\n return '\\\\u00' + a.charCodeAt(0).toString(16);\n }).join('');\n }).join('');\n };\n});\n","PayPal_Braintree/js/helper/replace-single-quote-character.js":"define([\n 'underscore'\n], function (_) {\n 'use strict';\n\n /**\n * Replace single quote character to HTML entity string.\n *\n * @param {string} value\n * @return {string}\n */\n return function (value) {\n return _.isString(value) ? value.replace(/'/g, ''') : '';\n };\n});\n","PayPal_Braintree/js/helper/get-braintree-config.js":"define(['jquery'], function ($) {\n 'use strict';\n\n return function () {\n return $.ajax({\n method: 'POST',\n url: '/graphql',\n contentType: 'application/json',\n data: JSON.stringify({\n query: `{\n storeConfig {\n braintree_merchant_account_id,\n braintree_3dsecure_verify_3dsecure,\n braintree_3dsecure_always_request_3ds,\n braintree_3dsecure_threshold_amount,\n braintree_3dsecure_allowspecific,\n braintree_3dsecure_specificcountry\n }\n }`\n })\n });\n };\n});\n","PayPal_Braintree/js/helper/replace-unsupported-characters.js":"define(function () {\n 'use strict';\n\n /**\n * Regex to replace all unsupported characters from string.\n *\n * @param {String} str\n * @return {String}\n */\n return function (str) {\n // eslint-disable-next-line no-useless-escape\n return str.replace('/[^a-zA-Z0-9\\s\\-.\\']/', '').substring(0, 127);\n };\n});\n","PayPal_Braintree/js/helper/get-cart-line-items-helper.js":"define([\n 'jquery',\n 'underscore',\n 'PayPal_Braintree/js/helper/format-amount',\n 'PayPal_Braintree/js/helper/replace-unsupported-characters',\n 'Magento_Checkout/js/model/quote'\n], function (\n $,\n _,\n formatAmount,\n replaceUnsupportedCharacters,\n quote\n) {\n 'use strict';\n\n /**\n * Get line items\n *\n * @returns {Array}\n */\n return function () {\n let lineItems = [];\n\n /**\n * Line items array\n *\n * {Array}\n */\n var lineItemsArray = [\n 'name',\n 'kind',\n 'quantity',\n 'unitAmount',\n 'productCode',\n 'description'\n ];\n\n if (window.checkoutConfig.payment['braintree_paypal'].canSendLineItems) {\n let giftWrappingItems = 0, giftWrappingOrder = 0, storeCredit = 0, giftCardAccount = 0,\n giftWrappingPrintedCard = 0,\n baseDiscountAmount = formatAmount(Math.abs(quote.totals()['base_discount_amount']).toString()),\n baseTaxAmount = formatAmount(quote.totals()['base_tax_amount']);\n\n $.each(quote.totals()['total_segments'], function (segmentsKey, segmentsItem) {\n if (segmentsItem['code'] === 'customerbalance') {\n storeCredit = formatAmount(Math.abs(segmentsItem['value']).toString());\n }\n if (segmentsItem['code'] === 'giftcardaccount') {\n giftCardAccount = formatAmount(Math.abs(segmentsItem['value']).toString());\n }\n if (segmentsItem['code'] === 'giftwrapping') {\n let extensionAttributes = segmentsItem['extension_attributes'];\n\n giftWrappingOrder = extensionAttributes['gw_base_price'];\n giftWrappingItems = extensionAttributes['gw_items_base_price'];\n giftWrappingPrintedCard = extensionAttributes['gw_card_base_price'];\n }\n });\n\n $.each(quote.getItems(), function (quoteItemKey, quoteItem) {\n if (quoteItem.parent_item_id !== null || quoteItem.price === 0.0) {\n return true;\n }\n\n let floatQty = parseFloat(quoteItem.qty),\n itemName = replaceUnsupportedCharacters(quoteItem.name),\n itemSku = replaceUnsupportedCharacters(quoteItem.sku),\n hasQty = floatQty > Math.floor(floatQty) && floatQty < Math.ceil(floatQty),\n description = hasQty\n ? 'Item quantity is ' + floatQty.toFixed(2) + ' and per unit amount is '\n + parseFloat(quoteItem.price).toFixed(2)\n : '',\n itemUnitAmount = hasQty\n ? parseFloat(floatQty * parseFloat(quoteItem.price)) : parseFloat(quoteItem.price),\n itemQty = hasQty ? parseFloat('1') : floatQty,\n lineItemValues = [\n itemName,\n 'debit',\n itemQty.toFixed(2),\n itemUnitAmount.toFixed(2),\n itemSku,\n description\n ],\n\n mappedLineItems = $.map(lineItemsArray, function (itemElement, itemIndex) {\n return [[\n lineItemsArray[itemIndex],\n lineItemValues[itemIndex]\n ]];\n });\n\n lineItems[quoteItemKey] = Object.fromEntries(mappedLineItems);\n });\n\n /**\n * Adds credit (refund or discount) kind as LineItems for the\n * PayPal transaction if discount amount is greater than 0(Zero)\n * as discountAmount lineItem field is not being used by PayPal.\n *\n * developer.paypal.com/braintree/docs/reference/response/transaction-line-item/php#discount_amount\n */\n if (baseDiscountAmount > 0) {\n let discountLineItem = {\n 'name': 'Discount',\n 'kind': 'credit',\n 'quantity': 1.00,\n 'unitAmount': baseDiscountAmount\n };\n\n lineItems = $.merge(lineItems, [discountLineItem]);\n }\n\n /**\n * Adds shipping as LineItems for the PayPal transaction\n * if shipping amount is greater than 0(Zero) to manage\n * the totals with client-side implementation as there is\n * no any field exist in the client-side implementation\n * to send the shipping amount to the Braintree.\n */\n if (quote.totals()['base_shipping_amount'] > 0) {\n let shippingLineItem = {\n 'name': 'Shipping',\n 'kind': 'debit',\n 'quantity': 1.00,\n 'unitAmount': quote.totals()['base_shipping_amount']\n };\n\n lineItems = $.merge(lineItems, [shippingLineItem]);\n }\n\n if (baseTaxAmount > 0) {\n let taxLineItem = {\n 'name': 'Tax',\n 'kind': 'debit',\n 'quantity': 1.00,\n 'unitAmount': baseTaxAmount\n };\n\n lineItems = $.merge(lineItems, [taxLineItem]);\n }\n\n /**\n * Adds credit (Store Credit) kind as LineItems for the\n * PayPal transaction if store credit is greater than 0(Zero)\n * to manage the totals with client-side implementation\n */\n if (storeCredit > 0) {\n let storeCreditItem = {\n 'name': 'Store Credit',\n 'kind': 'credit',\n 'quantity': 1.00,\n 'unitAmount': storeCredit\n };\n\n lineItems = $.merge(lineItems, [storeCreditItem]);\n }\n\n /**\n * Adds Gift Wrapping for items as LineItems for the PayPal\n * transaction if it is greater than 0(Zero) to manage\n * the totals with client-side implementation\n */\n if (giftWrappingItems > 0) {\n let gwItems = {\n 'name': 'Gift Wrapping for Items',\n 'kind': 'debit',\n 'quantity': 1.00,\n 'unitAmount': giftWrappingItems\n };\n\n lineItems = $.merge(lineItems, [gwItems]);\n }\n\n /**\n * Adds Gift Wrapping for order as LineItems for the PayPal\n * transaction if it is greater than 0(Zero) to manage\n * the totals with client-side implementation\n */\n if (giftWrappingOrder > 0) {\n let gwOrderItem = {\n 'name': 'Gift Wrapping for Order',\n 'kind': 'debit',\n 'quantity': 1.00,\n 'unitAmount': giftWrappingOrder\n };\n\n lineItems = $.merge(lineItems, [gwOrderItem]);\n }\n\n /**\n * Adds Gift Wrapping Printed Card as LineItems for the PayPal\n * transaction if it is greater than 0(Zero) to manage\n * the totals with client-side implementation\n */\n if (giftWrappingPrintedCard > 0) {\n let gwPrintedCard = {\n 'name': 'Printed Card',\n 'kind': 'debit',\n 'quantity': 1.00,\n 'unitAmount': giftWrappingPrintedCard\n };\n\n lineItems = $.merge(lineItems, [gwPrintedCard]);\n }\n\n /**\n * Adds Gift Cards as credit LineItems for the PayPal\n * transaction if it is greater than 0(Zero) to manage\n * the totals with client-side implementation\n */\n if (giftCardAccount > 0) {\n let giftCardItem = {\n 'name': 'Gift Cards',\n 'kind': 'credit',\n 'quantity': 1.00,\n 'unitAmount': giftCardAccount\n };\n\n lineItems = $.merge(lineItems, [giftCardItem]);\n }\n\n if (lineItems.length >= 250) {\n lineItems = [];\n }\n }\n return lineItems;\n };\n});\n","PayPal_Braintree/js/lpm/process-fallback-response.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'Magento_Checkout/js/view/payment/default',\n 'Magento_Customer/js/customer-data',\n 'Magento_Checkout/js/model/quote',\n 'jquery',\n 'braintree',\n 'braintreeLpm',\n 'PayPal_Braintree/js/model/full-screen-loader',\n 'mage/translate',\n 'underscore'\n], function (Component, customerData, quote, $, braintree, lpm, fullScreenLoader, $t, _) {\n 'use strict';\n\n return Component.extend({\n code: 'braintree_local_payment',\n paymentMethodNonce: null,\n config: {\n clientToken: null,\n merchantAccountId: null,\n redirectOnFail: null\n },\n\n /**\n * Initialize config values\n *\n * @param config\n */\n initialize: function (config) {\n this._super();\n this.config.clientToken = config.clientToken;\n this.config.merchantAccountId = config.merchantAccountId;\n this.config.redirectOnFail = config.redirectOnFail;\n this.setupLpmFallback();\n },\n\n /**\n * Setup local payment fallback scenario\n */\n setupLpmFallback: function () {\n let self = this;\n\n fullScreenLoader.startLoader();\n\n braintree.create({\n authorization: self.config.clientToken\n }, function (clientError, clientInstance) {\n if (clientError) {\n self.redirectCustomerOnFailure($t('Unable to initialize Braintree Client.'));\n return;\n }\n\n lpm.create({\n client: clientInstance,\n merchantAccountId: self.config.merchantAccountId\n }, function (lpmError, lpmInstance) {\n if (lpmError) {\n self.redirectCustomerOnFailure($t(lpmError.message));\n }\n\n if (lpmInstance.hasTokenizationParams()) {\n lpmInstance.tokenize(function (tokenizeError, payload) {\n if (tokenizeError) {\n self.redirectCustomerOnFailure($t(tokenizeError.message));\n } else {\n // Send the nonce to the server to create a transaction\n self.setPaymentMethodNonce(payload.nonce);\n self.isPlaceOrderActionAllowed(true);\n\n if (!window.checkoutConfig.isCustomerLoggedIn) {\n // Set the email to the quote.\n let checkoutData = customerData.get('checkout-data')();\n\n quote.guestEmail = checkoutData.inputFieldEmailValue;\n }\n\n // Check all agreements if any available.\n let agreements = $('.checkout-agreements input[type=\"checkbox\"]');\n\n if (agreements.length) {\n agreements.prop('checked', true);\n }\n\n self.placeOrder();\n }\n });\n } else {\n let error = 'Payment can not be processed as invalid parameters received';\n\n self.redirectCustomerOnFailure($t(error));\n }\n });\n });\n },\n\n /**\n * Get code\n *\n * @returns {string}\n */\n getCode: function () {\n return this.code;\n },\n\n /**\n * Set payment method nonce\n *\n * @param nonce\n */\n setPaymentMethodNonce: function (nonce) {\n this.paymentMethodNonce = nonce;\n },\n\n /**\n * Get data\n *\n * @returns {{additional_data: {payment_method_nonce: null}, method: string}}\n */\n getData: function () {\n let data = {\n 'method': this.getCode(),\n 'additional_data': {\n 'payment_method_nonce': this.paymentMethodNonce\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n return data;\n },\n\n /**\n * redirect customer to the configured page if any error/failure/cancelled.\n */\n redirectCustomerOnFailure: function (message) {\n if (message) {\n let braintreeData = customerData.get('braintree')(),\n errors = braintreeData.errors || [];\n\n errors.push(message);\n\n customerData.set('braintree', { errors: errors });\n }\n\n window.location.href = this.config.redirectOnFail;\n }\n });\n});\n","PayPal_Braintree/js/checkoutAgreements/view/checkout-agreements-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n 'underscore'\n], function (_) {\n 'use strict';\n\n return function (CheckoutAgreements) {\n return CheckoutAgreements.extend({\n /**\n * Replace checkboxes unique id with Braintree PayPal Vault unique id using the index.\n * First call the original & extend in order to prevent unwanted behaviour.\n *\n * @param {Object} context - the ko context\n * @param {Number} agreementId\n */\n getCheckboxId: function (context, agreementId) {\n let result = this._super(context, agreementId),\n\n /* Fetch corresponding payment method from parent context */\n paymentMethodRenderer = context.$parents[1],\n paymentMethodName;\n\n /* We only want to check for Braintree PayPal Vault methods with set properties */\n if (!paymentMethodRenderer ||\n _.get(paymentMethodRenderer, ['code'], null) !== 'braintree_paypal_vault' ||\n !_.has(paymentMethodRenderer, 'index')\n ) {\n return result;\n }\n\n paymentMethodName = paymentMethodRenderer.index;\n\n /* Now check that the relevant index `braintree_paypal_vault_X` has global variables set */\n if (!this.hasVaultInCheckoutConfig(paymentMethodName)) {\n return result;\n }\n\n /* If yes, use unique name */\n return 'agreement_' + paymentMethodName + '_' + agreementId;\n },\n\n /**\n * Check whether the current method renderer index has configuration in the checkout global.\n *\n * @param {String} vaultIndex\n * @return {Boolean}\n */\n hasVaultInCheckoutConfig: function (vaultIndex) {\n return _.has(window.checkoutConfig.payment, ['vault', vaultIndex]);\n }\n });\n };\n});\n","PayPal_Braintree/js/customer/utilities.js":"/* eslint-disable max-depth */\ndefine([\n 'jquery',\n 'ko',\n 'mage/url',\n 'mage/translate',\n 'mage/calendar'\n], function ($, ko, urlBuilder) {\n 'use strict';\n return {\n\n viewModel: {\n activeVM: ko.observableArray(null),\n pausedVM: ko.observableArray(null),\n pendingVM: ko.observableArray(null),\n\n updatedOrderEntityId: ko.observable(null),\n showBanner: ko.observable(false),\n errorModal: {\n visible: ko.observable(false),\n message: ko.observable(null)\n }\n },\n sectionCounter: 0,\n\n makeCall: function (url, verb, callback, viewModel) {\n var self = this;\n\n $.ajax({\n url: urlBuilder.build(url),\n contentType: 'application/json',\n global: true,\n type: verb,\n showLoader: true,\n cache: false,\n success: function (response) {\n callback(response);\n self.handleSuccess(self.viewModel.updatedOrderEntityId());\n },\n error: function (xhr, status, error) {\n $('body').trigger('processStop');\n if (viewModel) {\n self.hideModal(viewModel);\n }\n\n self.handleError(xhr, status, error);\n }\n });\n },\n\n //Get entity ID from response json back from update\n //After section updates, run this to find the updatedOrderEntityId value and add the class\n //Find a div with that ID and add a class to it\n handleSuccess: function (entity_id) {\n var self = this,\n successClass = 'updated-success',\n orderItem = $('.repeat-order-id-' + entity_id),\n parentContainer = orderItem.closest('.repeat-order');\n\n // If there is another success message on an item then reset\n if ($('.updated-success').length) {\n $(this).removeClass(successClass);\n }\n\n orderItem.addClass(successClass);\n parentContainer.addClass(successClass);\n\n //Remove the class\n //Set the entityid value back to null, so the success message is only shown once\n setTimeout(function () {\n orderItem.removeClass(successClass);\n parentContainer.removeClass(successClass);\n self.viewModel.updatedOrderEntityId(null);\n }, 20000);\n },\n\n hideModal: function (viewModel) {\n return viewModel.visible(false);\n },\n\n //Get a message relating to a particular response and show it on the page in a modal\n handleError: function (xhr) {\n this.viewModel.errorModal.message(JSON.parse(xhr.responseText).message);\n this.viewModel.errorModal.visible(true);\n },\n\n formatDate: function (value, format) {\n if (!format || typeof format == 'undefined') {\n format = 'MM dd, yy';\n }\n\n return $.datepicker.formatDate(format, new Date(value));\n },\n\n formatCurrency: function (value) {\n //If the price is a negative number, make it a positive number. eg -1.25 becomes 1.25\n var formattedValue = Math.abs(value);\n\n //Set number to 2 decimal places as it is a price\n formattedValue = formattedValue.toFixed(2);\n\n return formattedValue;\n },\n\n formatWeeks: function (value) {\n var dayValue = value / 7;\n\n return dayValue === 1 ? $.mage.__('Week') : dayValue + ' ' + $.mage.__('Weeks');\n },\n\n //Used for payment details as they are formatted as a string of json:\n //eg '{\"type\":\"VI\",\"maskedCC\":\"1111\",\"expirationDate\":\"11\\/2022\"}'\n parseStringtoJSON: function (string) {\n var result = JSON.parse(string);\n\n return result;\n },\n\n //Find the image url in the product.media_gallery_entries array\n getImgUrl: function (data) {\n var imgUrl,\n i = 0,\n j = 0,\n dataLength = data.length;\n\n for (i = 0; i < dataLength; i++) {\n\n for (j = 0; j < data[i].types.length; j++) {\n if (data[i].types[j] === 'thumbnail') {\n imgUrl = data[i].file;\n\n break;\n }\n }\n }\n\n return '/media/catalog/product' + imgUrl;\n },\n\n //Find the image label to be used as an alt tag in the product.media_gallery_entries array\n getImgAltTag: function (data) {\n var altTag,\n i = 0,\n j = 0,\n dataLength = data.length;\n\n for (i = 0; i < dataLength; i++) {\n\n for (j = 0; j < data[i].types.length; j++) {\n altTag = this.updateAltTag(data[i].types[j]);\n\n if (data[i].types[j] === 'thumbnail') {\n\n if (data[i].label === null || data[i].label === '') {\n altTag = ' ';\n }\n else {\n altTag = data[i].label;\n }\n\n break;\n }\n }\n }\n\n return altTag;\n }\n };\n});\n","PayPal_Braintree/js/customer/modals/address-modal.js":"define([\n 'jquery',\n 'ko',\n 'PayPal_Braintree/js/customer/utilities',\n 'mageUtils'\n], function ($, ko, utilities, utils) {\n 'use strict';\n\n return {\n viewModel: {\n visible: ko.observable(false),\n newAddressFormVisible: ko.observable(false),\n selectExistingVisible: ko.observable(false),\n currentAddresses: ko.observableArray([]),\n initialSubscriptionAddressId: ko.observable(null),\n currentShippingId: ko.observable(null),\n currentEntityId: ko.observable(null),\n currentOrderIsGrouped: ko.observable(false),\n useForSelected: ko.observable(false),\n saveAddressDisabled: ko.observable(true),\n confirmationVisibleType: ko.observable(null),\n defaultForAllAddressId: ko.observable(null),\n isLookup: ko.observable(true),\n newAddress: {\n firstName: document.getElementById('firstname').value,\n lastName: document.getElementById('lastname').value,\n street: document.getElementById('street_1').value,\n street2: document.getElementById('street_2').value,\n city: document.getElementById('city').value,\n postcode: document.getElementById('zip').value,\n country: document.getElementById('country').value,\n telephone: document.getElementById('telephone').value,\n region: document.getElementById('region_id').value\n },\n currentCountryId: ko.observable(null),\n countries: ko.observableArray(null)\n },\n\n fetchAllAddressUrl: 'rest/V1/repeat-orders/user-addresses',\n assignAddressUrl: 'rest/V1/repeat-orders/grouped/set-shipping-address/',\n useForAllUrl: 'rest/V1/repeat-orders/set-shipping-address-for-all/',\n addAddressUrl: 'rest/V1/repeat-orders/add-shipping-address/',\n validatedPostCodeExample: [],\n\n showAddressModal: function (entity_id, groupedOrdersLength, shippingId, countryId) {\n var self = this;\n\n this.viewModel.visible(true);\n this.viewModel.selectExistingVisible(true);\n this.viewModel.currentEntityId(entity_id);\n this.viewModel.initialSubscriptionAddressId(shippingId);\n this.viewModel.currentOrderIsGrouped(groupedOrdersLength > 1);\n this.viewModel.useForSelected(false);\n this.clearAddressField();\n\n fetch('/graphql', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n query: `{\n customer {\n addresses {\n id,\n street,\n country_id,\n region {\n region_code\n },\n telephone,\n postcode,\n firstname,\n lastname,\n city\n }\n }\n }`\n })\n }).then(response => response.json()).then(response => {\n const addresses = response.data.customer?.addresses || [];\n\n self.viewModel.currentAddresses.removeAll();\n\n //Get addresses from response and put them in an observable array\n //The template looks at the array and builds the <select> dropdown form\n for (let i = 0; i < addresses.length; i++) {\n const address = {\n id: addresses[i].id,\n firstname: addresses[i].firstname,\n lastname: addresses[i].lastname,\n region: {\n region_code: addresses[i].region.region_code\n },\n telephone: addresses[i].telephone,\n postcode: addresses[i].postcode,\n country_id: addresses[i].country_id,\n city: addresses[i].city,\n street: addresses[i].street.join(', ')\n };\n\n self.viewModel.currentAddresses.push(address);\n }\n\n self.viewModel.currentShippingId(shippingId);\n self.viewModel.currentCountryId(countryId);\n self.viewModel.saveAddressDisabled(true);\n });\n },\n\n hideAddressModal: function () {\n this.viewModel.newAddressFormVisible(false);\n this.viewModel.selectExistingVisible(false);\n this.viewModel.confirmationVisibleType(null);\n this.viewModel.visible(false);\n\n // Remove previous clickToAddress initialization block\n $('#cc_c2a').remove();\n },\n\n showConfirmChangeAddress: function (event, context, type) {\n if (type === 'new') {\n let form = $(event.target).closest('form');\n\n if (!(form.validation() && form.validation('isValid'))) {\n return false;\n }\n }\n\n this.viewModel.newAddressFormVisible(false);\n this.viewModel.selectExistingVisible(false);\n this.viewModel.confirmationVisibleType(type);\n },\n\n /**\n * @param {*} postCode\n * @param {*} countryId\n * @return {Boolean}\n */\n validatePostCode: function (postCode, countryId) {\n var pattern, regex,\n patterns = window.checkout.postCodes[countryId];\n\n this.validatedPostCodeExample = [];\n\n if (!utils.isEmpty(postCode) && !utils.isEmpty(patterns)) {\n for (pattern in patterns) {\n if (patterns.hasOwnProperty(pattern)) { //eslint-disable-line max-depth\n this.validatedPostCodeExample.push(patterns[pattern].example);\n regex = new RegExp(patterns[pattern].pattern);\n\n if (regex.test(postCode)) { //eslint-disable-line max-depth\n return true;\n }\n }\n }\n\n return false;\n }\n\n return true;\n },\n\n postcodeValidation: function (postcodeElement) {\n var countryId = $('select[name=\"country\"]:visible').val(),\n validationResult,\n warnMessage,\n warnElement = $('.warning-postcode');\n\n if (postcodeElement == null || postcodeElement.val() == null) {\n return true;\n }\n\n warnElement.hide();\n warnElement.text('');\n\n validationResult = this.validatePostCode(postcodeElement.val(), countryId, []);\n\n if (!validationResult) {\n warnMessage = 'Please enter a valid post code.';\n warnElement.show();\n warnElement.text(warnMessage);\n\n if (warnMessage) {\n warnElement.prev().addClass('input-postcode-error');\n }\n\n } else {\n warnElement.prev().removeClass('input-postcode-error');\n }\n\n return validationResult;\n },\n\n toggleNewAddAddressForm: function (show) {\n this.viewModel.newAddressFormVisible(show);\n this.viewModel.selectExistingVisible(!show);\n this.viewModel.isLookup(show);\n this.clearAddressField();\n },\n\n clearAddressField: function () {\n $('#cc_c2a').remove();\n this.viewModel.currentShippingId(null);\n this.viewModel.newAddress.street = null;\n this.viewModel.newAddress.street = null;\n this.viewModel.newAddress.street2 = null;\n this.viewModel.newAddress.city = null;\n this.viewModel.newAddress.postcode = null;\n this.viewModel.newAddress.telephone = null;\n this.viewModel.newAddress.country = this.viewModel.currentCountryId();\n },\n\n updateCurrentAddressId: function () {\n var current = this.viewModel.currentShippingId(),\n initial = this.viewModel.initialSubscriptionAddressId();\n\n this.viewModel.saveAddressDisabled(current === initial);\n this.viewModel.useForSelected(false);\n },\n\n onUseForAllChange: function (type, event) {\n if (event && event.target) {\n this.viewModel.useForSelected(event.target.checked);\n }\n\n if (type === 'existing') {\n let currentId = this.viewModel.currentShippingId(),\n initialId = this.viewModel.initialSubscriptionAddressId(),\n defaultForAll = this.viewModel.defaultForAllAddressId();\n\n if (currentId === initialId && defaultForAll === currentId && this.viewModel.useForSelected()) {\n this.viewModel.saveAddressDisabled(!this.viewModel.saveAddressDisabled());\n }\n }\n\n return true;\n },\n\n submitChanges: function (event) {\n if (this.viewModel.confirmationVisibleType() === 'new') {\n return this.submitNewAddress(event);\n }\n\n return this.submitExistingAddress();\n },\n\n submitExistingAddress: function () {\n var self = this,\n entityId = this.viewModel.currentEntityId(),\n addressId = this.viewModel.currentShippingId(),\n useForAll = this.viewModel.useForSelected(),\n url = (useForAll ? this.useForAllUrl : this.assignAddressUrl + entityId + '/') + addressId,\n verb = useForAll ? 'POST' : 'PUT';\n\n utilities.makeCall(url, verb, function () {\n self.hideAddressModal();\n utilities.viewModel.updatedOrderEntityId(entityId);\n }, self.viewModel);\n\n return true;\n },\n\n submitNewAddress: function () {\n var self = this,\n entityId = this.viewModel.currentEntityId,\n firstName = this.viewModel.newAddress.firstName,\n lastName = this.viewModel.newAddress.lastName,\n street = this.viewModel.newAddress.street,\n city = this.viewModel.newAddress.city,\n postcode = this.viewModel.newAddress.postcode,\n country = this.viewModel.currentCountryId,\n telephone = this.viewModel.newAddress.telephone,\n url = this.addAddressUrl +\n '?entityId=' + entityId +\n '&firstName=' + firstName +\n '&lastName=' + lastName +\n '&street=' + street +\n '&postcode=' + postcode +\n '&city=' + city +\n '&countryId=' + country +\n '&telephone=' + telephone;\n\n utilities.makeCall(\n url,\n 'POST',\n function (response) {\n self.viewModel.currentShippingId(response.id);\n self.submitExistingAddress();\n }, self.viewModel);\n\n return true;\n }\n };\n});\n","PayPal_Braintree/js/customer/payment/address-form-initializer.js":"define([\n 'jquery',\n 'uiComponent',\n 'ko',\n 'PayPal_Braintree/js/customer/modals/address-modal',\n 'mageUtils',\n 'Magento_Checkout/js/model/payment/additional-validators'\n], function (\n $,\n Component,\n ko,\n addressModal,\n utils,\n additionalValidators\n) {\n 'use strict';\n return Component.extend({\n\n defaults: {\n template: 'Paypal_Braintree/customer/payment/address-wrapper',\n addressModal: addressModal,\n deliveryIntervals: ko.observableArray(null),\n currentlySelectedInterval: ko.observable(null),\n minDatePickerValue: 1,\n standardDeliveryDays: 1,\n baseUrl: ko.observable(),\n updatedOrderEntityId: null,\n countryId: 'GB',\n submitBtnSelector: '#braintree_submit',\n phoneNumberMaxLength: ko.observable(11),\n phoneNumberMinLength: ko.observable(2),\n phoneNumberMaxLengthErrorVisible: ko.observable(false),\n phoneNumberMinLengthErrorVisible: ko.observable(false)\n },\n\n initialize: function () {\n this._super();\n let self = this;\n\n additionalValidators.registerValidator({\n validate: function () {\n const $form = $('#form-validate');\n\n $form.validation();\n return $form.validation('isValid');\n }\n });\n\n fetch('/graphql', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n query: `{\n countries {\n full_name_locale,\n two_letter_abbreviation\n }\n }`\n })\n }).then(response => response.json()).then(response => {\n const countries = response.data.countries || [];\n\n countries.forEach(country => {\n self.addressModal.viewModel.countries.push({\n countryCode: country.two_letter_abbreviation,\n countryName: country.full_name_locale\n });\n });\n });\n },\n\n toggleSubmit: function (disable) {\n var submitBtn = $(this.submitBtnSelector);\n\n if (submitBtn.length) {\n submitBtn.attr('disabled', disable);\n }\n },\n\n showAddressModal: function (entity_id, groupedOrdersLength, shippingId, countryId) {\n this.addressModal.viewModel.selectExistingVisible(true);\n this.addressModal.viewModel.currentCountryId(this.countryId);\n this.addressModal.showAddressModal(entity_id, groupedOrdersLength, shippingId, countryId);\n let addressLength = this.addressModal.viewModel.currentAddresses().length;\n\n this.addressModal.viewModel.newAddressFormVisible(addressLength === 0);\n this.showLookupForm();\n this.toggleSubmit(true);\n },\n\n showNewAddressForm: function () {\n this.addressModal.toggleNewAddAddressForm(true);\n if (this.addressModal.toggleNewAddAddressForm) {\n document.getElementById('form-validate').style.display = 'block';\n }\n this.addressModal.viewModel.isLookup(false);\n\n this.toggleSubmit(false);\n },\n\n showLookupForm: function () {\n this.addressModal.toggleNewAddAddressForm(true);\n },\n\n showExistingSelector: function () {\n this.addressModal.toggleNewAddAddressForm(false);\n if (this.addressModal.toggleNewAddAddressForm) {\n document.getElementById('form-validate').style.display = 'none';\n }\n\n this.toggleSubmit(false);\n },\n\n /**\n * @param {*} postCode\n * @param {*} countryId\n * @param {Array} postCodesPatterns\n * @return {Boolean}\n */\n validatePostCode: function (postCode, countryId) {\n var pattern, regex,\n patterns = window.checkout.postCodes[countryId];\n\n this.validatedPostCodeExample = [];\n\n if (!utils.isEmpty(postCode) && !utils.isEmpty(patterns)) {\n for (pattern in patterns) {\n if (patterns.hasOwnProperty(pattern)) { //eslint-disable-line max-depth\n this.validatedPostCodeExample.push(patterns[pattern].example);\n regex = new RegExp(patterns[pattern].pattern);\n\n if (regex.test(postCode)) { //eslint-disable-line max-depth\n return true;\n }\n }\n }\n\n return false;\n }\n\n return true;\n },\n\n postcodeValidation: function (postcodeElement) {\n var countryId = this.countryId,\n validationResult,\n warnMessage,\n warnElement = $('.warning-postcode');\n\n if (postcodeElement == null || postcodeElement.val() == null) {\n return true;\n }\n\n warnElement.hide();\n warnElement.text('');\n\n validationResult = this.validatePostCode(postcodeElement.val(), countryId, []);\n\n if (!validationResult) {\n warnMessage = 'Please enter a valid post code.';\n\n warnElement.show();\n warnElement.text(warnMessage);\n\n if (warnMessage) {\n warnElement.prev().addClass('input-postcode-error');\n }\n } else {\n warnElement.prev().removeClass('input-postcode-error');\n }\n\n return validationResult;\n }\n });\n});\n","PayPal_Braintree/js/customer/payment/update-payment.js":"define([\n 'uiComponent',\n 'jquery',\n 'ko',\n 'uiRegistry'\n], function (Component, $, ko, registry) {\n 'use strict';\n return Component.extend({\n defaults: {\n addNewCardVM: {\n visible: ko.observable(false)\n },\n addNewPayPalVM: {\n visible: ko.observable(false)\n },\n errorModalVM: {\n visible: ko.observable(false),\n message: ko.observable(null),\n header: ko.observable('Error')\n }\n },\n\n /**\n * Add the repeat order block to the frontend\n */\n initialize: function () {\n this.modifyKnockoutRemovalBehaviour();\n\n this._super();\n },\n\n /**\n * By moving the billing address form inside of Knockout it\n * conflicts with the mage.directoryRegionUpdater widget.\n *\n * Knockout will run a cleanData method that removes jQuery events so removes the region updater events\n * so User's will no longer see the correct region fields.\n */\n modifyKnockoutRemovalBehaviour: function () {\n const normalFunction = ko.utils.domNodeDisposal.cleanExternalData;\n\n ko.utils.domNodeDisposal.cleanExternalData = function (node) {\n if (node.id === 'country') {\n return;\n }\n\n normalFunction(node);\n };\n },\n\n showAddCardModal: function () {\n this.addNewCardVM.visible(true);\n\n $('html, body').animate({scrollTop: 0}, 400);\n },\n\n hideAddCardModal: function () {\n this.addNewCardVM.visible(false);\n },\n\n showAddPayPalModal: function () {\n var braintreePaypal = registry.get('new-form-braintree-paypal');\n\n braintreePaypal.setup();\n this.addNewPayPalVM.visible(true);\n },\n\n hideAddPayPalModal: function () {\n var braintreePaypal = registry.get('new-form-braintree-paypal');\n\n braintreePaypal.teardownPayPalInstance();\n this.addNewPayPalVM.visible(false);\n }\n });\n});\n","PayPal_Braintree/js/customer/payment/braintree-card.js":"define([\n 'uiComponent',\n 'jquery',\n 'ko',\n 'underscore',\n 'mage/translate',\n 'uiRegistry',\n 'braintreeThreeDSecure',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'PayPal_Braintree/js/helper/get-braintree-config',\n 'PayPal_Braintree/js/view/payment/adapter'\n], function (Component, $, ko, _, $t, uiRegistry, threeDSecure, additionalValidators, getBraintreeConfig, braintree) {\n 'use strict';\n\n /**\n * braintree is not an instance of Component so we need to merge in our changes\n * and return an instance of Component with the final merged object.\n */\n var uiC = _.extend(braintree, {\n clientToken: null,\n uiConfig: null,\n paymentMethodNonce: null,\n selectedCardType: null,\n\n isValidCardNumber: false,\n isValidExpirationDate: false,\n isValidCvvNumber: false,\n\n viewModel: {\n paymentMethodNonce: ko.observable(null),\n publicHash: ko.observable(null),\n paymentMethodCode: 'braintree',\n total: ko.observable(0),\n isThreeDSecureEnabled: ko.observable(false),\n selectedMethod: {\n price: ko.observable(0)\n },\n errorMessage: ko.observable()\n },\n\n /**\n * Additional payment data\n *\n * {Object}\n */\n additionalData: {},\n\n /**\n * @inheritDoc\n */\n initialize: async function (uiConfig) {\n this._super().observe([\n 'selectedCardType'\n ]);\n\n await this.getBraintreeConfig();\n\n this.uiConfig = uiConfig;\n this.icons = uiConfig.icons;\n this.cvvImage = uiConfig.cvvImage;\n this.viewModel.isThreeDSecureEnabled(uiConfig.isThreeDSecureEnabled);\n this.viewModel.total(parseFloat(uiConfig.amount).toFixed(2));\n\n let self = this;\n\n const elm = await this._waitForElm('#co-transparent-form-braintree');\n\n if (elm) {\n this.clientConfig = {\n additionalData: {},\n\n /**\n * Device data initialization\n * @param {String} deviceData\n */\n onDeviceDataReceived: function (deviceData) {\n this.additionalData['device_data'] = deviceData;\n },\n\n /**\n * Triggers on any Braintree error\n * @param {Object} response\n */\n onError: function (response) {\n self.showError($t('Please enter a valid card number, expiry date and CVV Number.'));\n throw response.message;\n },\n\n /**\n * Triggers when customer click \"Cancel\"\n */\n onCancelled: function () {\n self.showError($t('The process has been cancelled'));\n },\n\n onReady: function (context) {\n context.setupHostedFields();\n },\n\n /**\n * Allow a new nonce to be generated\n */\n onPaymentMethodError: function () {\n this.isProcessing = false;\n },\n\n /**\n * Set payment nonce\n * @param {String} paymentMethodNonce\n */\n setPaymentMethodNonce: function (paymentMethodNonce) {\n this.paymentMethodNonce = paymentMethodNonce;\n },\n\n\n /**\n * After Braintree instance initialization\n */\n onInstanceReady: function (instance) {\n instance.on('validityChange', self.onValidityChange.bind(self));\n instance.on('cardTypeChange', self.onCardTypeChange.bind(self));\n },\n\n id: 'co-transparent-form-braintree',\n\n hostedFields: {\n number: {\n selector: '#braintree_cc_number',\n placeholder: '4111 1111 1111 1111'\n },\n expirationDate: {\n selector: '#braintree_expirationDate',\n placeholder: $t('MM/YYYY')\n },\n cvv: {\n selector: '#braintree_cc_cid',\n placeholder: $t('000')\n }\n },\n\n styles: {\n 'input': {\n 'font-size': '14px',\n 'color': '#3A3A3A'\n },\n ':focus': {\n 'color': 'black'\n },\n '.valid': {\n 'color': 'green'\n },\n '.invalid': {\n 'color': 'red'\n }\n },\n\n onPaymentMethodReceived: function (response) {\n $.ajax({\n url: '/rest/default/V1/braintree/mine/payment/vault',\n type: 'POST',\n data: JSON.stringify({\n billingAddress: {},\n payment: {\n payment_method_code: self.viewModel.paymentMethodCode,\n payment_method_nonce: response.nonce,\n device_data: this.additionalData.device_data\n }\n }),\n contentType:'application/json; charset=utf-8',\n success: function () {\n window.location.reload();\n },\n error: function (error) {\n $('body').trigger('processStop');\n console.warn(error.message);\n }\n });\n }\n };\n\n this.setConfig(this.clientConfig);\n this.clientToken = uiConfig.clientToken;\n this.setup();\n }\n },\n\n /**\n * Get list of card types\n * @returns {Object}\n */\n getCcTypesMapper: function () {\n return this.uiConfig.ccTypeMapper;\n },\n\n /**\n * Find mage card type by Braintree type\n * @param {String} type\n * @param {Object} availableTypes\n * @returns {*}\n */\n getMageCardType: function (type, availableTypes) {\n var storedCardType = null,\n mapper = this.getCcTypesMapper();\n\n if (type && typeof mapper[type] !== 'undefined') {\n storedCardType = mapper[type];\n\n if (_.indexOf(availableTypes, storedCardType) !== -1) {\n return storedCardType;\n }\n }\n\n return null;\n },\n\n getBraintreeConfig: function () {\n return getBraintreeConfig()\n .then(response => {\n this.merchantAccountId = response.data.storeConfig.braintree_merchant_account_id;\n });\n },\n\n /**\n * Triggers on Hosted Field changes\n * @param {Object} event\n * @returns {Boolean}\n */\n onValidityChange: function (event) {\n // Handle a change in validation or card type\n if (event.emittedBy === 'number') {\n this.selectedCardType(null);\n\n if (event.cards.length === 1) {\n this.isValidCardNumber = event.fields.number.isValid;\n this.selectedCardType(\n this.getMageCardType(event.cards[0].type, this.uiConfig.availableCardTypes));\n this.validateCardType();\n } else {\n this.isValidCardNumber = event.fields.number.isValid;\n this.validateCardType();\n }\n }\n\n // Other field validations\n if (event.emittedBy === 'expirationDate') {\n this.isValidExpirationDate = event.fields.expirationDate.isValid;\n }\n if (event.emittedBy === 'cvv') {\n this.isValidCvvNumber = event.fields.cvv.isValid;\n }\n },\n\n /**\n * Triggers on Hosted Field card type changes\n * @param {Object} event\n * @returns {Boolean}\n */\n onCardTypeChange: function (event) {\n if (event.cards.length === 1) {\n this.selectedCardType(\n this.getMageCardType(event.cards[0].type, this.uiConfig.availableCardTypes)\n );\n } else {\n this.selectedCardType(null);\n }\n },\n\n _waitForElm: function (selector) {\n return new Promise(resolve => {\n if (document.querySelector(selector)) {\n return resolve(document.querySelector(selector));\n }\n\n const observer = new MutationObserver(() => {\n if (document.querySelector(selector)) {\n resolve(document.querySelector(selector));\n observer.disconnect();\n }\n });\n\n observer.observe(document.body, {\n childList: true,\n subtree: true\n });\n });\n },\n\n /**\n * @inheritDoc\n */\n getClientToken: function () {\n return this.clientToken;\n },\n\n /**\n * Trigger order placing\n */\n placeOrderClick: function () {\n if (this.validateFormFields() && additionalValidators.validate()) {\n this.handleNonce();\n }\n },\n\n /**\n * Get jQuery selector\n * @param {String} field\n * @returns {String}\n */\n getSelector: function (field) {\n return '#' + this.code + '_' + field;\n },\n\n /**\n * Get card icons\n *\n * @param {String} type\n * @returns {Object|Boolean}\n */\n getIcons: function (findType) {\n return this.icons.find(({ type }) => type === findType);\n },\n\n /**\n * Toggle invalid class on selector\n * @param selector\n * @param state\n * @returns {boolean}\n */\n validateField: function (selector, state) {\n var $selector = $(this.getSelector(selector)),\n invalidClass = 'braintree-hosted-fields-invalid';\n\n if (state === true) {\n $selector.removeClass(invalidClass);\n return true;\n }\n\n $selector.addClass(invalidClass);\n return false;\n },\n\n /**\n * Validate all fields\n * @returns {boolean}\n */\n validateFormFields: function () {\n return (this.validateCardType() && this.validateExpirationDate() && this.validateCvvNumber()) === true;\n },\n\n /**\n * Validate current credit card type\n * @returns {Boolean}\n */\n validateCardType: function () {\n return this.validateField(\n 'cc_number',\n this.isValidCardNumber\n );\n },\n\n /**\n * Validate current expiry date\n * @returns {boolean}\n */\n validateExpirationDate: function () {\n return this.validateField(\n 'expirationDate',\n this.isValidExpirationDate === true\n );\n },\n\n /**\n * Validate current CVV field\n * @returns {boolean}\n */\n validateCvvNumber: function () {\n return this.validateField(\n 'cc_cid',\n this.isValidCvvNumber === true\n );\n },\n\n /**\n * Get image for CVV\n * @returns {String}\n */\n getCvvImageHtml: function () {\n return '<img src=\"' + this.cvvImage +\n '\" alt=\"' + $t('Card Verification Number Visual Reference') +\n '\" title=\"' + $t('Card Verification Number Visual Reference') +\n '\" />';\n },\n\n /**\n * Prepare data to place order\n */\n handleNonce: function () {\n\n $('body').trigger('processStart');\n this.viewModel.errorMessage('');\n\n let state = $.Deferred(),\n addressBilling = uiRegistry.get('store-braintree-card-form.address'),\n shippingId = addressBilling.addressModal.viewModel.currentShippingId(),\n\n // If we have a shipping ID then get the selected address otherwise use the new address.\n currentAddress = shippingId\n ? addressBilling.addressModal.viewModel.currentAddresses().find(function (address) {\n return address.id === shippingId;\n }) : {\n firstname: document.getElementById('firstname').value,\n lastname: document.getElementById('lastname').value,\n telephone: document.getElementById('telephone').value,\n street: [\n document.getElementById('street_1').value,\n document.getElementById('street_2').value\n ],\n city: document.getElementById('city').value,\n region: {\n region_code: document.getElementById('region_id').value\n },\n postcode: document.getElementById('zip').value,\n country_id: document.getElementById('country').value\n };\n\n const billingAddress = {\n givenName: currentAddress.firstname,\n surname: currentAddress.lastname,\n phoneNumber: currentAddress.telephone,\n streetAddress: currentAddress.street[0],\n extendedAddress: currentAddress.street[1],\n locality: currentAddress.city,\n region: currentAddress.region.region_code,\n postalCode: currentAddress.postcode,\n countryCodeAlpha2: currentAddress.country_id\n };\n\n this.hostedFieldsInstance\n .tokenize({\n vault: true,\n billingAddress\n }).then(function (payload) {\n this.viewModel.paymentMethodNonce(payload.nonce);\n let threeDSEnabled = this.viewModel.isThreeDSecureEnabled();\n\n const callback = () => {\n const nonce = this.viewModel.paymentMethodNonce();\n\n this.clientConfig.onPaymentMethodReceived({ nonce });\n };\n\n if (threeDSEnabled) {\n threeDSecure.create({\n version: 2,\n client: this.clientInstance\n }, function (threeDSecureErr, threeDSecureInstance) {\n if (threeDSecureErr) {\n console.warn(threeDSecureErr);\n return;\n }\n\n threeDSecureInstance.verifyCard({\n amount: this.viewModel.total(),\n nonce: payload.nonce,\n bin: payload.details.bin,\n cardAddChallengeRequested: true,\n vault: true,\n\n onLookupComplete: function (data, next) {\n next();\n }\n }, function (err, response) {\n if (err) {\n $('body').trigger('processStop');\n this.viewModel.errorMessage($t('Please try again with another form of payment.'));\n return state.reject($t('Please try again with another form of payment.'));\n }\n\n let liability = {\n shifted: response.liabilityShifted,\n shiftPossible: response.liabilityShiftPossible\n };\n\n if (liability.shifted || !liability.shifted && !liability.shiftPossible) {\n this.viewModel.paymentMethodNonce(response.nonce);\n state.resolve();\n\n // Validation Passed\n callback();\n\n } else {\n // eslint-disable-next-line max-len\n this.viewModel.errorMessage($t('We could not validate your payment method. Please try again with another form of payment.'));\n $('body').trigger('processStop');\n state.reject($t('Please try again with another form of payment.'));\n }\n }.bind(this));\n }.bind(this));\n } else {\n callback();\n }\n }.bind(this))\n .catch(function () {\n $('body').trigger('processStop');\n });\n }\n });\n\n return Component.extend(uiC);\n});\n","PayPal_Braintree/js/customer/payment/braintree-paypal.js":"define([\n 'uiComponent',\n 'jquery',\n 'ko',\n 'underscore',\n 'PayPal_Braintree/js/view/payment/adapter',\n 'braintreePayPalCheckout',\n 'mage/translate'\n], function (Component, $, ko, _, braintree, paypalCheckout, $t) {\n 'use strict';\n\n /**\n * braintree is not an instance of Component so we need to merge in our changes\n * and return an instance of Component with the final merged object.\n */\n var uiC = _.extend(braintree, {\n clientToken: null,\n uiConfig: null,\n paymentMethodNonce: null,\n\n viewModel: {\n errorMessage: ko.observable()\n },\n\n /**\n * @inheritDoc\n */\n initialize: function (uiConfig) {\n this._super();\n\n this.uiConfig = uiConfig;\n this.merchantName = uiConfig.merchantName;\n this.locale = uiConfig.locale;\n this.currency = uiConfig.currency;\n this.orderAmount = uiConfig.orderAmount;\n const self = this;\n\n this.clientConfig = {\n\n additionalData: {},\n buttonId: 'paypal_container',\n\n /**\n * Device data initialization\n * @param {String} deviceData\n */\n onDeviceDataReceived: function (deviceData) {\n this.additionalData['device_data'] = deviceData;\n },\n\n /**\n * Triggers when widget is loaded\n * @param {Object} context\n */\n onReady: function (context) {\n paypalCheckout.create({\n client: context.clientInstance\n }, async function (paypalCheckoutErr, paypalCheckoutInstance) {\n self.setPayPalInstance(paypalCheckoutInstance);\n\n await paypalCheckoutInstance.loadPayPalSDK({\n vault: true\n });\n\n window.paypal.Buttons({\n fundingSource: window.paypal.FUNDING.PAYPAL,\n\n createBillingAgreement: function () {\n return paypalCheckoutInstance.createPayment({\n flow: 'vault',\n\n enableShippingAddress: false,\n shippingAddressEditable: false,\n\n amount: self.orderAmount,\n currency: self.currency,\n locale: self.locale\n });\n },\n\n onApprove: function (data) {\n $('body').trigger('processStart');\n return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {\n if (err) {\n $('body').trigger('processStop');\n self.viewModel.errorMessage(\n $t('Please try again with another form of payment.'));\n return;\n }\n\n $.ajax({\n url: '/rest/default/V1/braintree/mine/payment/vault',\n type: 'POST',\n data: JSON.stringify({\n payment: {\n payment_method_code: 'braintree_paypal',\n payment_method_nonce: payload.nonce,\n device_data: self.deviceData\n }\n }),\n contentType:'application/json; charset=utf-8',\n success: function () {\n window.location.reload();\n },\n error: function (error) {\n $('body').trigger('processStop');\n console.warn(error.message);\n }\n });\n });\n },\n\n onCancel: function (data) {\n console.log('PayPal payment canceled', JSON.stringify(data, 0, 2));\n },\n\n onError: function (err) {\n console.error('PayPal error', err);\n }\n }).render('#paypal_container_account');\n });\n },\n\n /**\n * Triggers on any Braintree error\n * @param {Object} response\n */\n onError: function (response) {\n self.showError($t('PayPal error msg'));\n throw response.message;\n },\n\n /**\n * Triggers when customer click \"Cancel\"\n */\n onCancelled: function () {\n self.showError($t('The process has been cancelled'));\n },\n\n onPaymentMethodReceived: function (response) {\n self.paymentMethodNonce = response.nonce;\n $('#braintree-paypal-payment-method-nonce').val(response.nonce);\n $('#braintree-paypal-form').trigger('submit');\n },\n\n dataCollector: {\n paypal: true\n },\n paypal: {\n container: 'paypal_container_account',\n flow: 'vault',\n singleUse: false,\n amount: self.orderAmount,\n currency: self.currency,\n locale: self.locale,\n enableShippingAddress: false,\n displayName: self.merchantName,\n\n /**\n * Triggers on any Braintree error\n */\n onError: function () {\n this.paymentMethodNonce = null;\n },\n\n /**\n * Triggers if browser doesn't support PayPal Checkout\n */\n onUnsupported: function () {\n this.paymentMethodNonce = null;\n }\n }\n };\n\n this.setConfig(this.clientConfig);\n this.clientToken = uiConfig.clientToken;\n },\n\n /**\n * @inheritDoc\n */\n getClientToken: function () {\n return this.clientToken;\n },\n\n /**\n * @returns {String}\n */\n getColor: function () {\n return this.color;\n },\n\n /**\n * @returns {String}\n */\n getShape: function () {\n return this.shape;\n },\n\n /**\n * @returns {String}\n */\n getLayout: function () {\n return this.layout;\n },\n\n /**\n * @returns {String}\n */\n getSize: function () {\n return this.size;\n },\n\n /**\n * @returns {String}\n */\n getEnvironment: function () {\n return this.environment;\n },\n\n /**\n * @returns {String}\n */\n getDisabledFunding: function () {\n return this.disabledFunding;\n },\n\n /**\n * Set the PayPal instance or null it by setting the value of the property.\n *\n * @param val\n */\n setPayPalInstance: function (val) {\n this.paypalInstance = val;\n },\n\n /**\n * Run the teardown script to remove the PayPal instance.\n */\n teardownPayPalInstance: function () {\n if (this.paypalInstance) {\n this.paypalInstance.teardown(function () {\n $('#paypal_container_account').empty();\n });\n this.paypalInstance = null;\n }\n\n window.dispatchEvent(new Event('paypal:reinit-express'));\n }\n });\n\n return Component.extend(uiC);\n});\n","PayPal_Braintree/js/googlepay/api.js":"/**\n * Braintree Google Pay button api\n **/\ndefine([\n 'uiComponent',\n 'underscore',\n 'jquery',\n 'mage/translate',\n 'mage/storage',\n 'PayPal_Braintree/js/form-builder',\n 'PayPal_Braintree/js/googlepay/implementations/shortcut/3d-secure',\n 'PayPal_Braintree/js/googlepay/model/parsed-response',\n 'PayPal_Braintree/js/googlepay/model/payment-data',\n 'PayPal_Braintree/js/helper/remove-non-digit-characters',\n 'PayPal_Braintree/js/view/payment/validator-manager'\n], function (\n Component,\n _,\n $,\n $t,\n storage,\n formBuilder,\n threeDSecureValidator,\n parsedResponseModel,\n paymentDataModel,\n removeNonDigitCharacters,\n validatorManager\n) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n validatorManager: validatorManager,\n threeDSecureValidator: threeDSecureValidator,\n clientToken: null,\n merchantId: null,\n currencyCode: null,\n actionSuccess: null,\n amount: null,\n cardTypes: [],\n btnColor: 0,\n email: null,\n paymentMethodNonce: null,\n creditCardBin: null\n },\n\n /**\n * Set & get environment\n * \"PRODUCTION\" or \"TEST\"\n */\n setEnvironment: function (value) {\n this.environment = value;\n },\n getEnvironment: function () {\n return this.environment;\n },\n\n /**\n * Set & get api token\n */\n setClientToken: function (value) {\n this.clientToken = value;\n },\n getClientToken: function () {\n return this.clientToken;\n },\n\n /**\n * Set and get display name\n */\n setMerchantId: function (value) {\n this.merchantId = value;\n },\n getMerchantId: function () {\n return this.merchantId;\n },\n\n /**\n * Set and get currency code\n */\n setAmount: function (value) {\n this.amount = parseFloat(value).toFixed(2);\n },\n getAmount: function () {\n return this.amount;\n },\n\n /**\n * Set and get currency code\n */\n setCurrencyCode: function (value) {\n this.currencyCode = value;\n },\n getCurrencyCode: function () {\n return this.currencyCode;\n },\n\n /**\n * Set and get success redirection url\n */\n setActionSuccess: function (value) {\n this.actionSuccess = value;\n },\n getActionSuccess: function () {\n return this.actionSuccess;\n },\n\n /**\n * Set and get success redirection url\n */\n setCardTypes: function (value) {\n this.cardTypes = value;\n },\n getCardTypes: function () {\n return this.cardTypes;\n },\n\n /**\n * BTN Color\n */\n setBtnColor: function (value) {\n this.btnColor = value;\n },\n getBtnColor: function () {\n return this.btnColor;\n },\n\n /**\n * Add the 3D Secure validator config.\n *\n * @param {object} value\n */\n setThreeDSecureValidatorConfig: function (value) {\n this.threeDSecureValidator.setConfig(value);\n },\n\n /**\n * Add the 3D Secure validator to the validation manager with amount & billing address data set.\n * It will be added only if 3D Secure is active.\n */\n addThreeDSecureValidator: function () {\n this.threeDSecureValidator.setBillingAddress(this.getThreeDSecureBillingAddressData());\n this.threeDSecureValidator.setShippingAddress(this.getThreeDSecureShippingAddressData());\n this.threeDSecureValidator.setTotalAmount(this.getAmount());\n\n this.validatorManager.add(this.threeDSecureValidator);\n },\n\n /**\n * Payment request info\n */\n getPaymentRequest: function () {\n let result = {\n transactionInfo: {\n totalPriceStatus: 'ESTIMATED',\n totalPrice: this.getAmount(),\n currencyCode: this.getCurrencyCode()\n },\n allowedPaymentMethods: [\n {\n 'type': 'CARD',\n 'parameters': {\n 'allowedCardNetworks': this.getCardTypes(),\n 'billingAddressRequired': true,\n 'billingAddressParameters': {\n format: 'FULL',\n phoneNumberRequired: true\n }\n }\n\n }\n ],\n shippingAddressRequired: true,\n shippingAddressParameters: {\n phoneNumberRequired: true\n },\n emailRequired: true\n };\n\n if (this.getEnvironment() !== 'TEST') {\n result.merchantInfo = { merchantId: this.getMerchantId() };\n }\n\n return result;\n },\n\n /**\n * Place the order\n */\n startPlaceOrder: function (deviceData) {\n let self = this,\n payload = {\n details: {\n shippingAddress: self.getShippingAddressData(),\n billingAddress: self.getBillingAddressData()\n },\n nonce: self.paymentMethodNonce,\n isNetworkTokenized: parsedResponseModel.getIsNetworkTokenized(),\n deviceData: deviceData\n };\n\n self.email = paymentDataModel.getEmail();\n self.paymentMethodNonce = parsedResponseModel.getNonce();\n self.creditCardBin = parsedResponseModel.getBin();\n\n\n if (parsedResponseModel.getIsNetworkTokenized() === false) {\n /* Add 3D Secure verification to payment & validate payment for non network tokenized cards */\n self.addThreeDSecureValidator();\n\n self.validatorManager.validate(self, function () {\n /* Set the new nonce from the 3DS verification */\n payload.nonce = self.paymentMethodNonce;\n\n return formBuilder.build({\n action: self.getActionSuccess(),\n fields: {\n result: JSON.stringify(payload)\n }\n }).submit();\n }, function () {\n self.paymentMethodNonce = null;\n self.creditCardBin = null;\n });\n } else {\n formBuilder.build({\n action: this.getActionSuccess(),\n fields: {\n result: JSON.stringify(payload)\n }\n }).submit();\n }\n },\n\n /**\n * Get the shipping address from the payment data model which should already be set by the calling script.\n *\n * @return {?Object}\n */\n getShippingAddressData: function () {\n let shippingAddress = paymentDataModel.getShippingAddress();\n\n if (shippingAddress === null) {\n return null;\n }\n\n return {\n streetAddress: shippingAddress.address1 + '\\n' + shippingAddress.address2,\n locality: shippingAddress.locality,\n postalCode: shippingAddress.postalCode,\n countryCodeAlpha2: shippingAddress.countryCode,\n email: paymentDataModel.getEmail(),\n name: shippingAddress.name,\n telephone: removeNonDigitCharacters(_.get(shippingAddress, 'phoneNumber', '')),\n region: _.get(shippingAddress, 'administrativeArea', '')\n };\n },\n\n /**\n * Get the billing address from the payment data model which should already be set by the calling script.\n *\n * @return {?Object}\n */\n getBillingAddressData: function () {\n let paymentMethodData = paymentDataModel.getPaymentMethodData(),\n billingAddress = _.get(paymentMethodData, ['info', 'billingAddress'], null);\n\n if (paymentMethodData === null) {\n return null;\n }\n\n\n if (billingAddress === null) {\n return null;\n }\n\n return {\n streetAddress: billingAddress.address1 + '\\n' + billingAddress.address2,\n locality: billingAddress.locality,\n postalCode: billingAddress.postalCode,\n countryCodeAlpha2: billingAddress.countryCode,\n email: paymentDataModel.getEmail(),\n name: billingAddress.name,\n telephone: removeNonDigitCharacters(_.get(billingAddress, 'phoneNumber', '')),\n region: _.get(billingAddress, 'administrativeArea', '')\n };\n },\n\n /**\n * Get the billing address data as required for 3D Secure verification.\n *\n * For First & last name, use a simple split by space.\n *\n * @return {?Object}\n */\n getThreeDSecureBillingAddressData: function () {\n let paymentMethodData = paymentDataModel.getPaymentMethodData(),\n billingAddress = _.get(paymentMethodData, ['info', 'billingAddress'], null);\n\n if (paymentMethodData === null) {\n return null;\n }\n\n if (billingAddress === null) {\n return null;\n }\n\n return {\n firstname: billingAddress.name.substring(0, billingAddress.name.indexOf(' ')),\n lastname: billingAddress.name.substring(billingAddress.name.indexOf(' ') + 1),\n telephone: removeNonDigitCharacters(_.get(billingAddress, 'phoneNumber', '')),\n street: [\n billingAddress.address1,\n billingAddress.address2\n ],\n city: billingAddress.locality,\n regionCode: _.get(billingAddress, 'administrativeArea', ''),\n postcode: billingAddress.postalCode,\n countryId: billingAddress.countryCode\n };\n },\n\n /**\n * Get the shipping address data as required for 3D Secure verification.\n *\n * For First & last name, use a simple split by space.\n *\n * @return {?Object}\n */\n getThreeDSecureShippingAddressData: function () {\n let shippingAddress = paymentDataModel.getShippingAddress();\n\n if (shippingAddress === null) {\n return null;\n }\n\n return {\n firstname: shippingAddress.name.substring(0, shippingAddress.name.indexOf(' ')),\n lastname: shippingAddress.name.substring(shippingAddress.name.indexOf(' ') + 1),\n telephone: removeNonDigitCharacters(_.get(shippingAddress, 'phoneNumber', '')),\n street: [\n shippingAddress.address1,\n shippingAddress.address2\n ],\n city: shippingAddress.locality,\n regionCode: _.get(shippingAddress, 'administrativeArea', ''),\n postcode: shippingAddress.postalCode,\n countryId: shippingAddress.countryCode\n };\n }\n });\n});\n","PayPal_Braintree/js/googlepay/button.js":"/**\n * Braintree Google Pay button\n **/\ndefine(\n [\n 'uiComponent',\n 'underscore',\n 'knockout',\n 'jquery',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_CheckoutAgreements/js/view/checkout-agreements',\n 'PayPal_Braintree/js/googlepay/model/parsed-response',\n 'PayPal_Braintree/js/googlepay/model/payment-data',\n 'PayPal_Braintree/js/view/payment/adapter',\n 'braintree',\n 'braintreeDataCollector',\n 'braintreeGooglePay',\n 'mage/translate',\n 'googlePayLibrary'\n ],\n function (\n Component,\n _,\n ko,\n $,\n additionalValidators,\n checkoutAgreements,\n parsedResponseModel,\n paymentDataModel,\n braintreeMainAdapter,\n braintree,\n dataCollector,\n googlePay,\n $t\n ) {\n 'use strict';\n\n return {\n init: function (element, context) {\n\n // No element or context\n if (!element || !context) {\n return;\n }\n\n // Context must implement these methods\n if (typeof context.getClientToken !== 'function') {\n console.error(\n 'Braintree GooglePay Context passed does not provide a getClientToken method',\n context\n );\n return;\n }\n if (typeof context.getPaymentRequest !== 'function') {\n console.error(\n 'Braintree GooglePay Context passed does not provide a getPaymentRequest method',\n context\n );\n return;\n }\n if (typeof context.startPlaceOrder !== 'function') {\n console.error(\n 'Braintree GooglePay Context passed does not provide a startPlaceOrder method',\n context\n );\n return;\n }\n\n // init google pay object\n let paymentsClient = new window.google.payments.api.PaymentsClient({\n environment: context.getEnvironment()\n }),\n\n // Create a button within the KO element, as Google Pay can only be instantiated through\n // a valid on click event (ko onclick bind interferes with this).\n button = document.createElement('button'),\n color = context.getBtnColor() === 1 ? 'black' : 'white';\n\n button.className = 'braintree-googlepay-button long ' + color;\n button.title = $t('Buy with Google Pay');\n\n // init braintree api\n braintree.create({\n authorization: context.getClientToken()\n }, function (clientErr, clientInstance) {\n this.initGooglePay(clientErr, clientInstance, paymentsClient, button, element, context);\n }.bind(this));\n },\n\n initGooglePay: function (clientErr, clientInstance, paymentsClient, button, element, context) {\n if (clientErr) {\n console.error('Error creating client:', clientErr);\n return;\n }\n dataCollector.create({\n client: clientInstance\n }, function (dataCollectorErr, dataCollectorInstance) {\n if (dataCollectorErr) {\n return;\n }\n googlePay.create({\n client: clientInstance,\n googlePayVersion: 2\n }, function (googlePayErr, googlePaymentInstance) {\n this.render(\n clientInstance,\n googlePayErr,\n googlePaymentInstance,\n dataCollectorInstance,\n paymentsClient,\n button,\n element,\n context\n );\n }.bind(this));\n }.bind(this));\n },\n\n render: function (clientInstance, googlePayErr, googlePaymentInstance,\n dataCollectorInstance, paymentsClient, button, element, context) {\n // No instance\n if (googlePayErr) {\n console.error('Braintree GooglePay Error creating googlePayInstance:', googlePayErr);\n return;\n }\n\n /**\n * Assign existing client instance to braintree adapter to use existing one\n * otherwise new client instance needs to be created for 3DS verification\n * which calls the Braintree Client & Device Collector SDK twice and\n * makes process slow.\n */\n braintreeMainAdapter.clientInstance = clientInstance;\n braintreeMainAdapter.deviceData = dataCollectorInstance.deviceData;\n\n paymentsClient.isReadyToPay({\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: googlePaymentInstance.createPaymentDataRequest().allowedPaymentMethods\n }).then(function (response) {\n if (response.result) {\n button.addEventListener('click', function (event) {\n let agreements = checkoutAgreements().agreements,\n shouldDisableActions = false;\n\n _.each(agreements, function (item) {\n if (checkoutAgreements().isAgreementRequired(item)) {\n let inputId = '#agreement_braintree_googlepay_' + item.agreementId,\n inputEl = document.querySelector(inputId);\n\n if (inputEl !== null && !inputEl.checked) {\n shouldDisableActions = true;\n }\n\n }\n });\n\n if ($(button).parents('#braintree-googlepay-express-payment').length === 0\n && !additionalValidators.validate(false)) {\n event.preventDefault();\n return false;\n }\n\n if (!shouldDisableActions) {\n event.preventDefault();\n $('body').loader('show');\n\n let paymentDataRequest = googlePaymentInstance.createPaymentDataRequest(\n context.getPaymentRequest()\n );\n\n paymentsClient.loadPaymentData(paymentDataRequest).then(function (paymentData) {\n // Persist the paymentData (shipping address etc.)\n paymentDataModel.setPaymentMethodData(_.get(\n paymentData,\n 'paymentMethodData',\n null\n ));\n paymentDataModel.setEmail(_.get(paymentData, 'email', ''));\n paymentDataModel.setShippingAddress(_.get(\n paymentData,\n 'shippingAddress',\n null\n ));\n // Return the braintree nonce promise\n return googlePaymentInstance.parseResponse(paymentData);\n }).then(function (result) {\n parsedResponseModel.setNonce(result.nonce);\n parsedResponseModel.setIsNetworkTokenized(_.get(\n result,\n ['details', 'isNetworkTokenized'],\n false\n ));\n parsedResponseModel.setBin(_.get(\n result,\n ['details', 'bin'],\n null\n ));\n\n context.startPlaceOrder(dataCollectorInstance.deviceData);\n $('body').loader('hide');\n }).catch(function (err) {\n // Handle errors\n // err = {statusCode: \"CANCELED\"}\n console.error(err);\n parsedResponseModel.resetDefaultData();\n $('body').loader('hide');\n });\n }\n });\n element.appendChild(button);\n }\n }).catch(function (err) {\n console.error(err);\n $('body').loader('hide');\n });\n }\n };\n }\n);\n","PayPal_Braintree/js/googlepay/implementations/shortcut.js":"/**\n * Braintree Google Pay mini cart payment method integration.\n **/\ndefine(\n [\n 'uiComponent',\n 'PayPal_Braintree/js/googlepay/button',\n 'PayPal_Braintree/js/googlepay/api',\n 'domReady!'\n ],\n function (\n Component,\n button,\n buttonApi\n ) {\n 'use strict';\n\n return Component.extend({\n\n defaults: {\n id: null,\n clientToken: null,\n merchantId: null,\n currencyCode: null,\n actionSuccess: null,\n amount: null,\n environment: 'TEST',\n cardType: [],\n btnColor: 0,\n threeDSecure: null\n },\n\n /**\n * @returns {Object}\n */\n initialize: function () {\n this._super();\n\n /* Add client token & environment to 3DS Config */\n this.threeDSecure.clientToken = this.clientToken;\n this.threeDSecure.environment = this.environment;\n\n let api = new buttonApi();\n\n api.setEnvironment(this.environment);\n api.setCurrencyCode(this.currencyCode);\n api.setClientToken(this.clientToken);\n api.setMerchantId(this.merchantId);\n api.setActionSuccess(this.actionSuccess);\n api.setAmount(this.amount);\n api.setCardTypes(this.cardTypes);\n api.setBtnColor(this.btnColor);\n api.setThreeDSecureValidatorConfig(this.threeDSecure);\n\n // Attach the button\n button.init(\n document.getElementById(this.id),\n api\n );\n\n return this;\n }\n });\n }\n);\n","PayPal_Braintree/js/googlepay/implementations/shortcut/3d-secure.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'underscore',\n 'jquery',\n 'mage/translate',\n 'braintreeThreeDSecure',\n 'PayPal_Braintree/js/googlepay/implementations/shortcut/adapter',\n 'PayPal_Braintree/js/helper/escape-non-ascii-characters',\n 'PayPal_Braintree/js/helper/remove-non-digit-characters',\n 'PayPal_Braintree/js/helper/format-amount',\n 'PayPal_Braintree/js/model/full-screen-loader'\n], function (\n _,\n $,\n $t,\n threeDSecure,\n braintree,\n escapeNonAsciiCharacters,\n removeNonDigitCharacters,\n formatAmount,\n defaultFullScreenLoader\n) {\n 'use strict';\n\n /**\n * 3D Secure implementation generic enough to be used for GooglePay button payments.\n *\n * This can be used in other pages along with the basket page, but not in the checkout page when placing an order.\n */\n return {\n code: 'three_d_secure',\n fullScreenLoader: defaultFullScreenLoader,\n config: null,\n billingAddress: null,\n shippingAddress: null,\n totalAmount: null,\n\n /**\n * Get code.\n *\n * @returns {string}\n */\n getCode: function () {\n return this.code;\n },\n\n /**\n *\n * @return {boolean}\n */\n isEnabled: function () {\n return this.config !== null ? _.get(this.config, ['enabled'], false) : false;\n },\n\n /**\n * Set the full screen loader implementation.\n *\n * @param fullScreenLoader\n */\n setFullScreenLoader: function (fullScreenLoader) {\n this.fullScreenLoader = fullScreenLoader;\n },\n\n /**\n * Get the full screen loader implementation.\n */\n getFullScreenLoader: function () {\n return this.fullScreenLoader;\n },\n\n /**\n * Set 3d secure config.\n *\n * @param {object} config\n */\n setConfig: function (config) {\n this.config = config;\n this.config.thresholdAmount = parseFloat(_.get(config, 'thresholdAmount', '0.0'));\n },\n\n /**\n * Get the billing address data.\n */\n getBillingAddress: function () {\n return this.billingAddress;\n },\n\n /**\n * Set the billing address data.\n *\n * @param {object} value\n */\n setBillingAddress: function (value) {\n this.billingAddress = value;\n },\n\n /**\n * Get the shipping address data.\n */\n getShippingAddress: function () {\n return this.shippingAddress;\n },\n\n /**\n * Set the shipping address data.\n *\n * @param {object} value\n */\n setShippingAddress: function (value) {\n this.shippingAddress = value;\n },\n\n /**\n * Get the total amount to be charged.\n */\n getTotalAmount: function () {\n return this.totalAmount;\n },\n\n /**\n * Set the full screen loader implementation.\n *\n * @param {string} value\n */\n setTotalAmount: function (value) {\n this.totalAmount = formatAmount(value);\n },\n\n /**\n * Get the Braintree environment.\n *\n * @return {string|null}\n */\n getEnvironment: function () {\n return _.get(this.config, 'environment', 'TEST');\n },\n\n /**\n * Get the Braintree Client Token.\n *\n * @return {string|null}\n */\n getClientToken: function () {\n return _.get(this.config, 'clientToken', null);\n },\n\n /**\n * Check minimal amount for 3d secure activation.\n *\n * @param {Number} amount\n * @returns {Boolean}\n */\n isAmountAvailable: function (amount) {\n amount = parseFloat(amount.toString());\n\n return amount >= this.config.thresholdAmount;\n },\n\n /**\n * Check if current country is available for 3d secure.\n *\n * @param {String} countryId\n * @returns {Boolean}\n */\n isCountryAvailable: function (countryId) {\n let key,\n specificCountries = _.get(this.config, 'specificCountries', []);\n\n // all countries are available\n if (!specificCountries.length) {\n return true;\n }\n\n for (key in specificCountries) {\n if (countryId === specificCountries[key]) {\n return true;\n }\n }\n\n return false;\n },\n\n /**\n * Check billing/shipping address line lengths\n *\n * @param errorMessage\n * @param billingAddress\n * @param shippingAddress\n * @returns {*}\n */\n checkBillingLineLengths: function (errorMessage, billingAddress, shippingAddress) {\n let lineError = null;\n\n if (billingAddress.street[0].length > 50 ||\n (shippingAddress.street !== undefined && shippingAddress.street[0].length > 50)) {\n lineError = 'line1';\n } else if (billingAddress.street[1].length > 50 ||\n (shippingAddress.street !== undefined && shippingAddress.street[1].length > 50)) {\n lineError = 'line2';\n }\n\n if (lineError) {\n let error = `Billing/Shipping ${lineError} must be string and less than 50 characters.`;\n\n return $t(`${error} Please update the address and try again.`);\n }\n },\n\n /**\n * Get the challenge requested config (default false).\n *\n * @returns {Boolean}\n */\n getChallengeRequested: function () {\n return _.get(this.config, 'challengeRequested', false);\n },\n\n /**\n * Get Customer's IP Address\n *\n * @returns {Boolean}\n */\n getIpAddress: function () {\n return _.get(this.config, 'ipAddress', '');\n },\n\n /**\n * Trigger 3DS verification & validate Braintree payment nonce.\n *\n * @param {Object} context\n * @returns {Object}\n */\n validate: function (context) {\n let self = this,\n clientInstance = braintree.getApiClient(),\n state = $.Deferred(),\n billingAddress = self.getBillingAddress(),\n shippingAddress = self.getShippingAddress(),\n setup3d;\n\n // Handle billing address region code\n if (billingAddress.regionCode == null) {\n billingAddress.regionCode = undefined;\n }\n if (billingAddress.regionCode !== undefined && billingAddress.regionCode.length > 2) {\n billingAddress.regionCode = undefined;\n }\n\n // Handle shipping address region code\n if (shippingAddress.regionCode == null) {\n shippingAddress.regionCode = undefined;\n }\n if (shippingAddress.regionCode !== undefined && shippingAddress.regionCode.length > 2) {\n shippingAddress.regionCode = undefined;\n }\n\n if (!self.isAmountAvailable(self.getTotalAmount()) || !self.isCountryAvailable(billingAddress.countryId)) {\n state.resolve();\n return state.promise();\n }\n\n self.getFullScreenLoader().startLoader();\n\n setup3d = function (client) {\n threeDSecure.create({\n version: 2,\n client: client\n }, function (threeDSecureErr, threeDSecureInstance) {\n if (threeDSecureErr) {\n self.getFullScreenLoader().stopLoader();\n return state.reject($t('Please try again with another form of payment.'));\n }\n\n let threeDSContainer = document.createElement('div'),\n tdMask = document.createElement('div'),\n tdFrame = document.createElement('div'),\n tdBody = document.createElement('div'),\n threeDSecureParameters;\n\n threeDSContainer.className = 'braintree-three-d-modal';\n tdMask.className = 'bt-mask';\n tdFrame.className = 'bt-modal-frame';\n tdBody.className = 'bt-modal-body';\n\n tdFrame.appendChild(tdBody);\n threeDSContainer.appendChild(tdMask);\n threeDSContainer.appendChild(tdFrame);\n\n threeDSecureParameters = {\n amount: self.getTotalAmount(),\n nonce: context.paymentMethodNonce,\n bin: context.creditCardBin,\n collectDeviceData: true,\n challengeRequested: self.getChallengeRequested(),\n billingAddress: {\n givenName: escapeNonAsciiCharacters(billingAddress.firstname),\n surname: escapeNonAsciiCharacters(billingAddress.lastname),\n phoneNumber: billingAddress.telephone !== null\n ? removeNonDigitCharacters(billingAddress.telephone)\n : billingAddress.telephone,\n streetAddress: billingAddress.street[0],\n extendedAddress: billingAddress.street[1],\n locality: billingAddress.city,\n region: billingAddress.regionCode,\n postalCode: billingAddress.postcode,\n countryCodeAlpha2: billingAddress.countryId\n },\n additionalInformation: {\n shippingGivenName: escapeNonAsciiCharacters(shippingAddress.firstname),\n shippingSurname: escapeNonAsciiCharacters(shippingAddress.lastname),\n shippingAddress: {\n streetAddress: shippingAddress.street[0],\n extendedAddress: shippingAddress.street[1],\n locality: shippingAddress.city,\n region: shippingAddress.regionCode,\n postalCode: shippingAddress.postcode,\n countryCodeAlpha2: shippingAddress.countryId\n },\n shippingPhone: shippingAddress.telephone !== null\n ? removeNonDigitCharacters(shippingAddress.telephone)\n : shippingAddress.telephone,\n ipAddress: self.getIpAddress()\n },\n onLookupComplete: function (data, next) {\n next();\n },\n addFrame: function (err, iframe) {\n self.getFullScreenLoader().stopLoader();\n\n if (err) {\n console.log('Unable to verify card over 3D Secure', err);\n return state.reject($t('Please try again with another form of payment.'));\n }\n\n tdBody.appendChild(iframe);\n document.body.appendChild(threeDSContainer);\n },\n removeFrame: function () {\n self.getFullScreenLoader().startLoader();\n document.body.removeChild(threeDSContainer);\n }\n };\n\n if (_.has(context, 'email') && context.email !== null) {\n threeDSecureParameters.email = context.email;\n }\n\n threeDSecureInstance.verifyCard(threeDSecureParameters, function (err, response) {\n self.getFullScreenLoader().stopLoader();\n\n if (err) {\n console.error('3DSecure validation failed', err);\n if (err.code === 'THREEDS_LOOKUP_VALIDATION_ERROR') {\n let errorMessage = err.details.originalError.details.originalError.error.message,\n error = self.checkBillingLineLengths(errorMessage, billingAddress, shippingAddress);\n\n return error ? state.reject(error) : state.reject($t(errorMessage));\n }\n\n return state.reject($t('Please try again with another form of payment.'));\n }\n\n let liability = {\n shifted: response.liabilityShifted,\n shiftPossible: response.liabilityShiftPossible\n };\n\n if (liability.shifted || !liability.shifted && !liability.shiftPossible) {\n context.paymentMethodNonce = response.nonce;\n state.resolve();\n } else {\n state.reject($t('Please try again with another form of payment.'));\n }\n }.bind(this));\n });\n };\n\n if (!clientInstance) {\n self.createClientInstance(setup3d);\n } else {\n setup3d(clientInstance);\n }\n\n return state.promise();\n },\n\n /**\n * Create a Braintree client instance with simplified form.\n *\n * @param {Function} setupThreeDSecureCallback\n * @return {*}\n */\n createClientInstance: function (setupThreeDSecureCallback) {\n let self = this;\n\n return require(['PayPal_Braintree/js/googlepay/implementations/shortcut/form'], function (c) {\n c.defaults.clientConfig.clientToken = self.getClientToken();\n c.defaults.clientConfig.environment = self.getEnvironment();\n braintree.setConfig(c.defaults.clientConfig);\n braintree.setup(setupThreeDSecureCallback);\n });\n }\n };\n});\n","PayPal_Braintree/js/googlepay/implementations/shortcut/form.js":"/*browser:true*/\ndefine([\n 'underscore',\n 'jquery',\n 'uiComponent'\n], function (_, $, Component) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n braintreeClient: null,\n code: 'braintree',\n isProcessing: false,\n\n /**\n * Braintree client configuration\n *\n * {Object}\n */\n clientConfig: {\n onReady: function () {},\n\n /**\n * Triggers on payment nonce receive\n */\n onPaymentMethodReceived: function () {\n this.isProcessing = false;\n },\n\n /**\n * Allow a new nonce to be generated\n */\n onPaymentMethodError: function () {\n this.isProcessing = false;\n },\n\n /**\n * After Braintree instance initialization\n */\n onInstanceReady: function () {},\n\n /**\n * Triggers on any Braintree error\n * @param {Object} response\n */\n onError: function (response) {\n this.isProcessing = false;\n throw response.message;\n },\n\n /**\n * Triggers when customer click \"Cancel\"\n */\n onCancelled: function () {\n this.isProcessing = false;\n }\n }\n },\n\n /**\n * Set list of observable attributes\n *\n * @returns {exports.initObservable}\n */\n initObservable: function () {\n this._super();\n\n this.initClientConfig();\n\n return this;\n },\n\n /**\n * Get payment name\n *\n * @returns {String}\n */\n getCode: function () {\n return this.code;\n },\n\n /**\n * Init config\n */\n initClientConfig: function () {\n _.each(this.clientConfig, function (fn, name) {\n if (typeof fn === 'function') {\n this.clientConfig[name] = fn.bind(this);\n }\n }, this);\n }\n });\n});\n","PayPal_Braintree/js/googlepay/implementations/shortcut/adapter.js":"/*browser:true*/\ndefine([\n 'underscore',\n 'jquery',\n 'mage/translate',\n 'braintree',\n 'PayPal_Braintree/js/model/full-screen-loader',\n 'Magento_Ui/js/model/messageList'\n], function (\n _,\n $,\n $t,\n client,\n defaultFullScreenLoader,\n globalMessageList\n) {\n 'use strict';\n\n /**\n * Braintree Client adapter implementation generic enough to be used for GooglePay button payments.\n *\n * This can be used in other pages along with the basket page, but not in the checkout page when placing an order.\n */\n return {\n fullScreenLoader: defaultFullScreenLoader,\n apiClient: null,\n config: {},\n checkout: null,\n clientInstance: null,\n code: 'braintree',\n\n /**\n * {Object}\n */\n events: {\n onClick: null,\n onCancel: null,\n onError: null\n },\n\n /**\n * Get Braintree api client.\n *\n * @returns {Object}\n */\n getApiClient: function () {\n return this.clientInstance;\n },\n\n /**\n * Set configuration.\n *\n * @param {Object} config\n */\n setConfig: function (config) {\n this.config = config;\n\n if (_.has(this.config, 'code')) {\n this.code = this.config.code;\n }\n },\n\n /**\n * Get payment name.\n *\n * @returns {string}\n */\n getCode: function () {\n return this.code;\n },\n\n /**\n * Get client token\n *\n * @returns {string|*}\n */\n getClientToken: function () {\n return this.config.hasOwnProperty('clientToken') ? this.config.clientToken : null;\n },\n\n /**\n * @returns {string}\n */\n getEnvironment: function () {\n return this.config.hasOwnProperty('environment') ? this.config.environment : null;\n },\n\n /**\n * Set fullscreen loader implementation allowing to use custom.\n *\n * @param {Function} fullScreenLoader\n */\n setFullScreenLoader: function (fullScreenLoader) {\n this.fullScreenLoader = fullScreenLoader;\n },\n\n /**\n * Get the full screen loader implementation.\n *\n * @return {Object}\n */\n getFullScreenLoader: function () {\n return this.fullScreenLoader;\n },\n\n /**\n * Show error message\n *\n * @param {string} errorMessage\n */\n showError: function (errorMessage) {\n globalMessageList.addErrorMessage({\n message: errorMessage\n });\n\n this.getFullScreenLoader().stopLoader(true);\n },\n\n /**\n * Setup Braintree SDK.\n *\n * @param {Function|null} callback\n */\n setup: function (callback = null) {\n if (!this.getClientToken()) {\n this.showError($t('Sorry, but something went wrong.'));\n return;\n }\n\n if (this.clientInstance) {\n if (typeof this.config.onReady === 'function') {\n this.config.onReady(this);\n }\n\n if (typeof callback === 'function') {\n callback(this.clientInstance);\n }\n\n return;\n }\n\n client.create({\n authorization: this.getClientToken()\n }, function (clientErr, clientInstance) {\n if (clientErr) {\n console.error('Braintree Setup Error', clientErr);\n return this.showError('Sorry, but something went wrong. Please contact the store owner.');\n }\n\n this.clientInstance = clientInstance;\n\n if (typeof this.config.onReady === 'function') {\n this.config.onReady(this);\n }\n\n if (typeof callback === 'function') {\n callback(this.clientInstance);\n }\n }.bind(this));\n }\n };\n});\n","PayPal_Braintree/js/googlepay/implementations/core-checkout/method-googlepay.js":"define([\n 'uiComponent',\n 'Magento_Checkout/js/model/payment/renderer-list'\n], function (Component, rendererList) {\n 'use strict';\n\n let config = window.checkoutConfig.payment;\n\n if (config['braintree_googlepay'].clientToken) {\n rendererList.push({\n type: 'braintree_googlepay',\n component: 'PayPal_Braintree/js/googlepay/implementations/core-checkout/method-renderer/googlepay'\n });\n }\n\n return Component.extend({});\n});\n","PayPal_Braintree/js/googlepay/implementations/core-checkout/method-renderer/googlepay.js":"/**\n * Braintree Google Pay payment method integration.\n **/\ndefine([\n 'underscore',\n 'Magento_Checkout/js/view/payment/default',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Vault/js/view/payment/vault-enabler',\n 'PayPal_Braintree/js/googlepay/button',\n 'PayPal_Braintree/js/googlepay/model/parsed-response',\n 'PayPal_Braintree/js/view/payment/validator-handler'\n], function (\n _,\n Component,\n quote,\n VaultEnabler,\n GooglePayButton,\n parsedResponseModel,\n validatorManager\n) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'PayPal_Braintree/googlepay/core-checkout',\n validatorManager: validatorManager,\n paymentMethodNonce: null,\n creditCardBin: null,\n deviceData: null,\n grandTotalAmount: 0,\n vaultEnabler: null,\n additionalData: {}\n },\n\n /**\n * @returns {exports.initialize}\n */\n initialize: function () {\n this._super();\n this.vaultEnabler = new VaultEnabler();\n this.vaultEnabler.setPaymentCode(this.getVaultCode());\n\n return this;\n },\n\n /**\n * Inject the Google Pay button into the target element\n */\n getGooglePayBtn: function (id) {\n GooglePayButton.init(\n document.getElementById(id),\n this\n );\n },\n\n /**\n * Subscribe to grand totals\n */\n initObservable: function () {\n this._super();\n this.vaultEnabler = new VaultEnabler();\n this.vaultEnabler.setPaymentCode(this.getVaultCode());\n\n this.validatorManager.initialize();\n\n this.grandTotalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2);\n this.currencyCode = quote.totals()['base_currency_code'];\n\n quote.totals.subscribe(function () {\n if (this.grandTotalAmount !== quote.totals()['base_grand_total']) {\n this.grandTotalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2);\n }\n }.bind(this));\n\n return this;\n },\n\n /**\n * Google Pay place order method\n */\n startPlaceOrder: function (device_data) {\n let self = this;\n\n /* Set the nonce & bin and trigger 3DS if card is not network tokenized */\n self.paymentMethodNonce = parsedResponseModel.getNonce();\n self.creditCardBin = parsedResponseModel.getBin();\n\n if (parsedResponseModel.getIsNetworkTokenized() === false) {\n // place order on success validation\n self.validatorManager.validate(self, function () {\n self.setDeviceData(device_data);\n return self.placeOrder('parent');\n }, function () {\n self.paymentMethodNonce = null;\n self.creditCardBin = null;\n });\n } else {\n self.setDeviceData(device_data);\n self.placeOrder();\n }\n },\n\n /**\n * Save device_data\n */\n setDeviceData: function (device_data) {\n this.deviceData = device_data;\n },\n\n /**\n * Retrieve the client token\n * @returns null|string\n */\n getClientToken: function () {\n return window.checkoutConfig.payment[this.getCode()].clientToken;\n },\n\n /**\n * Payment request info\n */\n getPaymentRequest: function () {\n let result = {\n transactionInfo: {\n totalPriceStatus: 'FINAL',\n totalPrice: this.grandTotalAmount,\n currencyCode: this.currencyCode\n },\n allowedPaymentMethods: [\n {\n 'type': 'CARD',\n 'parameters': {\n 'allowedCardNetworks': this.getCardTypes(),\n 'billingAddressRequired': true,\n 'billingAddressParameters': {\n format: 'FULL',\n phoneNumberRequired: true\n }\n }\n\n }\n ],\n shippingAddressRequired: false,\n emailRequired: false\n };\n\n if (this.getEnvironment() !== 'TEST') {\n result.merchantInfo = { merchantId: this.getMerchantId() };\n }\n\n return result;\n },\n\n /**\n * Merchant display name\n */\n getMerchantId: function () {\n return window.checkoutConfig.payment[this.getCode()].merchantId;\n },\n\n /**\n * Environment\n */\n getEnvironment: function () {\n return window.checkoutConfig.payment[this.getCode()].environment;\n },\n\n /**\n * Card Types\n */\n getCardTypes: function () {\n return window.checkoutConfig.payment[this.getCode()].cardTypes;\n },\n\n /**\n * BTN Color\n */\n getBtnColor: function () {\n return window.checkoutConfig.payment[this.getCode()].btnColor;\n },\n\n /**\n * Get data\n * @returns {Object}\n */\n getData: function () {\n let data = {\n 'method': this.getCode(),\n 'additional_data': {\n 'payment_method_nonce': this.paymentMethodNonce,\n 'device_data': this.deviceData,\n 'is_network_tokenized': parsedResponseModel.getIsNetworkTokenized()\n }\n };\n\n if (parsedResponseModel.getIsNetworkTokenized() === false) {\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n this.vaultEnabler.visitAdditionalData(data);\n }\n\n return data;\n },\n\n /**\n * Return image url for the Google Pay mark\n */\n getPaymentMarkSrc: function () {\n return window.checkoutConfig.payment[this.getCode()].paymentMarkSrc;\n },\n\n /**\n * @returns {Boolean}\n */\n isVaultEnabled: function () {\n return this.vaultEnabler.isVaultEnabled();\n },\n\n /**\n * @returns {String}\n */\n getVaultCode: function () {\n return window.checkoutConfig.payment[this.getCode()].vaultCode;\n }\n });\n});\n","PayPal_Braintree/js/googlepay/model/parsed-response.js":"define([\n 'underscore',\n 'ko'\n], function (_, ko) {\n 'use strict';\n\n let nonce = ko.observable(null),\n isNetworkTokenized = ko.observable(false),\n bin = ko.observable(null);\n\n return {\n nonce: nonce,\n isNetworkTokenized: isNetworkTokenized,\n bin: bin,\n\n /**\n * Get the payment nonce.\n *\n * @return {?string}\n */\n getNonce: function () {\n return this.nonce();\n },\n\n /**\n * Set the payment nonce.\n *\n * @param {?string} value\n * @return {void}\n */\n setNonce: function (value) {\n this.nonce(_.isString(value) ? value : null);\n },\n\n /**\n * Get is network tokenized property for used card.\n *\n * @return {boolean}\n */\n getIsNetworkTokenized: function () {\n return this.isNetworkTokenized();\n },\n\n /**\n * Set is network tokenized property for used card.\n *\n * @param {boolean} value\n * @return {void}\n */\n setIsNetworkTokenized: function (value) {\n this.isNetworkTokenized(_.isBoolean(value) ? value : false);\n },\n\n /**\n * Get card bin.\n *\n * @return {?string}\n */\n getBin: function () {\n return this.bin();\n },\n\n /**\n * Set the card bin.\n *\n * @param {?string} value\n * @return {void}\n */\n setBin: function (value) {\n this.bin(_.isString(value) ? value : null);\n },\n\n /**\n * Reset data to default.\n */\n resetDefaultData: function () {\n this.setNonce(null);\n this.setIsNetworkTokenized(false);\n this.setBin(null);\n }\n };\n});\n","PayPal_Braintree/js/googlepay/model/payment-data.js":"define([\n 'underscore',\n 'ko'\n], function (_, ko) {\n 'use strict';\n\n let paymentMethodData = ko.observable(null),\n email = ko.observable(null),\n shippingAddress = ko.observable(null);\n\n return {\n paymentMethodData: paymentMethodData,\n email: email,\n shippingAddress: shippingAddress,\n\n /**\n * Get Google Pay payment method data details.\n *\n * @return {?Object}\n */\n getPaymentMethodData: function () {\n return this.paymentMethodData();\n },\n\n /**\n * Set Google Pay payment method data details.\n *\n * @param {?Object} value\n * @return {void}\n */\n setPaymentMethodData: function (value) {\n this.paymentMethodData(_.isObject(value) ? value : null);\n },\n\n /**\n * Get Google Pay email.\n *\n * @return {?string}\n */\n getEmail: function () {\n return this.email();\n },\n\n /**\n * Set Google Pay email.\n *\n * @param {?string} value\n * @return {void}\n */\n setEmail: function (value) {\n this.email(_.isString(value) ? value : null);\n },\n\n /**\n * Get Google Pay shipping address.\n *\n * @return {?Object}\n */\n getShippingAddress: function () {\n return shippingAddress();\n },\n\n /**\n * Set Google Pay shipping address.\n *\n * @param {?Object} value\n * @return {void}\n */\n setShippingAddress: function (value) {\n this.shippingAddress(_.isObject(value) ? value : null);\n },\n\n /**\n * Reset data to default.\n */\n resetDefaultData: function () {\n this.setPaymentMethodData(null);\n this.setEmail(null);\n this.setShippingAddress(null);\n }\n };\n});\n","PayPal_Braintree/js/view/product-page.js":"define(\n ['uiComponent'],\n function (Component) {\n 'use strict';\n\n return Component.extend({\n\n });\n }\n);\n","PayPal_Braintree/js/view/payment/venmo.js":"define(\n [\n 'uiComponent',\n 'Magento_Checkout/js/model/payment/renderer-list'\n ],\n function (\n Component,\n rendererList\n ) {\n 'use strict';\n\n rendererList.push(\n {\n type: 'braintree_venmo',\n component: 'PayPal_Braintree/js/view/payment/method-renderer/venmo'\n }\n );\n\n return Component.extend({});\n }\n);\n","PayPal_Braintree/js/view/payment/validator-manager.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n\ndefine([\n 'jquery',\n 'Magento_Ui/js/model/messageList',\n 'PayPal_Braintree/js/model/full-screen-loader'\n], function (\n $,\n globalMessageList,\n defaultFullScreenLoader\n) {\n 'use strict';\n\n /**\n * New Validator handler implementation that can be used across website areas including checkout.\n */\n return {\n fullScreenLoader: defaultFullScreenLoader,\n validators: [],\n\n /**\n * Set the full screen loader implementation.\n *\n * @param fullScreenLoader\n */\n setFullScreenLoader: function (fullScreenLoader) {\n this.fullScreenLoader = fullScreenLoader;\n },\n\n /**\n * Get the full screen loader implementation.\n */\n getFullScreenLoader: function () {\n return this.fullScreenLoader;\n },\n\n /**\n * Add new validator if enabled.\n *\n * Always expect the validator to have the isEnabled method (property), if not skip.\n *\n * @param {Object} validator\n */\n add: function (validator) {\n if (!validator.hasOwnProperty('isEnabled')\n || typeof validator.isEnabled !== 'function'\n || !validator.isEnabled()\n ) {\n return;\n }\n\n this.validators.push(validator);\n },\n\n /**\n * Run pull of validators.\n *\n * @param {Object} context\n * @param {Function} callback\n * @param {Function} errorCallback\n */\n validate: function (context, callback, errorCallback) {\n let self = this,\n deferred;\n\n // no available validators\n if (!self.validators.length) {\n callback();\n\n return;\n }\n\n // get list of deferred validators\n deferred = $.map(self.validators, function (current) {\n return current.validate(context);\n });\n\n $.when.apply($, deferred)\n .done(function () {\n callback();\n }).fail(function (error) {\n errorCallback();\n self.showError(error);\n });\n },\n\n /**\n * Show error message.\n *\n * @param {string} errorMessage\n */\n showError: function (errorMessage) {\n globalMessageList.addErrorMessage({\n message: errorMessage\n });\n\n this.getFullScreenLoader().stopLoader(true);\n }\n };\n});\n","PayPal_Braintree/js/view/payment/3d-secure.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n\ndefine([\n 'jquery',\n 'PayPal_Braintree/js/view/payment/adapter',\n 'Magento_Checkout/js/model/quote',\n 'mage/translate',\n 'braintreeThreeDSecure',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'PayPal_Braintree/js/helper/remove-non-digit-characters',\n 'PayPal_Braintree/js/helper/escape-non-ascii-characters',\n 'PayPal_Braintree/js/model/vault-enabler'\n], function (\n $,\n braintree,\n quote,\n $t,\n threeDSecure,\n fullScreenLoader,\n removeNonDigitCharacters,\n escapeNonAsciiCharacters,\n vaultEnablerModel\n) {\n 'use strict';\n\n return {\n config: null,\n\n /**\n * Set 3d secure config\n * @param {Object} config\n */\n setConfig: function (config) {\n this.config = config;\n this.config.thresholdAmount = parseFloat(config.thresholdAmount);\n\n // Initialize vault enabler to check is it actually enabled or passed\n vaultEnablerModel.setPaymentCode(this.config.ccVaultCode);\n },\n\n /**\n * Get code\n * @returns {String}\n */\n getCode: function () {\n return 'three_d_secure';\n },\n\n /**\n * Check billing/shipping address line lengths\n *\n * @param errorMessage\n * @param billingAddress\n * @param shippingAddress\n * @returns {*}\n */\n checkBillingLineLengths: function (errorMessage, billingAddress, shippingAddress) {\n let lineError = null;\n\n if (billingAddress.street[0].length > 50 ||\n (shippingAddress.street !== undefined && shippingAddress.street[0].length > 50)) {\n lineError = 'line1';\n } else if (billingAddress.street[1].length > 50 ||\n (shippingAddress.street !== undefined && shippingAddress.street[1].length > 50)) {\n lineError = 'line2';\n }\n\n if (lineError) {\n let error = `Billing/Shipping ${lineError} must be string and less than 50 characters.`;\n\n return $t(`${error} Please update the address and try again.`);\n }\n },\n\n /**\n * Validate Braintree payment nonce\n * @param {Object} context\n * @returns {Object}\n */\n validate: function (context) {\n let self = this,\n clientInstance = braintree.getApiClient(),\n state = $.Deferred(),\n totalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2),\n billingAddress = quote.billingAddress(),\n shippingAddress = quote.shippingAddress(),\n setup3d;\n\n // Handle billing address region code\n if (billingAddress.regionCode == null) {\n billingAddress.regionCode = undefined;\n }\n if (billingAddress.regionCode !== undefined && billingAddress.regionCode.length > 2) {\n billingAddress.regionCode = undefined;\n }\n\n // Handle shipping address region code\n if (!quote.isVirtual()) {\n if (shippingAddress.regionCode == null) {\n shippingAddress.regionCode = undefined;\n }\n if (shippingAddress.regionCode !== undefined && shippingAddress.regionCode.length > 2) {\n shippingAddress.regionCode = undefined;\n }\n }\n\n // No 3d secure if using CVV verification on vaulted cards\n if (quote.paymentMethod().method.indexOf('braintree_cc_vault_') !== -1) {\n if (this.config.useCvvVault === true) {\n state.resolve();\n return state.promise();\n }\n }\n\n if (!this.isAmountAvailable(totalAmount) || !this.isCountryAvailable(billingAddress.countryId)) {\n state.resolve();\n return state.promise();\n }\n\n fullScreenLoader.startLoader();\n\n setup3d = function (client) {\n threeDSecure.create({\n version: 2,\n client: client\n }, function (threeDSecureErr, threeDSecureInstance) {\n if (threeDSecureErr) {\n fullScreenLoader.stopLoader();\n return state.reject($t('Please try again with another form of payment.'));\n }\n\n let threeDSContainer = document.createElement('div'),\n tdMask = document.createElement('div'),\n tdFrame = document.createElement('div'),\n tdBody = document.createElement('div'),\n threeDSecureParameters;\n\n threeDSContainer.className = 'braintree-three-d-modal';\n tdMask.className = 'bt-mask';\n tdFrame.className = 'bt-modal-frame';\n tdBody.className = 'bt-modal-body';\n\n tdFrame.appendChild(tdBody);\n threeDSContainer.appendChild(tdMask);\n threeDSContainer.appendChild(tdFrame);\n\n threeDSecureParameters = {\n amount: totalAmount,\n nonce: context.paymentMethodNonce,\n bin: context.creditCardBin,\n collectDeviceData: true,\n challengeRequested: self.getChallengeRequested(),\n cardAddChallengeRequested: self.getCardAddChallengeRequested(),\n billingAddress: {\n givenName: escapeNonAsciiCharacters(billingAddress.firstname),\n surname: escapeNonAsciiCharacters(billingAddress.lastname),\n phoneNumber: billingAddress.telephone !== null\n ? removeNonDigitCharacters(billingAddress.telephone)\n : billingAddress.telephone,\n streetAddress: billingAddress.street[0],\n extendedAddress: billingAddress.street[1],\n locality: billingAddress.city,\n region: billingAddress.regionCode,\n postalCode: billingAddress.postcode,\n countryCodeAlpha2: billingAddress.countryId\n },\n additionalInformation: {\n ipAddress: self.getIpAddress()\n },\n onLookupComplete: function (data, next) {\n next();\n },\n addFrame: function (err, iframe) {\n fullScreenLoader.stopLoader();\n\n if (err) {\n console.log('Unable to verify card over 3D Secure', err);\n return state.reject($t('Please try again with another form of payment.'));\n }\n\n tdBody.appendChild(iframe);\n document.body.appendChild(threeDSContainer);\n },\n removeFrame: function () {\n fullScreenLoader.startLoader();\n document.body.removeChild(threeDSContainer);\n }\n };\n\n if (context.hasOwnProperty('email') && context.email !== null) {\n threeDSecureParameters.email = context.email;\n }\n\n if (!quote.isVirtual()) {\n threeDSecureParameters.additionalInformation = {\n shippingGivenName: escapeNonAsciiCharacters(shippingAddress.firstname),\n shippingSurname: escapeNonAsciiCharacters(shippingAddress.lastname),\n shippingAddress: {\n streetAddress: shippingAddress.street[0],\n extendedAddress: shippingAddress.street[1],\n locality: shippingAddress.city,\n region: shippingAddress.regionCode,\n postalCode: shippingAddress.postcode,\n countryCodeAlpha2: shippingAddress.countryId\n },\n shippingPhone: shippingAddress.telephone !== null\n ? removeNonDigitCharacters(shippingAddress.telephone)\n : shippingAddress.telephone,\n ipAddress: threeDSecureParameters.additionalInformation.ipAddress\n }\n }\n\n threeDSecureInstance.verifyCard(threeDSecureParameters, function (err, response) {\n fullScreenLoader.stopLoader();\n\n if (err) {\n console.error('3DSecure validation failed', err);\n if (err.code === 'THREEDS_LOOKUP_VALIDATION_ERROR') {\n let errorMessage = err.details.originalError.details.originalError.error.message,\n error = self.checkBillingLineLengths(errorMessage, billingAddress, shippingAddress);\n\n return error ? state.reject(error) : state.reject($t(errorMessage));\n }\n\n return state.reject($t('Please try again with another form of payment.'));\n }\n\n let liability = {\n shifted: response.liabilityShifted,\n shiftPossible: response.liabilityShiftPossible\n };\n\n if (liability.shifted || !liability.shifted && !liability.shiftPossible) {\n context.paymentMethodNonce = response.nonce;\n state.resolve();\n } else {\n state.reject($t('Please try again with another form of payment.'));\n }\n });\n });\n };\n\n if (!clientInstance) {\n require(['PayPal_Braintree/js/view/payment/method-renderer/cc-form'], function (c) {\n let config = c.extend({\n defaults: {\n clientConfig: {\n onReady: function () {}\n }\n }\n });\n\n braintree.setConfig(config.defaults.clientConfig);\n braintree.setup(setup3d);\n });\n } else {\n setup3d(clientInstance);\n }\n\n return state.promise();\n },\n\n /**\n * Check minimal amount for 3d secure activation\n * @param {Number} amount\n * @returns {Boolean}\n */\n isAmountAvailable: function (amount) {\n amount = parseFloat(amount.toString());\n\n return amount >= this.config.thresholdAmount;\n },\n\n /**\n * Check if current country is available for 3d secure\n * @param {String} countryId\n * @returns {Boolean}\n */\n isCountryAvailable: function (countryId) {\n let key,\n specificCountries = this.config.specificCountries;\n\n // all countries are available\n if (!specificCountries.length) {\n return true;\n }\n\n for (key in specificCountries) {\n if (countryId === specificCountries[key]) {\n return true;\n }\n }\n\n return false;\n },\n\n /**\n * Get the challenge requested config\n * it will only be returned TRUE when Vault is disabled(FALSE)\n * and 'PaymentTokenEnabler' is set to FALSE.\n *\n * @returns {Boolean}\n */\n getChallengeRequested: function () {\n if (vaultEnablerModel.isVaultEnabled() && vaultEnablerModel.isActivePaymentTokenEnabler()) {\n return false;\n }\n return this.config.challengeRequested;\n },\n\n /**\n * This parameter will be passed as TRUE when\n * Vault is enabled(TRUE) and 'PaymentTokenEnabler'\n * is set to TRUE.\n *\n * @returns {boolean}\n */\n getCardAddChallengeRequested: function () {\n if (vaultEnablerModel.isVaultEnabled() && vaultEnablerModel.isActivePaymentTokenEnabler()) {\n return true;\n }\n return false;\n },\n\n /**\n * Get the Customer's IP Address\n *\n * @returns {*}\n */\n getIpAddress: function () {\n return this.config.ipAddress;\n }\n };\n});\n","PayPal_Braintree/js/view/payment/lpm.js":"define(\n [\n 'uiComponent',\n 'Magento_Checkout/js/model/payment/renderer-list'\n ],\n function (\n Component,\n rendererList\n ) {\n 'use strict';\n\n rendererList.push(\n {\n type: 'braintree_local_payment',\n component: 'PayPal_Braintree/js/view/payment/method-renderer/lpm'\n }\n );\n\n return Component.extend({});\n }\n);\n","PayPal_Braintree/js/view/payment/braintree.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'uiComponent',\n 'Magento_Checkout/js/model/payment/renderer-list',\n 'Magento_Customer/js/customer-data',\n 'Magento_Ui/js/model/messageList'\n], function (Component, rendererList, customerData, globalMessageList) {\n 'use strict';\n\n let config = window.checkoutConfig.payment,\n braintreeType = 'braintree',\n payPalType = 'braintree_paypal',\n braintreeAchDirectDebit = 'braintree_ach_direct_debit',\n braintreeVenmo = 'braintree_venmo',\n braintreeLocalPayment = 'braintree_local_payment';\n\n if (config[braintreeType] && config[braintreeType].isActive && config[braintreeType].clientToken) {\n rendererList.push({\n type: braintreeType,\n component: 'PayPal_Braintree/js/view/payment/method-renderer/hosted-fields'\n });\n }\n\n if (config[payPalType] && config[payPalType].isActive) {\n rendererList.push({\n type: payPalType,\n component: 'PayPal_Braintree/js/view/payment/method-renderer/paypal'\n });\n }\n\n if (config[braintreeVenmo] && config[braintreeVenmo].isAllowed && config[braintreeVenmo].clientToken) {\n rendererList.push({\n type: braintreeVenmo,\n component: 'PayPal_Braintree/js/view/payment/method-renderer/venmo'\n });\n }\n\n if (config[braintreeAchDirectDebit] && config[braintreeAchDirectDebit].isActive\n && config[braintreeAchDirectDebit].clientToken) {\n rendererList.push({\n type: braintreeAchDirectDebit,\n component: 'PayPal_Braintree/js/view/payment/method-renderer/ach'\n });\n }\n\n if (config[braintreeLocalPayment] && config[braintreeLocalPayment].clientToken) {\n rendererList.push({\n type: braintreeLocalPayment,\n component: 'PayPal_Braintree/js/view/payment/method-renderer/lpm'\n });\n }\n\n /** Add view logic here if needed */\n return Component.extend({\n initialize: function () {\n this._super();\n\n let braintreeData = customerData.get('braintree')(),\n errors = braintreeData.errors || [];\n\n errors.forEach(function (error) {\n globalMessageList.addErrorMessage({ 'message': error });\n });\n\n customerData.set('braintree', { errors: [] });\n\n return this;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/adapter.js":"/**\n * Copyright 2013-2017 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'jquery',\n 'braintree',\n 'braintreeDataCollector',\n 'braintreeHostedFields',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'Magento_Ui/js/model/messageList',\n 'mage/translate'\n], function ($, client, dataCollector, hostedFields, fullScreenLoader, globalMessageList, $t) {\n 'use strict';\n\n return {\n apiClient: null,\n config: {},\n checkout: null,\n deviceData: null,\n clientInstance: null,\n hostedFieldsInstance: null,\n paypalInstance: null,\n code: 'braintree',\n\n /**\n * {Object}\n */\n events: {\n onClick: null,\n onCancel: null,\n onError: null\n },\n\n /**\n * Get Braintree api client\n * @returns {Object}\n */\n getApiClient: function () {\n return this.clientInstance;\n },\n\n /**\n * Set configuration\n * @param {Object} config\n */\n setConfig: function (config) {\n this.config = config;\n },\n\n /**\n * Get payment name\n * @returns {String}\n */\n getCode: function () {\n if (window.checkoutConfig.payment[this.code]) {\n return this.code;\n }\n return 'braintree_paypal';\n\n },\n\n /**\n * Get client token\n * @returns {String|*}\n */\n getClientToken: function () {\n return window.checkoutConfig.payment[this.getCode()].clientToken;\n },\n\n /**\n * @returns {String}\n */\n getEnvironment: function () {\n return window.checkoutConfig.payment[this.getCode()].environment;\n },\n\n getCurrentCode: function (paypalType = null) {\n var code = 'braintree_paypal';\n\n if (paypalType !== 'paypal') {\n code = code + '_' + paypalType;\n }\n return code;\n },\n\n /**\n * @returns {String}\n */\n getColor: function (paypalType = null) {\n return window.checkoutConfig.payment[this.getCurrentCode(paypalType)].style.color;\n },\n\n /**\n * @returns {String}\n */\n getShape: function (paypalType = null) {\n return window.checkoutConfig.payment[this.getCurrentCode(paypalType)].style.shape;\n },\n\n /**\n * @returns {String}\n */\n getLabel: function (paypalType = null) {\n return window.checkoutConfig.payment[this.getCurrentCode(paypalType)].style.label;\n },\n\n /**\n * @returns {String}\n */\n getBranding: function () {\n return null;\n },\n\n /**\n * @returns {String}\n */\n getFundingIcons: function () {\n return null;\n },\n\n /**\n * @returns {String}\n */\n getDisabledFunding: function () {\n return window.checkoutConfig.payment[this.getCode()].disabledFunding;\n },\n\n /**\n * Show error message\n *\n * @param {String} errorMessage\n */\n showError: function (errorMessage) {\n globalMessageList.addErrorMessage({\n message: errorMessage\n });\n fullScreenLoader.stopLoader(true);\n },\n\n /**\n * Disable submit button\n */\n disableButton: function () {\n // stop any previous shown loaders\n fullScreenLoader.stopLoader(true);\n fullScreenLoader.startLoader();\n $('[data-button=\"place\"]').attr('disabled', 'disabled');\n },\n\n /**\n * Enable submit button\n */\n enableButton: function () {\n $('[data-button=\"place\"]').removeAttr('disabled');\n fullScreenLoader.stopLoader();\n },\n\n /**\n * Has PayPal been init'd already\n */\n getPayPalInstance: function () {\n if (typeof this.config.paypalInstance !== 'undefined' && this.config.paypalInstance) {\n return this.config.paypalInstance;\n }\n\n return null;\n },\n\n setPayPalInstance: function (val) {\n this.config.paypalInstance = val;\n },\n\n /**\n * Setup Braintree SDK\n *\n * @param {Function|null} callback\n */\n setup: function (callback = null) {\n if (!this.getClientToken()) {\n this.showError($t('Sorry, but something went wrong.'));\n return;\n }\n\n if (this.clientInstance) {\n if (typeof this.config.onReady === 'function') {\n this.config.onDeviceDataReceived(this.deviceData);\n this.config.onReady(this);\n }\n\n if (typeof callback === 'function') {\n callback(this.clientInstance);\n }\n return;\n }\n\n client.create({\n authorization: this.getClientToken()\n }, function (clientErr, clientInstance) {\n if (clientErr) {\n console.error('Braintree Setup Error', clientErr);\n return this.showError('Sorry, but something went wrong. Please contact the store owner.');\n }\n\n let options = {\n client: clientInstance\n };\n\n if (typeof this.config.dataCollector === 'object'\n && typeof this.config.dataCollector.paypal === 'boolean'\n ) {\n options.paypal = true;\n }\n\n this.clientInstance = clientInstance;\n\n if (typeof this.config.onReady === 'function') {\n this.config.onReady(this);\n }\n\n dataCollector.create(options, function (err, dataCollectorInstance) {\n if (err) {\n return console.log(err);\n }\n\n this.deviceData = dataCollectorInstance.deviceData;\n this.config.onDeviceDataReceived(this.deviceData);\n\n if (typeof callback === 'function') {\n callback(this.clientInstance);\n }\n }.bind(this));\n }.bind(this));\n },\n\n /**\n * Setup hosted fields instance\n */\n setupHostedFields: function () {\n var self = this;\n\n if (this.hostedFieldsInstance) {\n this.hostedFieldsInstance.teardown(function () {\n this.hostedFieldsInstance = null;\n this.setupHostedFields();\n }.bind(this));\n return;\n }\n\n hostedFields.create({\n client: this.clientInstance,\n fields: this.config.hostedFields,\n styles: this.config.styles\n }, function (createErr, hostedFieldsInstance) {\n if (createErr) {\n let error = 'Braintree hosted fields could not be initialized. Please contact the store owner.';\n\n self.showError($t(error));\n console.error('Braintree hosted fields error', createErr);\n return;\n }\n\n this.config.onInstanceReady(hostedFieldsInstance);\n this.hostedFieldsInstance = hostedFieldsInstance;\n }.bind(this));\n },\n\n tokenizeHostedFields: function () {\n this.hostedFieldsInstance.tokenize({}, function (tokenizeErr, payload) {\n if (tokenizeErr) {\n switch (tokenizeErr.code) {\n case 'HOSTED_FIELDS_FIELDS_EMPTY':\n // occurs when none of the fields are filled in\n console.error('All fields are empty! Please fill out the form.');\n break;\n case 'HOSTED_FIELDS_FIELDS_INVALID':\n // occurs when certain fields do not pass client side validation\n console.error('Some fields are invalid:', tokenizeErr.details.invalidFieldKeys);\n break;\n case 'HOSTED_FIELDS_TOKENIZATION_FAIL_ON_DUPLICATE':\n // occurs when:\n // * the client token used for client authorization was generated\n // with a customer ID and the fail on duplicate payment method\n // option is set to true\n // * the card being tokenized has previously been vaulted (with any customer)\n // eslint-disable-next-line\n // See: https://developers.braintreepayments.com/reference/request/client-token/generate/#options.fail_on_duplicate_payment_method\n console.error('This payment method already exists in your vault.');\n break;\n case 'HOSTED_FIELDS_TOKENIZATION_CVV_VERIFICATION_FAILED':\n // occurs when:\n // * the client token used for client authorization was generated\n // with a customer ID and the verify card option is set to true\n // and you have credit card verification turned on in the Braintree\n // control panel\n // * the cvv does not pass verfication\n // (developers.braintreepayments.com/reference/general/testing/#avs-and-cvv/cid-responses)\n // eslint-disable-next-line\n // See: developers.braintreepayments.com/reference/request/client-token/generate/#options.verify_card\n console.error('CVV did not pass verification');\n break;\n case 'HOSTED_FIELDS_FAILED_TOKENIZATION':\n // occurs for any other tokenization error on the server\n console.error('Tokenization failed server side. Is the card valid?');\n break;\n case 'HOSTED_FIELDS_TOKENIZATION_NETWORK_ERROR':\n // occurs when the Braintree gateway cannot be contacted\n console.error('Network error occurred when tokenizing.');\n break;\n default:\n console.error('Something bad happened!', tokenizeErr);\n }\n } else {\n this.config.onPaymentMethodReceived(payload);\n }\n }.bind(this));\n }\n };\n});\n\n","PayPal_Braintree/js/view/payment/validator-handler.js":"/**\n * Copyright 2013-2017 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n\ndefine([\n 'jquery',\n 'Magento_Ui/js/model/messageList',\n 'PayPal_Braintree/js/view/payment/3d-secure',\n 'Magento_Checkout/js/model/full-screen-loader'\n], function ($, globalMessageList, verify3DSecure, fullScreenLoader) {\n 'use strict';\n\n return {\n validators: [],\n\n /**\n * Get payment config\n * @returns {Object}\n */\n getConfig: function () {\n return window.checkoutConfig.payment;\n },\n\n /**\n * Init list of validators\n */\n initialize: function () {\n let config = this.getConfig();\n\n if (config[verify3DSecure.getCode()].enabled) {\n verify3DSecure.setConfig(config[verify3DSecure.getCode()]);\n this.add(verify3DSecure);\n }\n },\n\n /**\n * Add new validator\n * @param {Object} validator\n */\n add: function (validator) {\n this.validators.push(validator);\n },\n\n /**\n * Run pull of validators\n * @param {Object} context\n * @param {Function} callback\n */\n validate: function (context, callback, errorCallback) {\n var self = this,\n deferred;\n\n // no available validators\n if (!self.validators.length) {\n callback();\n\n return;\n }\n\n // get list of deferred validators\n deferred = $.map(self.validators, function (current) {\n return current.validate(context);\n });\n\n $.when.apply($, deferred)\n .done(function () {\n callback();\n }).fail(function (error) {\n errorCallback();\n self.showError(error);\n });\n },\n\n /**\n * Show error message\n * @param {String} errorMessage\n */\n showError: function (errorMessage) {\n globalMessageList.addErrorMessage({\n message: errorMessage\n });\n fullScreenLoader.stopLoader(true);\n }\n };\n});\n","PayPal_Braintree/js/view/payment/ach.js":"define(\n [\n 'uiComponent',\n 'Magento_Checkout/js/model/payment/renderer-list'\n ],\n function (\n Component,\n rendererList\n ) {\n 'use strict';\n\n rendererList.push(\n {\n type: 'braintree_ach_direct_debit',\n component: 'PayPal_Braintree/js/view/payment/method-renderer/ach'\n }\n );\n\n return Component.extend({});\n }\n);\n","PayPal_Braintree/js/view/payment/method-renderer/venmo.js":"define(\n [\n 'Magento_Checkout/js/view/payment/default',\n 'braintree',\n 'braintreeDataCollector',\n 'braintreeVenmo',\n 'PayPal_Braintree/js/form-builder',\n 'Magento_Ui/js/model/messageList',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'mage/translate',\n 'Magento_Vault/js/view/payment/vault-enabler',\n 'underscore'\n ],\n function (\n Component,\n braintree,\n dataCollector,\n venmo,\n formBuilder,\n messageList,\n fullScreenLoader,\n additionalValidators,\n $t,\n VaultEnabler,\n _\n ) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n deviceData: null,\n paymentMethodNonce: null,\n template: 'PayPal_Braintree/payment/venmo',\n venmoInstance: null,\n vaultEnabler: null\n },\n\n clickVenmoBtn: function () {\n var self = this;\n\n if (!additionalValidators.validate()) {\n return false;\n }\n\n if (!this.venmoInstance) {\n this.setErrorMsg($t('Venmo not initialized, please try reloading.'));\n return;\n }\n\n this.venmoInstance.tokenize(function (tokenizeErr, payload) {\n if (tokenizeErr) {\n if (tokenizeErr.code === 'VENMO_CANCELED') {\n self.setErrorMsg($t('Venmo app is not available or the payment flow was cancelled.'));\n } else if (tokenizeErr.code === 'VENMO_APP_CANCELED') {\n self.setErrorMsg($t('Venmo payment flow cancelled.'));\n } else {\n self.setErrorMsg(tokenizeErr.message);\n }\n } else {\n self.handleVenmoSuccess(payload);\n }\n });\n },\n\n collectDeviceData: function (clientInstance, callback) {\n var self = this;\n\n dataCollector.create({\n client: clientInstance,\n paypal: true\n }, function (dataCollectorErr, dataCollectorInstance) {\n if (dataCollectorErr) {\n return;\n }\n self.deviceData = dataCollectorInstance.deviceData;\n callback();\n });\n },\n\n getClientToken: function () {\n return window.checkoutConfig.payment[this.getCode()].clientToken;\n },\n\n getCode: function () {\n return 'braintree_venmo';\n },\n\n getData: function () {\n let data = {\n 'method': this.getCode(),\n 'additional_data': {\n 'payment_method_nonce': this.paymentMethodNonce,\n 'device_data': this.deviceData\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n this.vaultEnabler.visitAdditionalData(data);\n\n return data;\n },\n\n getPaymentMarkSrc: function () {\n return window.checkoutConfig.payment[this.getCode()].paymentMarkSrc;\n },\n\n getTitle: function () {\n return 'Venmo';\n },\n\n handleVenmoSuccess: function (payload) {\n this.setPaymentMethodNonce(payload.nonce);\n this.placeOrder();\n },\n\n initialize: function () {\n var self = this;\n\n this._super();\n this.vaultEnabler = new VaultEnabler();\n this.vaultEnabler.setPaymentCode(this.getVaultCode());\n\n this.vaultEnabler.isActivePaymentTokenEnabler.subscribe(function () {\n self.venmoInstance.teardown(function () {\n self.initVenmo();\n });\n\n });\n this.initVenmo();\n return this;\n },\n\n isAllowed: function () {\n return window.checkoutConfig.payment[this.getCode()].isAllowed;\n },\n\n setErrorMsg: function (message) {\n messageList.addErrorMessage({\n message: message\n });\n },\n\n setPaymentMethodNonce: function (nonce) {\n this.paymentMethodNonce = nonce;\n },\n\n setVenmoInstance: function (instance) {\n this.venmoInstance = instance;\n },\n\n isVaultEnabled: function () {\n return this.vaultEnabler.isVaultEnabled();\n },\n\n /**\n * @returns {String}\n */\n getVaultCode: function () {\n return window.checkoutConfig.payment[this.getCode()].vaultCode;\n },\n\n getPaymentMethodUsage: function () {\n return this.vaultEnabler.isActivePaymentTokenEnabler()\n ? 'multi_use'\n : 'single_use';\n },\n\n initVenmo: function () {\n var self = this;\n\n braintree.create({\n authorization: self.getClientToken()\n }, function (clientError, clientInstance) {\n if (clientError) {\n this.setErrorMsg($t('Unable to initialize Braintree Client.'));\n return;\n }\n\n // Collect device data\n self.collectDeviceData(clientInstance, function () {\n // callback from collectDeviceData\n venmo.create({\n client: clientInstance,\n allowDesktop: true,\n allowDesktopWebLogin: true,\n mobileWebFallBack: true,\n paymentMethodUsage: self.getPaymentMethodUsage(),\n allowNewBrowserTab: false\n }, function (venmoErr, venmoInstance) {\n if (venmoErr) {\n self.setErrorMsg($t('Error initializing Venmo: %1').replace('%1', venmoErr));\n return;\n }\n\n if (!venmoInstance.isBrowserSupported()) {\n console.log('Browser does not support Venmo');\n return;\n }\n\n self.setVenmoInstance(venmoInstance);\n });\n });\n });\n }\n });\n }\n);\n","PayPal_Braintree/js/view/payment/method-renderer/hosted-fields.js":"/**\n * Copyright 2013-2017 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n\ndefine([\n 'jquery',\n 'PayPal_Braintree/js/view/payment/method-renderer/cc-form',\n 'PayPal_Braintree/js/model/vault-enabler',\n 'PayPal_Braintree/js/validator',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'mage/translate'\n], function ($, Component, vaultEnablerModel, validator, additionalValidators, $t) {\n 'use strict';\n\n return Component.extend({\n\n defaults: {\n template: 'PayPal_Braintree/payment/form',\n clientConfig: {\n\n /**\n * {String}\n */\n id: 'co-transparent-form-braintree'\n },\n isValidCardNumber: false,\n isValidExpirationDate: false,\n isValidCvvNumber: false,\n\n onInstanceReady: function (instance) {\n instance.on('validityChange', this.onValidityChange.bind(this));\n instance.on('cardTypeChange', this.onCardTypeChange.bind(this));\n }\n },\n\n /**\n * @returns {exports.initialize}\n */\n initialize: function () {\n this._super();\n this.vaultEnabler = vaultEnablerModel.getVaultEnabler();\n vaultEnablerModel.setPaymentCode(this.getVaultCode());\n\n return this;\n },\n\n /**\n * Init config\n */\n initClientConfig: function () {\n this._super();\n\n this.clientConfig.hostedFields = this.getHostedFields();\n this.clientConfig.styles = {\n 'input': {\n 'font-size': '14pt',\n 'color': '#3A3A3A'\n },\n ':focus': {\n 'color': 'black'\n },\n '.valid': {\n 'color': 'green'\n },\n '.invalid': {\n 'color': 'red'\n }\n };\n this.clientConfig.onInstanceReady = this.onInstanceReady.bind(this);\n },\n\n /**\n * @returns {Object}\n */\n getData: function () {\n var data = this._super();\n\n vaultEnablerModel.visitAdditionalData(data);\n\n return data;\n },\n\n /**\n * @returns {Bool}\n */\n isVaultEnabled: function () {\n return vaultEnablerModel.isVaultEnabled();\n },\n\n /**\n * Get Braintree Hosted Fields\n * @returns {Object}\n */\n getHostedFields: function () {\n var self = this,\n fields = {\n number: {\n selector: self.getSelector('cc_number'),\n placeholder: $t('4111 1111 1111 1111')\n },\n expirationDate: {\n selector: self.getSelector('expirationDate'),\n placeholder: $t('MM/YYYY')\n }\n };\n\n if (self.hasVerification()) {\n fields.cvv = {\n selector: self.getSelector('cc_cid'),\n placeholder: $t('123')\n };\n }\n\n return fields;\n },\n\n /**\n * Triggers on Hosted Field changes\n * @param {Object} event\n * @returns {Boolean}\n */\n onValidityChange: function (event) {\n // Handle a change in validation or card type\n if (event.emittedBy === 'number') {\n this.selectedCardType(null);\n\n if (event.cards.length === 1) {\n this.isValidCardNumber = event.fields.number.isValid;\n this.selectedCardType(\n validator.getMageCardType(event.cards[0].type, this.getCcAvailableTypes())\n );\n this.validateCardType();\n } else {\n this.isValidCardNumber = event.fields.number.isValid;\n this.validateCardType();\n }\n }\n\n // Other field validations\n if (event.emittedBy === 'expirationDate') {\n this.isValidExpirationDate = event.fields.expirationDate.isValid;\n }\n if (event.emittedBy === 'cvv') {\n this.isValidCvvNumber = event.fields.cvv.isValid;\n }\n },\n\n /**\n * Triggers on Hosted Field card type changes\n * @param {Object} event\n * @returns {Boolean}\n */\n onCardTypeChange: function (event) {\n if (event.cards.length === 1) {\n this.selectedCardType(\n validator.getMageCardType(event.cards[0].type, this.getCcAvailableTypes())\n );\n } else {\n this.selectedCardType(null);\n }\n },\n\n /**\n * Toggle invalid class on selector\n * @param selector\n * @param state\n * @returns {boolean}\n */\n validateField: function (selector, state) {\n var $selector = $(this.getSelector(selector)),\n invalidClass = 'braintree-hosted-fields-invalid';\n\n if (state === true) {\n $selector.removeClass(invalidClass);\n return true;\n }\n\n $selector.addClass(invalidClass);\n return false;\n },\n\n /**\n * Validate current credit card type\n * @returns {Boolean}\n */\n validateCardType: function () {\n return this.validateField(\n 'cc_number',\n this.isValidCardNumber\n );\n },\n\n /**\n * Validate current expiry date\n * @returns {boolean}\n */\n validateExpirationDate: function () {\n return this.validateField(\n 'expirationDate',\n this.isValidExpirationDate === true\n );\n },\n\n /**\n * Validate current CVV field\n * @returns {boolean}\n */\n validateCvvNumber: function () {\n var self = this;\n\n if (self.hasVerification() === false) {\n return true;\n }\n\n return this.validateField(\n 'cc_cid',\n this.isValidCvvNumber === true\n );\n },\n\n /**\n * Validate all fields\n * @returns {boolean}\n */\n validateFormFields: function () {\n return (this.validateCardType() && this.validateExpirationDate() && this.validateCvvNumber()) === true;\n },\n\n /**\n * Trigger order placing\n */\n placeOrderClick: function () {\n if (this.validateFormFields() && additionalValidators.validate()) {\n this.placeOrder();\n }\n },\n\n /**\n * @returns {String}\n */\n getVaultCode: function () {\n return window.checkoutConfig.payment[this.getCode()].ccVaultCode;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/lpm.js":"define(\n [\n 'Magento_Checkout/js/view/payment/default',\n 'ko',\n 'underscore',\n 'jquery',\n 'braintree',\n 'braintreeLpm',\n 'PayPal_Braintree/js/form-builder',\n 'Magento_Ui/js/model/messageList',\n 'Magento_Checkout/js/action/select-billing-address',\n 'PayPal_Braintree/js/helper/remove-non-digit-characters',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'mage/url',\n 'mage/translate'\n ],\n function (\n Component,\n ko,\n _,\n $,\n braintree,\n lpm,\n formBuilder,\n messageList,\n selectBillingAddress,\n removeNonDigitCharacters,\n fullScreenLoader,\n quote,\n additionalValidators,\n url,\n $t\n ) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n code: 'braintree_local_payment',\n paymentMethodsAvailable: ko.observable(false),\n paymentMethodNonce: null,\n template: 'PayPal_Braintree/payment/lpm'\n },\n\n clickPaymentBtn: function (method) {\n let self = this;\n\n if (additionalValidators.validate()) {\n fullScreenLoader.startLoader();\n\n braintree.create({\n authorization: self.getClientToken()\n }, function (clientError, clientInstance) {\n if (clientError) {\n self.setErrorMsg($t('Unable to initialize Braintree Client.'));\n fullScreenLoader.stopLoader();\n return;\n }\n\n lpm.create({\n client: clientInstance,\n merchantAccountId: self.getMerchantAccountId()\n }, function (lpmError, lpmInstance) {\n if (lpmError) {\n self.setErrorMsg(lpmError);\n fullScreenLoader.stopLoader();\n return;\n }\n\n lpmInstance.startPayment({\n amount: self.getAmount(),\n currencyCode: self.getCurrencyCode(),\n email: self.getCustomerDetails().email,\n phone: removeNonDigitCharacters(_.get(self.getCustomerDetails(), 'phone', '')),\n givenName: self.getCustomerDetails().firstName,\n surname: self.getCustomerDetails().lastName,\n shippingAddressRequired: !quote.isVirtual(),\n address: self.getAddress(),\n paymentType: method,\n onPaymentStart: function (data, start) {\n start();\n },\n // This is a required option, however it will apparently never be used in the current\n // payment flow. Therefore, both values are set to allow the payment flow to continue,\n // rather than error out.\n fallback: {\n url: self.getFallbackUrl(),\n buttonText: self.getFallbackButtonText()\n }\n }, function (startPaymentError, payload) {\n fullScreenLoader.stopLoader();\n if (startPaymentError) {\n switch (startPaymentError.code) {\n case 'LOCAL_PAYMENT_POPUP_CLOSED':\n self.setErrorMsg($t('Local Payment popup was closed unexpectedly.'));\n break;\n case 'LOCAL_PAYMENT_WINDOW_OPEN_FAILED':\n self.setErrorMsg($t('Local Payment popup failed to open.'));\n break;\n case 'LOCAL_PAYMENT_WINDOW_CLOSED':\n self.setErrorMsg($t('Local Payment popup was closed. Payment cancelled.'));\n break;\n default:\n self.setErrorMsg('Error! ' + startPaymentError);\n break;\n }\n } else {\n // Send the nonce to your server to create a transaction\n self.setPaymentMethodNonce(payload.nonce);\n self.placeOrder();\n }\n });\n });\n });\n }\n },\n\n getAddress: function () {\n let shippingAddress = quote.shippingAddress();\n\n if (quote.isVirtual()) {\n return {\n countryCode: shippingAddress.countryId\n };\n }\n\n return {\n streetAddress: shippingAddress.street[0],\n extendedAddress: shippingAddress.street[1],\n locality: shippingAddress.city,\n postalCode: shippingAddress.postcode,\n region: shippingAddress.region,\n countryCode: shippingAddress.countryId\n };\n },\n\n getAmount: function () {\n return quote.totals()['base_grand_total'].toString();\n },\n\n getBillingAddress: function () {\n return quote.billingAddress();\n },\n\n getClientToken: function () {\n return window.checkoutConfig.payment[this.getCode()].clientToken;\n },\n\n getCode: function () {\n return this.code;\n },\n\n getCurrencyCode: function () {\n return quote.totals()['base_currency_code'];\n },\n\n getCustomerDetails: function () {\n let billingAddress = quote.billingAddress();\n\n return {\n firstName: billingAddress.firstname,\n lastName: billingAddress.lastname,\n phone: billingAddress.telephone !== null ? billingAddress.telephone : '',\n email: typeof quote.guestEmail === 'string'\n ? quote.guestEmail : window.checkoutConfig.customerData.email\n };\n },\n\n getData: function () {\n let data = {\n 'method': this.getCode(),\n 'additional_data': {\n 'payment_method_nonce': this.paymentMethodNonce\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n return data;\n },\n\n getMerchantAccountId: function () {\n return window.checkoutConfig.payment[this.getCode()].merchantAccountId;\n },\n\n getPaymentMethod: function (method) {\n let methods = this.getPaymentMethods();\n\n for (let i = 0; i < methods.length; i++) {\n if (methods[i].method === method) {\n return methods[i];\n }\n }\n },\n\n /**\n * Get allowed local payment methods\n *\n * @returns {*}\n */\n getPaymentMethods: function () {\n return window.checkoutConfig.payment[this.getCode()].allowedMethods;\n },\n\n /**\n * Get payment icons\n *\n * @returns {*}\n */\n getPaymentMarkSrc: function () {\n return window.checkoutConfig.payment[this.getCode()].paymentIcons;\n },\n\n /**\n * Get title\n *\n * @returns {*}\n */\n getTitle: function () {\n return window.checkoutConfig.payment[this.getCode()].title;\n },\n\n /**\n * Get fallback url\n *\n * @returns {String}\n */\n getFallbackUrl: function () {\n return window.checkoutConfig.payment[this.getCode()].fallbackUrl;\n },\n\n /**\n * Get fallback button text\n * @returns {String}\n */\n getFallbackButtonText: function () {\n return window.checkoutConfig.payment[this.getCode()].fallbackButtonText;\n },\n\n /**\n * Initialize\n *\n * @returns {*}\n */\n initialize: function () {\n this._super();\n return this;\n },\n\n /**\n * Is payment method active?\n *\n * @returns {boolean}\n */\n isActive: function () {\n let address = quote.billingAddress() || quote.shippingAddress(),\n methods = this.getPaymentMethods();\n\n for (let i = 0; i < methods.length; i++) {\n if (methods[i].countries.includes(address.countryId)) {\n return true;\n }\n }\n\n return false;\n },\n\n /**\n * Is country and currency valid?\n *\n * @param method\n * @returns {boolean}\n */\n isValidCountryAndCurrency: function (method) {\n let address = quote.billingAddress(),\n countryId = address.countryId,\n quoteCurrency = quote.totals()['base_currency_code'],\n paymentMethodDetails = this.getPaymentMethod(method);\n\n if (!address) {\n this.paymentMethodsAvailable(false);\n return false;\n }\n\n if (countryId !== 'GB' && paymentMethodDetails.countries.includes(countryId)\n && (quoteCurrency === 'EUR' || quoteCurrency === 'PLN') || countryId === 'GB'\n && paymentMethodDetails.countries.includes(countryId) && quoteCurrency === 'GBP') {\n this.paymentMethodsAvailable(true);\n return true;\n }\n\n return false;\n },\n\n /**\n * Set error message\n *\n * @param message\n */\n setErrorMsg: function (message) {\n messageList.addErrorMessage({\n message: message\n });\n },\n\n /**\n * Set payment method nonce\n *\n * @param nonce\n */\n setPaymentMethodNonce: function (nonce) {\n this.paymentMethodNonce = nonce;\n },\n\n /**\n * Validate form\n *\n * @param form\n * @returns {*|jQuery}\n */\n validateForm: function (form) {\n return $(form).validation() && $(form).validation('isValid');\n }\n });\n }\n);\n","PayPal_Braintree/js/view/payment/method-renderer/vault.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'ko',\n 'jquery',\n 'Magento_Vault/js/view/payment/method-renderer/vault',\n 'PayPal_Braintree/js/view/payment/adapter',\n 'Magento_Ui/js/model/messageList',\n 'PayPal_Braintree/js/view/payment/validator-handler',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'braintree',\n 'braintreeHostedFields',\n 'mage/url'\n], function (\n ko,\n $,\n VaultComponent,\n Braintree,\n globalMessageList,\n validatorManager,\n additionalValidators,\n fullScreenLoader,\n client,\n hostedFields,\n url\n) {\n 'use strict';\n\n return VaultComponent.extend({\n defaults: {\n active: false,\n hostedFieldsInstance: null,\n imports: {\n onActiveChange: 'active'\n },\n modules: {\n hostedFields: '${ $.parentName }.braintree'\n },\n template: 'PayPal_Braintree/payment/cc/vault',\n updatePaymentUrl: url.build('braintree/payment/updatepaymentmethod'),\n vaultedCVV: ko.observable(''),\n validatorManager: validatorManager,\n isValidCvv: false,\n onInstanceReady: function (instance) {\n instance.on('validityChange', this.onValidityChange.bind(this));\n }\n },\n\n /**\n * Event fired by Braintree SDK whenever input value length matches the validation length.\n * In the case of a CVV, this is 3, or 4 for AMEX.\n *\n * @param event\n */\n onValidityChange: function (event) {\n if (event.emittedBy === 'cvv') {\n this.isValidCvv = event.fields.cvv.isValid;\n }\n },\n\n /**\n * @returns {exports}\n */\n initObservable: function () {\n this._super().observe(['active']);\n this.validatorManager.initialize();\n return this;\n },\n\n /**\n * Is payment option active?\n *\n * @returns {boolean}\n */\n isActive: function () {\n let active = this.getId() === this.isChecked();\n\n this.active(active);\n return active;\n },\n\n /**\n * Fired whenever a payment option is changed.\n *\n * @param isActive\n */\n onActiveChange: function (isActive) {\n let self = this;\n\n if (!isActive) {\n return;\n }\n\n if (self.showCvvVerify()) {\n if (self.hostedFieldsInstance) {\n self.hostedFieldsInstance.teardown(function (teardownError) {\n if (teardownError) {\n globalMessageList.addErrorMessage({\n message: teardownError.message\n });\n }\n self.hostedFieldsInstance = null;\n self.initHostedCvvField();\n });\n return;\n }\n self.initHostedCvvField();\n }\n },\n\n /**\n * Initialize the CVV input field with the Braintree Hosted Fields SDK.\n */\n initHostedCvvField: function () {\n let self = this;\n\n client.create({\n authorization: Braintree.getClientToken()\n }, function (clientError, clientInstance) {\n if (clientError) {\n globalMessageList.addErrorMessage({\n message: clientError.message\n });\n }\n hostedFields.create({\n client: clientInstance,\n fields: {\n cvv: {\n selector: '#' + self.getId() + '_cid',\n placeholder: '123'\n }\n }\n }, function (hostedError, hostedFieldsInstance) {\n if (hostedError) {\n globalMessageList.addErrorMessage({\n message: hostedError.message\n });\n return;\n }\n\n self.hostedFieldsInstance = hostedFieldsInstance;\n self.onInstanceReady(self.hostedFieldsInstance);\n });\n });\n },\n\n /**\n * Return the payment method code.\n *\n * @returns {string}\n */\n getCode: function () {\n return 'braintree_cc_vault';\n },\n\n /**\n * Get last 4 digits of card\n *\n * @returns {String}\n */\n getMaskedCard: function () {\n return this.details.maskedCC;\n },\n\n /**\n * Get expiration date\n *\n * @returns {String}\n */\n getExpirationDate: function () {\n return this.details.expirationDate;\n },\n\n /**\n * Get card type\n *\n * @returns {String}\n */\n getCardType: function () {\n return this.details.type;\n },\n\n /**\n * Get card icons\n *\n * @param {String} type\n * @returns {Boolean}\n */\n getIcons: function (type) {\n return window.checkoutConfig.payment.braintree.icons.hasOwnProperty(type) ?\n window.checkoutConfig.payment.braintree.icons[type]\n : false;\n },\n\n /**\n * Get show CVV Field\n *\n * @returns {Boolean}\n */\n showCvvVerify: function () {\n return window.checkoutConfig.payment[this.code].cvvVerify;\n },\n\n /**\n * Show or hide the error message.\n *\n * @param selector\n * @param state\n * @returns {boolean}\n */\n validateCvv: function (selector, state) {\n let $selector = $(selector),\n invalidClass = 'braintree-hosted-fields-invalid';\n\n if (state === true) {\n $selector.removeClass(invalidClass);\n return true;\n }\n\n $selector.addClass(invalidClass);\n return false;\n },\n\n /**\n * Place order\n */\n placeOrder: function () {\n let self = this;\n\n if (self.showCvvVerify()) {\n if (!self.validateCvv('#' + self.getId() + '_cid', self.isValidCvv)\n || !additionalValidators.validate()) {\n return;\n }\n } else if (!additionalValidators.validate()) {\n return;\n }\n\n fullScreenLoader.startLoader();\n\n if (self.showCvvVerify() && typeof self.hostedFieldsInstance !== 'undefined') {\n self.hostedFieldsInstance.tokenize({}, function (error, payload) {\n if (error) {\n fullScreenLoader.stopLoader();\n globalMessageList.addErrorMessage({\n message: error.message\n });\n return;\n }\n $.getJSON(self.updatePaymentUrl, {\n 'nonce': payload.nonce,\n 'public_hash': self.publicHash\n }).done(function (response) {\n if (response.success === false) {\n fullScreenLoader.stopLoader();\n globalMessageList.addErrorMessage({\n message: 'CVV verification failed.'\n });\n return;\n }\n self.getPaymentMethodNonce();\n });\n });\n } else {\n self.getPaymentMethodNonce();\n }\n },\n\n /**\n * Send request to get payment method nonce\n */\n getPaymentMethodNonce: function () {\n let self = this;\n\n fullScreenLoader.startLoader();\n $.getJSON(self.nonceUrl, {\n 'public_hash': self.publicHash,\n 'cvv': self.vaultedCVV()\n }).done(function (response) {\n fullScreenLoader.stopLoader();\n self.hostedFields(function (formComponent) {\n formComponent.setPaymentMethodNonce(response.paymentMethodNonce);\n formComponent.setCreditCardBin(response.details.bin);\n formComponent.additionalData['public_hash'] = self.publicHash;\n formComponent.code = self.code;\n if (self.vaultedCVV()) {\n formComponent.additionalData['cvv'] = self.vaultedCVV();\n }\n\n self.validatorManager.validate(formComponent, function () {\n fullScreenLoader.stopLoader();\n return formComponent.placeOrder('parent');\n }, function () {\n // No teardown actions required.\n fullScreenLoader.stopLoader();\n formComponent.setPaymentMethodNonce(null);\n formComponent.setCreditCardBin(null);\n });\n\n });\n }).fail(function (response) {\n let error = JSON.parse(response.responseText);\n\n fullScreenLoader.stopLoader();\n globalMessageList.addErrorMessage({\n message: error.message\n });\n });\n }\n });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/cc-form.js":"/**\n * Copyright 2013-2017 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine(\n [\n 'underscore',\n 'jquery',\n 'Magento_Payment/js/view/payment/cc-form',\n 'Magento_Checkout/js/model/quote',\n 'PayPal_Braintree/js/view/payment/adapter',\n 'mage/translate',\n 'PayPal_Braintree/js/validator',\n 'PayPal_Braintree/js/view/payment/validator-handler',\n 'Magento_Checkout/js/model/full-screen-loader'\n ],\n function (\n _,\n $,\n Component,\n quote,\n braintree,\n $t,\n validator,\n validatorManager,\n fullScreenLoader\n ) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n active: false,\n braintreeClient: null,\n braintreeDeviceData: null,\n paymentMethodNonce: null,\n lastBillingAddress: null,\n validatorManager: validatorManager,\n code: 'braintree',\n isProcessing: false,\n creditCardBin: null,\n\n /**\n * Additional payment data\n *\n * {Object}\n */\n additionalData: {},\n\n /**\n * Braintree client configuration\n *\n * {Object}\n */\n clientConfig: {\n onReady: function (context) {\n context.setupHostedFields();\n },\n\n /**\n * Triggers on payment nonce receive\n * @param {Object} response\n */\n onPaymentMethodReceived: function (response) {\n this.handleNonce(response);\n this.isProcessing = false;\n },\n\n /**\n * Allow a new nonce to be generated\n */\n onPaymentMethodError: function () {\n this.isProcessing = false;\n },\n\n /**\n * Device data initialization\n * @param {String} deviceData\n */\n onDeviceDataReceived: function (deviceData) {\n if (this.additionalData === undefined) {\n this.additionalData = {};\n }\n this.additionalData['device_data'] = deviceData;\n },\n\n /**\n * After Braintree instance initialization\n */\n onInstanceReady: function () {},\n\n /**\n * Triggers on any Braintree error\n * @param {Object} response\n */\n onError: function (response) {\n this.isProcessing = false;\n braintree.showError($t('Payment ' + this.getTitle() + ' can\\'t be initialized'));\n throw response.message;\n },\n\n /**\n * Triggers when customer click \"Cancel\"\n */\n onCancelled: function () {\n this.paymentMethodNonce = null;\n this.isProcessing = false;\n }\n },\n imports: {\n onActiveChange: 'active'\n }\n },\n\n /**\n * Set list of observable attributes\n *\n * @returns {exports.initObservable}\n */\n initObservable: function () {\n validator.setConfig(window.checkoutConfig.payment[this.getCode()]);\n this._super()\n .observe(['active']);\n this.validatorManager.initialize();\n this.initClientConfig();\n\n return this;\n },\n\n /**\n * Get payment name\n *\n * @returns {String}\n */\n getCode: function () {\n return this.code;\n },\n\n /**\n * Check if payment is active\n *\n * @returns {Boolean}\n */\n isActive: function () {\n let active = this.getCode() === this.isChecked();\n\n this.active(active);\n\n return active;\n },\n\n /**\n * Triggers when payment method change\n * @param {Boolean} isActive\n */\n onActiveChange: function (isActive) {\n if (!isActive) {\n return;\n }\n\n this.initBraintree();\n },\n\n /**\n * Init config\n */\n initClientConfig: function () {\n _.each(this.clientConfig, function (fn, name) {\n if (typeof fn === 'function') {\n this.clientConfig[name] = fn.bind(this);\n }\n }, this);\n },\n\n /**\n * Init Braintree configuration\n */\n initBraintree: function () {\n let intervalId = setInterval(function () {\n // stop loader when frame will be loaded\n if ($('#braintree-hosted-field-number').length) {\n clearInterval(intervalId);\n fullScreenLoader.stopLoader(true);\n }\n }, 500);\n\n if (braintree.checkout) {\n braintree.checkout.teardown(function () {\n braintree.checkout = null;\n });\n }\n\n fullScreenLoader.startLoader();\n braintree.setConfig(this.clientConfig);\n braintree.setup();\n },\n\n /**\n * Get full selector name\n *\n * @param {String} field\n * @returns {String}\n */\n getSelector: function (field) {\n return '#' + this.getCode() + '_' + field;\n },\n\n /**\n * Get list of available CC types\n *\n * @returns {Object}\n */\n getCcAvailableTypes: function () {\n let availableTypes = validator.getAvailableCardTypes(),\n billingAddress = quote.billingAddress(),\n billingCountryId;\n\n this.lastBillingAddress = quote.shippingAddress();\n\n if (!billingAddress) {\n billingAddress = this.lastBillingAddress;\n }\n\n billingCountryId = billingAddress.countryId;\n\n if (billingCountryId && validator.getCountrySpecificCardTypes(billingCountryId)) {\n return validator.collectTypes(\n availableTypes,\n validator.getCountrySpecificCardTypes(billingCountryId)\n );\n }\n\n return availableTypes;\n },\n\n /**\n * @returns {String}\n */\n getEnvironment: function () {\n return window.checkoutConfig.payment[this.getCode()].environment;\n },\n\n /**\n * Get data\n *\n * @returns {Object}\n */\n getData: function () {\n let data = {\n 'method': this.getCode(),\n 'additional_data': {\n 'payment_method_nonce': this.paymentMethodNonce,\n 'g-recaptcha-response' : $('#token-grecaptcha-braintree').val()\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n return data;\n },\n\n /**\n * Set payment nonce\n * @param {String} paymentMethodNonce\n */\n setPaymentMethodNonce: function (paymentMethodNonce) {\n this.paymentMethodNonce = paymentMethodNonce;\n },\n\n /**\n * Set credit card bin\n * @param creditCardBin\n */\n setCreditCardBin: function (creditCardBin) {\n this.creditCardBin = creditCardBin;\n },\n\n /**\n * Prepare payload to place order\n * @param {Object} payload\n */\n handleNonce: function (payload) {\n let self = this;\n\n this.setPaymentMethodNonce(payload.nonce);\n this.setCreditCardBin(payload.details.bin);\n\n // place order on success validation\n self.validatorManager.validate(self, function () {\n return self.placeOrder('parent');\n }, function () {\n self.isProcessing = false;\n self.paymentMethodNonce = null;\n self.creditCardBin = null;\n });\n },\n\n /**\n * Action to place order\n * @param {String} key\n */\n placeOrder: function (key) {\n if (key) {\n return this._super();\n }\n\n if (this.isProcessing) {\n return false;\n }\n this.isProcessing = true;\n\n\n braintree.tokenizeHostedFields();\n return false;\n },\n\n /**\n * Get payment icons\n * @param {String} type\n * @returns {Boolean}\n */\n getIcons: function (type) {\n return window.checkoutConfig.payment.braintree.icons.hasOwnProperty(type) ?\n window.checkoutConfig.payment.braintree.icons[type]\n : false;\n }\n });\n }\n);\n","PayPal_Braintree/js/view/payment/method-renderer/ach-vault.js":"/*browser:true*/\ndefine([\n 'ko',\n 'jquery',\n 'underscore',\n 'Magento_Vault/js/view/payment/method-renderer/vault',\n 'Magento_Ui/js/model/messageList',\n 'PayPal_Braintree/js/view/payment/validator-handler',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_Checkout/js/model/full-screen-loader'\n], function (\n ko,\n $,\n _,\n VaultComponent,\n globalMessageList,\n validatorManager,\n additionalValidators,\n fullScreenLoader\n) {\n 'use strict';\n\n return VaultComponent.extend({\n defaults: {\n active: false,\n imports: {\n onActiveChange: 'active'\n },\n template: 'PayPal_Braintree/payment/ach/vault',\n validatorManager: validatorManager,\n additionalData: {}\n },\n\n /**\n * @returns {exports}\n */\n initObservable: function () {\n this._super().observe(['active']);\n this.validatorManager.initialize();\n return this;\n },\n\n /**\n * Is payment option active?\n *\n * @returns {boolean}\n */\n isActive: function () {\n let active = this.getId() === this.isChecked();\n\n this.active(active);\n return active;\n },\n\n /**\n * Return the payment method code.\n *\n * @returns {String}\n */\n getCode: function () {\n return 'braintree_ach_direct_debit_vault';\n },\n\n /**\n * Get Bank Account last 4 digits.\n *\n * @returns {String}\n */\n getAccountNumberLastFourDigits: function () {\n return this.details.last4;\n },\n\n /**\n *\n * Get bank's routing number\n *\n * @returns {String}\n */\n getRoutingNumber: function () {\n return this.details.routingNumber;\n },\n\n /**\n * Get the ACH icon.\n *\n * @return {String}\n */\n getPaymentIcon() {\n return window.checkoutConfig.payment['braintree_ach_direct_debit'].paymentIcon;\n },\n\n /**\n * Trigger Place order action.\n *\n * Set payment method nonce & place order.\n */\n triggerPlaceOrder: function () {\n this.getPaymentMethodNonce();\n },\n\n /**\n * Send request to get payment method nonce & places order.\n */\n getPaymentMethodNonce: function () {\n let self = this;\n\n fullScreenLoader.startLoader();\n $.getJSON(self.nonceUrl, {\n 'public_hash': self.publicHash\n }).done(function (response) {\n fullScreenLoader.stopLoader();\n self.additionalData['payment_method_nonce'] = response.paymentMethodNonce;\n self.placeOrder();\n }).fail(function (response) {\n let error = JSON.parse(response.responseText);\n\n fullScreenLoader.stopLoader();\n globalMessageList.addErrorMessage({\n message: error.message\n });\n });\n },\n\n /**\n * Get payment method data.\n *\n * @returns {Object}\n */\n getData: function () {\n let data = {\n 'method': this.code,\n 'additional_data': {\n 'public_hash': this.publicHash\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n return data;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/venmo-vault.js":"/*browser:true*/\n\ndefine([\n 'ko',\n 'jquery',\n 'underscore',\n 'Magento_Vault/js/view/payment/method-renderer/vault',\n 'Magento_Ui/js/model/messageList',\n 'PayPal_Braintree/js/view/payment/validator-handler',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_Checkout/js/model/full-screen-loader'\n], function (\n ko,\n $,\n _,\n VaultComponent,\n globalMessageList,\n validatorManager,\n additionalValidators,\n fullScreenLoader\n) {\n 'use strict';\n\n return VaultComponent.extend({\n defaults: {\n active: false,\n imports: {\n onActiveChange: 'active'\n },\n template: 'PayPal_Braintree/payment/venmo/vault',\n validatorManager: validatorManager,\n additionalData: {}\n },\n\n /**\n * @returns {exports}\n */\n initObservable: function () {\n this._super().observe(['active']);\n this.validatorManager.initialize();\n return this;\n },\n\n /**\n * Is payment option active?\n *\n * @returns {boolean}\n */\n isActive: function () {\n let active = this.getId() === this.isChecked();\n\n this.active(active);\n return active;\n },\n\n /**\n * Return the payment method code.\n *\n * @returns {string}\n */\n getCode: function () {\n return 'braintree_venmo_vault';\n },\n\n /**\n * Get venmo username\n *\n * @returns {String}\n */\n getVenmoUsername: function () {\n return this.details.username;\n },\n\n /**\n * Get the Venmo icon\n *\n * @param type\n * @return {*|boolean}\n */\n getVenmoIcon() {\n return window.checkoutConfig.payment.braintree_venmo.paymentMarkSrc;\n },\n\n /**\n * trigger Place order action.\n *\n * Set payment method nonce & place order.\n */\n triggerPlaceOrder: function () {\n this.getPaymentMethodNonce();\n },\n\n /**\n * Send request to get payment method nonce & places order.\n */\n getPaymentMethodNonce: function () {\n let self = this;\n\n fullScreenLoader.startLoader();\n $.getJSON(self.nonceUrl, {\n 'public_hash': self.publicHash\n }).done(function (response) {\n fullScreenLoader.stopLoader();\n self.additionalData['payment_method_nonce'] = response.paymentMethodNonce;\n self.placeOrder();\n }).fail(function (response) {\n let error = JSON.parse(response.responseText);\n\n fullScreenLoader.stopLoader();\n globalMessageList.addErrorMessage({\n message: error.message\n });\n });\n },\n\n /**\n * Get payment method data.\n *\n * @returns {Object}\n */\n getData: function () {\n let data = {\n 'method': this.code,\n 'additional_data': {\n 'public_hash': this.publicHash\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n return data;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/paypal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'jquery',\n 'underscore',\n 'Magento_Checkout/js/view/payment/default',\n 'braintree',\n 'braintreeCheckoutPayPalAdapter',\n 'braintreePayPalCheckout',\n 'PayPal_Braintree/js/helper/format-amount',\n 'PayPal_Braintree/js/helper/remove-non-digit-characters',\n 'PayPal_Braintree/js/helper/replace-unsupported-characters',\n 'PayPal_Braintree/js/helper/get-cart-line-items-helper',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_Checkout/js/model/step-navigator',\n 'Magento_Vault/js/view/payment/vault-enabler',\n 'Magento_Checkout/js/action/create-billing-address',\n 'Magento_Checkout/js/action/select-billing-address',\n 'Magento_CheckoutAgreements/js/view/checkout-agreements',\n 'mage/translate'\n], function (\n $,\n _,\n Component,\n braintree,\n Braintree,\n paypalCheckout,\n formatAmount,\n removeNonDigitCharacters,\n replaceUnsupportedCharacters,\n getCartLineItems,\n quote,\n fullScreenLoader,\n additionalValidators,\n stepNavigator,\n VaultEnabler,\n createBillingAddress,\n selectBillingAddress,\n checkoutAgreements,\n $t\n) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'PayPal_Braintree/payment/paypal',\n code: 'braintree_paypal',\n active: false,\n paypalInstance: null,\n paymentMethodNonce: null,\n grandTotalAmount: null,\n isReviewRequired: false,\n customerEmail: null,\n\n /**\n * Additional payment data\n *\n * {Object}\n */\n additionalData: {},\n\n /**\n * Line items array\n *\n * {Array}\n */\n lineItemsArray: [\n 'name',\n 'kind',\n 'quantity',\n 'unitAmount',\n 'productCode',\n 'description'\n ],\n\n /**\n * PayPal client configuration\n *\n * {Object}\n */\n clientConfig: {\n offerCredit: false,\n offerCreditOnly: false,\n dataCollector: {\n paypal: true\n },\n\n buttonPayPalId: 'braintree_paypal_placeholder',\n buttonCreditId: 'braintree_paypal_credit_placeholder',\n buttonPayLaterId: 'braintree_paypal_paylater_placeholder',\n\n onDeviceDataReceived: function (deviceData) {\n this.additionalData['device_data'] = deviceData;\n },\n\n /**\n * Triggers when widget is loaded\n */\n onReady: function () {\n this.setupPayPal();\n },\n\n /**\n * Triggers on payment nonce receive\n *\n * @param {Object} response\n */\n onPaymentMethodReceived: function (response) {\n this.beforePlaceOrder(response);\n }\n },\n imports: {\n onActiveChange: 'active'\n }\n },\n\n /**\n * Set list of observable attributes\n *\n * @returns {exports.initObservable}\n */\n initObservable: function () {\n let self = this;\n\n this._super()\n .observe(['active', 'isReviewRequired', 'customerEmail']);\n\n window.addEventListener('hashchange', function (e) {\n let methodCode = quote.paymentMethod();\n\n if (methodCode === 'braintree_paypal' || methodCode === 'braintree_paypal_vault') {\n if (e.newURL.indexOf('payment') > 0 && self.grandTotalAmount !== null) {\n self.reInitPayPal();\n }\n }\n });\n\n quote.paymentMethod.subscribe(function (value) {\n let methodCode = value;\n\n if (methodCode === 'braintree_paypal' || methodCode === 'braintree_paypal_vault') {\n self.reInitPayPal();\n }\n });\n\n this.vaultEnabler = new VaultEnabler();\n this.vaultEnabler.setPaymentCode(this.getVaultCode());\n this.vaultEnabler.isActivePaymentTokenEnabler.subscribe(function () {\n self.onVaultPaymentTokenEnablerChange();\n });\n\n this.grandTotalAmount = quote.totals()['base_grand_total'];\n\n quote.totals.subscribe(function () {\n if (self.grandTotalAmount !== quote.totals()['base_grand_total']) {\n self.grandTotalAmount = quote.totals()['base_grand_total'];\n let methodCode = quote.paymentMethod();\n\n if (methodCode &&\n (methodCode.method === 'braintree_paypal' || methodCode.method === 'braintree_paypal_vault')) {\n self.reInitPayPal();\n }\n }\n });\n\n // for each component initialization need update property\n this.isReviewRequired(false);\n this.initClientConfig();\n\n return this;\n },\n\n /**\n * Get payment name\n *\n * @returns {String}\n */\n getCode: function () {\n return this.code;\n },\n\n /**\n * Get payment title\n *\n * @returns {String}\n */\n getTitle: function () {\n return window.checkoutConfig.payment[this.getCode()].title;\n },\n\n /**\n * Check if payment is active\n *\n * @returns {Boolean}\n */\n isActive: function () {\n let active = this.getCode() === this.isChecked();\n\n this.active(active);\n\n return active;\n },\n\n /**\n * Triggers when payment method change\n *\n * @param {Boolean} isActive\n */\n onActiveChange: function (isActive) {\n if (!isActive) {\n return;\n }\n\n // need always re-init Braintree with PayPal configuration\n this.reInitPayPal();\n },\n\n /**\n * Init config\n */\n initClientConfig: function () {\n this.clientConfig = _.extend(this.clientConfig, this.getPayPalConfig());\n\n _.each(this.clientConfig, function (fn, name) {\n if (typeof fn === 'function') {\n this.clientConfig[name] = fn.bind(this);\n }\n }, this);\n },\n\n /**\n * Set payment nonce\n *\n * @param {String} paymentMethodNonce\n */\n setPaymentMethodNonce: function (paymentMethodNonce) {\n this.paymentMethodNonce = paymentMethodNonce;\n },\n\n /**\n * Update quote billing address\n *\n * @param {Object}customer\n * @param {Object}address\n */\n setBillingAddress: function (customer, address) {\n let billingAddress = {\n street: [address.line1],\n city: address.city,\n postcode: address.postalCode,\n countryId: address.countryCode,\n email: customer.email,\n firstname: customer.firstName,\n lastname: customer.lastName,\n telephone: removeNonDigitCharacters(_.get(customer, 'phone', '00000000000'))\n };\n\n billingAddress['region_code'] = typeof address.state === 'string' ? address.state : '';\n billingAddress = createBillingAddress(billingAddress);\n quote.billingAddress(billingAddress);\n },\n\n /**\n * Prepare data to place order\n *\n * @param {Object} data\n */\n beforePlaceOrder: function (data) {\n this.setPaymentMethodNonce(data.nonce);\n this.customerEmail(data.details.email);\n if (quote.isVirtual()) {\n this.isReviewRequired(true);\n } else if (this.isRequiredBillingAddress() === '1' || quote.billingAddress() === null) {\n if (typeof data.details.billingAddress !== 'undefined') {\n this.setBillingAddress(data.details, data.details.billingAddress);\n } else {\n this.setBillingAddress(data.details, data.details.shippingAddress);\n }\n } else if (quote.shippingAddress() === quote.billingAddress()) {\n selectBillingAddress(quote.shippingAddress());\n } else {\n selectBillingAddress(quote.billingAddress());\n }\n this.placeOrder();\n },\n\n /**\n * Re-init PayPal Auth Flow\n */\n reInitPayPal: function () {\n this.disableButton();\n this.clientConfig.paypal.amount = formatAmount(this.grandTotalAmount);\n\n if (!quote.isVirtual()) {\n this.clientConfig.paypal.enableShippingAddress = true;\n this.clientConfig.paypal.shippingAddressEditable = false;\n this.clientConfig.paypal.shippingAddressOverride = this.getShippingAddress();\n }\n // Send Line Items\n this.clientConfig.paypal.lineItems = getCartLineItems();\n\n Braintree.setConfig(this.clientConfig);\n\n if (Braintree.getPayPalInstance()) {\n Braintree.getPayPalInstance().teardown(function () {\n Braintree.setup();\n });\n Braintree.setPayPalInstance(null);\n } else {\n Braintree.setup();\n this.enableButton();\n }\n },\n\n /**\n * Setup PayPal instance\n */\n setupPayPal: function () {\n if (Braintree.config.paypalInstance) {\n fullScreenLoader.stopLoader(true);\n return;\n }\n\n paypalCheckout.create({\n client: Braintree.clientInstance\n }, function (createErr, paypalCheckoutInstance) {\n if (createErr) {\n Braintree.showError(\n $t('PayPal Checkout could not be initialized. Please contact the store owner.'));\n console.error('paypalCheckout error', createErr);\n return;\n }\n let quoteObj = quote.totals(),\n configSDK = {\n components: 'buttons,messages,funding-eligibility',\n 'enable-funding': this.isCreditEnabled() ? 'credit' : 'paylater',\n currency: quoteObj['base_currency_code']\n },\n buyerCountry = this.getMerchantCountry();\n\n if (Braintree.getEnvironment() === 'sandbox' && buyerCountry !== null) {\n configSDK['buyer-country'] = buyerCountry;\n }\n paypalCheckoutInstance.loadPayPalSDK(configSDK, function () {\n this.loadPayPalButton(paypalCheckoutInstance, 'paypal');\n if (this.isCreditEnabled()) {\n this.loadPayPalButton(paypalCheckoutInstance, 'credit');\n }\n if (this.isPayLaterEnabled()) {\n this.loadPayPalButton(paypalCheckoutInstance, 'paylater');\n }\n\n }.bind(this));\n }.bind(this));\n },\n\n loadPayPalButton: function (paypalCheckoutInstance, funding) {\n let paypalPayment = Braintree.config.paypal,\n onPaymentMethodReceived = Braintree.config.onPaymentMethodReceived,\n style = {\n label: Braintree.getLabel(funding),\n color: Braintree.getColor(funding),\n shape: Braintree.getShape(funding)\n },\n button,\n events = Braintree.events,\n payPalButtonId,\n payPalButtonElement;\n\n if (funding === 'credit') {\n Braintree.config.buttonId = this.getCreditButtonId();\n } else if (funding === 'paylater') {\n Braintree.config.buttonId = this.getPayLaterButtonId();\n } else {\n Braintree.config.buttonId = this.getPayPalButtonId();\n }\n\n payPalButtonId = Braintree.config.buttonId;\n payPalButtonElement = $('#' + Braintree.config.buttonId);\n payPalButtonElement.html('');\n\n // Render\n Braintree.config.paypalInstance = paypalCheckoutInstance;\n\n button = window.paypal.Buttons({\n fundingSource: funding,\n env: Braintree.getEnvironment(),\n style: style,\n commit: true,\n locale: Braintree.config.paypal.locale,\n\n onInit: function (data, actions) {\n let agreements = checkoutAgreements().agreements,\n shouldDisableActions = false;\n\n actions.disable();\n\n _.each(agreements, function (item) {\n if (checkoutAgreements().isAgreementRequired(item)) {\n let paymentMethodCode = quote.paymentMethod().method,\n inputId = '#agreement_' + paymentMethodCode + '_' + item.agreementId,\n inputEl = document.querySelector(inputId);\n\n if (!inputEl.checked) {\n shouldDisableActions = true;\n }\n\n inputEl.addEventListener('change', function () {\n if (additionalValidators.validate()) {\n actions.enable();\n } else {\n actions.disable();\n }\n });\n }\n });\n\n if (!shouldDisableActions) {\n actions.enable();\n }\n },\n\n createOrder: function () {\n return paypalCheckoutInstance.createPayment(paypalPayment).catch(function (err) {\n throw err.details.originalError.details.originalError.paymentResource;\n });\n },\n\n onCancel: function (data) {\n console.log('checkout.js payment cancelled', JSON.stringify(data, 0, 2));\n\n if (typeof events.onCancel === 'function') {\n events.onCancel();\n }\n },\n\n onError: function (err) {\n if (err.errorName === 'VALIDATION_ERROR' && err.errorMessage.indexOf('Value is invalid') !== -1) {\n Braintree.showError(\n $t(\n 'Address failed validation. Please check and confirm your City, State, and Postal Code'\n )\n );\n } else {\n Braintree.showError(\n $t('PayPal Checkout could not be initialized. Please contact the store owner.'));\n }\n Braintree.config.paypalInstance = null;\n console.error('Paypal checkout.js error', err);\n\n if (typeof events.onError === 'function') {\n events.onError(err);\n }\n },\n\n onClick: function (data) {\n if (!quote.isVirtual()) {\n this.clientConfig.paypal.enableShippingAddress = true;\n this.clientConfig.paypal.shippingAddressEditable = false;\n this.clientConfig.paypal.shippingAddressOverride = this.getShippingAddress();\n }\n\n // To check term & conditions input checked - validate additional validators.\n if (!additionalValidators.validate()) {\n return false;\n }\n\n if (typeof events.onClick === 'function') {\n events.onClick(data);\n }\n }.bind(this),\n\n onApprove: function (data) {\n return paypalCheckoutInstance.tokenizePayment(data)\n .then(function (payload) {\n onPaymentMethodReceived(payload);\n });\n }\n });\n\n if (button.isEligible() && payPalButtonElement.length) {\n button.render('#' + payPalButtonId).then(function () {\n Braintree.enableButton();\n if (typeof Braintree.config.onPaymentMethodError === 'function') {\n Braintree.config.onPaymentMethodError();\n }\n }).then(function (data) {\n if (typeof events.onRender === 'function') {\n events.onRender(data);\n }\n });\n }\n },\n\n /**\n * Get locale\n *\n * @returns {String}\n */\n getLocale: function () {\n return window.checkoutConfig.payment[this.getCode()].locale;\n },\n\n /**\n * Is Billing Address required from PayPal side\n *\n * @returns {exports.isRequiredBillingAddress|(function())|boolean}\n */\n isRequiredBillingAddress: function () {\n return window.checkoutConfig.payment[this.getCode()].isRequiredBillingAddress;\n },\n\n /**\n * Get configuration for PayPal\n *\n * @returns {Object}\n */\n getPayPalConfig: function () {\n let totals = quote.totals(),\n config = {},\n isActiveVaultEnabler = this.isActiveVault();\n\n config.paypal = {\n flow: 'checkout',\n amount: formatAmount(this.grandTotalAmount),\n currency: totals['base_currency_code'],\n locale: this.getLocale(),\n\n /**\n * Triggers on any Braintree error\n */\n onError: function () {\n this.paymentMethodNonce = null;\n },\n\n /**\n * Triggers if browser doesn't support PayPal Checkout\n */\n onUnsupported: function () {\n this.paymentMethodNonce = null;\n }\n };\n\n if (isActiveVaultEnabler) {\n config.paypal.requestBillingAgreement = true;\n }\n\n if (!quote.isVirtual()) {\n config.paypal.enableShippingAddress = true;\n config.paypal.shippingAddressEditable = false;\n config.paypal.shippingAddressOverride = this.getShippingAddress();\n }\n\n if (this.getMerchantName()) {\n config.paypal.displayName = this.getMerchantName();\n }\n\n return config;\n },\n\n /**\n * Get shipping address\n *\n * @returns {Object}\n */\n getShippingAddress: function () {\n let address = quote.shippingAddress();\n\n return {\n recipientName: address.firstname + ' ' + address.lastname,\n line1: address.street[0],\n line2: typeof address.street[2] === 'undefined'\n ? address.street[1] : address.street[1] + ' ' + address.street[2],\n city: address.city,\n countryCode: address.countryId,\n postalCode: address.postcode,\n state: address.regionCode\n };\n },\n\n /**\n * Get merchant name\n *\n * @returns {String}\n */\n getMerchantName: function () {\n return window.checkoutConfig.payment[this.getCode()]['merchantName'];\n },\n\n /**\n * Get data\n *\n * @returns {Object}\n */\n getData: function () {\n let data = {\n 'method': this.getCode(),\n 'additional_data': {\n 'payment_method_nonce': this.paymentMethodNonce\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n this.vaultEnabler.visitAdditionalData(data);\n\n return data;\n },\n\n /**\n * Returns payment acceptance mark image path\n *\n * @returns {String}\n */\n getPaymentAcceptanceMarkSrc: function () {\n return window.checkoutConfig.payment[this.getCode()]['paymentAcceptanceMarkSrc'];\n },\n\n /**\n * Get paypal vault payment method code\n *\n * @returns {String}\n */\n getVaultCode: function () {\n return window.checkoutConfig.payment[this.getCode()]['vaultCode'];\n },\n\n /**\n * Check if vault is active\n *\n * @returns {Boolean}\n */\n isActiveVault: function () {\n return this.vaultEnabler.isVaultEnabled() && this.vaultEnabler.isActivePaymentTokenEnabler();\n },\n\n /**\n * Re-init PayPal Auth flow to use Vault\n */\n onVaultPaymentTokenEnablerChange: function () {\n this.clientConfig.paypal.singleUse = !this.isActiveVault();\n this.reInitPayPal();\n },\n\n /**\n * Disable submit button\n */\n disableButton: function () {\n // stop any previous shown loaders\n fullScreenLoader.stopLoader(true);\n fullScreenLoader.startLoader();\n $('[data-button=\"place\"]').attr('disabled', 'disabled');\n },\n\n /**\n * Enable submit button\n */\n enableButton: function () {\n $('[data-button=\"place\"]').removeAttr('disabled');\n fullScreenLoader.stopLoader(true);\n },\n\n /**\n * Triggers when customer click \"Continue to PayPal\" button\n */\n payWithPayPal: function () {\n if (additionalValidators.validate()) {\n Braintree.checkout.paypal.initAuthFlow();\n }\n },\n\n /**\n * Get PayPal button id\n *\n * @returns {String}\n */\n getPayPalButtonId: function () {\n return this.clientConfig.buttonPayPalId;\n },\n\n /**\n * Get Credit button id\n *\n * @returns {String}\n */\n getCreditButtonId: function () {\n return this.clientConfig.buttonCreditId;\n },\n\n /**\n * Get Pay Later button id\n *\n * @returns {String}\n */\n getPayLaterButtonId: function () {\n return this.clientConfig.buttonPayLaterId;\n },\n\n /**\n * Check if Pay Later enabled\n *\n * @returns {*}\n */\n isPayLaterEnabled: function () {\n return window.checkoutConfig.payment['braintree_paypal_paylater']['isActive'];\n },\n\n /**\n * Check if Pay Later messaging enabled\n *\n * @returns {*}\n */\n isPayLaterMessageEnabled: function () {\n return window.checkoutConfig.payment['braintree_paypal_paylater']['isMessageActive'];\n },\n\n /**\n * Get grand total\n *\n * @returns {string}\n */\n getGrandTotalAmount: function () {\n return formatAmount(this.grandTotalAmount);\n },\n\n /**\n * Check if PayPal Credit enabled\n *\n * @returns {*}\n */\n isCreditEnabled: function () {\n return window.checkoutConfig.payment['braintree_paypal_credit']['isActive'];\n },\n\n /**\n * Get Message Layout\n *\n * @returns {string}\n */\n getMessagingLayout: function () {\n return window.checkoutConfig.payment['braintree_paypal_paylater']['message']['layout'];\n },\n\n /**\n * Get Message Logo\n *\n * @returns {string}\n */\n getMessagingLogo: function () {\n return window.checkoutConfig.payment['braintree_paypal_paylater']['message']['logo'];\n },\n\n /**\n * Get Message Logo position\n *\n * @returns {string}\n */\n getMessagingLogoPosition: function () {\n return window.checkoutConfig.payment['braintree_paypal_paylater']['message']['logo_position'];\n },\n\n /**\n * Get Message Text Color\n *\n * @returns {string}\n */\n getMessagingTextColor: function () {\n return window.checkoutConfig.payment['braintree_paypal_paylater']['message']['text_color'];\n },\n\n /**\n * Get merchant country\n *\n * @returns {*}\n */\n getMerchantCountry: function () {\n return window.checkoutConfig.payment[this.getCode()]['merchantCountry'];\n },\n\n /**\n * Regex to replace all unsupported characters.\n *\n * @param str\n */\n replaceUnsupportedCharacters: function (str) {\n // eslint-disable-next-line no-useless-escape\n str.replace('/[^a-zA-Z0-9\\s\\-.\\']/', '');\n return str.substr(0, 127);\n },\n\n /**\n * Can send line items\n *\n * @returns {Boolean}\n */\n canSendLineItems: function () {\n return window.checkoutConfig.payment[this.getCode()].canSendLineItems;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/googlepay-vault.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'ko',\n 'jquery',\n 'underscore',\n 'Magento_Vault/js/view/payment/method-renderer/vault',\n 'Magento_Ui/js/model/messageList',\n 'PayPal_Braintree/js/view/payment/validator-handler',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_Checkout/js/model/full-screen-loader'\n], function (\n ko,\n $,\n _,\n VaultComponent,\n globalMessageList,\n validatorManager,\n additionalValidators,\n fullScreenLoader\n) {\n 'use strict';\n\n return VaultComponent.extend({\n defaults: {\n active: false,\n imports: {\n onActiveChange: 'active'\n },\n template: 'PayPal_Braintree/googlepay/vault',\n validatorManager: validatorManager,\n additionalData: {}\n },\n\n /**\n * @returns {exports}\n */\n initObservable: function () {\n this._super().observe(['active']);\n this.validatorManager.initialize();\n return this;\n },\n\n /**\n * Is payment option active?\n *\n * @returns {boolean}\n */\n isActive: function () {\n let active = this.getId() === this.isChecked();\n\n this.active(active);\n return active;\n },\n\n /**\n * Return the payment method code.\n *\n * @returns {string}\n */\n getCode: function () {\n return this.code;\n },\n\n /**\n * Get last 4 digits of card.\n *\n * @returns {String}\n */\n getMaskedCard: function () {\n return this.details.maskedCC;\n },\n\n /**\n * Get expiration date.\n *\n * @returns {String}\n */\n getExpirationDate: function () {\n return this.details.expirationDate;\n },\n\n /**\n * Get card type.\n *\n * @returns {String}\n */\n getCardType: function () {\n return this.details.type;\n },\n\n /**\n * Get the Google Pay Card icons.\n *\n * @param type\n * @return {*|boolean}\n */\n getGooglePayIcons: function (type) {\n let lowerCasedType = type.toLowerCase();\n\n return window.checkoutConfig.payment.braintree_googlepay.icons.hasOwnProperty(lowerCasedType) ?\n window.checkoutConfig.payment.braintree_googlepay.icons[lowerCasedType]\n : false;\n },\n\n /**\n * trigger Place order action.\n *\n * Set payment method nonce & place order.\n */\n triggerPlaceOrder: function () {\n this.getPaymentMethodNonce();\n },\n\n /**\n * Send request to get payment method nonce & places order.\n */\n getPaymentMethodNonce: function () {\n let self = this;\n\n fullScreenLoader.startLoader();\n $.getJSON(self.nonceUrl, {\n 'public_hash': self.publicHash\n }).done(function (response) {\n fullScreenLoader.stopLoader();\n self.additionalData['payment_method_nonce'] = response.paymentMethodNonce;\n self.placeOrder();\n }).fail(function (response) {\n let error = JSON.parse(response.responseText);\n\n fullScreenLoader.stopLoader();\n globalMessageList.addErrorMessage({\n message: error.message\n });\n });\n },\n\n /**\n * Get payment method data.\n *\n * @returns {Object}\n */\n getData: function () {\n let data = {\n 'method': this.code,\n 'additional_data': {\n 'public_hash': this.publicHash\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n return data;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/paypal-vault.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'jquery',\n 'underscore',\n 'Magento_Vault/js/view/payment/method-renderer/vault',\n 'Magento_Ui/js/model/messageList',\n 'Magento_Checkout/js/model/full-screen-loader'\n], function ($, _, VaultComponent, globalMessageList, fullScreenLoader) {\n 'use strict';\n\n return VaultComponent.extend({\n defaults: {\n template: 'PayPal_Braintree/payment/paypal/vault',\n additionalData: {}\n },\n\n /**\n * Get PayPal payer email\n * @returns {String}\n */\n getPayerEmail: function () {\n return this.details.payerEmail;\n },\n\n /**\n * Get type of payment\n * @returns {String}\n */\n getPaymentIcon: function () {\n return window.checkoutConfig.payment['braintree_paypal'].paymentIcon;\n },\n\n /**\n * Place order\n */\n beforePlaceOrder: function () {\n this.getPaymentMethodNonce();\n },\n\n /**\n * Send request to get payment method nonce\n */\n getPaymentMethodNonce: function () {\n var self = this;\n\n fullScreenLoader.startLoader();\n $.getJSON(self.nonceUrl, {\n 'public_hash': self.publicHash\n })\n .done(function (response) {\n fullScreenLoader.stopLoader();\n self.additionalData['payment_method_nonce'] = response.paymentMethodNonce;\n self.placeOrder();\n })\n .fail(function (response) {\n var error = JSON.parse(response.responseText);\n\n fullScreenLoader.stopLoader();\n globalMessageList.addErrorMessage({\n message: error.message\n });\n });\n },\n\n /**\n * Get payment method data\n * @returns {Object}\n */\n getData: function () {\n var data = {\n 'method': this.code,\n 'additional_data': {\n 'public_hash': this.publicHash\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n return data;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/applepay-vault.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'ko',\n 'jquery',\n 'underscore',\n 'Magento_Vault/js/view/payment/method-renderer/vault',\n 'Magento_Ui/js/model/messageList',\n 'PayPal_Braintree/js/view/payment/validator-handler',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_Checkout/js/model/full-screen-loader'\n], function (\n ko,\n $,\n _,\n VaultComponent,\n globalMessageList,\n validatorManager,\n additionalValidators,\n fullScreenLoader\n) {\n 'use strict';\n\n return VaultComponent.extend({\n defaults: {\n active: false,\n imports: {\n onActiveChange: 'active'\n },\n template: 'PayPal_Braintree/applepay/vault',\n validatorManager: validatorManager,\n additionalData: {}\n },\n\n /**\n * @returns {exports}\n */\n initObservable: function () {\n this._super().observe(['active']);\n this.validatorManager.initialize();\n return this;\n },\n\n /**\n * Is payment option active?\n *\n * @returns {boolean}\n */\n isActive: function () {\n let active = this.getId() === this.isChecked();\n\n this.active(active);\n return active;\n },\n\n /**\n * Return the payment method code.\n *\n * @returns {string}\n */\n getCode: function () {\n return 'braintree_applepay_vault';\n },\n\n /**\n * Get last 4 digits of card.\n *\n * @returns {String}\n */\n getMaskedCard: function () {\n return this.details.maskedCC;\n },\n\n /**\n * Get expiration date.\n *\n * @returns {String}\n */\n getExpirationDate: function () {\n return this.details.expirationDate;\n },\n\n /**\n * Get card type.\n *\n * @returns {String}\n */\n getCardType: function () {\n return this.details.type;\n },\n\n /**\n * Get the ApplePay Card icons.\n *\n * @param type\n * @return {*|boolean}\n */\n getApplePayIcons(type) {\n let lowerCasedType = type.toLowerCase();\n\n return window.checkoutConfig.payment.braintree_applepay.icons.hasOwnProperty(lowerCasedType) ?\n window.checkoutConfig.payment.braintree_applepay.icons[lowerCasedType]\n : false;\n },\n\n /**\n * trigger Place order action.\n *\n * Set payment method nonce & place order.\n */\n triggerPlaceOrder: function () {\n this.getPaymentMethodNonce();\n },\n\n /**\n * Send request to get payment method nonce & places order.\n */\n getPaymentMethodNonce: function () {\n let self = this;\n\n fullScreenLoader.startLoader();\n $.getJSON(self.nonceUrl, {\n 'public_hash': self.publicHash\n }).done(function (response) {\n fullScreenLoader.stopLoader();\n self.additionalData['payment_method_nonce'] = response.paymentMethodNonce;\n self.placeOrder();\n }).fail(function (response) {\n let error = JSON.parse(response.responseText);\n\n fullScreenLoader.stopLoader();\n globalMessageList.addErrorMessage({\n message: error.message\n });\n });\n },\n\n /**\n * Get payment method data.\n *\n * @returns {Object}\n */\n getData: function () {\n let data = {\n 'method': this.code,\n 'additional_data': {\n 'public_hash': this.publicHash\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n return data;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/ach.js":"define(\n [\n 'Magento_Checkout/js/view/payment/default',\n 'ko',\n 'jquery',\n 'braintree',\n 'braintreeDataCollector',\n 'braintreeAch',\n 'PayPal_Braintree/js/form-builder',\n 'Magento_Ui/js/model/messageList',\n 'Magento_Checkout/js/action/select-billing-address',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'Magento_Checkout/js/model/quote',\n 'mage/translate',\n 'Magento_Vault/js/view/payment/vault-enabler',\n 'underscore'\n ],\n function (\n Component,\n ko,\n $,\n braintree,\n dataCollector,\n ach,\n formBuilder,\n messageList,\n selectBillingAddress,\n fullScreenLoader,\n quote,\n $t,\n VaultEnabler,\n _\n ) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n deviceData: null,\n paymentMethodNonce: null,\n template: 'PayPal_Braintree/payment/ach',\n achInstance: null,\n routingNumber: ko.observable(''),\n accountNumber: ko.observable(''),\n accountType: ko.observable('checking'),\n ownershipType: ko.observable('personal'),\n firstName: ko.observable(''),\n lastName: ko.observable(''),\n businessName: ko.observable(''),\n hasAuthorization: ko.observable(false),\n business: ko.observable(false), // for ownership type\n personal: ko.observable(true), // for ownership type\n vaultEnabler: null\n },\n\n clickAchBtn: function () {\n if (!this.validateForm('#' + this.getCode() + '-form')) {\n return;\n }\n\n fullScreenLoader.startLoader();\n\n let self = this,\n\n billingAddress = quote.billingAddress(),\n\n regionCode,\n\n bankDetails = {\n routingNumber: self.routingNumber(),\n accountNumber: self.accountNumber(),\n accountType: self.accountType(),\n ownershipType: self.ownershipType(),\n billingAddress: {\n streetAddress: billingAddress.street[0],\n extendedAddress: billingAddress.street[1],\n locality: billingAddress.city,\n region: billingAddress.regionCode,\n postalCode: billingAddress.postcode\n }\n },\n\n mandateText = document.getElementById(self.isVaultActive()\n ? 'braintree-ach-mandate-vault'\n : 'braintree-ach-mandate'\n ).textContent;\n\n if (bankDetails.ownershipType === 'personal') {\n bankDetails.firstName = self.firstName();\n bankDetails.lastName = self.lastName();\n } else {\n bankDetails.businessName = self.businessName();\n }\n\n // if no region code is available, lets find one!\n if (typeof billingAddress.regionCode === 'undefined') {\n $.get('/rest/V1/directory/countries/' + billingAddress.countryId).done(function (data) {\n if (typeof data.available_regions !== 'undefined') {\n data.available_regions.forEach(function (availableRegion) {\n if (availableRegion.id === billingAddress.regionId) {\n regionCode = availableRegion.code;\n bankDetails.billingAddress.region = regionCode;\n self.tokenizeAch(bankDetails, mandateText);\n }\n });\n } else {\n fullScreenLoader.stopLoader();\n self.tokenizeAch(bankDetails, mandateText);\n }\n }).fail(function () {\n fullScreenLoader.stopLoader();\n });\n } else {\n self.tokenizeAch(bankDetails, mandateText);\n }\n },\n\n tokenizeAch: function (bankDetails, mandateText) {\n let self = this;\n\n self.achInstance.tokenize({\n bankDetails: bankDetails,\n mandateText: mandateText\n }, function (tokenizeErr, tokenizedPayload) {\n if (tokenizeErr) {\n let error = 'There was an error with the provided bank details. Please check and try again.';\n\n self.setErrorMsg($t(error));\n self.hasAuthorization(false);\n fullScreenLoader.stopLoader();\n } else {\n fullScreenLoader.stopLoader();\n self.handleAchSuccess(tokenizedPayload);\n }\n });\n },\n\n getClientToken: function () {\n return window.checkoutConfig.payment[this.getCode()].clientToken;\n },\n\n getCode: function () {\n return 'braintree_ach_direct_debit';\n },\n\n getStoreName: function () {\n return window.checkoutConfig.payment[this.getCode()].storeName;\n },\n\n getData: function () {\n let data = {\n 'method': this.getCode(),\n 'additional_data': {\n 'payment_method_nonce': this.paymentMethodNonce,\n 'device_data': this.deviceData\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n this.vaultEnabler.visitAdditionalData(data);\n\n return data;\n },\n\n getTitle: function () {\n return 'ACH Direct Debit';\n },\n\n handleAchSuccess: function (payload) {\n this.setPaymentMethodNonce(payload.nonce);\n this.placeOrder();\n },\n\n initialize: function () {\n this._super();\n this.vaultEnabler = new VaultEnabler();\n this.vaultEnabler.setPaymentCode(this.getVaultCode());\n\n let self = this;\n\n this.vaultEnabler.isActivePaymentTokenEnabler.subscribe(function () {\n self.achInstance.teardown(function () {\n self.initAch();\n });\n });\n\n this.initAch();\n\n return this;\n },\n\n isAllowed: function () {\n return window.checkoutConfig.payment[this.getCode()].isAllowed;\n },\n\n /**\n * Change the account type.\n *\n * @param data\n * @param event\n */\n changeOwnershipType: function (data, event) {\n let self = this;\n\n if (event.currentTarget.value === 'business') {\n self.business(true);\n self.personal(false);\n } else {\n self.business(false);\n self.personal(true);\n }\n },\n\n /**\n * Is Business type account.\n *\n * @returns {Boolean}\n */\n isBusiness: function () {\n return this.business;\n },\n\n /**\n * Is Personal type account.\n *\n * @returns {Boolean}\n */\n isPersonal: function () {\n return this.personal;\n },\n\n /**\n * Get the account holder name input.\n *\n * @returns {String}\n */\n getAccountHolderName: function () {\n if (this.firstName() !== '' || this.lastName() !== '') {\n return this.firstName() + ' ' + this.lastName();\n }\n\n return 'XXXX';\n },\n\n /**\n * Get the account number input.\n *\n * @returns {String}\n */\n getAccountNumber: function () {\n return this.accountNumber() !== '' ? this.accountNumber() : 'XXXX';\n },\n\n /**\n * Get the Bank Routing Number input.\n *\n * @returns {String}\n */\n getRoutingNumber: function () {\n return this.routingNumber() !== '' ? this.routingNumber() : 'XXXX';\n },\n\n /**\n * Get the quote totals value.\n *\n * @returns {String}\n */\n getGrandTotal: function () {\n let totals = quote.getTotals()();\n\n if (totals) {\n return totals['grand_total'];\n }\n\n return quote['grand_total'];\n },\n\n /**\n * Get the current date in US format (ACH is US only).\n *\n * @returns {String}\n */\n getCurrentDate: function () {\n const today = new Date();\n\n return today.toLocaleDateString('en-US');\n },\n\n setErrorMsg: function (message) {\n messageList.addErrorMessage({\n message: message\n });\n },\n\n setPaymentMethodNonce: function (nonce) {\n this.paymentMethodNonce = nonce;\n },\n\n /**\n * Set the ACH instance.\n *\n * @param {*} instance\n */\n setAchInstance: function (instance) {\n this.achInstance = instance;\n },\n\n /**\n * Validate ACH form.\n *\n * @param {*} form\n * @returns {*|jQuery}\n */\n validateForm: function (form) {\n return $(form).validation() && $(form).validation('isValid');\n },\n\n /**\n * Get ACH's should vault checkbox element ID.\n *\n * @returns {String}\n */\n getVaultCheckboxId: function () {\n return this.getCode() + '_enable_vault';\n },\n\n /**\n * Check whether Vault is enabled.\n *\n * @returns {Boolean}\n */\n isVaultEnabled: function () {\n return this.vaultEnabler.isVaultEnabled();\n },\n\n /**\n * Is Vault enabled & vaulting payment active (checked)\n *\n * @returns {Boolean}\n */\n isVaultActive: function () {\n return this.isVaultEnabled() && this.vaultEnabler.isActivePaymentTokenEnabler();\n },\n\n /**\n * Get ACH vault payment method code.\n *\n * @returns {String}\n */\n getVaultCode: function () {\n return window.checkoutConfig.payment[this.getCode()]['vaultCode'];\n },\n\n /**\n * Initialize ACH component.\n *\n * @returns {void}\n */\n initAch: function () {\n let self = this;\n\n braintree.create({\n authorization: self.getClientToken()\n }, function (clientError, clientInstance) {\n if (clientError) {\n this.setErrorMsg($t('Unable to initialize Braintree Client.'));\n return;\n }\n\n /* Collect device data */\n self.collectDeviceData(clientInstance, function () {\n /* callback from collectDeviceData */\n ach.create({\n client: clientInstance\n }, function (achErr, achInstance) {\n if (achErr) {\n self.setErrorMsg($t('Error initializing ACH: %1').replace('%1', achErr));\n return;\n }\n\n self.setAchInstance(achInstance);\n });\n });\n });\n },\n\n /**\n * Collect device data.\n *\n * @param clientInstance\n * @param {Function} callback\n * @returns {void}\n */\n collectDeviceData: function (clientInstance, callback) {\n let self = this;\n\n dataCollector.create({\n client: clientInstance,\n paypal: true\n }, function (dataCollectorErr, dataCollectorInstance) {\n if (dataCollectorErr) {\n return;\n }\n\n self.deviceData = dataCollectorInstance.deviceData;\n callback();\n });\n }\n });\n }\n);\n","PayPal_Braintree/js/view/payment/method-renderer/paypal-customer-vault.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'jquery',\n 'underscore',\n 'mage/translate',\n 'braintree',\n 'braintreeDataCollector',\n 'braintreePayPalCheckout',\n 'PayPal_Braintree/js/helper/format-amount',\n 'PayPal_Braintree/js/helper/remove-non-digit-characters',\n 'PayPal_Braintree/js/helper/replace-unsupported-characters',\n 'Magento_Checkout/js/action/create-billing-address',\n 'Magento_Checkout/js/action/select-billing-address',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_CheckoutAgreements/js/view/checkout-agreements',\n 'Magento_Vault/js/view/payment/method-renderer/vault',\n 'Magento_Ui/js/model/messageList'\n], function (\n $,\n _,\n $t,\n client,\n dataCollector,\n paypalCheckout,\n formatAmount,\n removeNonDigitCharacters,\n replaceUnsupportedCharacters,\n createBillingAddress,\n selectBillingAddress,\n fullScreenLoader,\n quote,\n additionalValidators,\n checkoutAgreements,\n VaultComponent,\n globalMessageList\n) {\n 'use strict';\n\n return VaultComponent.extend({\n defaults: {\n template: 'PayPal_Braintree/payment/paypal/customer-vault',\n\n /**\n * Component config set via provider.\n */\n code: null,\n nonceUrl: null,\n publicHash: null,\n clientToken: null,\n clientInstance: null,\n checkout: null,\n details: {},\n\n /**\n * {Object}\n */\n events: {\n onClick: null,\n onCancel: null,\n onError: null,\n onRender: null\n },\n\n /**\n * Additional payment data\n *\n * {Object}\n */\n additionalData: {},\n\n /**\n * Placeholders for PayPal instance vaulted payment.\n */\n paypalInstance: null,\n paymentMethodNonce: null,\n grandTotalAmount: null,\n isReviewRequired: false,\n customerEmail: null,\n\n /**\n * {Array}\n */\n lineItemsArray: [\n 'name',\n 'kind',\n 'quantity',\n 'unitAmount',\n 'productCode',\n 'description'\n ],\n\n /**\n * PayPal client configuration\n *\n * {Object}\n */\n clientConfig: {\n dataCollector: {\n paypal: true\n },\n\n /**\n * Triggers when widget is loaded\n */\n onReady: function () {\n this.setupPayPal();\n },\n\n /**\n * Triggers on payment nonce receive\n * @param {Object} response\n */\n onPaymentMethodReceived: function (response) {\n this.beforePlaceOrder(response);\n }\n },\n\n imports: {\n onActiveChange: 'active'\n }\n },\n\n /**\n * Set list of observable attributes\n *\n * @returns {exports.initObservable}\n */\n initObservable: function () {\n let self = this;\n\n this._super().observe(['active', 'isReviewRequired', 'customerEmail']);\n\n window.addEventListener('hashchange', function (e) {\n let methodCode = quote.paymentMethod();\n\n if (methodCode && methodCode.method === self.getId()) {\n if (e.newURL.indexOf('payment') > 0 && self.grandTotalAmount !== null) {\n self.reInitPayPalVault();\n }\n }\n });\n\n quote.paymentMethod.subscribe(function (value) {\n if (value.method && value.method === self.getId()) {\n self.reInitPayPalVault();\n }\n });\n\n self.grandTotalAmount = quote.totals()['base_grand_total'];\n\n quote.totals.subscribe(function () {\n if (self.grandTotalAmount !== quote.totals()['base_grand_total']) {\n self.grandTotalAmount = quote.totals()['base_grand_total'];\n let methodCode = quote.paymentMethod();\n\n if (methodCode && methodCode.method === self.getId()) {\n self.reInitPayPalVault();\n }\n }\n });\n\n self.isReviewRequired(false);\n self.initClientConfig();\n\n return this;\n },\n\n /**\n * Triggers when payment method change\n *\n * @param {Boolean} isActive\n */\n onActiveChange: function (isActive) {\n if (!isActive) {\n return;\n }\n\n // need always re-init Braintree with PayPal configuration\n this.reInitPayPalVault();\n },\n\n /**\n * Init config\n */\n initClientConfig: function () {\n this.clientConfig = _.extend(this.clientConfig, this.getPayPalConfig());\n\n _.each(this.clientConfig, function (fn, name) {\n if (typeof fn === 'function') {\n this.clientConfig[name] = fn.bind(this);\n }\n }, this);\n },\n\n /**\n * Get configuration for PayPal\n *\n * @returns {Object}\n */\n getPayPalConfig: function () {\n let totals = quote.totals(),\n config = {};\n\n config.paypal = {\n flow: 'checkout',\n amount: formatAmount(this.grandTotalAmount),\n currency: totals['base_currency_code'],\n locale: this.getLocale(),\n\n /**\n * Triggers on any Braintree error\n */\n onError: function () {\n this.paymentMethodNonce = null;\n },\n\n /**\n * Triggers if browser doesn't support PayPal Checkout\n */\n onUnsupported: function () {\n this.paymentMethodNonce = null;\n }\n };\n\n if (!quote.isVirtual()) {\n config.paypal.enableShippingAddress = true;\n config.paypal.shippingAddressEditable = false;\n config.paypal.shippingAddressOverride = this.getShippingAddress();\n }\n\n if (this.getMerchantName()) {\n config.paypal.displayName = this.getMerchantName();\n }\n\n return config;\n },\n\n /**\n * Re-init PayPal Vault Auth Flow\n */\n reInitPayPalVault: function () {\n this.disableButton();\n this.clientConfig.paypal.amount = formatAmount(this.grandTotalAmount);\n\n if (!quote.isVirtual()) {\n this.clientConfig.paypal.enableShippingAddress = true;\n this.clientConfig.paypal.shippingAddressEditable = false;\n this.clientConfig.paypal.shippingAddressOverride = this.getShippingAddress();\n }\n\n // Send Line Items\n this.clientConfig.paypal.lineItems = this.getLineItems();\n\n if (this.getPayPalInstance()) {\n this.getPayPalInstance().teardown(function () {\n this.setPayPalInstance(null);\n this.createClientInstance(null);\n }.bind(this));\n } else {\n this.createClientInstance(null);\n this.enableButton();\n }\n },\n\n /**\n * Get the current Braintree client instance.\n *\n * Null if not set.\n *\n * @return {*|null}\n */\n getClientInstance: function () {\n if (typeof this.clientInstance !== 'undefined' && this.clientInstance) {\n return this.clientInstance;\n }\n\n return null;\n },\n\n /**\n * Set the Braintree client instance or null it.\n *\n * @param val\n */\n setClientInstance: function (val) {\n this.clientInstance = val;\n },\n\n /**\n * Get the PayPal instance if already instantiated, otherwise null.\n *\n * @return {*|null}\n */\n getPayPalInstance: function () {\n if (typeof this.paypalInstance !== 'undefined' && this.paypalInstance) {\n return this.paypalInstance;\n }\n\n return null;\n },\n\n /**\n * Set the PayPal instance or null it by setting the value of the property.\n *\n * @param val\n */\n setPayPalInstance: function (val) {\n this.paypalInstance = val;\n },\n\n /**\n * Create the Braintree client instance.\n *\n * @param {Function|null} callback\n */\n createClientInstance: function (callback = null) {\n if (this.getClientToken() === null) {\n this.showError($t('Sorry, but something went wrong.'));\n return;\n }\n\n if (this.getClientInstance()) {\n if (typeof this.clientConfig.onReady === 'function') {\n this.clientConfig.onReady(this);\n }\n\n if (typeof callback === 'function') {\n callback(this.clientInstance);\n }\n\n return;\n }\n\n client.create({\n authorization: this.getClientToken()\n }, function (clientErr, clientInstance) {\n if (clientErr) {\n console.error('Braintree Setup Error', clientErr);\n return this.showError('Sorry, but something went wrong. Please contact the store owner.');\n }\n\n let options = {\n client: clientInstance\n };\n\n if (typeof this.clientConfig.dataCollector === 'object'\n && typeof this.clientConfig.dataCollector.paypal === 'boolean')\n {\n options.paypal = true;\n }\n\n dataCollector.create(options, function (err, dataCollectorInstance) {\n if (err) {\n return console.log(err);\n }\n this.additionalData['device_data'] = dataCollectorInstance.deviceData;\n }.bind(this));\n\n this.setClientInstance(clientInstance);\n\n if (typeof this.clientConfig.onReady === 'function') {\n this.clientConfig.onReady(this);\n }\n\n if (typeof callback === 'function') {\n callback(this.getClientInstance());\n }\n }.bind(this));\n },\n\n /**\n * Get Environment\n *\n * @returns {String}\n */\n getEnvironment: function () {\n return window.checkoutConfig.payment['braintree_paypal'].environment;\n },\n\n /**\n * Setup PayPal instance\n */\n setupPayPal: function () {\n if (this.getPayPalInstance()) {\n fullScreenLoader.stopLoader(true);\n return;\n }\n\n paypalCheckout.create({\n autoSetDataUserIdToken: true,\n client: this.getClientInstance()\n }, function (createErr, paypalCheckoutInstance) {\n if (createErr) {\n this.showError(\n $t('PayPal Checkout could not be initialized. Please contact the store owner.')\n );\n console.error('paypalCheckout error', createErr);\n return;\n }\n\n let quoteObj = quote.totals(),\n\n configSDK = {\n components: 'buttons,messages,funding-eligibility',\n 'enable-funding': 'paylater',\n currency: quoteObj['base_currency_code']\n },\n\n buyerCountry = this.getMerchantCountry();\n\n if (this.getEnvironment() === 'sandbox' && buyerCountry !== null) {\n configSDK['buyer-country'] = buyerCountry;\n }\n\n paypalCheckoutInstance.loadPayPalSDK(configSDK, function () {\n this.loadPayPalButton(paypalCheckoutInstance, 'paypal');\n\n if (this.isPayLaterEnabled()) {\n this.loadPayPalButton(paypalCheckoutInstance, 'paylater');\n }\n }.bind(this));\n }.bind(this));\n },\n\n /**\n * Load PayPal buttons\n *\n * @param paypalCheckoutInstance\n * @param funding\n */\n loadPayPalButton: function (paypalCheckoutInstance, funding) {\n let paypalPayment = this.clientConfig.paypal,\n onPaymentMethodReceived = this.clientConfig.onPaymentMethodReceived,\n\n style = {\n label: this.getLabelByFunding(funding),\n color: this.getColorByFunding(funding),\n shape: this.getShapeByFunding(funding)\n },\n\n payPalButtonId = this.getButtonIdByFunding(funding),\n payPalButtonElement = $('#' + payPalButtonId),\n button,\n events = this.events;\n\n payPalButtonElement.html('');\n\n // Render\n this.setPayPalInstance(paypalCheckoutInstance);\n\n button = window.paypal.Buttons({\n fundingSource: funding,\n env: this.getEnvironment(),\n style: style,\n commit: true,\n locale: this.clientConfig.paypal.locale,\n\n onInit: function (data, actions) {\n let agreements = checkoutAgreements().agreements,\n shouldDisableActions = false;\n\n actions.disable();\n\n _.each(agreements, function (item) {\n if (checkoutAgreements().isAgreementRequired(item)) {\n let paymentMethodCode = quote.paymentMethod().method,\n inputId = '#agreement_' + paymentMethodCode + '_' + item.agreementId,\n inputEl = document.querySelector(inputId);\n\n if (!inputEl.checked) {\n shouldDisableActions = true;\n }\n\n inputEl.addEventListener('change', function () {\n if (additionalValidators.validate(false)) {\n actions.enable();\n } else {\n actions.disable();\n }\n });\n }\n });\n\n if (!shouldDisableActions) {\n actions.enable();\n }\n },\n\n createOrder: function () {\n return paypalCheckoutInstance.createPayment(paypalPayment).catch(function (err) {\n throw err.details.originalError.details.originalError.paymentResource;\n });\n },\n\n onCancel: function (data) {\n console.log('checkout.js payment cancelled', JSON.stringify(data, 0, 2));\n\n if (typeof events.onCancel === 'function') {\n events.onCancel();\n }\n },\n\n onError: function (err) {\n if (err.errorName === 'VALIDATION_ERROR'\n && err.errorMessage.indexOf('Value is invalid') !== -1\n ) {\n this.showError(\n $t('Address failed validation. Please check and confirm your City, State, and Postal Code')\n );\n } else {\n this.showError($t('PayPal Checkout could not be initialized. Please contact the store owner.'));\n }\n\n this.setPayPalInstance(null);\n console.error('Paypal checkout.js error', err);\n\n if (typeof events.onError === 'function') {\n events.onError(err);\n }\n }.bind(this),\n\n onClick: function (data) {\n if (!quote.isVirtual()) {\n this.clientConfig.paypal.enableShippingAddress = true;\n this.clientConfig.paypal.shippingAddressEditable = false;\n this.clientConfig.paypal.shippingAddressOverride = this.getShippingAddress();\n }\n\n // To check term & conditions input checked - validate additional validators.\n if (!additionalValidators.validate(false)) {\n return false;\n }\n\n if (typeof events.onClick === 'function') {\n events.onClick(data);\n }\n }.bind(this),\n\n onApprove: function (data) {\n return paypalCheckoutInstance.tokenizePayment(data)\n .then(function (payload) {\n onPaymentMethodReceived(payload);\n });\n }\n\n });\n\n if (button.isEligible() && payPalButtonElement.length) {\n button.render('#' + payPalButtonId).then(function () {\n this.enableButton();\n\n if (typeof this.clientConfig.onPaymentMethodError === 'function') {\n this.clientConfig.onPaymentMethodError();\n }\n }.bind(this)).then(function (data) {\n if (typeof events.onRender === 'function') {\n events.onRender(data);\n }\n });\n }\n },\n\n /**\n * Prepare data to place order\n *\n * @param {Object} data\n */\n beforePlaceOrder: function (data) {\n this.setPaymentMethodNonce(data.nonce);\n this.customerEmail(data.details.email);\n if (quote.isVirtual()) {\n this.isReviewRequired(true);\n } else if (this.isRequiredBillingAddress() === '1' || quote.billingAddress() === null) {\n if (typeof data.details.billingAddress !== 'undefined') {\n this.setBillingAddress(data.details, data.details.billingAddress);\n } else {\n this.setBillingAddress(data.details, data.details.shippingAddress);\n }\n } else if (quote.shippingAddress() === quote.billingAddress()) {\n selectBillingAddress(quote.shippingAddress());\n } else {\n selectBillingAddress(quote.billingAddress());\n }\n this.placeOrder();\n },\n\n /**\n * Get the component's client token.\n *\n * @return {String}\n */\n getClientToken: function () {\n return this.clientToken;\n },\n\n /**\n * Get merchant country\n *\n * @returns {*}\n */\n getMerchantCountry: function () {\n return _.get(window.checkoutConfig.payment, ['braintree_paypal', 'merchantCountry'], null);\n },\n\n /**\n * Get PayPal payer email\n *\n * @returns {String}\n */\n getPayerEmail: function () {\n return this.details.payerEmail;\n },\n\n /**\n * Get type of payment\n *\n * @returns {String}\n */\n getPaymentIcon: function () {\n return window.checkoutConfig.payment['braintree_paypal'].paymentIcon;\n },\n\n /**\n * Get merchant name\n *\n * @returns {String}\n */\n getMerchantName: function () {\n return window.checkoutConfig.payment['braintree_paypal'].merchantName;\n },\n\n /**\n * Get payment method data\n *\n * @returns {Object}\n */\n getData: function () {\n let data = {\n 'method': this.code,\n 'additional_data': {\n 'public_hash': this.publicHash,\n 'payment_method_nonce': this.paymentMethodNonce\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n return data;\n },\n\n /**\n * Set payment nonce.\n *\n * @param {String} paymentMethodNonce\n */\n setPaymentMethodNonce: function (paymentMethodNonce) {\n this.paymentMethodNonce = paymentMethodNonce;\n },\n\n /**\n * Get shipping address\n *\n * @returns {Object}\n */\n getShippingAddress: function () {\n let address = quote.shippingAddress();\n\n return {\n recipientName: address.firstname + ' ' + address.lastname,\n line1: address.street[0],\n line2: typeof address.street[2] === 'undefined'\n ? address.street[1]\n : address.street[1] + ' ' + address.street[2],\n city: address.city,\n countryCode: address.countryId,\n postalCode: address.postcode,\n state: address.regionCode\n };\n },\n\n /**\n * Update quote billing address\n *\n * @param {Object}customer\n * @param {Object}address\n */\n setBillingAddress: function (customer, address) {\n let billingAddress = {\n street: [address.line1],\n city: address.city,\n postcode: address.postalCode,\n countryId: address.countryCode,\n email: customer.email,\n firstname: customer.firstName,\n lastname: customer.lastName,\n telephone: removeNonDigitCharacters(_.get(customer, 'phone', '00000000000'))\n };\n\n billingAddress['region_code'] = typeof address.state === 'string' ? address.state : '';\n billingAddress = createBillingAddress(billingAddress);\n quote.billingAddress(billingAddress);\n },\n\n /**\n * Disable submit button\n */\n disableButton: function () {\n // stop any previous shown loaders\n fullScreenLoader.stopLoader(true);\n fullScreenLoader.startLoader();\n $('[data-button=\"place\"]').attr('disabled', 'disabled');\n },\n\n /**\n * Enable submit button\n */\n enableButton: function () {\n $('[data-button=\"place\"]').removeAttr('disabled');\n fullScreenLoader.stopLoader(true);\n },\n\n /**\n * Triggers when customer click \"Continue to PayPal\" button\n */\n payWithPayPal: function () {\n if (additionalValidators.validate(false)) {\n this.checkout.paypal.initAuthFlow();\n }\n },\n\n /**\n * Get a kebab case formatted string of the component ID (normally with `_`).\n *\n * @return {String|null}\n */\n getKebabCaseId: function () {\n if (this.getId() === null) {\n return null;\n }\n\n return this.getId().replace('_', '-');\n },\n\n /**\n * Get the PayPal button placeholder id.\n *\n * @returns {String}\n */\n getPayPalButtonId: function () {\n return this.getId() + '_placeholder';\n },\n\n /**\n * Get PayPal Pay Later button placeholder id.\n *\n * @returns {String}\n */\n getPayLaterButtonId: function () {\n return this.getId() + '_paylater_placeholder';\n },\n\n /**\n * Check if Pay Later enabled.\n *\n * @returns {boolean}\n */\n isPayLaterEnabled: function () {\n return _.get(window.checkoutConfig.payment, ['braintree_paypal_paylater', 'isActive'], false);\n },\n\n /**\n * Check if Pay Later messaging enabled.\n *\n * @returns {boolean}\n */\n isPayLaterMessageEnabled: function () {\n return _.get(window.checkoutConfig.payment, ['braintree_paypal_paylater', 'isMessageActive'], false);\n },\n\n /**\n * Get the formatted grand total.\n *\n * @return {string}\n */\n getGrandTotalAmount: function () {\n return formatAmount(this.grandTotalAmount);\n },\n\n /**\n * Get locale\n *\n * @returns {String}\n */\n getLocale: function () {\n return _.get(window.checkoutConfig.payment, ['braintree_paypal', 'locale'], '');\n },\n\n /**\n * Get PayPal Pay Later Message Layout.\n *\n * @returns {string}\n */\n getMessagingLayout: function () {\n return _.get(window.checkoutConfig.payment, ['braintree_paypal_paylater', 'message', 'layout'], '');\n },\n\n /**\n * Get PayPal Pay Later Message Logo.\n *\n * @returns {string}\n */\n getMessagingLogo: function () {\n return _.get(window.checkoutConfig.payment, ['braintree_paypal_paylater', 'message', 'logo'], '');\n },\n\n /**\n * Get PayPal Pay Later Message Logo position.\n *\n * @returns {string}\n */\n getMessagingLogoPosition: function () {\n return _.get(window.checkoutConfig.payment, ['braintree_paypal_paylater', 'message', 'logo_position'], '');\n },\n\n /**\n * Get PayPal Pay Later Message Text Color.\n *\n * @returns {string}\n */\n getMessagingTextColor: function () {\n return _.get(window.checkoutConfig.payment, ['braintree_paypal_paylater', 'message', 'text_color'], '');\n },\n\n /**\n * Is Billing Address required from PayPal side.\n *\n * @returns {exports.isRequiredBillingAddress|(function())|boolean|String}\n */\n isRequiredBillingAddress: function () {\n return window.checkoutConfig.payment['braintree_paypal'].isRequiredBillingAddress;\n },\n\n /**\n * Show error message\n *\n * @param {String} errorMessage\n */\n showError: function (errorMessage) {\n globalMessageList.addErrorMessage({\n message: errorMessage\n });\n fullScreenLoader.stopLoader(true);\n },\n\n /**\n * Get line items\n *\n * @returns {Array}\n */\n getLineItems: function () {\n let self = this,\n lineItems = [];\n\n if (this.canSendLineItems()) {\n let giftWrappingItems = 0,\n giftWrappingOrder = 0,\n storeCredit = 0,\n giftCardAccount = 0,\n giftWrappingPrintedCard = 0,\n baseDiscountAmount,\n baseTaxAmount;\n\n $.each(quote.totals()['total_segments'], function (segmentsKey, segmentsItem) {\n if (segmentsItem['code'] === 'customerbalance') {\n storeCredit = formatAmount(Math.abs(segmentsItem['value']).toString());\n }\n if (segmentsItem['code'] === 'giftcardaccount') {\n giftCardAccount = formatAmount(Math.abs(segmentsItem['value']).toString());\n }\n if (segmentsItem['code'] === 'giftwrapping') {\n let extensionAttributes = segmentsItem['extension_attributes'];\n\n giftWrappingOrder = extensionAttributes['gw_base_price'];\n giftWrappingItems = extensionAttributes['gw_items_base_price'];\n giftWrappingPrintedCard = extensionAttributes['gw_card_base_price'];\n }\n });\n\n $.each(quote.getItems(), function (quoteItemKey, quoteItem) {\n if (quoteItem.parent_item_id !== null || quoteItem.price === 0.0) {\n return true;\n }\n\n let itemName = replaceUnsupportedCharacters(quoteItem.name),\n itemSku = replaceUnsupportedCharacters(quoteItem.sku),\n\n description = '',\n itemQty = parseFloat(quoteItem.qty),\n itemUnitAmount = parseFloat(quoteItem.price),\n lineItemValues,\n mappedLineItems;\n\n if (itemQty > Math.floor(itemQty) && itemQty < Math.ceil(itemQty)) {\n description = 'Item quantity is ' + itemQty.toFixed(2)\n + ' and per unit amount is ' + itemUnitAmount.toFixed(2);\n itemUnitAmount = parseFloat(itemQty * itemUnitAmount);\n itemQty = parseFloat('1');\n }\n\n lineItemValues = [\n itemName,\n 'debit',\n itemQty.toFixed(2),\n itemUnitAmount.toFixed(2),\n itemSku,\n description\n ],\n\n mappedLineItems = $.map(self.lineItemsArray, function (itemElement, itemIndex) {\n return [[\n self.lineItemsArray[itemIndex],\n lineItemValues[itemIndex]\n ]];\n });\n\n lineItems[quoteItemKey] = Object.fromEntries(mappedLineItems);\n });\n\n /**\n * Adds credit (refund or discount) kind as LineItems for the\n * PayPal transaction if discount amount is greater than 0(Zero)\n * as discountAmount lineItem field is not being used by PayPal.\n *\n * developer.paypal.com/braintree/docs/reference/response/transaction-line-item/php#discount_amount\n */\n baseDiscountAmount = formatAmount(Math.abs(quote.totals()['base_discount_amount']).toString());\n\n if (baseDiscountAmount > 0) {\n let discountLineItem = {\n 'name': 'Discount',\n 'kind': 'credit',\n 'quantity': 1.00,\n 'unitAmount': baseDiscountAmount\n };\n\n lineItems = $.merge(lineItems, [discountLineItem]);\n }\n\n /**\n * Adds shipping as LineItems for the PayPal transaction\n * if shipping amount is greater than 0(Zero) to manage\n * the totals with client-side implementation as there is\n * no any field exist in the client-side implementation\n * to send the shipping amount to the Braintree.\n */\n if (quote.totals()['base_shipping_amount'] > 0) {\n let shippingLineItem = {\n 'name': 'Shipping',\n 'kind': 'debit',\n 'quantity': 1.00,\n 'unitAmount': quote.totals()['base_shipping_amount']\n };\n\n lineItems = $.merge(lineItems, [shippingLineItem]);\n }\n\n baseTaxAmount = formatAmount(quote.totals()['base_tax_amount']);\n\n if (baseTaxAmount > 0) {\n let taxLineItem = {\n 'name': 'Tax',\n 'kind': 'debit',\n 'quantity': 1.00,\n 'unitAmount': baseTaxAmount\n };\n\n lineItems = $.merge(lineItems, [taxLineItem]);\n }\n\n /**\n * Adds credit (Store Credit) kind as LineItems for the\n * PayPal transaction if store credit is greater than 0(Zero)\n * to manage the totals with client-side implementation\n */\n if (storeCredit > 0) {\n let storeCreditItem = {\n 'name': 'Store Credit',\n 'kind': 'credit',\n 'quantity': 1.00,\n 'unitAmount': storeCredit\n };\n\n lineItems = $.merge(lineItems, [storeCreditItem]);\n }\n\n /**\n * Adds Gift Wrapping for items as LineItems for the PayPal\n * transaction if it is greater than 0(Zero) to manage\n * the totals with client-side implementation\n */\n if (giftWrappingItems > 0) {\n let gwItems = {\n 'name': 'Gift Wrapping for Items',\n 'kind': 'debit',\n 'quantity': 1.00,\n 'unitAmount': giftWrappingItems\n };\n\n lineItems = $.merge(lineItems, [gwItems]);\n }\n\n /**\n * Adds Gift Wrapping for order as LineItems for the PayPal\n * transaction if it is greater than 0(Zero) to manage\n * the totals with client-side implementation\n */\n if (giftWrappingOrder > 0) {\n let gwOrderItem = {\n 'name': 'Gift Wrapping for Order',\n 'kind': 'debit',\n 'quantity': 1.00,\n 'unitAmount': giftWrappingOrder\n };\n\n lineItems = $.merge(lineItems, [gwOrderItem]);\n }\n\n /**\n * Adds Gift Wrapping Printed Card as LineItems for the PayPal\n * transaction if it is greater than 0(Zero) to manage\n * the totals with client-side implementation\n */\n if (giftWrappingPrintedCard > 0) {\n let gwPrintedCard = {\n 'name': 'Printed Card',\n 'kind': 'debit',\n 'quantity': 1.00,\n 'unitAmount': giftWrappingPrintedCard\n };\n\n lineItems = $.merge(lineItems, [gwPrintedCard]);\n }\n\n /**\n * Adds Gift Cards as credit LineItems for the PayPal\n * transaction if it is greater than 0(Zero) to manage\n * the totals with client-side implementation\n */\n if (giftCardAccount > 0) {\n let giftCardItem = {\n 'name': 'Gift Cards',\n 'kind': 'credit',\n 'quantity': 1.00,\n 'unitAmount': giftCardAccount\n };\n\n lineItems = $.merge(lineItems, [giftCardItem]);\n }\n\n if (lineItems.length >= 250) {\n lineItems = [];\n }\n }\n return lineItems;\n },\n\n /**\n * Can send line items\n *\n * @returns {Boolean}\n */\n canSendLineItems: function () {\n return window.checkoutConfig.payment['braintree_paypal'].canSendLineItems;\n },\n\n /**\n * Get the Button ID for the required funding\n *\n * @param {string} funding\n * @return {string}\n */\n getButtonIdByFunding: function (funding) {\n if (funding === 'paylater') {\n return this.getPayLaterButtonId();\n }\n\n return this.getPayPalButtonId();\n },\n\n /**\n * Get the label config associated to the PayPal funding source.\n *\n * @param {string} funding\n * @return {string}\n */\n getLabelByFunding: function (funding) {\n return _.get(\n window.checkoutConfig.payment,\n [this.getPaymentMethodCodeByFunding(funding), 'style', 'label'],\n ''\n );\n },\n\n /**\n * Get the color config associated to the PayPal funding source.\n *\n * @param {string} funding\n * @return {string}\n */\n getColorByFunding: function (funding) {\n return _.get(\n window.checkoutConfig.payment,\n [this.getPaymentMethodCodeByFunding(funding), 'style', 'color'],\n ''\n );\n },\n\n /**\n * Get the shape config associated to the PayPal funding source.\n *\n * @param {string} funding\n * @return {string}\n */\n getShapeByFunding: function (funding) {\n return _.get(\n window.checkoutConfig.payment,\n [this.getPaymentMethodCodeByFunding(funding), 'style', 'shape'],\n ''\n );\n },\n\n /**\n * Get the payment method code related to the PayPal funding source.\n *\n * @param {string} funding\n * @return {string}\n */\n getPaymentMethodCodeByFunding: function (funding) {\n if (funding === 'paylater') {\n return 'braintree_paypal_paylater';\n }\n\n return 'braintree_paypal';\n }\n });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/multishipping/hosted-fields.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n\ndefine([\n 'jquery',\n 'PayPal_Braintree/js/view/payment/method-renderer/hosted-fields',\n 'PayPal_Braintree/js/validator',\n 'Magento_Ui/js/model/messageList',\n 'mage/translate',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'Magento_Checkout/js/action/set-payment-information',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'PayPal_Braintree/js/view/payment/adapter'\n], function (\n $,\n Component,\n validator,\n messageList,\n $t,\n fullScreenLoader,\n setPaymentInformationAction,\n additionalValidators,\n braintree\n) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'PayPal_Braintree/payment/multishipping/form'\n },\n\n /**\n * Get list of available CC types\n *\n * @returns {Object}\n */\n getCcAvailableTypes: function () {\n let availableTypes = validator.getAvailableCardTypes(),\n billingCountryId;\n\n billingCountryId = $('#multishipping_billing_country_id').val();\n\n if (billingCountryId && validator.getCountrySpecificCardTypes(billingCountryId)) {\n return validator.collectTypes(\n availableTypes, validator.getCountrySpecificCardTypes(billingCountryId)\n );\n }\n\n return availableTypes;\n },\n\n /**\n * @override\n */\n handleNonce: function (payload) {\n let self = this;\n\n this.setPaymentMethodNonce(payload.nonce);\n this.setCreditCardBin(payload.details.bin);\n\n // place order on success validation\n self.validatorManager.validate(self, function () {\n return self.setPaymentInformation();\n }, function () {\n self.isProcessing = false;\n self.paymentMethodNonce = null;\n self.creditCardBin = null;\n });\n },\n\n /**\n * @override\n */\n placeOrder: function () {\n if (this.isProcessing) {\n return false;\n }\n this.isProcessing = true;\n\n\n braintree.tokenizeHostedFields();\n return false;\n },\n\n /**\n * @override\n */\n getData: function () {\n let data = this._super();\n\n data['additional_data']['is_active_payment_token_enabler'] = true;\n\n return data;\n },\n\n /**\n * @override\n */\n setPaymentInformation: function () {\n if (additionalValidators.validate()) {\n fullScreenLoader.startLoader();\n $.when(\n setPaymentInformationAction(\n this.messageContainer,\n this.getData()\n )\n ).done(this.done.bind(this))\n .fail(this.fail.bind(this));\n }\n },\n\n /**\n * {Function}\n */\n fail: function () {\n fullScreenLoader.stopLoader();\n\n return this;\n },\n\n /**\n * {Function}\n */\n done: function () {\n fullScreenLoader.stopLoader();\n $('#multishipping-billing-form').trigger('submit');\n\n return this;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/method-renderer/multishipping/paypal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\ndefine([\n 'jquery',\n 'underscore',\n 'braintreeCheckoutPayPalAdapter',\n 'Magento_Checkout/js/model/quote',\n 'PayPal_Braintree/js/view/payment/method-renderer/paypal',\n 'PayPal_Braintree/js/helper/format-amount',\n 'Magento_Checkout/js/action/set-payment-information',\n 'Magento_Checkout/js/model/payment/additional-validators',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'mage/translate'\n], function (\n $,\n _,\n Braintree,\n quote,\n Component,\n formatAmount,\n setPaymentInformationAction,\n additionalValidators,\n fullScreenLoader,\n $t\n) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'PayPal_Braintree/payment/multishipping/paypal',\n submitButtonSelector: '[id=\"parent-payment-continue\"]',\n reviewButtonHtml: ''\n },\n\n /**\n * @override\n */\n initObservable: function () {\n this.reviewButtonHtml = $(this.submitButtonSelector).html();\n return this._super();\n },\n\n initClientConfig: function () {\n this.clientConfig = _.extend(this.clientConfig, this.getPayPalConfig());\n this.clientConfig.paypal.enableShippingAddress = false;\n\n _.each(this.clientConfig, function (fn, name) {\n if (typeof fn === 'function') {\n this.clientConfig[name] = fn.bind(this);\n }\n }, this);\n this.clientConfig.buttonPayPalId = 'parent-payment-continue';\n },\n\n /**\n * @override\n */\n onActiveChange: function (isActive) {\n this.updateSubmitButtonHtml(isActive);\n this._super(isActive);\n },\n\n /**\n * @override\n */\n beforePlaceOrder: function (data) {\n this._super(data);\n },\n\n /**\n * Re-init PayPal Auth Flow\n */\n reInitPayPal: function () {\n this.disableButton();\n this.clientConfig.paypal.amount = formatAmount(this.grandTotalAmount);\n\n if (!quote.isVirtual()) {\n this.clientConfig.paypal.enableShippingAddress = false;\n this.clientConfig.paypal.shippingAddressEditable = false;\n }\n\n Braintree.setConfig(this.clientConfig);\n\n if (Braintree.getPayPalInstance()) {\n Braintree.getPayPalInstance().teardown(function () {\n Braintree.setup();\n });\n Braintree.setPayPalInstance(null);\n } else {\n Braintree.setup();\n this.enableButton();\n }\n },\n\n loadPayPalButton: function (paypalCheckoutInstance, funding) {\n if (funding === 'credit') {\n Braintree.config.buttonId = this.getCreditButtonId();\n } else if (funding === 'paylater') {\n Braintree.config.buttonId = this.getPayLaterButtonId();\n } else {\n Braintree.config.buttonId = this.getPayPalButtonId();\n }\n\n let paypalPayment = Braintree.config.paypal,\n onPaymentMethodReceived = Braintree.config.onPaymentMethodReceived,\n style = {\n label: Braintree.getLabel(funding),\n color: Braintree.getColor(funding),\n shape: Braintree.getShape(funding)\n },\n payPalButtonId = Braintree.config.buttonId,\n payPalButtonElement = $('#' + Braintree.config.buttonId),\n events = Braintree.events,\n\n button = window.paypal.Buttons({\n fundingSource: funding,\n env: Braintree.getEnvironment(),\n style: style,\n commit: true,\n locale: Braintree.config.paypal.locale,\n\n createOrder: function () {\n return paypalCheckoutInstance.createPayment(paypalPayment);\n },\n\n onCancel: function (data) {\n console.log('checkout.js payment cancelled', JSON.stringify(data, 0, 2));\n\n if (typeof events.onCancel === 'function') {\n events.onCancel();\n }\n },\n\n onError: function (err) {\n let error = 'PayPal Checkout could not be initialized. Please contact the store owner.';\n\n Braintree.showError($t(error));\n Braintree.config.paypalInstance = null;\n console.error('Paypal checkout.js error', err);\n\n if (typeof events.onError === 'function') {\n events.onError(err);\n }\n },\n\n onClick: function (data) {\n // To check term & conditions input checked - validate additional validators.\n if (!additionalValidators.validate()) {\n return false;\n }\n\n if (typeof events.onClick === 'function') {\n events.onClick(data);\n }\n },\n\n onApprove: function (data) {\n return paypalCheckoutInstance.tokenizePayment(data)\n .then(function (payload) {\n onPaymentMethodReceived(payload);\n });\n }\n });\n\n payPalButtonElement.html('');\n\n // Render\n Braintree.config.paypalInstance = paypalCheckoutInstance;\n\n if (button.isEligible() && payPalButtonElement.length) {\n button.render('#' + payPalButtonId).then(function () {\n Braintree.enableButton();\n if (typeof Braintree.config.onPaymentMethodError === 'function') {\n Braintree.config.onPaymentMethodError();\n }\n }).then(function (data) {\n if (typeof events.onRender === 'function') {\n events.onRender(data);\n }\n });\n }\n },\n\n /**\n * Get configuration for PayPal\n *\n * @returns {Object}\n */\n getPayPalConfig: function () {\n let totals = quote.totals(),\n config = {};\n\n config.paypal = {\n flow: 'checkout',\n amount: formatAmount(this.grandTotalAmount),\n currency: totals['base_currency_code'],\n locale: this.getLocale(),\n requestBillingAgreement: true,\n\n /**\n * Triggers on any Braintree error\n */\n onError: function () {\n this.paymentMethodNonce = null;\n },\n\n /**\n * Triggers if browser doesn't support PayPal Checkout\n */\n onUnsupported: function () {\n this.paymentMethodNonce = null;\n }\n };\n\n if (!quote.isVirtual()) {\n config.paypal.enableShippingAddress = false;\n config.paypal.shippingAddressEditable = false;\n }\n\n if (this.getMerchantName()) {\n config.paypal.displayName = this.getMerchantName();\n }\n\n return config;\n },\n\n /**\n * Get shipping address\n *\n * @returns {{}}\n */\n getShippingAddress: function () {\n return {};\n },\n\n /**\n * @override\n */\n getData: function () {\n let data = this._super();\n\n data['additional_data']['is_active_payment_token_enabler'] = true;\n\n return data;\n },\n\n /**\n * @override\n */\n isActiveVault: function () {\n return true;\n },\n\n /**\n * Checks if payment method nonce is already received.\n *\n * @returns {Boolean}\n */\n isPaymentMethodNonceReceived: function () {\n return this.paymentMethodNonce !== null;\n },\n\n /**\n * Update submit button on multi-addresses checkout billing form.\n *\n * @param {Boolean} isActive\n */\n updateSubmitButtonHtml: function (isActive) {\n $(this.submitButtonSelector).removeClass('primary');\n if (this.isPaymentMethodNonceReceived() || !isActive) {\n $(this.submitButtonSelector).addClass('primary');\n $(this.submitButtonSelector).html(this.reviewButtonHtml);\n }\n },\n\n /**\n * @override\n */\n placeOrder: function () {\n if (!this.isPaymentMethodNonceReceived()) {\n this.payWithPayPal();\n } else {\n fullScreenLoader.startLoader();\n\n $.when(\n setPaymentInformationAction(\n this.messageContainer,\n this.getData()\n )\n ).done(this.done.bind(this))\n .fail(this.fail.bind(this));\n }\n },\n\n /**\n * {Function}\n */\n fail: function () {\n fullScreenLoader.stopLoader();\n\n return this;\n },\n\n /**\n * {Function}\n */\n done: function () {\n fullScreenLoader.stopLoader();\n $('#multishipping-billing-form').trigger('submit');\n\n return this;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/express/express-payment.js":"/**\n * General express payment component that initializes braintree payment buttons\n */\ndefine([\n 'jquery',\n 'uiComponent',\n 'domReady!'\n], function ($, Component) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'PayPal_Braintree/express/express-payment'\n },\n\n /**\n * Initializes regular properties of instance.\n *\n * @returns {Object} Chainable.\n */\n initConfig: function () {\n this._super();\n\n return this;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/express/express-paypal.js":"/**\n * Express Paypal button component\n */\n\ndefine([\n 'jquery',\n 'underscore',\n 'uiComponent',\n 'mage/url',\n 'PayPal_Braintree/js/paypal/button',\n 'PayPal_Braintree/js/helper/get-cart-line-items-helper',\n 'domReady!'\n], function ($, _, Component, url, paypalButton, getCartLineItems) {\n 'use strict';\n\n const config = _.get(window.checkoutConfig.payment, 'braintree_paypal', {});\n\n return Component.extend({\n defaults: {\n template: 'PayPal_Braintree/express/express-paypal',\n isActive: _.get(config, 'isActive', false),\n clientToken: _.get(config, 'clientToken', null),\n checkoutCurrency: window.checkoutConfig.quoteData.base_currency_code,\n checkoutAmount: window.checkoutConfig.quoteData.base_grand_total,\n checkoutLocale: _.get(config, 'locale', null),\n buttonLabel: _.get(config, ['style', 'label'], null),\n buttonColor: _.get(config, ['style', 'color'], null),\n buttonShape: _.get(config, ['style', 'shape'], null),\n actionSuccess: url.build('braintree/paypal/review/')\n },\n\n /**\n * Initializes regular properties of instance.\n *\n * @returns {Object} Chainable.\n */\n initConfig: function () {\n this._super();\n\n return this;\n },\n\n /**\n * Is the payment method active.\n *\n * @return {boolean}\n */\n isMethodActive: function () {\n return this.isActive;\n },\n\n /**\n * Is Billing address required.\n *\n * @return {string}\n */\n getIsRequiredBillingAddress: function () {\n return _.get(config, 'isRequiredBillingAddress', '0') === '0' ? '' : 'true';\n },\n\n /**\n * Get the merchant's name config.\n *\n * @return {string}\n */\n getMerchantName: function () {\n return _.get(config, 'merchantName', '');\n },\n\n /**\n * Initialize Braintree PayPal buttons.\n *\n * PayPal Credit & PayPal Pay Later & PayPal Pay Later Messaging rely on PayPal to be enabled.\n */\n initPayPalButtons: function () {\n if (!this.isMethodActive() || !this.clientToken) {\n return;\n }\n\n let buttonConfig = {\n 'clientToken': this.clientToken,\n 'currency': this.checkoutCurrency,\n 'environment': config.environment,\n 'merchantCountry': config.merchantCountry,\n 'isCreditActive': _.get(window.checkoutConfig.payment,\n ['braintree_paypal_credit', 'isActive'], false)\n },\n\n cartLineItems = getCartLineItems();\n\n paypalButton.init(\n buttonConfig,\n JSON.stringify(cartLineItems)\n );\n }\n });\n});\n","PayPal_Braintree/js/view/payment/express/express-paypal-paylater.js":"/**\n * Express PayLater button component\n */\ndefine([\n 'jquery',\n 'underscore',\n 'uiComponent',\n 'mage/url',\n 'domReady!'\n], function ($, _, Component, url) {\n 'use strict';\n\n const config = _.get(window.checkoutConfig.payment, 'braintree_paypal_paylater', {});\n\n return Component.extend({\n defaults: {\n template: 'PayPal_Braintree/express/express-paypal-paylater',\n isActive: _.get(config, 'isActive', false),\n checkoutCurrency: window.checkoutConfig.quoteData.base_currency_code,\n checkoutAmount: window.checkoutConfig.quoteData.base_grand_total,\n checkoutLocale: _.get(config, 'locale', null),\n buttonLabel: _.get(config, ['style', 'label'], null),\n buttonColor: _.get(config, ['style', 'color'], null),\n buttonShape: _.get(config, ['style', 'shape'], null),\n actionSuccess: url.build('braintree/paypal/review/'),\n isMessageActive: _.get(config, 'isMessageActive', false),\n messageTextColor: _.get(config ,['message', 'text_color'], null),\n messageLayout: _.get(config ,['message', 'layout'], null),\n messageLogoPosition: _.get(config ,['message', 'logo_position'], null),\n messageLogo: _.get(config ,['message', 'logo'], null)\n },\n\n /**\n * Initializes regular properties of instance.\n *\n * @returns {Object} Chainable.\n */\n initConfig: function () {\n this._super();\n\n return this;\n },\n\n /**\n * Is the payment method active.\n *\n * @return {boolean}\n */\n isMethodActive: function () {\n return this.isActive;\n },\n\n /**\n * Is the payment method message active.\n *\n * @return {boolean}\n */\n isMethodMessageActive: function () {\n return this.isMessageActive;\n },\n\n /**\n * Is Billing address required.\n *\n * @return {string}\n */\n getIsRequiredBillingAddress: function () {\n return _.get(config, 'isRequiredBillingAddress', '0') === '0' ? '' : 'true';\n },\n\n /**\n * Get the merchant's name config.\n *\n * @return {string}\n */\n getMerchantName: function () {\n return _.get(config, 'merchantName', '');\n }\n });\n});\n","PayPal_Braintree/js/view/payment/express/express-googlepay.js":"/**\n * Express GooglePay button component\n */\n\ndefine([\n 'jquery',\n 'underscore',\n 'uiComponent',\n 'mage/url',\n 'PayPal_Braintree/js/googlepay/button',\n 'PayPal_Braintree/js/googlepay/api',\n 'domReady!'\n], function ($, _, Component, url, button, buttonApi) {\n 'use strict';\n\n const config = _.get(window.checkoutConfig.payment, 'braintree_googlepay', {});\n\n return Component.extend({\n\n defaults: {\n template: 'PayPal_Braintree/express/express-googlepay',\n id: 'braintree-googlepay-express-payment',\n isActive: !_.isEmpty(config),\n clientToken: _.get(config, 'clientToken', null),\n merchantId: _.get(config, 'merchantId', null),\n currencyCode: window.checkoutConfig.quoteData.base_currency_code,\n actionSuccess: url.build('braintree/googlepay/review/'),\n amount: window.checkoutConfig.quoteData.base_grand_total,\n environment: _.get(config, 'environment', 'TEST'),\n cardTypes: _.get(config, 'cardTypes', []),\n btnColor: _.get(config, 'btnColor', ''),\n threeDSecure: null\n },\n\n /**\n * Is the payment method active.\n *\n * @return {boolean}\n */\n isMethodActive: function () {\n return this.isActive;\n },\n\n /**\n * Get the 3D Secure config object.\n *\n * @return {\n * {\n * thresholdAmount: (number|*),\n * specificCountries: ([]|*),\n * challengeRequested: (boolean|*),\n * enabled: boolean\n * } ||\n * {\n * thresholdAmount: number,\n * specificCountries: *[],\n * challengeRequested: boolean,\n * enabled: boolean\n * }\n * }\n */\n get3DSecureConfig: function () {\n let secureConfig = _.get(window.checkoutConfig.payment, 'three_d_secure', {});\n\n if (_.isEmpty(secureConfig)) {\n return {\n 'enabled': false,\n 'challengeRequested': false,\n 'thresholdAmount': 0.0,\n 'specificCountries': [],\n 'ipAddress': ''\n };\n }\n\n return {\n 'enabled': true,\n 'challengeRequested': secureConfig.challengeRequested ,\n 'thresholdAmount': secureConfig.thresholdAmount,\n 'specificCountries': secureConfig.specificCountries,\n 'ipAddress': secureConfig.ipAddress\n };\n },\n\n /**\n * Initialize Google Pay express.\n */\n initGooglePayExpress: function () {\n if (!this.isMethodActive()) {\n return;\n }\n\n this.threeDSecure = this.get3DSecureConfig();\n\n /* Add client token & environment to 3DS Config */\n this.threeDSecure.clientToken = this.clientToken;\n this.threeDSecure.environment = this.environment;\n\n let api = new buttonApi();\n\n api.setEnvironment(this.environment);\n api.setCurrencyCode(this.currencyCode);\n api.setClientToken(this.clientToken);\n api.setMerchantId(this.merchantId);\n api.setActionSuccess(this.actionSuccess);\n api.setAmount(this.amount);\n api.setCardTypes(this.cardTypes);\n api.setBtnColor(this.btnColor);\n api.setThreeDSecureValidatorConfig(this.threeDSecure);\n\n // Attach the button\n button.init(\n document.getElementById(this.id),\n api\n );\n },\n\n /**\n * @returns {Object}\n */\n initialize: function () {\n this._super();\n\n return this;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/express/express-applepay.js":"/**\n * Braintree Apple Pay express payment method integration.\n **/\ndefine([\n 'underscore',\n 'uiComponent',\n 'PayPal_Braintree/js/applepay/button',\n 'PayPal_Braintree/js/applepay/api',\n 'PayPal_Braintree/js/helper/format-amount',\n 'mage/translate',\n 'mage/url',\n 'domReady!'\n], function (\n _,\n Component,\n button,\n buttonApi,\n formatAmount,\n $t,\n url\n) {\n 'use strict';\n\n const config = _.get(window.checkoutConfig.payment, 'braintree_applepay', {});\n\n return Component.extend({\n\n defaults: {\n template: 'PayPal_Braintree/express/express-applepay',\n id: 'braintree-applepay-express-payment',\n isActive: !_.isEmpty(config),\n clientToken: _.get(config, 'clientToken', null),\n quoteId: window.checkoutConfig.quoteId,\n displayName: _.get(config, 'merchantName', null),\n actionSuccess: url.build('checkout/onepage/success'),\n grandTotalAmount: window.checkoutConfig.quoteData.base_grand_total,\n isLoggedIn: false,\n storeCode: window.checkoutConfig.storeCode\n },\n\n /**\n * Is the payment method active.\n *\n * @return {boolean}\n */\n isMethodActive: function () {\n return this.isActive;\n },\n\n /**\n * Initialize Apple Pay express.\n */\n initApplePayExpress: function () {\n if (!this.isMethodActive() || !this.clientToken) {\n return;\n }\n\n if (!this.displayName) {\n this.displayName = $t('Store');\n }\n\n this.isLoggedIn = window.checkoutConfig.customer_is_guest === '1' ? 'true' : 'false';\n\n let api = new buttonApi();\n\n api.setGrandTotalAmount(formatAmount(this.grandTotalAmount));\n api.setClientToken(this.clientToken);\n api.setDisplayName(this.displayName);\n api.setQuoteId(this.quoteId);\n api.setActionSuccess(this.actionSuccess);\n api.setIsLoggedIn(this.isLoggedIn);\n api.setStoreCode(this.storeCode);\n\n // Attach the button\n button.init(\n document.getElementById(this.id),\n api\n );\n },\n\n /**\n * @returns {Object}\n */\n initialize: function () {\n this._super();\n\n return this;\n }\n });\n});\n","PayPal_Braintree/js/view/payment/express/express-paypal-credit.js":"/**\n * Express Paypal Credit button component\n */\ndefine([\n 'jquery',\n 'underscore',\n 'uiComponent',\n 'mage/url',\n 'domReady!'\n], function ($, _, Component, url) {\n 'use strict';\n\n const config = _.get(window.checkoutConfig.payment, 'braintree_paypal_credit', {});\n\n return Component.extend({\n defaults: {\n template: 'PayPal_Braintree/express/express-paypal-credit',\n isActive: _.get(config, 'isActive', false),\n checkoutCurrency: window.checkoutConfig.quoteData.base_currency_code,\n checkoutAmount: window.checkoutConfig.quoteData.base_grand_total,\n checkoutLocale: _.get(config, 'locale', null),\n buttonLabel: _.get(config, ['style', 'label'], null),\n buttonColor: _.get(config, ['style', 'color'], null),\n buttonShape: _.get(config, ['style', 'shape'], null),\n actionSuccess: url.build('braintree/paypal/review/')\n },\n\n /**\n * Initializes regular properties of instance.\n *\n * @returns {Object} Chainable.\n */\n initConfig: function () {\n this._super();\n\n return this;\n },\n\n /**\n * Is the payment method active.\n *\n * @return {boolean}\n */\n isMethodActive: function () {\n return this.isActive;\n },\n\n /**\n * Is Billing address required.\n *\n * @return {string}\n */\n getIsRequiredBillingAddress: function () {\n return _.get(config, 'isRequiredBillingAddress', '0') === '0' ? '' : 'true';\n },\n\n /**\n * Get the merchant's name config.\n *\n * @return {string}\n */\n getMerchantName: function () {\n return _.get(config, 'merchantName', '');\n }\n });\n});\n","PayPal_Braintree/js/paypal/button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(\n [\n 'rjsResolver',\n 'uiRegistry',\n 'uiComponent',\n 'underscore',\n 'jquery',\n 'Magento_Customer/js/customer-data',\n 'mage/translate',\n 'braintree',\n 'braintreeCheckoutPayPalAdapter',\n 'braintreeDataCollector',\n 'braintreePayPalCheckout',\n 'PayPal_Braintree/js/form-builder',\n 'PayPal_Braintree/js/helper/remove-non-digit-characters',\n 'PayPal_Braintree/js/helper/replace-single-quote-character',\n 'domReady!'\n ],\n function (\n resolver,\n registry,\n Component,\n _,\n $,\n customerData,\n $t,\n braintree,\n Braintree,\n dataCollector,\n paypalCheckout,\n formBuilder,\n removeNonDigitCharacters,\n replaceSingleQuoteCharacter\n ) {\n 'use strict';\n\n return {\n events: {\n onClick: null,\n onCancel: null,\n onError: null\n },\n\n /**\n * Initialize button\n *\n * @param buttonConfig\n * @param lineItems\n */\n init: function (buttonConfig, lineItems) {\n if ($('.action-braintree-paypal-message').length) {\n $('.product-add-form form').on('keyup change paste', 'input, select, textarea', function () {\n let currentPrice, currencySymbol;\n\n currentPrice = $('.product-info-main span').find('[data-price-type=\\'finalPrice\\']').text();\n currencySymbol = $('.action-braintree-paypal-message[data-pp-type=\"product\"]')\n .data('currency-symbol');\n $('.action-braintree-paypal-message[data-pp-type=\"product\"]')\n .attr('data-pp-amount', currentPrice.replace(currencySymbol,''));\n });\n }\n\n this.loadSDK(buttonConfig, lineItems);\n\n window.addEventListener('hashchange', function () {\n const step = window.location.hash.replace('#', '');\n\n if (step === 'shipping') {\n Braintree.getPayPalInstance().teardown(function () {\n this.loadSDK(buttonConfig, lineItems);\n }.bind(this));\n }\n\n }.bind(this));\n\n window.addEventListener('paypal:reinit-express', function () {\n this.loadSDK(buttonConfig, lineItems);\n }.bind(this));\n },\n\n /**\n * Load Braintree PayPal SDK\n *\n * @param buttonConfig\n * @param lineItems\n */\n loadSDK: function (buttonConfig, lineItems) {\n braintree.create({\n authorization: buttonConfig.clientToken\n }, function (clientErr, clientInstance) {\n if (clientErr) {\n console.error('paypalCheckout error', clientErr);\n let error = 'PayPal Checkout could not be initialized. Please contact the store owner.';\n\n return this.showError(error);\n }\n dataCollector.create({\n client: clientInstance,\n paypal: true\n }, function (err) {\n if (err) {\n return console.log(err);\n }\n });\n paypalCheckout.create({\n client: clientInstance\n }, function (err, paypalCheckoutInstance) {\n Braintree.setPayPalInstance(paypalCheckoutInstance);\n let configSDK = {\n components: 'buttons,messages,funding-eligibility',\n 'enable-funding': this.isCreditActive(buttonConfig) ? 'credit' : 'paylater',\n currency: buttonConfig.currency\n },\n\n buyerCountry = this.getMerchantCountry(buttonConfig);\n\n if (buttonConfig.environment === 'sandbox'\n && (buyerCountry !== '' || buyerCountry !== 'undefined'))\n {\n configSDK['buyer-country'] = buyerCountry;\n }\n paypalCheckoutInstance.loadPayPalSDK(configSDK, function () {\n this.renderPayPalButtons(paypalCheckoutInstance, lineItems);\n this.renderPayPalMessages();\n }.bind(this));\n }.bind(this));\n }.bind(this));\n },\n\n /**\n * Is Credit enabled\n *\n * @param buttonConfig\n * @returns {boolean}\n */\n isCreditActive: function (buttonConfig) {\n return buttonConfig.isCreditActive;\n },\n\n /**\n * Get merchant country\n *\n * @param buttonConfig\n * @returns {string}\n */\n getMerchantCountry: function (buttonConfig) {\n return buttonConfig.merchantCountry;\n },\n\n /**\n * Render PayPal buttons\n *\n * @param paypalCheckoutInstance\n * @param lineItems\n */\n renderPayPalButtons: function (paypalCheckoutInstance, lineItems) {\n this.payPalButton(paypalCheckoutInstance, lineItems);\n },\n\n /**\n * Render PayPal messages\n */\n renderPayPalMessages: function () {\n $('.action-braintree-paypal-message').each(function () {\n window.paypal.Messages({\n amount: $(this).data('pp-amount'),\n pageType: $(this).data('pp-type'),\n style: {\n layout: $(this).data('messaging-layout'),\n text: {\n color: $(this).data('messaging-text-color')\n },\n logo: {\n type: $(this).data('messaging-logo'),\n position: $(this).data('messaging-logo-position')\n }\n }\n }).render('#' + $(this).attr('id'));\n\n\n });\n },\n\n /**\n * @param paypalCheckoutInstance\n * @param lineItems\n */\n payPalButton: function (paypalCheckoutInstance, lineItems) {\n $('.action-braintree-paypal-logo').each(function () {\n let currentElement = $(this),\n style = {\n label: currentElement.data('label'),\n color: currentElement.data('color'),\n shape: currentElement.data('shape')\n },\n button;\n\n if (currentElement.data('fundingicons')) {\n style.fundingicons = currentElement.data('fundingicons');\n }\n\n // Render\n button = window.paypal.Buttons({\n fundingSource: currentElement.data('funding'),\n style: style,\n createOrder: function () {\n return paypalCheckoutInstance.createPayment({\n amount: currentElement.data('amount'),\n locale: currentElement.data('locale'),\n currency: currentElement.data('currency'),\n flow: 'checkout',\n enableShippingAddress: true,\n displayName: currentElement.data('displayname'),\n lineItems: JSON.parse(lineItems)\n });\n },\n validate: function (actions) {\n let cart = customerData.get('cart'),\n customer = customerData.get('customer'),\n declinePayment = false,\n isGuestCheckoutAllowed;\n\n isGuestCheckoutAllowed = cart().isGuestCheckoutAllowed;\n declinePayment = !customer().firstname && !isGuestCheckoutAllowed\n && typeof isGuestCheckoutAllowed !== 'undefined';\n\n if (declinePayment) {\n actions.disable();\n }\n },\n\n onCancel: function () {\n jQuery('#maincontent').trigger('processStop');\n },\n\n onError: function (errorData) {\n console.error('paypalCheckout button render error', errorData);\n jQuery('#maincontent').trigger('processStop');\n },\n\n onClick: function () {\n if (currentElement.data('location') === 'productpage') {\n let form = $('#product_addtocart_form');\n\n if (!(form.validation() && form.validation('isValid'))) {\n return false;\n }\n }\n\n let cart = customerData.get('cart'),\n customer = customerData.get('customer'),\n declinePayment = false,\n isGuestCheckoutAllowed;\n\n isGuestCheckoutAllowed = cart().isGuestCheckoutAllowed;\n declinePayment = !customer().firstname && !isGuestCheckoutAllowed\n && typeof isGuestCheckoutAllowed !== 'undefined';\n if (declinePayment) {\n // eslint-disable-next-line\n alert($t('To check out, please sign in with your email address.'));\n }\n },\n\n onApprove: function (approveData) {\n return paypalCheckoutInstance.tokenizePayment(approveData, function (err, payload) {\n jQuery('#maincontent').trigger('processStart');\n\n /* Set variables & default values for shipping/recipient name to billing */\n let accountFirstName = replaceSingleQuoteCharacter(payload.details.firstName),\n accountLastName = replaceSingleQuoteCharacter(payload.details.lastName),\n accountEmail = replaceSingleQuoteCharacter(payload.details.email),\n recipientFirstName = accountFirstName,\n recipientLastName = accountLastName,\n address = payload.details.shippingAddress,\n recipientName = null,\n actionSuccess,\n isRequiredBillingAddress,\n phone = _.get(payload, ['details', 'phone'], '');\n\n // Map the shipping address correctly\n if (!_.isUndefined(address.recipientName) && _.isString(address.recipientName)) {\n /*\n * Trim leading/ending spaces before splitting,\n * filter to remove array keys with empty values\n * & set to variable.\n */\n recipientName = address.recipientName.trim().split(' ').filter(n => n);\n }\n\n /*\n * If the recipientName is not null, and it is an array with\n * first/last name, use it. Otherwise, keep the default billing first/last name.\n * This is to avoid cases of old accounts where spaces were allowed to first or\n * last name in PayPal and the result was an array with empty fields\n * resulting in empty names in the system.\n */\n if (!_.isNull(recipientName) && !_.isUndefined(recipientName[1])) {\n recipientFirstName = replaceSingleQuoteCharacter(recipientName[0]);\n recipientLastName = replaceSingleQuoteCharacter(recipientName[1]);\n }\n\n payload.details.shippingAddress = {\n streetAddress: typeof address.line2 !== 'undefined' && _.isString(address.line2)\n ? replaceSingleQuoteCharacter(address.line1)\n + ' ' + replaceSingleQuoteCharacter(address.line2)\n : replaceSingleQuoteCharacter(address.line1),\n locality: replaceSingleQuoteCharacter(address.city),\n postalCode: address.postalCode,\n countryCodeAlpha2: address.countryCode,\n email: accountEmail,\n recipientFirstName: recipientFirstName,\n recipientLastName: recipientLastName,\n telephone: removeNonDigitCharacters(phone),\n region: typeof address.state !== 'undefined'\n ? replaceSingleQuoteCharacter(address.state)\n : ''\n };\n\n payload.details.email = accountEmail;\n payload.details.firstName = accountFirstName;\n payload.details.lastName = accountLastName;\n if (typeof payload.details.businessName !== 'undefined'\n && _.isString(payload.details.businessName)) {\n payload.details.businessName\n = replaceSingleQuoteCharacter(payload.details.businessName);\n }\n\n // Map the billing address correctly\n isRequiredBillingAddress = currentElement.data('requiredbillingaddress');\n\n if (isRequiredBillingAddress === 1\n && typeof payload.details.billingAddress !== 'undefined') {\n let billingAddress = payload.details.billingAddress;\n\n payload.details.billingAddress = {\n streetAddress: typeof billingAddress.line2 !== 'undefined'\n && _.isString(billingAddress.line2)\n ? replaceSingleQuoteCharacter(billingAddress.line1)\n + ' ' + replaceSingleQuoteCharacter(billingAddress.line2)\n : replaceSingleQuoteCharacter(billingAddress.line1),\n locality: replaceSingleQuoteCharacter(billingAddress.city),\n postalCode: billingAddress.postalCode,\n countryCodeAlpha2: billingAddress.countryCode,\n telephone: removeNonDigitCharacters(phone),\n region: typeof billingAddress.state !== 'undefined'\n ? replaceSingleQuoteCharacter(billingAddress.state)\n : ''\n };\n }\n\n if (currentElement.data('location') === 'productpage') {\n let form = $('#product_addtocart_form');\n\n payload.additionalData = form.serialize();\n }\n\n actionSuccess = currentElement.data('actionsuccess');\n\n formBuilder.build(\n {\n action: actionSuccess,\n fields: {\n result: JSON.stringify(payload)\n }\n }\n ).submit();\n });\n }\n });\n\n if (!button.isEligible()) {\n console.log('PayPal button is not elligible');\n currentElement.parent().remove();\n return;\n }\n if (button.isEligible() && $('#' + currentElement.attr('id')).length) {\n button.render('#' + currentElement.attr('id'));\n }\n });\n }\n };\n }\n);\n","PayPal_Braintree/js/paypal/form-builder.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(\n [\n 'jquery',\n 'underscore',\n 'mage/template'\n ],\n function ($, _, mageTemplate) {\n 'use strict';\n\n return {\n\n /**\n * @param {Object} formData\n * @returns {*|jQuery}\n */\n build: function (formData) {\n var formTmpl = mageTemplate('<form action=\"<%= data.action %>\"' +\n ' method=\"POST\" hidden enctype=\"application/x-www-form-urlencoded\">' +\n '<% _.each(data.fields, function(val, key){ %>' +\n '<input value=\\'<%= val %>\\' name=\"<%= key %>\" type=\"hidden\">' +\n '<% }); %>' +\n '</form>');\n\n return $(formTmpl({\n data: {\n action: formData.action,\n fields: formData.fields\n }\n })).appendTo($('[data-container=\"body\"]'));\n }\n };\n }\n);\n","PayPal_Braintree/js/paypal/product-page.js":"define(\n ['PayPal_Braintree/js/paypal/button', 'jquery'],\n function (button, $) {\n 'use strict';\n\n return button.extend({\n\n defaults: {\n label: 'buynow',\n branding: true\n },\n\n /**\n * The validation on the add-to-cart form is done after the PayPal window has opened.\n * This is because the validate method exposed by the PP Button requires an event to\n * disable/enable the button.\n * We can't fire an event due to the way the mage.validation widget works and we can't\n * do something gross like an interval because the validation() method shows the error\n * messages and focuses the user's input on the first erroring input field.\n * @param payload\n * @returns {*}\n */\n beforeSubmit: function (payload) {\n var form = $('#product_addtocart_form');\n\n if (!(form.validation() && form.validation('isValid'))) {\n return false;\n }\n\n payload.additionalData = form.serialize();\n\n return payload;\n }\n });\n }\n);\n","PayPal_Braintree/js/paypal/credit/calculator.js":"define([\n 'underscore',\n 'uiComponent'\n], function (_, Component) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'PayPal_Braintree/credit/calculator',\n displaySummary: true, // \"From X per month\"\n displayInterestDetails: false, // Display the more in-depth summary of interest rates\n instalmentsFrom: 0,\n currentInstalment: {\n term: 0,\n monthlyPayment: 0,\n apr: 0,\n cost: 0,\n costIncInterest: 0\n },\n endpoint: null,\n instalments: [],\n visible: false,\n merchantName: ''\n },\n\n /**\n * initialize and observe the default variables\n *\n * @returns {*}\n */\n initObservable: function () {\n this._super();\n if (this.instalments.length > 0) {\n this.currentInstalment = this.instalments[0];\n this.instalmentsFrom = this.instalments[this.instalments.length - 1].monthlyPayment;\n this.visible = true;\n } else {\n this.loadInstalments();\n }\n\n this.observe(['instalments', 'currentInstalment', 'instalmentsFrom', 'visible']);\n return this;\n },\n\n /**\n * check current instalment\n *\n * @param term\n * @returns {boolean}\n */\n isCurrentInstalment: function (term) {\n return this.currentInstalment().term === term;\n },\n\n /**\n * set current instalment\n *\n * @param instalment\n */\n setCurrentInstalment: function (instalment) {\n this.currentInstalment(instalment);\n },\n\n /**\n * load instalments\n *\n * @returns {boolean}\n */\n loadInstalments: function () {\n if (!this.endpoint) {\n return false;\n }\n\n let self = this;\n\n require(['Magento_Checkout/js/model/quote', 'jquery'], function (quote, $) {\n if (typeof quote.totals()['base_grand_total'] === 'undefined') {\n return false;\n }\n\n $.getJSON(self.endpoint, {amount: quote.totals()['base_grand_total']}, function (response) {\n self.instalments(response);\n self.setCurrentInstalment(response[0]);\n self.visible(true);\n });\n });\n }\n });\n});\n","PayPal_Braintree/js/applepay/api.js":"/**\n * Braintree Apple Pay button API\n *\n **/\ndefine(\n [\n 'jquery',\n 'underscore',\n 'uiComponent',\n 'mage/translate',\n 'mage/storage',\n 'Magento_Customer/js/customer-data',\n 'PayPal_Braintree/js/helper/remove-non-digit-characters'\n ],\n function (\n $,\n _,\n Component,\n $t,\n storage,\n customerData,\n removeNonDigitCharacters\n ) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n clientToken: null,\n quoteId: 0,\n displayName: null,\n actionSuccess: null,\n grandTotalAmount: 0,\n isLoggedIn: false,\n storeCode: 'default',\n shippingAddress: {},\n countryDirectory: null,\n shippingMethods: {}\n },\n\n initialize: function () {\n this._super();\n if (!this.countryDirectory) {\n storage.get('rest/V1/directory/countries').done(function (result) {\n this.countryDirectory = {};\n let i, data, x, region, name;\n\n for (i = 0; i < result.length; ++i) {\n data = result[i];\n this.countryDirectory[data.two_letter_abbreviation] = {};\n if (typeof data.available_regions === 'undefined') {\n continue;\n }\n\n for (x = 0; x < data.available_regions.length; ++x) {\n region = data.available_regions[x];\n name = region.name.toLowerCase().replace(/[^A-Z0-9]/ig, '');\n this.countryDirectory[data.two_letter_abbreviation][name] = region.id;\n }\n }\n }.bind(this));\n }\n },\n\n /**\n * Get region ID\n */\n getRegionId: function (countryCode, regionName) {\n if (typeof regionName !== 'string') {\n return null;\n }\n\n regionName = regionName.toLowerCase().replace(/[^A-Z0-9]/ig, '');\n\n if (typeof this.countryDirectory[countryCode] !== 'undefined'\n && typeof this.countryDirectory[countryCode][regionName] !== 'undefined') {\n return this.countryDirectory[countryCode][regionName];\n }\n\n return 0;\n },\n\n /**\n * Set & get api token\n */\n setClientToken: function (value) {\n this.clientToken = value;\n },\n getClientToken: function () {\n return this.clientToken;\n },\n\n /**\n * Set and get quote id\n */\n setQuoteId: function (value) {\n this.quoteId = value;\n },\n getQuoteId: function () {\n return this.quoteId;\n },\n\n /**\n * Set and get display name\n */\n setDisplayName: function (value) {\n this.displayName = value;\n },\n getDisplayName: function () {\n return this.displayName;\n },\n\n /**\n * Set and get success redirection url\n */\n setActionSuccess: function (value) {\n this.actionSuccess = value;\n },\n getActionSuccess: function () {\n return this.actionSuccess;\n },\n\n /**\n * Set and get grand total\n */\n setGrandTotalAmount: function (value) {\n this.grandTotalAmount = parseFloat(value).toFixed(2);\n },\n getGrandTotalAmount: function () {\n return parseFloat(this.grandTotalAmount);\n },\n\n /**\n * Set and get is logged in\n */\n setIsLoggedIn: function (value) {\n this.isLoggedIn = value;\n },\n getIsLoggedIn: function () {\n return this.isLoggedIn;\n },\n\n /**\n * Set and get store code\n */\n setStoreCode: function (value) {\n this.storeCode = value;\n },\n getStoreCode: function () {\n return this.storeCode;\n },\n\n /**\n * API Urls for logged in / guest\n */\n getApiUrl: function (uri) {\n if (this.getIsLoggedIn() === true) {\n return 'rest/' + this.getStoreCode() + '/V1/carts/mine/' + uri;\n }\n return 'rest/' + this.getStoreCode() + '/V1/guest-carts/' + this.getQuoteId() + '/' + uri;\n\n },\n\n /**\n * Payment request info\n */\n getPaymentRequest: function () {\n return {\n total: {\n label: this.getDisplayName(),\n amount: this.getGrandTotalAmount()\n },\n requiredShippingContactFields: ['postalAddress', 'name', 'email', 'phone'],\n requiredBillingContactFields: ['postalAddress', 'name']\n };\n },\n\n /**\n * Retrieve shipping methods based on address\n */\n onShippingContactSelect: function (event, session) {\n // Get the address.\n let address = event.shippingContact,\n\n // Create a payload.\n payload = {\n address: {\n city: address.locality,\n region: address.administrativeArea,\n country_id: address.countryCode.toUpperCase(),\n postcode: address.postalCode,\n save_in_address_book: 0\n }\n };\n\n this.shippingAddress = payload.address;\n\n // POST to endpoint for shipping methods.\n storage.post(\n this.getApiUrl('estimate-shipping-methods'),\n JSON.stringify(payload)\n ).done(function (result) {\n // Stop if no shipping methods.\n let virtualFlag = false,\n shippingMethods = [],\n totalsPayload = {};\n\n if (result.length === 0) {\n let productItems = customerData.get('cart')().items;\n\n _.each(productItems,\n function (item) {\n if (item.is_virtual || item.product_type === 'bundle') {\n virtualFlag = true;\n } else {\n virtualFlag = false;\n }\n }\n );\n if (!virtualFlag) {\n session.abort();\n // eslint-disable-next-line\n alert($t('There are no shipping methods available for you right now. Please try again or use an alternative payment method.'));\n return false;\n }\n }\n\n this.shippingMethods = {};\n\n // Format shipping methods array.\n for (let i = 0; i < result.length; i++) {\n if (typeof result[i].method_code !== 'string') {\n continue;\n }\n\n let method = {\n identifier: result[i].method_code,\n label: result[i].method_title,\n detail: result[i].carrier_title ? result[i].carrier_title : '',\n amount: parseFloat(result[i].amount).toFixed(2)\n };\n\n // Add method object to array.\n shippingMethods.push(method);\n\n this.shippingMethods[result[i].method_code] = result[i];\n\n if (!this.shippingMethod) {\n this.shippingMethod = result[i].method_code;\n }\n }\n\n // Create payload to get totals\n totalsPayload = {\n 'addressInformation': {\n 'address': {\n 'countryId': this.shippingAddress.country_id,\n 'region': this.shippingAddress.region,\n 'regionId': this.getRegionId(\n this.shippingAddress.country_id, this.shippingAddress.region),\n 'postcode': this.shippingAddress.postcode\n },\n 'shipping_method_code': virtualFlag\n ? null : this.shippingMethods[shippingMethods[0].identifier].method_code,\n 'shipping_carrier_code': virtualFlag\n ? null : this.shippingMethods[shippingMethods[0].identifier].carrier_code\n }\n };\n\n // POST to endpoint to get totals, using 1st shipping method\n storage.post(\n this.getApiUrl('totals-information'),\n JSON.stringify(totalsPayload)\n ).done(function (totals) {\n // Set total\n this.setGrandTotalAmount(totals.base_grand_total);\n\n // Pass shipping methods back\n session.completeShippingContactSelection(\n window.ApplePaySession.STATUS_SUCCESS,\n shippingMethods,\n {\n label: this.getDisplayName(),\n amount: this.getGrandTotalAmount()\n },\n [{\n type: 'final',\n label: $t('Shipping'),\n amount: virtualFlag ? 0 : shippingMethods[0].amount\n }]\n );\n }.bind(this)).fail(function (error) {\n session.abort();\n // eslint-disable-next-line\n alert($t('We\\'re unable to fetch the cart totals for you. Please try an alternative payment method.'));\n console.error('Braintree ApplePay: Unable to get totals', error);\n return false;\n });\n\n }.bind(this)).fail(function (result) {\n session.abort();\n // eslint-disable-next-line\n alert($t('We\\'re unable to find any shipping methods for you. Please try an alternative payment method.'));\n // eslint-disable-next-line\n console.error('Braintree ApplePay: Unable to find shipping methods for estimate-shipping-methods', result);\n return false;\n });\n },\n\n /**\n * Record which shipping method has been selected & Updated totals\n */\n onShippingMethodSelect: function (event, session) {\n let shippingMethod = event.shippingMethod,\n payload = {\n 'addressInformation': {\n 'address': {\n 'countryId': this.shippingAddress.country_id,\n 'region': this.shippingAddress.region,\n 'regionId': this.getRegionId(this.shippingAddress.country_id,\n this.shippingAddress.region),\n 'postcode': this.shippingAddress.postcode\n },\n 'shipping_method_code': this.shippingMethods[shippingMethod.identifier].method_code,\n 'shipping_carrier_code': this.shippingMethods[shippingMethod.identifier].carrier_code\n }\n };\n\n this.shippingMethod = shippingMethod.identifier;\n\n\n storage.post(\n this.getApiUrl('totals-information'),\n JSON.stringify(payload)\n ).done(function (r) {\n this.setGrandTotalAmount(r.base_grand_total);\n\n session.completeShippingMethodSelection(\n window.ApplePaySession.STATUS_SUCCESS,\n {\n label: this.getDisplayName(),\n amount: this.getGrandTotalAmount()\n },\n [{\n type: 'final',\n label: $t('Shipping'),\n amount: shippingMethod.amount\n }]\n );\n }.bind(this));\n },\n\n /**\n * Place the order\n */\n startPlaceOrder: function (nonce, event, session, device_data) {\n let shippingContact = event.payment.shippingContact,\n billingContact = event.payment.billingContact,\n payload = {\n 'addressInformation': {\n 'shipping_address': {\n 'email': shippingContact.emailAddress,\n 'telephone': removeNonDigitCharacters(_.get(shippingContact, 'phoneNumber', '')),\n 'firstname': shippingContact.givenName,\n 'lastname': shippingContact.familyName,\n 'street': shippingContact.addressLines,\n 'city': shippingContact.locality,\n 'region': shippingContact.administrativeArea,\n 'region_id': this.getRegionId(\n shippingContact.countryCode.toUpperCase(), shippingContact.administrativeArea),\n 'region_code': null,\n 'country_id': shippingContact.countryCode.toUpperCase(),\n 'postcode': shippingContact.postalCode,\n 'same_as_billing': 0,\n 'customer_address_id': 0,\n 'save_in_address_book': 0\n },\n 'billing_address': {\n 'email': shippingContact.emailAddress,\n 'telephone': removeNonDigitCharacters(_.get(shippingContact, 'phoneNumber', '')),\n 'firstname': billingContact.givenName,\n 'lastname': billingContact.familyName,\n 'street': billingContact.addressLines,\n 'city': billingContact.locality,\n 'region': billingContact.administrativeArea,\n 'region_id': this.getRegionId(\n billingContact.countryCode.toUpperCase(), billingContact.administrativeArea),\n 'region_code': null,\n 'country_id': billingContact.countryCode.toUpperCase(),\n 'postcode': billingContact.postalCode,\n 'same_as_billing': 0,\n 'customer_address_id': 0,\n 'save_in_address_book': 0\n },\n 'shipping_method_code': this.shippingMethod\n ? this.shippingMethods[this.shippingMethod].method_code : '' ,\n 'shipping_carrier_code': this.shippingMethod\n ? this.shippingMethods[this.shippingMethod].carrier_code : ''\n }\n };\n\n // Set addresses\n storage.post(\n this.getApiUrl('shipping-information'),\n JSON.stringify(payload)\n ).done(function () {\n // Submit payment information\n let paymentInformation = {\n 'email': shippingContact.emailAddress,\n 'paymentMethod': {\n 'method': 'braintree_applepay',\n 'additional_data': {\n 'payment_method_nonce': nonce,\n 'device_data': device_data\n }\n }\n };\n\n if (window.checkout && window.checkout.agreementIds) {\n paymentInformation.paymentMethod.extension_attributes = {\n 'agreement_ids': window.checkout.agreementIds\n };\n }\n storage.post(\n this.getApiUrl('payment-information'),\n JSON.stringify(paymentInformation)\n ).done(function () {\n document.location = this.getActionSuccess();\n session.completePayment(window.ApplePaySession.STATUS_SUCCESS);\n }.bind(this)).fail(function (r) {\n session.completePayment(window.ApplePaySession.STATUS_FAILURE);\n session.abort();\n // eslint-disable-next-line\n alert($t('We\\'re unable to take your payment through Apple Pay. Please try an again or use an alternative payment method.'));\n console.error('Braintree ApplePay Unable to take payment', r);\n return false;\n });\n\n }.bind(this)).fail(function (r) {\n console.error('Braintree ApplePay Unable to set shipping information', r);\n session.completePayment(window.ApplePaySession.STATUS_INVALID_BILLING_POSTAL_ADDRESS);\n });\n }\n });\n });\n","PayPal_Braintree/js/applepay/button.js":"/**\n * Braintree Apple Pay button\n **/\ndefine(\n [\n 'uiComponent',\n 'knockout',\n 'jquery',\n 'braintree',\n 'braintreeDataCollector',\n 'braintreeApplePay',\n 'mage/translate',\n 'Magento_Checkout/js/model/payment/additional-validators'\n ],\n function (\n Component,\n ko,\n $,\n braintree,\n dataCollector,\n applePay,\n $t,\n additionalValidators\n ) {\n 'use strict';\n\n return {\n init: function (element, context) {\n // No element or context\n if (!element || !context) {\n return;\n }\n\n // Context must implement these methods\n if (typeof context.getClientToken !== 'function') {\n console.error(\n 'Braintree ApplePay Context passed does not provide a getClientToken method',\n context\n );\n return;\n }\n if (typeof context.getPaymentRequest !== 'function') {\n console.error(\n 'Braintree ApplePay Context passed does not provide a getPaymentRequest method',\n context\n );\n return;\n }\n if (typeof context.startPlaceOrder !== 'function') {\n console.error(\n 'Braintree ApplePay Context passed does not provide a startPlaceOrder method',\n context\n );\n return;\n }\n\n if (this.deviceSupported() === false) {\n return;\n }\n\n // init braintree api\n braintree.create({\n authorization: context.getClientToken()\n }, function (clientErr, clientInstance) {\n this.initApplePay(clientErr, clientInstance, element, context);\n }.bind(this));\n },\n\n /**\n * Check the site is using HTTPS & apple pay is supported on this device.\n * @return boolean\n */\n deviceSupported: function () {\n if (location.protocol !== 'https:') {\n console.warn('Braintree Apple Pay requires your checkout be served over HTTPS');\n return false;\n }\n\n if ((window.ApplePaySession && window.ApplePaySession.canMakePayments()) !== true) {\n console.warn('Braintree Apple Pay is not supported on this device/browser');\n return false;\n }\n\n return true;\n },\n\n initApplePay: function (clientErr, clientInstance, element, context) {\n if (clientErr) {\n console.error('Error creating client:', clientErr);\n return;\n }\n\n dataCollector.create({\n client: clientInstance\n }, function (dataCollectorErr, dataCollectorInstance) {\n if (dataCollectorErr) {\n return;\n }\n\n applePay.create({\n client: clientInstance\n }, function (applePayErr, applePayInstance) {\n this.render(applePayErr, applePayInstance, dataCollectorInstance, element, context);\n }.bind(this));\n }.bind(this));\n },\n\n render: function (applePayErr, applePayInstance, dataCollectorInstance, element, context) {\n // No instance\n if (applePayErr) {\n console.error('Braintree ApplePay Error creating applePayInstance:', applePayErr);\n return;\n }\n\n // Create a button within the KO element, as apple pay can only be instantiated through\n // a valid on click event (ko onclick bind interferes with this).\n let el = document.createElement('div');\n\n el.className = 'braintree-apple-pay-button';\n el.title = $t('Pay with Apple Pay');\n el.alt = $t('Pay with Apple Pay');\n el.addEventListener('click', function (e) {\n e.preventDefault();\n\n if ($(el).parents('#braintree-applepay-express-payment').length === 0\n && !additionalValidators.validate()) {\n return false;\n }\n\n // Payment request object\n let paymentRequest = applePayInstance.createPaymentRequest(context.getPaymentRequest());\n\n if (!paymentRequest) {\n console.error('Braintree ApplePay Unable to create paymentRequest', paymentRequest);\n this.showError();\n return;\n }\n\n // Show the loader\n $('body').loader('show');\n\n // Init apple pay session\n try {\n let session = new window.ApplePaySession(1, paymentRequest);\n\n // Handle invalid merchant\n session.onvalidatemerchant = function (event) {\n applePayInstance.performValidation({\n validationURL: event.validationURL,\n displayName: context.getDisplayName()\n }, function (validationErr, merchantSession) {\n if (validationErr) {\n session.abort();\n console.error('Braintree ApplePay Error validating merchant:', validationErr);\n this.showError();\n return;\n }\n\n session.completeMerchantValidation(merchantSession);\n });\n };\n\n // Attach payment auth event\n session.onpaymentauthorized = function (event) {\n applePayInstance.tokenize({\n token: event.payment.token\n }, function (tokenizeErr, payload) {\n if (tokenizeErr) {\n console.error('Error tokenizing Apple Pay:', tokenizeErr);\n session.completePayment(window.ApplePaySession.STATUS_FAILURE);\n return;\n }\n\n let nonce = payload.nonce;\n\n // Pass the nonce back to the payment method\n context.startPlaceOrder(nonce, event, session, dataCollectorInstance.deviceData);\n });\n };\n\n // Attach onShippingContactSelect method\n if (typeof context.onShippingContactSelect === 'function') {\n session.onshippingcontactselected = function (event) {\n return context.onShippingContactSelect(event, session);\n };\n }\n\n // Attach onShippingMethodSelect method\n if (typeof context.onShippingMethodSelect === 'function') {\n session.onshippingmethodselected = function (event) {\n return context.onShippingMethodSelect(event, session);\n };\n }\n\n // Hook\n if (typeof context.onButtonClick === 'function') {\n context.onButtonClick(session, this, e);\n } else {\n $('body').loader('hide');\n session.begin();\n }\n } catch (err) {\n $('body').loader('hide');\n console.error('Braintree ApplePay Unable to create ApplePaySession', err);\n this.showError();\n return false;\n }\n }.bind(this));\n\n element.appendChild(el);\n },\n\n showError() {\n // eslint-disable-next-line\n alert($t('We\\'re unable to take payments through Apple Pay at the moment. Please try an alternative payment method.'));\n }\n };\n }\n);\n","PayPal_Braintree/js/applepay/implementations/shortcut.js":"/**\n * Braintree Apple Pay mini cart payment method integration.\n **/\ndefine(\n [\n 'uiComponent',\n 'PayPal_Braintree/js/applepay/button',\n 'PayPal_Braintree/js/applepay/api',\n 'mage/translate',\n 'domReady!'\n ],\n function (\n Component,\n button,\n buttonApi,\n $t\n ) {\n 'use strict';\n\n return Component.extend({\n\n defaults: {\n id: null,\n clientToken: null,\n quoteId: 0,\n displayName: null,\n actionSuccess: null,\n grandTotalAmount: 0,\n isLoggedIn: false,\n storeCode: 'default'\n },\n\n /**\n * @returns {Object}\n */\n initialize: function () {\n this._super();\n if (!this.displayName) {\n this.displayName = $t('Store');\n }\n\n let api = new buttonApi();\n\n api.setGrandTotalAmount(parseFloat(this.grandTotalAmount).toFixed(2));\n api.setClientToken(this.clientToken);\n api.setDisplayName(this.displayName);\n api.setQuoteId(this.quoteId);\n api.setActionSuccess(this.actionSuccess);\n api.setIsLoggedIn(this.isLoggedIn);\n api.setStoreCode(this.storeCode);\n\n // Attach the button\n button.init(\n document.getElementById(this.id),\n api\n );\n\n return this;\n }\n });\n }\n);\n","PayPal_Braintree/js/applepay/implementations/core-checkout/method-applepay.js":"define([\n 'uiComponent',\n 'Magento_Checkout/js/model/payment/renderer-list'\n], function (Component, rendererList) {\n 'use strict';\n\n let config = window.checkoutConfig.payment;\n\n if (config['braintree_applepay'].clientToken) {\n rendererList.push({\n type: 'braintree_applepay',\n component: 'PayPal_Braintree/js/applepay/implementations/core-checkout/method-renderer/applepay'\n });\n }\n\n return Component.extend({});\n});\n","PayPal_Braintree/js/applepay/implementations/core-checkout/method-renderer/applepay.js":"/**\n * Braintree Apple Pay payment method integration.\n **/\ndefine([\n 'underscore',\n 'Magento_Checkout/js/view/payment/default',\n 'Magento_Checkout/js/model/quote',\n 'Magento_Vault/js/view/payment/vault-enabler',\n 'PayPal_Braintree/js/applepay/button'\n], function (\n _,\n Component,\n quote,\n VaultEnabler,\n button\n) {\n 'use strict';\n\n return Component.extend({\n defaults: {\n template: 'PayPal_Braintree/applepay/core-checkout',\n paymentMethodNonce: null,\n deviceData: null,\n grandTotalAmount: 0,\n deviceSupported: button.deviceSupported(),\n vaultEnabler: null,\n additionalData: {}\n },\n\n /**\n * @returns {exports.initialize}\n */\n initialize: function () {\n this._super();\n this.vaultEnabler = new VaultEnabler();\n this.vaultEnabler.setPaymentCode(this.getVaultCode());\n\n return this;\n },\n\n /**\n * Inject the apple pay button into the target element\n */\n getApplePayBtn: function (id) {\n button.init(\n document.getElementById(id),\n this\n );\n },\n\n /**\n * Subscribe to grand totals\n */\n initObservable: function () {\n this._super();\n\n this.vaultEnabler = new VaultEnabler();\n this.vaultEnabler.setPaymentCode(this.getVaultCode());\n\n this.grandTotalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2);\n\n quote.totals.subscribe(function () {\n if (this.grandTotalAmount !== quote.totals()['base_grand_total']) {\n this.grandTotalAmount = parseFloat(quote.totals()['base_grand_total']).toFixed(2);\n }\n }.bind(this));\n\n return this;\n },\n\n /**\n * Apple pay place order method\n */\n startPlaceOrder: function (nonce, event, session, device_data) {\n this.setPaymentMethodNonce(nonce);\n this.setDeviceData(device_data);\n this.placeOrder();\n\n session.completePayment(window.ApplePaySession.STATUS_SUCCESS);\n },\n\n /**\n * Save nonce\n */\n setPaymentMethodNonce: function (nonce) {\n this.paymentMethodNonce = nonce;\n },\n\n /**\n * Save nonce\n */\n setDeviceData: function (device_data) {\n this.deviceData = device_data;\n },\n\n /**\n * Retrieve the client token\n * @returns null|string\n */\n getClientToken: function () {\n return window.checkoutConfig.payment[this.getCode()].clientToken;\n },\n\n /**\n * Payment request data\n */\n getPaymentRequest: function () {\n return {\n total: {\n label: this.getDisplayName(),\n amount: this.grandTotalAmount\n }\n };\n },\n\n /**\n * Merchant display name\n */\n getDisplayName: function () {\n return window.checkoutConfig.payment[this.getCode()].merchantName;\n },\n\n /**\n * Get data\n * @returns {Object}\n */\n getData: function () {\n var data = {\n 'method': this.getCode(),\n 'additional_data': {\n 'payment_method_nonce': this.paymentMethodNonce,\n 'device_data': this.deviceData\n }\n };\n\n data['additional_data'] = _.extend(data['additional_data'], this.additionalData);\n\n this.vaultEnabler.visitAdditionalData(data);\n\n return data;\n },\n\n /**\n * Return image url for the apple pay mark\n */\n getPaymentMarkSrc: function () {\n return window.checkoutConfig.payment[this.getCode()].paymentMarkSrc;\n },\n\n /**\n * @returns {Boolean}\n */\n isVaultEnabled: function () {\n return this.vaultEnabler.isVaultEnabled();\n },\n\n /**\n * @returns {String}\n */\n getVaultCode: function () {\n return window.checkoutConfig.payment[this.getCode()].vaultCode;\n }\n });\n});\n","PayPal_Braintree/js/model/full-screen-loader.js":"define([\n 'jquery',\n 'rjsResolver'\n], function ($, resolver) {\n 'use strict';\n\n /**\n * New full screen loader (spinner) implementation with configurable container.\n * It can be used across website areas including checkout.\n */\n return {\n container: 'body',\n\n /**\n * Set the container element with its ID to replace default container.\n *\n * Only allow to set elements by ID (as expected to be unique.\n * If the container has already been changed, do not allow changing again as this be set once per component.\n *\n * @param {string} value\n */\n setContainer: function (value) {\n if (this.container !== 'body' || !value.startsWith('#')) {\n return;\n }\n\n this.container = value;\n },\n\n /**\n * Get the container element.\n *\n * @return {string}\n */\n getContainer: function () {\n return this.container;\n },\n\n /**\n * Start full page loader action\n */\n startLoader: function () {\n $(this.getContainer()).trigger('processStart');\n },\n\n /**\n * Stop full page loader action\n *\n * @param {Boolean} [forceStop]\n */\n stopLoader: function (forceStop) {\n let $elem = $(this.getContainer()),\n stop = $elem.trigger.bind($elem, 'processStop'); //eslint-disable-line jquery-no-bind-unbind\n\n forceStop ? stop() : resolver(stop);\n }\n };\n});\n","PayPal_Braintree/js/model/vault-enabler.js":"define([\n 'Magento_Vault/js/view/payment/vault-enabler'\n], function (VaultEnabler) {\n 'use strict';\n\n return {\n // Initialise a single VaultEnabler instance.\n vaultEnabler: new VaultEnabler(),\n\n /**\n * @returns {VaultEnabler}\n */\n getVaultEnabler() {\n return this.vaultEnabler;\n },\n\n /**\n * Set the payment code against the vault enabler.\n *\n * @param {string} code\n */\n setPaymentCode(code) {\n this.vaultEnabler.setPaymentCode(code);\n },\n\n /**\n * Returns the vault enabled state.\n *\n * @returns {boolean}\n */\n isVaultEnabled() {\n return this.vaultEnabler.isVaultEnabled();\n },\n\n /**\n * Returns the active payment token enabler state.\n *\n * @returns {boolean}\n */\n isActivePaymentTokenEnabler() {\n return this.vaultEnabler.isActivePaymentTokenEnabler();\n },\n\n /**\n * @param {Object} data\n */\n visitAdditionalData(data) {\n this.vaultEnabler.visitAdditionalData(data);\n }\n };\n});\n","PayPal_Braintree/js/model/place-order-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable max-nested-callbacks */\n\ndefine([\n 'jquery',\n 'mage/utils/wrapper',\n 'Magento_ReCaptchaWebapiUi/js/webapiReCaptchaRegistry'\n], function ($, wrapper, recaptchaRegistry) {\n 'use strict';\n\n return function (placeOrder) {\n return wrapper.wrap(placeOrder, function (originalAction, serviceUrl, payload, messageContainer) {\n var recaptchaDeferred;\n\n if (recaptchaRegistry.triggers.hasOwnProperty('recaptcha-checkout-braintree')) {\n //ReCaptcha is present for checkout\n recaptchaDeferred = $.Deferred();\n recaptchaRegistry.addListener('recaptcha-checkout-braintree', function (token) {\n //Add reCaptcha value to place-order request and resolve deferred with the API call results\n payload.xReCaptchaValue = token;\n originalAction(serviceUrl, payload, messageContainer).done(function () {\n recaptchaDeferred.resolve.apply(recaptchaDeferred, arguments);\n }).fail(function () {\n recaptchaDeferred.reject.apply(recaptchaDeferred, arguments);\n });\n });\n //Trigger ReCaptcha validation\n recaptchaRegistry.triggers['recaptcha-checkout-braintree']();\n\n if (!recaptchaRegistry._isInvisibleType.hasOwnProperty('recaptcha-checkout-braintree') ||\n recaptchaRegistry._isInvisibleType['recaptcha-checkout-braintree'] === false\n ) {\n //remove listener so that place order action is only triggered by the 'Place Order' button\n recaptchaRegistry.removeListener('recaptcha-checkout-braintree');\n }\n return recaptchaDeferred;\n }\n\n //No ReCaptcha, just sending the request\n return originalAction(serviceUrl, payload, messageContainer);\n });\n };\n});\n","PayPal_Braintree/js/model/step-navigator-mixin.js":"define([\n 'mage/utils/wrapper'\n], function (wrapper) {\n 'use strict';\n\n let mixin = {\n handleHash: function (originalFn) {\n var hashString = window.location.hash.replace('#', '');\n\n if (hashString.indexOf('venmo') > -1) {\n return false;\n }\n\n return originalFn();\n }\n };\n\n return function (target) {\n return wrapper.extend(target, mixin);\n };\n});\n","PayPal_Braintree/js/reCaptcha/webapiReCaptchaRegistry-mixin.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 (originalFunction) {\n /**\n * {@inheritDoc}\n */\n originalFunction.addListener = function (id , func) {\n this._listeners[id] = func;\n };\n\n return originalFunction;\n };\n});\n","Magento_Cookie/js/require-cookie.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/alert',\n 'jquery-ui-modules/widget',\n 'mage/mage',\n 'mage/translate'\n], function ($, alert) {\n 'use strict';\n\n $.widget('mage.requireCookie', {\n options: {\n event: 'click',\n noCookieUrl: 'enable-cookies',\n triggers: ['.action.login', '.action.submit'],\n isRedirectCmsPage: true\n },\n\n /**\n * Constructor\n * @private\n */\n _create: function () {\n this._bind();\n },\n\n /**\n * This method binds elements found in this widget.\n * @private\n */\n _bind: function () {\n var events = {};\n\n $.each(this.options.triggers, function (index, value) {\n events['click ' + value] = '_checkCookie';\n });\n this._on(events);\n },\n\n /**\n * This method set the url for the redirect.\n * @param {jQuery.Event} event\n * @private\n */\n _checkCookie: function (event) {\n if (navigator.cookieEnabled) {\n return;\n }\n\n event.preventDefault();\n\n if (this.options.isRedirectCmsPage) {\n window.location = this.options.noCookieUrl;\n } else {\n alert({\n content: $.mage.__('Cookies are disabled in your browser.')\n });\n }\n }\n });\n\n return $.mage.requireCookie;\n});\n","Magento_Cookie/js/notices.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 'mage/cookies'\n], function ($) {\n 'use strict';\n\n $.widget('mage.cookieNotices', {\n /** @inheritdoc */\n _create: function () {\n if ($.mage.cookies.get(this.options.cookieName)) {\n this.element.hide();\n } else {\n this.element.show();\n }\n $(this.options.cookieAllowButtonSelector).on('click', $.proxy(function () {\n var cookieExpires = new Date(new Date().getTime() + this.options.cookieLifetime * 1000);\n\n $.mage.cookies.set(this.options.cookieName, JSON.stringify(this.options.cookieValue), {\n expires: cookieExpires\n });\n\n if ($.mage.cookies.get(this.options.cookieName)) {\n this.element.hide();\n $(document).trigger('user:allowed:save:cookie');\n } else {\n window.location.href = this.options.noCookiesUrl;\n }\n }, this));\n }\n });\n\n return $.mage.cookieNotices;\n});\n","Webkul_BuyButton/js/tabs.js":"define(\n [\n 'jquery'\n ],\n function($) {\n $.widget('webkul.collapsible',{\n options: {\n\n },\n\n _create: function() {\n var self = this;\n $(\"body\").on('click', self.options.element, function() {\n if ($(this).hasClass(\"no-tab\")) {\n return false;\n }\n var id = $(this).attr(\"id\");\n if ($(\".\"+id).hasClass(\"active\")) {\n $(\".\"+id).removeClass(\"active\");\n $(\".\"+id).slideUp(\"2000\");\n } else {\n if ($(\".bb-tab-content.active\").length > 0) {\n $(\".bb-tab-content.active\").slideUp(\"2000\", function() {\n $(\".\"+id).addClass(\"active\");\n $(\".\"+id).slideDown(\"2000\");\n });\n $(\".bb-tab-content.active\").removeClass(\"active\");\n } else {\n $(\".\"+id).addClass(\"active\");\n $(\".\"+id).slideDown(\"2000\");\n }\n }\n });\n \n } \n });\n\n return $.webkul.collapsible;\n});\n","Webkul_BuyButton/js/start.js":"define([\n 'uiComponent',\n 'uiLayout',\n 'uiRegistry',\n 'mage/translate',\n 'mage/template',\n 'jquery',\n 'ko',\n 'Magento_Ui/js/modal/modal'\n], function(\n Component,\n layout,\n registry,\n $t,\n mageTemplate,\n $,\n ko,\n modal\n) {\n 'use strict';\n return Component.extend({\n defaults: {\n template: \"Webkul_BuyButton/start.html\",\n inputType: false,\n productIds: ''\n },\n\n /**\n * @extends\n */\n initialize: function () {\n var self = this;\n this._super();\n },\n\n /**\n * initialize observers\n */\n initObservable: function () {\n this._super().observe('inputType productIds');\n return this;\n },\n\n initProductButton: function() {\n var self = this;\n self.inputType(arguments[0].productInputType?arguments[0].productInputType:false);\n var options = {\n autoOpen: true,\n modalClass: 'bb-modal-products',\n buttons: [{\n text: $t(\"Create Button\"),\n class: 'button primary',\n click: function() {\n let productIds = $(\"input[name=productIds]\").val();\n let storeId = $(\".front-store\").val();\n let currency = $(\".allowed-currecny\").val();\n if (productIds) {\n window.location.href = ajaxCreateUrl+\"?productIds=\"+productIds+\"&store=\"+storeId+\"¤cy=\"+currency;\n }\n } \n }],\n closed: function() {\n \n //$(\"body\").find(\".bb-modal-products\").remove();\n },\n clickableOverlay: false,\n title: $t(\"Select Product\"),\n type: \"slide\"\n };\n if ($(\"body\").find(\".bb-modal-products\").length == 0) {\n \n var gridComponentParams = {\n parent: this.name,\n name: this.name + '-product-grid',\n displayArea: 'products-grid',\n component: 'Webkul_BuyButton/js/grid-popup',\n provider:this,\n config: {\n productData: {}\n }\n };\n\n $.ajax({\n url: window.ajaxProductListUrl,\n type: 'GET',\n dataType: 'json',\n showLoader: true,\n headers: {\n \"Content-Type\": \"application/json\"\n },\n data: {\n pageSize: 20,\n pageNumber: 1,\n filter: '',\n sort:'name',\n },\n success: function(response) {\n gridComponentParams.config.productData = response;\n layout([gridComponentParams]);\n },\n error: function() {\n console.log(\"error\");\n }\n });\n }\n \n this._isElementLoaded(\".bb-grid-popup-container\", function() {\n let modalHtml = $('.bb-grid-popup-container');\n var popup = modal(options, modalHtml);\n popup.openModal();\n });\n },\n\n _isElementLoaded: function ($element, callback) {\n var self = this;\n setTimeout(function() {\n \n if ($($element).is(':visible')) {\n callback();\n } else {\n self._isElementLoaded($element, callback);\n }\n }, 50);\n },\n\n initCollectionButton: function () {\n this.initProductButton({productInputType:true});\n }\n\n });\n});","Webkul_BuyButton/js/grid-popup.js":"define([\n 'uiComponent',\n 'uiLayout',\n 'uiRegistry',\n 'mage/translate',\n 'mage/template',\n 'jquery',\n 'ko'\n], function(\n Component,\n layout,\n registry,\n $t,\n mageTemplate,\n $,\n ko\n) {\n 'use strict';\n return Component.extend({\n defaults: {\n template: \"Webkul_BuyButton/grid-popup.html\",\n productData:{},\n products: [],\n totalCount:0,\n productSelector: false,\n parentComponent: {},\n productSelectedCheckbox:[],\n productSelectedRadio:'',\n pageNumber: 1,\n searchString: '',\n pages:0,\n stores:window.stores,\n currencies:window.currencies\n },\n\n /**\n * @extends\n */\n initialize: function (config) {\n var self = this;\n this._super();\n this.parentComponent = config.provider;\n self.productSelector = config.provider.inputType;\n self.totalCount(self.productData.total_count);\n self.products(self.productData.items);\n self.pages(Math.ceil(self.totalCount()/20));\n self.productSelectedCheckbox.subscribe(function (ids) {\n self.parentComponent.productIds(ids.join(\",\"));\n });\n self.productSelectedRadio.subscribe(function (id) {\n self.parentComponent.productIds(id);\n });\n self.searchString.subscribe(function(q) {\n if (q.length > 2 || q.length == 0) {\n self.searchProduct(q);\n }\n });\n\n self.pageNumber.subscribe(function(n) {\n //console.log(n);\n if (n < 1) {\n self.pageNumber(1);\n return;\n } else if (n > self.pages()) {\n self.pageNumber(self.pages());\n return;\n }\n \n let promise = self.getProductCollection('');\n promise.then(function(response) {\n self.products(response.items);\n self.totalCount(response.total_count);\n }, function(error) {\n console.log(error);\n });\n });\n\n self.totalCount.subscribe(function (n) {\n self.pages(Math.ceil(n/20));\n self.pageNumber(1);\n });\n },\n\n /**\n * initialize observers\n */\n initObservable: function () {\n this._super().observe(\n 'totalCount products productSelectedCheckbox productSelectedRadio pageNumber searchString pages stores currencies'\n );\n return this;\n },\n\n prevPage: function() {\n let self = this;\n let pageNumber = parseInt(self.pageNumber());\n if (pageNumber <= 1) {\n self.pageNumber(1);\n } else {\n self.pageNumber(pageNumber-1);\n }\n },\n\n isFirst: function() {\n let self = this;\n if (self.pageNumber() == 1) {\n return true;\n }\n\n return false;\n },\n\n isLast: function() {\n let self = this;\n \n if (self.pageNumber() == self.pages()) {\n return true;\n }\n\n return false;\n },\n\n nextPage: function() {\n let self = this;\n let pageNumber = parseInt(self.pageNumber());\n \n self.pageNumber(pageNumber+1);\n \n },\n\n searchProduct: function(filter) {\n let self = this;\n if (!filter) {\n filter = $('.no-changes').val();\n }\n let promise = self.getProductCollection(filter);\n promise.then(function(response) {\n self.products(response.items);\n self.totalCount(response.total_count);\n }, function(error) {\n console.log(error);\n });\n },\n\n getProductCollection: function(filter) {\n let self = this;\n let promise = new Promise(function(resolve, reject) {\n $.ajax({\n url: window.ajaxProductListUrl,\n type: 'GET',\n dataType: 'json',\n showLoader: true,\n headers: {\n \"Content-Type\": \"application/json\"\n },\n data: {\n pageSize: 20,\n pageNumber: parseInt(self.pageNumber()),\n filter: filter,\n sort:'name',\n type: $('.filter-product-type').val()\n },\n success: function(response) {\n resolve(response);\n },\n error: function() {\n reject(\"some error occured\");\n }\n });\n });\n\n return promise;\n\n }\n\n\n });\n});","Webkul_BuyButton/js/create.js":"define([\n 'uiComponent',\n 'uiLayout',\n 'uiRegistry',\n 'mage/template',\n 'jquery',\n 'ko',\n 'Magento_Ui/js/modal/modal',\n 'Webkul_BuyButton/js/tabs',\n 'jquery/colorpicker/js/colorpicker',\n 'mage/translate'\n], function(\n Component,\n layout,\n registry,\n mageTemplate,\n $,\n ko,\n modal,\n collapsible\n) {\n 'use strict';\n \n return Component.extend({\n defaults: {\n template: \"Webkul_BuyButton/create.html\",\n inputType: false,\n productIds: '',\n showSizeDropdown: false,\n jsTemplate: '<div id=\"buybutton-init\"></div> <script>(function(d,s,id){var js,bjs=d.getElementsByTagName(s)[0];if(d.getElementById(id))return;js=d.createElement(s);js.id=id;js.async=true;js.src=\"${window.staticUrl}\";js.onload=function(){new BuyButton({productIds:<%- productIds %>, baseUrl: <%- baseUrl %>, styles: <%- styles %>});};bjs.parentNode.insertBefore(js,bjs);}(document,\"script\",\"buybutton-js\"));</script>',\n iframeWinodw:{},\n iframeDocument: {},\n changesCss: [],\n lessinput:'@containerBackground: #FFFFFF;@itemsAlign: center;@itemBackground: #FFFFFF;@itemWidth:18.4%;@buttonFont:Arial, Helvetica, sans-serif;@buttonFontSize:16px;@buttonFontColor:#FFF;@buttonBackgroundColor:#1979c3;@buttonBorderRadius:3px;@headingFont:Arial, Helvetica, sans-serif;@headingFontSize:18px;@headingFontColor:#000;@priceFont:Arial, Helvetica, sans-serif;@priceFontSize:18px;@priceFontColor:#000;@checkoutButtonColor: #fff;@checkoutButtonBackground: #1979c3;.buybutton-container{background: @containerBackground}.buybutton-item{text-align:@itemsAlign;background:@itemBackground;width:@itemWidth}.buybutton-item-name{font-family:@headingFont;font-size:@headingFontSize;color:@headingFontColor;}.buybutton-item-price{font-family:@priceFont;font-size:@priceFontSize;color:@priceFontColor;}.buybutton-item-view > button, .buybutton-product-addtocart > button.buybutton-primary {background:@buttonBackgroundColor;border-radius: @buttonBorderRadius;font-family:@buttonFont;font-size:@buttonFontSize;color:@buttonFontColor}.bb-cart-checkout > .button{font-family: @buttonFont; color: @checkoutButtonColor;background: @checkoutButtonBackground;border-color:@checkoutButtonBackground;}.buybutton-product-price, .bb-cart-item-price{font-family:@priceFont;font-size:@priceFontSize;color:@priceFontColor;} .bb-cart-item-name, .buybutton-product-name{font-family:@headingFont;font-size:@headingFontSize;color:@headingFontColor;}.buybutton-product-sku,.buybutton-product-description{font-family:@priceFont;font-size:@priceFontSize;color:#666666;}',\n dynamicCss: '',\n miniCartText: 'Cart',\n\t\t\taddToCartText: 'Add To Cart',\n\t\t\tbuyNowText: 'Buy Now',\n\t\t\titemInCartText: 'Item In Cart',\n cButtonText: 'Proceed To Checkout',\n vButtonText: 'View Details',\n noItemFoundText: 'No items found in cart.',\n shippingInfoText: '',\n\t\t\tqtyText: 'Qty',\n subTotalText: 'Cart Subtotal',\n dTemplate: 1,\n availableSerifFonts: [\n {\n label: 'Sans Serif',\n value: [\n {label:'Helvetica',value:'Helvetica, sans-serif'},\n ]\n },\n {\n label: 'Serif',\n value: [\n {label:'Times New Roman',value:'Times New Roman, Times, serif'},\n ]\n },\n {\n label: 'Mono',\n value : [\n {label:'Courier New', value:'Courier'},\n {label:'FreeMono',value:'FreeMono, monospace'},\n {label:'Monospace', value:'Lucida Console, Monaco, monospace'}\n ]\n }\n\n ],\n availableSizes: [\n {label: '12px', value:'12px'},\n {label: '14px', value:'14px'},\n {label: '16px', value:'16px'},\n {label: '18px', value:'18px'},\n {label: '20px', value:'20px'}\n ]\n },\n\n /**\n * @extends\n */\n initialize: function () {\n var self = this;\n this._super();\n /**\n * initialize buy button create page left customization panel\n */\n collapsible({element: '.bb-tab-title'}); \n \n /**\n * updating style in the by button demo when a customization is done in the customization panel\n */\n self.dynamicCss.subscribe(function(css) {\n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow; \n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.styles = css;\n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.addStyleTag;\n }); \n \n /**\n * changesCss is to array on modified css that needs to be merged with original css and update in the buy button code\n */\n self.changesCss.subscribe(function(cssArray) {\n let cssObj = {};\n $.each(cssArray, function(key, value) {\n $.extend(cssObj, value);\n });\n self.lessCompile(less, cssObj);\n });\n \n /**\n * listening mini cart text change to reflect it in the demo\n */\n self.miniCartText.subscribe(function(text) {\n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow;\n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.childData.miniCartText = text;\n });\n\n /**\n * listening add to cart text change to reflect it in the demo\n */\n self.addToCartText.subscribe(function(text) {\n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow; \n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.childData.addToCartText = text;\n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueQuickModel.addToCartLabel = text;\n self.iframeWinodw.wkaddTocartLabel.text = text;\n });\n\n /**\n * listening buy now button text change to reflect it in the demo\n */\n self.buyNowText.subscribe(function(text) {\n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow; \n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.childData.buyNowText = text;\n });\n\n /**\n * listening view details button text change to reflect it in the demo\n */\n self.vButtonText.subscribe(function(text) {\n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow; \n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.childData.vButtonText = text;\n });\n\n /**\n * listening item in cart text change to reflect it in the demo\n */\n self.itemInCartText.subscribe(function(text) {\n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow; \n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.childData.itemInCartText = text;\n });\n\n /**\n * listening proceed to checkout button text change to reflect it in the demo\n */\n self.cButtonText.subscribe(function(text) {\n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow; \n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.childData.cButtonText = text;\n });\n\n /**\n * listening item not found text change to reflect it in the demo\n */\n self.noItemFoundText.subscribe(function(text) {\n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow; \n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.childData.noItemFoundText = text;\n });\n\n /**\n * listening quantity text change to reflect it in the demo\n */\n self.qtyText.subscribe(function(text) {\n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow; \n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.childData.qtyText = text;\n });\n\n /**\n * listening subtotal text change to reflect it in the demo\n */\n self.subTotalText.subscribe(function(text) {\n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow; \n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.childData.subTotalText = text;\n });\n \n },\n\n /**\n * show buy button template or not\n */\n showTemplate: function() {\n let productIds = window.productIds.split(\",\");\n if (productIds.length > 1) {\n return false;\n }\n\n return true;\n },\n\n /**\n * update the design template(button, button with image name, button with image name desc ) \n * in the demo and buy button code\n */\n designTemplate: function(v) {\n let self = this;\n \n self.iframeWinodw = document.getElementById(\"bb-demo\").contentWindow; \n let productIds = window.productIds.split(\",\");\n if (productIds.length > 1) {\n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.designTemplate = 1;\n self.dTemplate(1);\n } else {\n self.iframeWinodw.wkBuyButtonRegistry.currenctObject.vueContainerModel.designTemplate = parseInt(v);\n self.dTemplate(v);\n }\n },\n \n /**\n * compile less to generate css\n */\n lessCompile: function (less, modifyVars) {\n var self = this;\n less.render(this.lessinput, {modifyVars: modifyVars}, (function(e, result) {\n if (e) {\n //console.log(e);\n } else {\n self.dynamicCss(result.css.trim());\n }\n }).bind(self));\n },\n\n /**\n * initialize observers\n */\n initObservable: function () {\n this._super().observe('showSizeDropdown inputType productIds availableSerifFonts availableSizes dynamicCss changesCss miniCartText addToCartText buyNowText itemInCartText cButtonText noItemFoundText qtyText subTotalText dTemplate vButtonText');\n return this;\n },\n\n /**\n * demo iframe initialization content\n */\n initChildFrameVars: function() {\n let iframeContent = `<html><body><div id=\"buybutton-init\"></div> <script>(function(d, s, id) { var js, bjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s);js.id = id; js.async = true; setTimeout(function() { js.src = '${window.jsUrl}'; js.onload = function() { new BuyButton({redirectToProduct: '${window.redirectToProduct}',locale: '${window.locale}', storeId: '${window.storeId}', currency_code: '${window.currency}', productIds: '${window.productIds}', baseUrl: '${window.baseUrl}', staticUrl:'${window.staticUrl}'}); }; bjs.parentNode.insertBefore(js, bjs); }, 2000); }(document, \"script\", \"buybutton-js\"));</script></body></html>`;\n return iframeContent;\n },\n\n /**\n * alignment change css\n */\n alignChange: function(data, event) {\n this.changesCss.push({'@itemsAlign': $(event.target).val()});\n },\n\n /**\n * TODO in future \n */\n actionChange: function(data, event) {\n // this.lessCompile(less, {'@buttonFace': 'back', '@buttonText': 'silver'});\n },\n\n /**\n * on size change small medium or large\n * @deprecated\n */\n sizeChange: function(data, event) {\n let size = $(event.target).val();\n let productIds = window.productIds.split(\",\");\n if (productIds.length > 1) {\n switch(size) {\n case 'small':\n this.changesCss.push({'@itemWidth': '16%'});\n break;\n case 'medium':\n this.changesCss.push({'@itemWidth': '18.4%'});\n break;\n case 'large':\n this.changesCss.push({'@itemWidth': '20%'});\n\n }\n } else {\n this.changesCss.push({'@itemWidth': '100%'});\n }\n },\n\n buttonFontChange: function(data, event) {\n this.changesCss.push({'@buttonFont': $(event.target).val()});\n },\n\n buttonBorderRadiusChange: function(data, event) {\n this.changesCss.push({'@buttonBorderRadius': $(event.target).val()});\n },\n\n headingFontChange: function(data, event) {\n this.changesCss.push({'@headingFont': $(event.target).val()});\n },\n\n priceFontChange: function(data, event) {\n this.changesCss.push({'@priceFont': $(event.target).val()});\n },\n\n buttonColorChange: function(data, event) {\n this.changesCss.push({'@buttonFontColor': $(event.target).val()});\n },\n\n buttonBackgroundColorChange: function(data, event) {\n this.changesCss.push({'@buttonBackgroundColor': $(event.target).val()});\n },\n\n headingColorChange: function(data, event) {\n this.changesCss.push({'@headingFontColor': $(event.target).val()});\n },\n\n priceColorChange: function(data, event) {\n this.changesCss.push({'@priceFontColor': $(event.target).val()});\n },\n\n buttonFontSizeChange: function(data, event) {\n this.changesCss.push({'@buttonFontSize': $(event.target).val()});\n },\n\n headingFontSizeChange: function(data, event) {\n this.changesCss.push({'@headingFontSize': $(event.target).val()});\n },\n\n priceFontSizeChange: function(data, event) {\n this.changesCss.push({'@priceFontSize': $(event.target).val()});\n },\n\n checkoutColorChange: function(data, event) {\n this.changesCss.push({'@checkoutButtonColor': $(event.target).val()});\n },\n\n checkoutBackgroundChange: function(data, event) {\n this.changesCss.push({'@checkoutButtonBackground': $(event.target).val()});\n },\n\n /**\n * generate the code for buybutton \n */\n generateCode: function() {\n var self = this;\n let options = {\n buttons: [{\n text: $.mage.__('Copy To Clipboard'),\n class: 'copy-button',\n click: function() {\n \n var range = document.createRange();\n range.selectNode(document.getElementById(\"bb-code-viewer\"));\n document.getElementById(\"bb-code-viewer\").focus();\n document.getElementById(\"bb-code-viewer\").select();\n var sel = window.getSelection();\n //sel.removeAllRanges();\n sel.addRange(range);\n document.execCommand(\"copy\");\n let buttonText = $(\".copy-button\").text();\n $(\".copy-button\").text(\"Copied\");\n $(\".copy-button\").attr(\"disabled\", true);\n setTimeout(function() {\n $(\".copy-button\").text(buttonText);\n $(\".copy-button\").removeAttr(\"disabled\");\n }, 2000);\n }\n }],\n closed: function() {\n document.getElementById(\"bb-code-viewer\").removeEventListener(\"dblclick\", function() {});\n $(\".buybutton-code-generate-modal\").parent().remove();\n },\n modalClass: 'buybutton-code-generate-modal',\n responsive: true,\n title: $.mage.__('Embed Code'),\n type: 'popup'\n };\n\n let template = this.jsTemplate, tmpl, progressTemplate;\n progressTemplate = mageTemplate(\"#buybutton-call-code\");\n tmpl = progressTemplate({\n productIds: window.productIds,\n baseUrl: window.baseUrl,\n staticUrl: window.staticUrl,\n redirectToProduct: window.redirectToProduct,\n styles: self.dynamicCss().trim().replace(/(\\r\\n\\t|\\n|\\r\\t)/gm,\"\"),\n jsUrl: window.jsUrl,\n miniCartText: self.miniCartText(),\n addToCartText: self.addToCartText(),\n buyNowText: self.buyNowText(),\n itemInCartText: self.itemInCartText(),\n cButtonText: self.cButtonText(),\n vButtonText: self.vButtonText(),\n noItemFoundText: self.noItemFoundText(),\n shippingInfoText: self.shippingInfoText,\n qtyText: self.qtyText(),\n subTotalText: self.subTotalText(),\n designTemplate: self.dTemplate(),\n locale: window.locale,\n currency_code: window.currency,\n storeId: window.storeId\n });\n var popup = modal(options, tmpl);\n popup.openModal();\n \n document.getElementById(\"bb-code-viewer\").addEventListener(\"dblclick\", function() {\n var range = document.createRange();\n this.select();\n range.selectNodeContents(this);\n var sel = window.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n document.execCommand(\"copy\");\n let buttonText = $(\".copy-button\").text();\n $(\".copy-button\").text(\"Copied\");\n setTimeout(function() {\n $(\".copy-button\").text(buttonText);\n }, 2000);\n });\n },\n\n /**\n * after knockout initialized adding color picker on different classes\n */\n afterTemplateRender: function() {\n var self = this;\n $.each(\n ['.cart_background_color', '.cart_button_color', '.button_color', '.button_background_color', '.price_color', '.heading_color'],\n function (key, value) {\n $(value).ColorPicker({\n color: '#0000ff',\n onShow: function (colpkr) {\n $(colpkr).fadeIn(500);\n return false;\n },\n onHide: function (colpkr) {\n $(colpkr).fadeOut(500);\n return false;\n },\n onChange: function(hsb, hex, rgb) {\n $(value).val('#'+hex);\n $(value).css({\"backgroundColor\": '#'+hex});\n $(value).trigger(\"change\");\n },\n });\n }\n );\n // self.lessinput = \"@buttonFace: red;@buttonText: green;.buybutton-view-product {color: @buttonFace;background: @buttonText;}\"\n require([\"//cdnjs.cloudflare.com/ajax/libs/less.js/2.7.1/less.min.js\"], (function() {}).bind(self));\n\n //console.log(self.iframeDocument.querySelector(\".buybutton-item-name > span\").style.font);\n \n }\n });\n});","Brandung_CashOnDeliveryFee/js/action/set-payment-and-update-totals.js":"/*jshint browser:true jquery:true*/\n/*global alert*/\ndefine(\n [\n 'Magento_Checkout/js/model/quote',\n 'Brandung_CashOnDeliveryFee/js/model/resource-url-manager',\n 'Magento_Customer/js/model/customer',\n 'Magento_Checkout/js/model/full-screen-loader',\n 'mage/storage',\n 'underscore'\n ],\n function (quote, resourceUrlManager, customer, fullScreenLoader, storage, _) {\n 'use strict';\n return function (paymentMethod) {\n var payload = {\n cartId: quote.getQuoteId(),\n billingAddress: quote.billingAddress(),\n paymentMethod: _.pick(\n paymentMethod,\n 'method',\n 'additional_data',\n 'po_number',\n 'extension_attributes'\n )\n };\n\n if (!customer.isLoggedIn()) {\n payload.email = quote.guestEmail;\n }\n\n fullScreenLoader.startLoader();\n storage.post(\n resourceUrlManager.getSetPaymentAndGetTotalsUrl(quote),\n JSON.stringify(payload)\n ).done(function (response) {\n quote.setTotals(response);\n }).always(function () {\n fullScreenLoader.stopLoader();\n });\n };\n }\n);\n","Brandung_CashOnDeliveryFee/js/view/checkout/summary/cash-on-delivery-fee.js":"/*jshint browser:true jquery:true*/\n/*global alert*/\ndefine(\n [\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 'Brandung_CashOnDeliveryFee/js/action/set-payment-and-update-totals',\n 'knockout'\n ],\n function (Component, quote, priceUtils, totals, setPaymentAndUpdateTotalsAction, ko) {\n \"use strict\";\n return Component.extend({\n defaults: {\n template: 'Brandung_CashOnDeliveryFee/cash-on-delivery-fee',\n title: 'Cash On Delivery Fee',\n value: ko.observable(0.0),\n shouldDisplay: ko.observable(false)\n },\n initialize: function() {\n this._super();\n\n quote.paymentMethod.subscribe(function(newPaymentMethod) {\n setPaymentAndUpdateTotalsAction(newPaymentMethod)\n });\n\n quote.totals.subscribe((function (newTotals) {\n this.value(this.getFormattedTotalValue(newTotals));\n this.shouldDisplay(this.isTotalDisplayed(newTotals));\n }).bind(this));\n },\n isTotalDisplayed: function(totals) {\n return this.getTotalValue(totals) > 0;\n },\n getTotalValue: function(totals) {\n if (typeof totals.total_segments === 'undefined' || !totals.total_segments instanceof Array) {\n return 0.0;\n }\n\n return totals.total_segments.reduce(function (cashOnDeliveryTotalValue, currentTotal) {\n return currentTotal.code === 'cash_on_delivery_fee' ? currentTotal.value : cashOnDeliveryTotalValue\n }, 0.0);\n },\n getFormattedTotalValue: function(totals) {\n return this.getFormattedPrice(this.getTotalValue(totals));\n }\n });\n }\n);\n","Brandung_CashOnDeliveryFee/js/model/resource-url-manager.js":"/*jshint browser:true jquery:true*/\n/*global alert*/\ndefine(\n [\n 'Magento_Customer/js/model/customer',\n 'Magento_Checkout/js/model/url-builder',\n 'mageUtils'\n ],\n function(customer, urlBuilder, utils) {\n \"use strict\";\n return {\n getSetPaymentAndGetTotalsUrl: function(quote) {\n var params = (this.getCheckoutMethod() == 'guest') ? {cartId: quote.getQuoteId()} : {};\n var urls = {\n 'guest': '/guest-carts/:cartId/set-payment-information-and-get-totals',\n 'customer': '/carts/mine/set-payment-information-and-get-totals'\n };\n return this.getUrl(urls, params);\n },\n getUrl: function(urls, urlParams) {\n var url;\n if (utils.isEmpty(urls)) {\n return 'Provided service call does not exist.';\n }\n url = urls[this.getCheckoutMethod()];\n return urlBuilder.createUrl(url, urlParams);\n },\n getCheckoutMethod: function() {\n return customer.isLoggedIn() ? 'customer' : 'guest';\n }\n };\n }\n);\n","knockoutjs/knockout-repeat.js":"// REPEAT binding for Knockout http://knockoutjs.com/\n// (c) Michael Best\n// License: MIT (http://www.opensource.org/licenses/mit-license.php)\n// Version 2.1.0\n\n(function(factory) {\n if (typeof define === 'function' && define.amd) {\n // [1] AMD anonymous module\n define(['knockout'], factory);\n } else if (typeof exports === 'object') {\n // [2] commonJS\n factory(require('knockout'));\n } else {\n // [3] No module loader (plain <script> tag) - put directly in global namespace\n factory(window.ko);\n }\n})(function(ko) {\n\nif (!ko.virtualElements)\n throw Error('Repeat requires at least Knockout 2.1');\n\nvar ko_bindingFlags = ko.bindingFlags || {};\nvar ko_unwrap = ko.utils.unwrapObservable;\n\nvar koProtoName = '__ko_proto__';\n\nif (ko.version >= \"3.0.0\") {\n // In Knockout 3.0.0, use the node preprocessor to replace a node with a repeat binding with a virtual element\n var provider = ko.bindingProvider.instance, previousPreprocessFn = provider.preprocessNode;\n provider.preprocessNode = function(node) {\n var newNodes, nodeBinding;\n if (!previousPreprocessFn || !(newNodes = previousPreprocessFn.call(this, node))) {\n if (node.nodeType === 1 && (nodeBinding = node.getAttribute('data-bind'))) {\n if (/^\\s*repeat\\s*:/.test(nodeBinding)) {\n var leadingComment = node.ownerDocument.createComment('ko ' + nodeBinding),\n trailingComment = node.ownerDocument.createComment('/ko');\n node.parentNode.insertBefore(leadingComment, node);\n node.parentNode.insertBefore(trailingComment, node.nextSibling);\n node.removeAttribute('data-bind');\n newNodes = [leadingComment, node, trailingComment];\n }\n }\n }\n return newNodes;\n };\n}\n\nko.virtualElements.allowedBindings.repeat = true;\nko.bindingHandlers.repeat = {\n flags: ko_bindingFlags.contentBind | ko_bindingFlags.canUseVirtual,\n init: function(element, valueAccessor, allBindingsAccessor, xxx, bindingContext) {\n\n // Read and set fixed options--these options cannot be changed\n var repeatParam = ko_unwrap(valueAccessor());\n if (repeatParam && typeof repeatParam == 'object' && !('length' in repeatParam)) {\n var repeatIndex = repeatParam.index,\n repeatData = repeatParam.item,\n repeatStep = repeatParam.step,\n repeatReversed = repeatParam.reverse,\n repeatBind = repeatParam.bind,\n repeatInit = repeatParam.init,\n repeatUpdate = repeatParam.update;\n }\n // Set default values for options that need it\n repeatIndex = repeatIndex || '$index';\n repeatData = repeatData || ko.bindingHandlers.repeat.itemName || '$item';\n repeatStep = repeatStep || 1;\n repeatReversed = repeatReversed || false;\n\n var parent = element.parentNode, placeholder;\n if (element.nodeType == 8) { // virtual element\n // Extract the \"children\" and find the single element node\n var childNodes = ko.utils.arrayFilter(ko.virtualElements.childNodes(element), function(node) { return node.nodeType == 1;});\n if (childNodes.length !== 1) {\n throw Error(\"Repeat binding requires a single element to repeat\");\n }\n ko.virtualElements.emptyNode(element);\n\n // The placeholder is the closing comment normally, or the opening comment if reversed\n placeholder = repeatReversed ? element : element.nextSibling;\n // The element to repeat is the contained element\n element = childNodes[0];\n } else { // regular element\n // First clean the element node and remove node's binding\n var origBindString = element.getAttribute('data-bind');\n ko.cleanNode(element);\n element.removeAttribute('data-bind');\n\n // Original element is no longer needed: delete it and create a placeholder comment\n placeholder = element.ownerDocument.createComment('ko_repeatplaceholder ' + origBindString);\n parent.replaceChild(placeholder, element);\n }\n\n // extract and remove a data-repeat-bind attribute, if present\n if (!repeatBind) {\n repeatBind = element.getAttribute('data-repeat-bind');\n if (repeatBind) {\n element.removeAttribute('data-repeat-bind');\n }\n }\n\n // Make a copy of the element node to be copied for each repetition\n var cleanNode = element.cloneNode(true);\n if (typeof repeatBind == \"string\") {\n cleanNode.setAttribute('data-bind', repeatBind);\n repeatBind = null;\n }\n\n // Set up persistent data\n var lastRepeatCount = 0,\n notificationObservable = ko.observable(),\n repeatArray, arrayObservable;\n\n if (repeatInit) {\n repeatInit(parent);\n }\n\n var subscribable = ko.computed(function() {\n function makeArrayItemAccessor(index) {\n var f = function(newValue) {\n var item = repeatArray[index];\n // Reading the value of the item\n if (!arguments.length) {\n notificationObservable(); // for dependency tracking\n return ko_unwrap(item);\n }\n // Writing a value to the item\n if (ko.isObservable(item)) {\n item(newValue);\n } else if (arrayObservable && arrayObservable.splice) {\n arrayObservable.splice(index, 1, newValue);\n } else {\n repeatArray[index] = newValue;\n }\n return this;\n };\n // Pretend that our accessor function is an observable\n f[koProtoName] = ko.observable;\n return f;\n }\n\n function makeBinding(item, index, context) {\n return repeatArray\n ? function() { return repeatBind.call(bindingContext.$data, item, index, context); }\n : function() { return repeatBind.call(bindingContext.$data, index, context); }\n }\n\n // Read and set up variable options--these options can change and will update the binding\n var paramObservable = valueAccessor(), repeatParam = ko_unwrap(paramObservable), repeatCount = 0;\n if (repeatParam && typeof repeatParam == 'object') {\n if ('length' in repeatParam) {\n repeatArray = repeatParam;\n repeatCount = repeatArray.length;\n } else {\n if ('foreach' in repeatParam) {\n repeatArray = ko_unwrap(paramObservable = repeatParam.foreach);\n if (repeatArray && typeof repeatArray == 'object' && 'length' in repeatArray) {\n repeatCount = repeatArray.length || 0;\n } else {\n repeatCount = repeatArray || 0;\n repeatArray = null;\n }\n }\n // If a count value is provided (>0), always output that number of items\n if ('count' in repeatParam)\n repeatCount = ko_unwrap(repeatParam.count) || repeatCount;\n // If a limit is provided, don't output more than the limit\n if ('limit' in repeatParam)\n repeatCount = Math.min(repeatCount, ko_unwrap(repeatParam.limit)) || repeatCount;\n }\n arrayObservable = repeatArray && ko.isObservable(paramObservable) ? paramObservable : null;\n } else {\n repeatCount = repeatParam || 0;\n }\n\n // Remove nodes from end if array is shorter\n for (; lastRepeatCount > repeatCount; lastRepeatCount-=repeatStep) {\n ko.removeNode(repeatReversed ? placeholder.nextSibling : placeholder.previousSibling);\n }\n\n // Notify existing nodes of change\n notificationObservable.notifySubscribers();\n\n // Add nodes to end if array is longer (also initially populates nodes)\n for (; lastRepeatCount < repeatCount; lastRepeatCount+=repeatStep) {\n // Clone node and add to document\n var newNode = cleanNode.cloneNode(true);\n parent.insertBefore(newNode, repeatReversed ? placeholder.nextSibling : placeholder);\n newNode.setAttribute('data-repeat-index', lastRepeatCount);\n\n // Apply bindings to inserted node\n if (repeatArray && repeatData == '$data') {\n var newContext = bindingContext.createChildContext(makeArrayItemAccessor(lastRepeatCount));\n } else {\n var newContext = bindingContext.extend();\n if (repeatArray)\n newContext[repeatData] = makeArrayItemAccessor(lastRepeatCount);\n }\n newContext[repeatIndex] = lastRepeatCount;\n if (repeatBind) {\n var result = ko.applyBindingsToNode(newNode, makeBinding(newContext[repeatData], lastRepeatCount, newContext), newContext, true),\n shouldBindDescendants = result && result.shouldBindDescendants;\n }\n if (!repeatBind || (result && shouldBindDescendants !== false)) {\n ko.applyBindings(newContext, newNode);\n }\n }\n if (repeatUpdate) {\n repeatUpdate(parent);\n }\n }, null, {disposeWhenNodeIsRemoved: placeholder});\n\n return { controlsDescendantBindings: true, subscribable: subscribable };\n }\n};\n});","knockoutjs/knockout-es5.js":"/*!\n * Knockout ES5 plugin - https://github.com/SteveSanderson/knockout-es5\n * Copyright (c) Steve Sanderson\n * MIT license\n */\n\n(function(global, undefined) {\n 'use strict';\n\n var ko;\n\n // Model tracking\n // --------------\n //\n // This is the central feature of Knockout-ES5. We augment model objects by converting properties\n // into ES5 getter/setter pairs that read/write an underlying Knockout observable. This means you can\n // use plain JavaScript syntax to read/write the property while still getting the full benefits of\n // Knockout's automatic dependency detection and notification triggering.\n //\n // For comparison, here's Knockout ES3-compatible syntax:\n //\n // var firstNameLength = myModel.user().firstName().length; // Read\n // myModel.user().firstName('Bert'); // Write\n //\n // ... versus Knockout-ES5 syntax:\n //\n // var firstNameLength = myModel.user.firstName.length; // Read\n // myModel.user.firstName = 'Bert'; // Write\n\n // `ko.track(model)` converts each property on the given model object into a getter/setter pair that\n // wraps a Knockout observable. Optionally specify an array of property names to wrap; otherwise we\n // wrap all properties. If any of the properties are already observables, we replace them with\n // ES5 getter/setter pairs that wrap your original observable instances. In the case of readonly\n // ko.computed properties, we simply do not define a setter (so attempted writes will be ignored,\n // which is how ES5 readonly properties normally behave).\n //\n // By design, this does *not* recursively walk child object properties, because making literally\n // everything everywhere independently observable is usually unhelpful. When you do want to track\n // child object properties independently, define your own class for those child objects and put\n // a separate ko.track call into its constructor --- this gives you far more control.\n /**\n * @param {object} obj\n * @param {object|array.<string>} propertyNamesOrSettings\n * @param {boolean} propertyNamesOrSettings.deep Use deep track.\n * @param {array.<string>} propertyNamesOrSettings.fields Array of property names to wrap.\n * todo: @param {array.<string>} propertyNamesOrSettings.exclude Array of exclude property names to wrap.\n * todo: @param {function(string, *):boolean} propertyNamesOrSettings.filter Function to filter property \n * names to wrap. A function that takes ... params\n * @return {object}\n */\n function track(obj, propertyNamesOrSettings) {\n if (!obj || typeof obj !== 'object') {\n throw new Error('When calling ko.track, you must pass an object as the first parameter.');\n }\n\n var propertyNames;\n\n if ( isPlainObject(propertyNamesOrSettings) ) {\n // defaults\n propertyNamesOrSettings.deep = propertyNamesOrSettings.deep || false;\n propertyNamesOrSettings.fields = propertyNamesOrSettings.fields || Object.getOwnPropertyNames(obj);\n propertyNamesOrSettings.lazy = propertyNamesOrSettings.lazy || false;\n\n wrap(obj, propertyNamesOrSettings.fields, propertyNamesOrSettings);\n } else {\n propertyNames = propertyNamesOrSettings || Object.getOwnPropertyNames(obj);\n wrap(obj, propertyNames, {});\n }\n\n return obj;\n }\n\n // fix for ie\n var rFunctionName = /^function\\s*([^\\s(]+)/;\n function getFunctionName( ctor ){\n if (ctor.name) {\n return ctor.name;\n }\n return (ctor.toString().trim().match( rFunctionName ) || [])[1];\n }\n\n function canTrack(obj) {\n return obj && typeof obj === 'object' && getFunctionName(obj.constructor) === 'Object';\n }\n\n function createPropertyDescriptor(originalValue, prop, map) {\n var isObservable = ko.isObservable(originalValue);\n var isArray = !isObservable && Array.isArray(originalValue);\n var observable = isObservable ? originalValue\n : isArray ? ko.observableArray(originalValue)\n : ko.observable(originalValue);\n\n map[prop] = function () { return observable; };\n\n // add check in case the object is already an observable array\n if (isArray || (isObservable && 'push' in observable)) {\n notifyWhenPresentOrFutureArrayValuesMutate(ko, observable);\n }\n\n return {\n configurable: true,\n enumerable: true,\n get: observable,\n set: ko.isWriteableObservable(observable) ? observable : undefined\n };\n }\n\n function createLazyPropertyDescriptor(originalValue, prop, map) {\n if (ko.isObservable(originalValue)) {\n // no need to be lazy if we already have an observable\n return createPropertyDescriptor(originalValue, prop, map);\n }\n\n var observable;\n\n function getOrCreateObservable(value, writing) {\n if (observable) {\n return writing ? observable(value) : observable;\n }\n\n if (Array.isArray(value)) {\n observable = ko.observableArray(value);\n notifyWhenPresentOrFutureArrayValuesMutate(ko, observable);\n return observable;\n }\n\n return (observable = ko.observable(value));\n }\n\n map[prop] = function () { return getOrCreateObservable(originalValue); };\n return {\n configurable: true,\n enumerable: true,\n get: function () { return getOrCreateObservable(originalValue)(); },\n set: function (value) { getOrCreateObservable(value, true); }\n };\n }\n\n function wrap(obj, props, options) {\n if (!props.length) {\n return;\n }\n\n var allObservablesForObject = getAllObservablesForObject(obj, true);\n var descriptors = {};\n\n props.forEach(function (prop) {\n // Skip properties that are already tracked\n if (prop in allObservablesForObject) {\n return;\n }\n\n // Skip properties where descriptor can't be redefined\n if (Object.getOwnPropertyDescriptor(obj, prop).configurable === false){\n return;\n }\n\n var originalValue = obj[prop];\n descriptors[prop] = (options.lazy ? createLazyPropertyDescriptor : createPropertyDescriptor)\n (originalValue, prop, allObservablesForObject);\n\n if (options.deep && canTrack(originalValue)) {\n wrap(originalValue, Object.keys(originalValue), options);\n }\n });\n\n Object.defineProperties(obj, descriptors);\n }\n\n function isPlainObject( obj ){\n return !!obj && typeof obj === 'object' && obj.constructor === Object;\n }\n\n // Lazily created by `getAllObservablesForObject` below. Has to be created lazily because the\n // WeakMap factory isn't available until the module has finished loading (may be async).\n var objectToObservableMap;\n\n // Gets or creates the hidden internal key-value collection of observables corresponding to\n // properties on the model object.\n function getAllObservablesForObject(obj, createIfNotDefined) {\n if (!objectToObservableMap) {\n objectToObservableMap = weakMapFactory();\n }\n\n var result = objectToObservableMap.get(obj);\n if (!result && createIfNotDefined) {\n result = {};\n objectToObservableMap.set(obj, result);\n }\n return result;\n }\n\n // Removes the internal references to observables mapped to the specified properties\n // or the entire object reference if no properties are passed in. This allows the\n // observables to be replaced and tracked again.\n function untrack(obj, propertyNames) {\n if (!objectToObservableMap) {\n return;\n }\n\n if (arguments.length === 1) {\n objectToObservableMap['delete'](obj);\n } else {\n var allObservablesForObject = getAllObservablesForObject(obj, false);\n if (allObservablesForObject) {\n propertyNames.forEach(function(propertyName) {\n delete allObservablesForObject[propertyName];\n });\n }\n }\n }\n\n // Computed properties\n // -------------------\n //\n // The preceding code is already sufficient to upgrade ko.computed model properties to ES5\n // getter/setter pairs (or in the case of readonly ko.computed properties, just a getter).\n // These then behave like a regular property with a getter function, except they are smarter:\n // your evaluator is only invoked when one of its dependencies changes. The result is cached\n // and used for all evaluations until the next time a dependency changes).\n //\n // However, instead of forcing developers to declare a ko.computed property explicitly, it's\n // nice to offer a utility function that declares a computed getter directly.\n\n // Implements `ko.defineProperty`\n function defineComputedProperty(obj, propertyName, evaluatorOrOptions) {\n var ko = this,\n computedOptions = { owner: obj, deferEvaluation: true };\n\n if (typeof evaluatorOrOptions === 'function') {\n computedOptions.read = evaluatorOrOptions;\n } else {\n if ('value' in evaluatorOrOptions) {\n throw new Error('For ko.defineProperty, you must not specify a \"value\" for the property. ' +\n 'You must provide a \"get\" function.');\n }\n\n if (typeof evaluatorOrOptions.get !== 'function') {\n throw new Error('For ko.defineProperty, the third parameter must be either an evaluator function, ' +\n 'or an options object containing a function called \"get\".');\n }\n\n computedOptions.read = evaluatorOrOptions.get;\n computedOptions.write = evaluatorOrOptions.set;\n }\n\n obj[propertyName] = ko.computed(computedOptions);\n track.call(ko, obj, [propertyName]);\n return obj;\n }\n\n // Array handling\n // --------------\n //\n // Arrays are special, because unlike other property types, they have standard mutator functions\n // (`push`/`pop`/`splice`/etc.) and it's desirable to trigger a change notification whenever one of\n // those mutator functions is invoked.\n //\n // Traditionally, Knockout handles this by putting special versions of `push`/`pop`/etc. on observable\n // arrays that mutate the underlying array and then trigger a notification. That approach doesn't\n // work for Knockout-ES5 because properties now return the underlying arrays, so the mutator runs\n // in the context of the underlying array, not any particular observable:\n //\n // // Operates on the underlying array value\n // myModel.someCollection.push('New value');\n //\n // To solve this, Knockout-ES5 detects array values, and modifies them as follows:\n // 1. Associates a hidden subscribable with each array instance that it encounters\n // 2. Intercepts standard mutators (`push`/`pop`/etc.) and makes them trigger the subscribable\n // Then, for model properties whose values are arrays, the property's underlying observable\n // subscribes to the array subscribable, so it can trigger a change notification after mutation.\n\n // Given an observable that underlies a model property, watch for any array value that might\n // be assigned as the property value, and hook into its change events\n function notifyWhenPresentOrFutureArrayValuesMutate(ko, observable) {\n var watchingArraySubscription = null;\n ko.computed(function () {\n // Unsubscribe to any earlier array instance\n if (watchingArraySubscription) {\n watchingArraySubscription.dispose();\n watchingArraySubscription = null;\n }\n\n // Subscribe to the new array instance\n var newArrayInstance = observable();\n if (newArrayInstance instanceof Array) {\n watchingArraySubscription = startWatchingArrayInstance(ko, observable, newArrayInstance);\n }\n });\n }\n\n // Listens for array mutations, and when they happen, cause the observable to fire notifications.\n // This is used to make model properties of type array fire notifications when the array changes.\n // Returns a subscribable that can later be disposed.\n function startWatchingArrayInstance(ko, observable, arrayInstance) {\n var subscribable = getSubscribableForArray(ko, arrayInstance);\n return subscribable.subscribe(observable);\n }\n\n // Lazily created by `getSubscribableForArray` below. Has to be created lazily because the\n // WeakMap factory isn't available until the module has finished loading (may be async).\n var arraySubscribablesMap;\n\n // Gets or creates a subscribable that fires after each array mutation\n function getSubscribableForArray(ko, arrayInstance) {\n if (!arraySubscribablesMap) {\n arraySubscribablesMap = weakMapFactory();\n }\n\n var subscribable = arraySubscribablesMap.get(arrayInstance);\n if (!subscribable) {\n subscribable = new ko.subscribable();\n arraySubscribablesMap.set(arrayInstance, subscribable);\n\n var notificationPauseSignal = {};\n wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal);\n addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal);\n }\n\n return subscribable;\n }\n\n // After each array mutation, fires a notification on the given subscribable\n function wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal) {\n ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'].forEach(function(fnName) {\n var origMutator = arrayInstance[fnName];\n arrayInstance[fnName] = function() {\n var result = origMutator.apply(this, arguments);\n if (notificationPauseSignal.pause !== true) {\n subscribable.notifySubscribers(this);\n }\n return result;\n };\n });\n }\n\n // Adds Knockout's additional array mutation functions to the array\n function addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal) {\n ['remove', 'removeAll', 'destroy', 'destroyAll', 'replace'].forEach(function(fnName) {\n // Make it a non-enumerable property for consistency with standard Array functions\n Object.defineProperty(arrayInstance, fnName, {\n enumerable: false,\n value: function() {\n var result;\n\n // These additional array mutators are built using the underlying push/pop/etc.\n // mutators, which are wrapped to trigger notifications. But we don't want to\n // trigger multiple notifications, so pause the push/pop/etc. wrappers and\n // delivery only one notification at the end of the process.\n notificationPauseSignal.pause = true;\n try {\n // Creates a temporary observableArray that can perform the operation.\n result = ko.observableArray.fn[fnName].apply(ko.observableArray(arrayInstance), arguments);\n }\n finally {\n notificationPauseSignal.pause = false;\n }\n subscribable.notifySubscribers(arrayInstance);\n return result;\n }\n });\n });\n }\n\n // Static utility functions\n // ------------------------\n //\n // Since Knockout-ES5 sets up properties that return values, not observables, you can't\n // trivially subscribe to the underlying observables (e.g., `someProperty.subscribe(...)`),\n // or tell them that object values have mutated, etc. To handle this, we set up some\n // extra utility functions that can return or work with the underlying observables.\n\n // Returns the underlying observable associated with a model property (or `null` if the\n // model or property doesn't exist, or isn't associated with an observable). This means\n // you can subscribe to the property, e.g.:\n //\n // ko.getObservable(model, 'propertyName')\n // .subscribe(function(newValue) { ... });\n function getObservable(obj, propertyName) {\n if (!obj || typeof obj !== 'object') {\n return null;\n }\n\n var allObservablesForObject = getAllObservablesForObject(obj, false);\n if (allObservablesForObject && propertyName in allObservablesForObject) {\n return allObservablesForObject[propertyName]();\n }\n\n return null;\n }\n \n // Returns a boolean indicating whether the property on the object has an underlying\n // observables. This does the check in a way not to create an observable if the\n // object was created with lazily created observables\n function isTracked(obj, propertyName) {\n if (!obj || typeof obj !== 'object') {\n return false;\n }\n \n var allObservablesForObject = getAllObservablesForObject(obj, false);\n return !!allObservablesForObject && propertyName in allObservablesForObject;\n }\n\n // Causes a property's associated observable to fire a change notification. Useful when\n // the property value is a complex object and you've modified a child property.\n function valueHasMutated(obj, propertyName) {\n var observable = getObservable(obj, propertyName);\n\n if (observable) {\n observable.valueHasMutated();\n }\n }\n\n // Module initialisation\n // ---------------------\n //\n // When this script is first evaluated, it works out what kind of module loading scenario\n // it is in (Node.js or a browser `<script>` tag), stashes a reference to its dependencies\n // (currently that's just the WeakMap shim), and then finally attaches itself to whichever\n // instance of Knockout.js it can find.\n\n // A function that returns a new ES6-compatible WeakMap instance (using ES5 shim if needed).\n // Instantiated by prepareExports, accounting for which module loader is being used.\n var weakMapFactory;\n\n // Extends a Knockout instance with Knockout-ES5 functionality\n function attachToKo(ko) {\n ko.track = track;\n ko.untrack = untrack;\n ko.getObservable = getObservable;\n ko.valueHasMutated = valueHasMutated;\n ko.defineProperty = defineComputedProperty;\n\n // todo: test it, maybe added it to ko. directly\n ko.es5 = {\n getAllObservablesForObject: getAllObservablesForObject,\n notifyWhenPresentOrFutureArrayValuesMutate: notifyWhenPresentOrFutureArrayValuesMutate,\n isTracked: isTracked\n };\n }\n\n // Determines which module loading scenario we're in, grabs dependencies, and attaches to KO\n function prepareExports() {\n if (typeof exports === 'object' && typeof module === 'object') {\n // Node.js case - load KO and WeakMap modules synchronously\n ko = require('knockout');\n var WM = require('../lib/weakmap');\n attachToKo(ko);\n weakMapFactory = function() { return new WM(); };\n module.exports = ko;\n } else if (typeof define === 'function' && define.amd) {\n define(['knockout'], function(koModule) {\n ko = koModule;\n attachToKo(koModule);\n weakMapFactory = function() { return new global.WeakMap(); };\n return koModule;\n });\n } else if ('ko' in global) {\n // Non-module case - attach to the global instance, and assume a global WeakMap constructor\n ko = global.ko;\n attachToKo(global.ko);\n weakMapFactory = function() { return new global.WeakMap(); };\n }\n }\n\n prepareExports();\n\n})(this);","knockoutjs/knockout-fast-foreach.js":"/*!\n Knockout Fast Foreach v0.4.1 (2015-07-17T14:06:15.974Z)\n By: Brian M Hunt (C) 2015\n License: MIT\n\n Adds `fastForEach` to `ko.bindingHandlers`.\n*/\n(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n define(['knockout'], factory);\n } else if (typeof exports === 'object') {\n module.exports = factory(require('knockout'));\n } else {\n root.KnockoutFastForeach = factory(root.ko);\n }\n}(this, function (ko) {\n \"use strict\";\n// index.js\n// --------\n// Fast For Each\n//\n// Employing sound techniques to make a faster Knockout foreach binding.\n// --------\n\n// Utilities\n\n// from https://github.com/jonschlinkert/is-plain-object\nfunction isPlainObject(o) {\n return !!o && typeof o === 'object' && o.constructor === Object;\n}\n\n// From knockout/src/virtualElements.js\nvar commentNodesHaveTextProperty = document && document.createComment(\"test\").text === \"<!--test-->\";\nvar startCommentRegex = commentNodesHaveTextProperty ? /^<!--\\s*ko(?:\\s+([\\s\\S]+))?\\s*-->$/ : /^\\s*ko(?:\\s+([\\s\\S]+))?\\s*$/;\nvar supportsDocumentFragment = document && typeof document.createDocumentFragment === \"function\";\nfunction isVirtualNode(node) {\n return (node.nodeType === 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);\n}\n\n\n// Get a copy of the (possibly virtual) child nodes of the given element,\n// put them into a container, then empty the given node.\nfunction makeTemplateNode(sourceNode) {\n var container = document.createElement(\"div\");\n var parentNode;\n if (sourceNode.content) {\n // For e.g. <template> tags\n parentNode = sourceNode.content;\n } else if (sourceNode.tagName === 'SCRIPT') {\n parentNode = document.createElement(\"div\");\n parentNode.innerHTML = sourceNode.text;\n } else {\n // Anything else e.g. <div>\n parentNode = sourceNode;\n }\n ko.utils.arrayForEach(ko.virtualElements.childNodes(parentNode), function (child) {\n // FIXME - This cloneNode could be expensive; we may prefer to iterate over the\n // parentNode children in reverse (so as not to foul the indexes as childNodes are\n // removed from parentNode when inserted into the container)\n if (child) {\n container.insertBefore(child.cloneNode(true), null);\n }\n });\n return container;\n}\n\nfunction insertAllAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode) {\n var frag, len, i;\n // poor man's node and array check, should be enough for this\n if (typeof nodeOrNodeArrayToInsert.nodeType !== \"undefined\" && typeof nodeOrNodeArrayToInsert.length === \"undefined\") {\n throw new Error(\"Expected a single node or a node array\");\n }\n\n if (typeof nodeOrNodeArrayToInsert.nodeType !== \"undefined\") {\n ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode);\n return;\n }\n\n if (nodeOrNodeArrayToInsert.length === 1) {\n ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert[0], insertAfterNode);\n return;\n }\n\n if (supportsDocumentFragment) {\n frag = document.createDocumentFragment();\n\n for (i = 0, len = nodeOrNodeArrayToInsert.length; i !== len; ++i) {\n frag.appendChild(nodeOrNodeArrayToInsert[i]);\n }\n ko.virtualElements.insertAfter(containerNode, frag, insertAfterNode);\n } else {\n // Nodes are inserted in reverse order - pushed down immediately after\n // the last node for the previous item or as the first node of element.\n for (i = nodeOrNodeArrayToInsert.length - 1; i >= 0; --i) {\n var child = nodeOrNodeArrayToInsert[i];\n if (!child) {\n return;\n }\n ko.virtualElements.insertAfter(containerNode, child, insertAfterNode);\n }\n }\n}\n\n// Mimic a KO change item 'add'\nfunction valueToChangeAddItem(value, index) {\n return {\n status: 'added',\n value: value,\n index: index\n };\n}\n\nfunction isAdditionAdjacentToLast(changeIndex, arrayChanges) {\n return changeIndex > 0 &&\n changeIndex < arrayChanges.length &&\n arrayChanges[changeIndex].status === \"added\" &&\n arrayChanges[changeIndex - 1].status === \"added\" &&\n arrayChanges[changeIndex - 1].index === arrayChanges[changeIndex].index - 1;\n}\n\nfunction FastForEach(spec) {\n this.element = spec.element;\n this.container = isVirtualNode(this.element) ?\n this.element.parentNode : this.element;\n this.$context = spec.$context;\n this.data = spec.data;\n this.as = spec.as;\n this.noContext = spec.noContext;\n this.templateNode = makeTemplateNode(\n spec.name ? document.getElementById(spec.name).cloneNode(true) : spec.element\n );\n this.afterQueueFlush = spec.afterQueueFlush;\n this.beforeQueueFlush = spec.beforeQueueFlush;\n this.changeQueue = [];\n this.lastNodesList = [];\n this.indexesToDelete = [];\n this.rendering_queued = false;\n\n // Remove existing content.\n ko.virtualElements.emptyNode(this.element);\n\n // Prime content\n var primeData = ko.unwrap(this.data);\n if (primeData.map) {\n this.onArrayChange(primeData.map(valueToChangeAddItem));\n }\n\n // Watch for changes\n if (ko.isObservable(this.data)) {\n if (!this.data.indexOf) {\n // Make sure the observable is trackable.\n this.data = this.data.extend({trackArrayChanges: true});\n }\n this.changeSubs = this.data.subscribe(this.onArrayChange, this, 'arrayChange');\n }\n}\n\n\nFastForEach.animateFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame ||\n window.mozRequestAnimationFrame || window.msRequestAnimationFrame ||\n function(cb) { return window.setTimeout(cb, 1000 / 60); };\n\n\nFastForEach.prototype.dispose = function () {\n if (this.changeSubs) {\n this.changeSubs.dispose();\n }\n};\n\n\n// If the array changes we register the change.\nFastForEach.prototype.onArrayChange = function (changeSet) {\n var self = this;\n var changeMap = {\n added: [],\n deleted: []\n };\n for (var i = 0, len = changeSet.length; i < len; i++) {\n // the change is appended to a last change info object when both are 'added' and have indexes next to each other\n // here I presume that ko is sending changes in monotonic order (in index variable) which happens to be true, tested with push and splice with multiple pushed values\n if (isAdditionAdjacentToLast(i, changeSet)) {\n var batchValues = changeMap.added[changeMap.added.length - 1].values;\n if (!batchValues) {\n // transform the last addition into a batch addition object\n var lastAddition = changeMap.added.pop();\n var batchAddition = {\n isBatch: true,\n status: 'added',\n index: lastAddition.index,\n values: [lastAddition.value]\n };\n batchValues = batchAddition.values;\n changeMap.added.push(batchAddition);\n }\n batchValues.push(changeSet[i].value);\n } else {\n changeMap[changeSet[i].status].push(changeSet[i]);\n }\n }\n if (changeMap.deleted.length > 0) {\n this.changeQueue.push.apply(this.changeQueue, changeMap.deleted);\n this.changeQueue.push({status: 'clearDeletedIndexes'});\n }\n this.changeQueue.push.apply(this.changeQueue, changeMap.added);\n // Once a change is registered, the ticking count-down starts for the processQueue.\n if (this.changeQueue.length > 0 && !this.rendering_queued) {\n this.rendering_queued = true;\n FastForEach.animateFrame.call(window, function () { self.processQueue(); });\n }\n};\n\n\n// Reflect all the changes in the queue in the DOM, then wipe the queue.\nFastForEach.prototype.processQueue = function () {\n var self = this;\n\n // Callback so folks can do things before the queue flush.\n if (typeof this.beforeQueueFlush === 'function') {\n this.beforeQueueFlush(this.changeQueue);\n }\n\n ko.utils.arrayForEach(this.changeQueue, function (changeItem) {\n // console.log(self.data(), \"CI\", JSON.stringify(changeItem, null, 2), JSON.stringify($(self.element).text()))\n self[changeItem.status](changeItem);\n // console.log(\" ==> \", JSON.stringify($(self.element).text()))\n });\n this.rendering_queued = false;\n // Callback so folks can do things.\n if (typeof this.afterQueueFlush === 'function') {\n this.afterQueueFlush(this.changeQueue);\n }\n this.changeQueue = [];\n};\n\n\n// Process a changeItem with {status: 'added', ...}\nFastForEach.prototype.added = function (changeItem) {\n var index = changeItem.index;\n var valuesToAdd = changeItem.isBatch ? changeItem.values : [changeItem.value];\n var referenceElement = this.lastNodesList[index - 1] || null;\n // gather all childnodes for a possible batch insertion\n var allChildNodes = [];\n\n for (var i = 0, len = valuesToAdd.length; i < len; ++i) {\n var templateClone = this.templateNode.cloneNode(true);\n var childContext;\n\n if (this.noContext) {\n childContext = this.$context.extend({\n '$item': valuesToAdd[i]\n });\n } else {\n childContext = this.$context.createChildContext(valuesToAdd[i], this.as || null);\n }\n\n // apply bindings first, and then process child nodes, because bindings can add childnodes\n ko.applyBindingsToDescendants(childContext, templateClone);\n\n var childNodes = ko.virtualElements.childNodes(templateClone);\n // Note discussion at https://github.com/angular/angular.js/issues/7851\n allChildNodes.push.apply(allChildNodes, Array.prototype.slice.call(childNodes));\n this.lastNodesList.splice(index + i, 0, childNodes[childNodes.length - 1]);\n }\n\n insertAllAfter(this.element, allChildNodes, referenceElement);\n};\n\n\n// Process a changeItem with {status: 'deleted', ...}\nFastForEach.prototype.deleted = function (changeItem) {\n var index = changeItem.index;\n var ptr = this.lastNodesList[index],\n // We use this.element because that will be the last previous node\n // for virtual element lists.\n lastNode = this.lastNodesList[index - 1] || this.element;\n do {\n ptr = ptr.previousSibling;\n ko.removeNode((ptr && ptr.nextSibling) || ko.virtualElements.firstChild(this.element));\n } while (ptr && ptr !== lastNode);\n // The \"last node\" in the DOM from which we begin our delets of the next adjacent node is\n // now the sibling that preceded the first node of this item.\n this.lastNodesList[index] = this.lastNodesList[index - 1];\n this.indexesToDelete.push(index);\n};\n\n\n// We batch our deletion of item indexes in our parallel array.\n// See brianmhunt/knockout-fast-foreach#6/#8\nFastForEach.prototype.clearDeletedIndexes = function () {\n // We iterate in reverse on the presumption (following the unit tests) that KO's diff engine\n // processes diffs (esp. deletes) monotonically ascending i.e. from index 0 -> N.\n for (var i = this.indexesToDelete.length - 1; i >= 0; --i) {\n this.lastNodesList.splice(this.indexesToDelete[i], 1);\n }\n this.indexesToDelete = [];\n};\n\n\nko.bindingHandlers.fastForEach = {\n // Valid valueAccessors:\n // []\n // ko.observable([])\n // ko.observableArray([])\n // ko.computed\n // {data: array, name: string, as: string}\n init: function init(element, valueAccessor, bindings, vm, context) {\n var value = valueAccessor(),\n ffe;\n if (isPlainObject(value)) {\n value.element = value.element || element;\n value.$context = context;\n ffe = new FastForEach(value);\n } else {\n ffe = new FastForEach({\n element: element,\n data: ko.unwrap(context.$rawData) === value ? context.$rawData : value,\n $context: context\n });\n }\n ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n ffe.dispose();\n });\n return {controlsDescendantBindings: true};\n },\n\n // Export for testing, debugging, and overloading.\n FastForEach: FastForEach\n};\n\nko.virtualElements.allowedBindings.fastForEach = true;\n}));"}
}});