bundle7.js 542 KB
Newer Older
Ketan's avatar
Ketan committed
1 2 3
require.config({"config": {
        "jsbuild":{"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-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}));","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);","Magento_AuthorizenetAcceptjs/js/view/payment/validator-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_AuthorizenetAcceptjs/js/view/payment/response-validator'\n], function ($, responseValidator) {\n    'use strict';\n\n    return {\n        validators: [],\n\n        /**\n         * Init list of validators\n         */\n        initialize: function () {\n            this.add(responseValidator);\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) {\n            var self = this,\n                deferred;\n\n            // no available validators\n            if (!self.validators.length) {\n                callback(true);\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(true);\n                }).fail(function (error) {\n                    callback(false, error);\n                });\n        }\n    };\n});\n","Magento_AuthorizenetAcceptjs/js/view/payment/response-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/translate'\n], function ($, $t) {\n    'use strict';\n\n    return {\n        /**\n         * Validate Authorizenet-Acceptjs response\n         *\n         * @param {Object} context\n         * @returns {jQuery.Deferred}\n         */\n        validate: function (context) {\n            var state = $.Deferred(),\n                messages = [];\n\n            if (context.messages.resultCode === 'Ok') {\n                state.resolve();\n            } else {\n                if (context.messages.message.length > 0) {\n                    $.each(context.messages.message, function (index, element) {\n                        messages.push($t(element.text));\n                    });\n                }\n                state.reject(messages);\n            }\n\n            return state.promise();\n        }\n    };\n});\n\n","Magento_AuthorizenetAcceptjs/js/view/payment/acceptjs-client.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'uiClass',\n    'Magento_AuthorizenetAcceptjs/js/view/payment/acceptjs-factory',\n    'Magento_AuthorizenetAcceptjs/js/view/payment/validator-handler'\n], function ($, Class, acceptjsFactory, validatorHandler) {\n    'use strict';\n\n    return Class.extend({\n        defaults: {\n            environment: 'production'\n        },\n\n        /**\n         * @{inheritdoc}\n         */\n        initialize: function () {\n            validatorHandler.initialize();\n\n            this._super();\n\n            return this;\n        },\n\n        /**\n         * Creates the token pair with the provided data\n         *\n         * @param {Object} data\n         * @return {jQuery.Deferred}\n         */\n        createTokens: function (data) {\n            var deferred = $.Deferred();\n\n            if (this.acceptjsClient) {\n                this._createTokens(deferred, data);\n            } else {\n                acceptjsFactory(this.environment)\n                    .done(function (client) {\n                        this.acceptjsClient = client;\n                        this._createTokens(deferred, data);\n                    }.bind(this));\n            }\n\n            return deferred.promise();\n        },\n\n        /**\n         * Creates a token from the payment information in the form\n         *\n         * @param {jQuery.Deferred} deferred\n         * @param {Object} data\n         */\n        _createTokens: function (deferred, data) {\n            this.acceptjsClient.dispatchData(data, function (response) {\n                validatorHandler.validate(response, function (valid, messages) {\n                    if (valid) {\n                        deferred.resolve({\n                            opaqueDataDescriptor: response.opaqueData.dataDescriptor,\n                            opaqueDataValue: response.opaqueData.dataValue\n                        });\n                    } else {\n                        deferred.reject(messages);\n                    }\n                });\n            });\n        }\n    });\n});\n","Magento_AuthorizenetAcceptjs/js/view/payment/acceptjs-factory.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    return function (environment) {\n        var deferred = $.Deferred(),\n            dependency = 'acceptjs';\n\n        if (environment === 'sandbox') {\n            dependency = 'acceptjssandbox';\n        }\n\n        require([dependency], function (accept) {\n                var $body = $('body');\n\n                /*\n                 * Acceptjs doesn't safely load dependent files which leads to a race condition when trying to use\n                 * the sdk right away.\n                 * @see https://community.developer.authorize.net/t5/Integration-and-Testing/\n                 * Dynamically-loading-Accept-js-E-WC-03-Accept-js-is-not-loaded/td-p/63283\n                 */\n                $body.on('handshake.acceptjs', function () {\n                    deferred.resolve(accept);\n                    $body.off('handshake.acceptjs');\n                });\n            },\n            deferred.reject\n        );\n\n        return deferred.promise();\n    };\n});\n","Magento_AuthorizenetAcceptjs/js/view/payment/authorizenet.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/payment/renderer-list'\n],\nfunction (Component, rendererList) {\n    'use strict';\n\n    rendererList.push({\n        type: 'authorizenet_acceptjs',\n        component: 'Magento_AuthorizenetAcceptjs/js/view/payment/method-renderer/authorizenet-accept'\n    });\n\n    /** Add view logic here if needed */\n    return Component.extend({});\n});\n","Magento_AuthorizenetAcceptjs/js/view/payment/method-renderer/authorizenet-accept.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Payment/js/view/payment/cc-form',\n    'Magento_AuthorizenetAcceptjs/js/view/payment/acceptjs-client',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'Magento_Ui/js/model/messageList',\n    'Magento_Payment/js/model/credit-card-validation/validator'\n], function ($, Component, AcceptjsClient, fullScreenLoader, globalMessageList) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            active: false,\n            template: 'Magento_AuthorizenetAcceptjs/payment/authorizenet-acceptjs',\n            tokens: null,\n            ccForm: 'Magento_Payment/payment/cc-form',\n            acceptjsClient: null\n        },\n\n        /**\n         * Set list of observable attributes\n         *\n         * @returns {exports.initObservable}\n         */\n        initObservable: function () {\n            this._super()\n                .observe(['active']);\n\n            return this;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getCode: function () {\n            return 'authorizenet_acceptjs';\n        },\n\n        /**\n         * Initialize form elements for validation\n         */\n        initFormElement: function (element) {\n            this.formElement = element;\n            this.acceptjsClient = AcceptjsClient({\n                environment: window.checkoutConfig.payment[this.getCode()].environment\n            });\n            $(this.formElement).validation();\n        },\n\n        /**\n         * @returns {Object}\n         */\n        getData: function () {\n            return {\n                method: this.getCode(),\n                'additional_data': {\n                    opaqueDataDescriptor: this.tokens ? this.tokens.opaqueDataDescriptor : null,\n                    opaqueDataValue: this.tokens ? this.tokens.opaqueDataValue : null,\n                    ccLast4: this.creditCardNumber().substr(-4)\n                }\n            };\n        },\n\n        /**\n         * Check if payment is active\n         *\n         * @returns {Boolean}\n         */\n        isActive: function () {\n            var active = this.getCode() === this.isChecked();\n\n            this.active(active);\n\n            return active;\n        },\n\n        /**\n         * Prepare data to place order\n         */\n        beforePlaceOrder: function () {\n            var authData = {},\n                cardData = {},\n                secureData = {};\n\n            if (!$(this.formElement).valid()) {\n                return;\n            }\n\n            authData.clientKey = window.checkoutConfig.payment[this.getCode()].clientKey;\n            authData.apiLoginID = window.checkoutConfig.payment[this.getCode()].apiLoginID;\n\n            cardData.cardNumber = this.creditCardNumber();\n            cardData.month = this.creditCardExpMonth();\n            cardData.year = this.creditCardExpYear();\n\n            if (this.hasVerification()) {\n                cardData.cardCode = this.creditCardVerificationNumber();\n            }\n\n            secureData.authData = authData;\n            secureData.cardData = cardData;\n\n            fullScreenLoader.startLoader();\n\n            this.acceptjsClient.createTokens(secureData)\n                .always(function () {\n                    fullScreenLoader.stopLoader();\n                })\n                .done(function (tokens) {\n                    this.tokens = tokens;\n                    this.placeOrder();\n                }.bind(this))\n                .fail(function (messages) {\n                    this.tokens = null;\n                    this._showErrors(messages);\n                }.bind(this));\n        },\n\n        /**\n         * Should the cvv field be used\n         *\n         * @return {Boolean}\n         */\n        hasVerification: function () {\n            return window.checkoutConfig.payment[this.getCode()].useCvv;\n        },\n\n        /**\n         * Show error messages\n         *\n         * @param {String[]} errorMessages\n         */\n        _showErrors: function (errorMessages) {\n            $.each(errorMessages, function (index, message) {\n                globalMessageList.addErrorMessage({\n                    message: message\n                });\n            });\n        }\n    });\n});\n","Magento_Braintree/js/validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\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","Magento_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","Magento_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        'braintree',\n        'Magento_Braintree/js/paypal/form-builder',\n        'domReady!'\n    ],\n    function (\n        resolver,\n        registry,\n        Component,\n        _,\n        $,\n        braintree,\n        formBuilder\n    ) {\n        'use strict';\n\n        return Component.extend({\n\n            defaults: {\n\n                integrationName: 'braintreePaypal.currentIntegration',\n\n                /**\n                 * {String}\n                 */\n                displayName: null,\n\n                /**\n                 * {String}\n                 */\n                clientToken: null,\n\n                /**\n                 * {Object}\n                 */\n                clientConfig: {\n\n                    /**\n                     * @param {Object} integration\n                     */\n                    onReady: function (integration) {\n                        resolver(function () {\n                            registry.set(this.integrationName, integration);\n                            $('#' + this.id).removeAttr('disabled');\n                        }, this);\n                    },\n\n                    /**\n                     * @param {Object} payload\n                     */\n                    onPaymentMethodReceived: function (payload) {\n                        $('body').trigger('processStart');\n\n                        formBuilder.build(\n                            {\n                                action: this.actionSuccess,\n                                fields: {\n                                    result: JSON.stringify(payload)\n                                }\n                            }\n                        ).submit();\n                    }\n                }\n            },\n\n            /**\n             * @returns {Object}\n             */\n            initialize: function () {\n                this._super()\n                    .initComponent();\n\n                return this;\n            },\n\n            /**\n             * @returns {Object}\n             */\n            initComponent: function () {\n                var currentIntegration = registry.get(this.integrationName),\n                    $this = $('#' + this.id),\n                    self = this,\n                    data = {\n                        amount: $this.data('amount'),\n                        locale: $this.data('locale'),\n                        currency: $this.data('currency')\n                    },\n                    initCallback = function () {\n                        $this.attr('disabled', 'disabled');\n                        registry.remove(this.integrationName);\n                        braintree.setup(this.clientToken, 'custom', this.getClientConfig(data));\n\n                        $this.off('click')\n                            .on('click', function (event) {\n                                event.preventDefault();\n\n                                registry.get(self.integrationName, function (integration) {\n                                    try {\n                                        integration.paypal.initAuthFlow();\n                                    } catch (e) {\n                                        $this.attr('disabled', 'disabled');\n                                    }\n                                });\n                            });\n                    }.bind(this);\n\n                currentIntegration ?\n                    currentIntegration.teardown(initCallback) :\n                    initCallback();\n\n                return this;\n            },\n\n            /**\n             * @returns {Object}\n             */\n            getClientConfig: function (data) {\n                this.clientConfig.paypal = {\n                    singleUse: true,\n                    amount: data.amount,\n                    currency: data.currency,\n                    locale: data.locale,\n                    enableShippingAddress: true,\n                    headless: true\n                };\n\n                if (this.displayName) {\n                    this.clientConfig.paypal.displayName = this.displayName;\n                }\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                return this.clientConfig;\n            }\n        });\n    }\n);\n","Magento_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/*global define*/\n\ndefine([\n    'jquery',\n    'Magento_Braintree/js/view/payment/adapter',\n    'Magento_Checkout/js/model/quote',\n    'mage/translate'\n], function ($, braintree, quote, $t) {\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\n        /**\n         * Get code\n         * @returns {String}\n         */\n        getCode: function () {\n            return 'three_d_secure';\n        },\n\n        /**\n         * Validate Braintree payment nonce\n         * @param {Object} context\n         * @returns {Object}\n         */\n        validate: function (context) {\n            var client = braintree.getApiClient(),\n                state = $.Deferred(),\n                totalAmount = quote.totals()['base_grand_total'],\n                billingAddress = quote.billingAddress();\n\n            if (!this.isAmountAvailable(totalAmount) || !this.isCountryAvailable(billingAddress.countryId)) {\n                state.resolve();\n\n                return state.promise();\n            }\n\n            client.verify3DS({\n                amount: totalAmount,\n                creditCard: context.paymentMethodNonce\n            }, function (error, response) {\n                var liability;\n\n                if (error) {\n                    state.reject(error.message);\n\n                    return;\n                }\n\n                liability = {\n                    shifted: response.verificationDetails.liabilityShifted,\n                    shiftPossible: response.verificationDetails.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            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);\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            var 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","Magento_Braintree/js/view/payment/validator-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\n\ndefine([\n    'jquery',\n    'Magento_Ui/js/model/messageList',\n    'Magento_Braintree/js/view/payment/3d-secure'\n], function ($, globalMessageList, verify3DSecure) {\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            var 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) {\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                    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        }\n    };\n});\n","Magento_Braintree/js/view/payment/adapter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine([\n    'jquery',\n    'braintree',\n    'Magento_Ui/js/model/messageList',\n    'mage/translate'\n], function ($, braintree, globalMessageList, $t) {\n    'use strict';\n\n    return {\n        apiClient: null,\n        config: {},\n        checkout: null,\n\n        /**\n         * Get Braintree api client\n         * @returns {Object}\n         */\n        getApiClient: function () {\n            if (!this.apiClient) {\n                this.apiClient = new braintree.api.Client({\n                    clientToken: this.getClientToken()\n                });\n            }\n\n            return this.apiClient;\n        },\n\n        /**\n         * Set configuration\n         * @param {Object} config\n         */\n        setConfig: function (config) {\n            this.config = config;\n        },\n\n        /**\n         * Setup Braintree SDK\n         */\n        setup: function () {\n            if (!this.getClientToken()) {\n                this.showError($t('Sorry, but something went wrong.'));\n            }\n\n            braintree.setup(this.getClientToken(), 'custom', this.config);\n        },\n\n        /**\n         * Get payment name\n         * @returns {String}\n         */\n        getCode: function () {\n            return 'braintree';\n        },\n\n        /**\n         * Get client token\n         * @returns {String|*}\n         */\n        getClientToken: function () {\n\n            return window.checkoutConfig.payment[this.getCode()].clientToken;\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\n        /**\n         * May be triggered on Braintree SDK setup\n         */\n        onReady: function () {}\n    };\n});\n","Magento_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*/\n/*global define*/\ndefine(\n    [\n        'uiComponent',\n        'Magento_Checkout/js/model/payment/renderer-list'\n    ],\n    function (\n        Component,\n        rendererList\n    ) {\n        'use strict';\n\n        var config = window.checkoutConfig.payment,\n            braintreeType = 'braintree',\n            payPalType = 'braintree_paypal';\n\n        if (config[braintreeType].isActive) {\n            rendererList.push(\n                {\n                    type: braintreeType,\n                    component: 'Magento_Braintree/js/view/payment/method-renderer/hosted-fields'\n                }\n            );\n        }\n\n        if (config[payPalType].isActive) {\n            rendererList.push(\n                {\n                    type: payPalType,\n                    component: 'Magento_Braintree/js/view/payment/method-renderer/paypal'\n                }\n            );\n        }\n\n        /** Add view logic here if needed */\n        return Component.extend({});\n    }\n);\n","Magento_Braintree/js/view/payment/method-renderer/cc-form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\ndefine(\n    [\n        'underscore',\n        'jquery',\n        'Magento_Payment/js/view/payment/cc-form',\n        'Magento_Checkout/js/model/quote',\n        'Magento_Braintree/js/view/payment/adapter',\n        'mage/translate',\n        'Magento_Braintree/js/validator',\n        'Magento_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                ccCode: null,\n                ccMessageContainer: null,\n                validatorManager: validatorManager,\n                code: 'braintree',\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\n                    /**\n                     * Triggers on payment nonce receive\n                     * @param {Object} response\n                     */\n                    onPaymentMethodReceived: function (response) {\n                        this.beforePlaceOrder(response);\n                    },\n\n                    /**\n                     * Device data initialization\n                     *\n                     * @param {Object} checkout\n                     */\n                    onReady: function (checkout) {\n                        braintree.checkout = checkout;\n                        braintree.onReady();\n                    },\n\n                    /**\n                     * Triggers on any Braintree error\n                     * @param {Object} response\n                     */\n                    onError: function (response) {\n                        braintree.showError($t('Payment ' + this.getTitle() + ' can\\'t be initialized'));\n                        this.isPlaceOrderActionAllowed(true);\n                        throw response.message;\n                    },\n\n                    /**\n                     * Triggers when customer click \"Cancel\"\n                     */\n                    onCancelled: function () {\n                        this.paymentMethodNonce = null;\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                var 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.restoreMessageContainer();\n                this.restoreCode();\n\n                /**\n                 * Define onReady callback\n                 */\n                braintree.onReady = function () {};\n                this.initBraintree();\n            },\n\n            /**\n             * Restore original message container for cc-form component\n             */\n            restoreMessageContainer: function () {\n                this.messageContainer = this.ccMessageContainer;\n            },\n\n            /**\n             * Restore original code for cc-form component\n             */\n            restoreCode: function () {\n                this.code = this.ccCode;\n            },\n\n            /** @inheritdoc */\n            initChildren: function () {\n                this._super();\n                this.ccMessageContainer = this.messageContainer;\n                this.ccCode = this.code;\n\n                return this;\n            },\n\n            /**\n             * Init config\n             */\n            initClientConfig: function () {\n                // Advanced fraud tools settings\n                if (this.hasFraudProtection()) {\n                    this.clientConfig = _.extend(this.clientConfig, this.kountConfig());\n                }\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             * Init Braintree configuration\n             */\n            initBraintree: function () {\n                var intervalId = setInterval(function () {\n                    // stop loader when frame will be loaded\n                    if ($('#braintree-hosted-field-number').length) {\n                        clearInterval(intervalId);\n                        fullScreenLoader.stopLoader();\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             * @returns {Object}\n             */\n            kountConfig: function () {\n                var config = {\n                    dataCollector: {\n                        kount: {\n                            environment: this.getEnvironment()\n                        }\n                    },\n\n                    /**\n                     * Device data initialization\n                     *\n                     * @param {Object} checkout\n                     */\n                    onReady: function (checkout) {\n                        braintree.checkout = checkout;\n                        this.additionalData['device_data'] = checkout.deviceData;\n                        braintree.onReady();\n                    }\n                };\n\n                if (this.getKountMerchantId()) {\n                    config.dataCollector.kount.merchantId = this.getKountMerchantId();\n                }\n\n                return config;\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                var 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, validator.getCountrySpecificCardTypes(billingCountryId)\n                    );\n                }\n\n                return availableTypes;\n            },\n\n            /**\n             * @returns {Boolean}\n             */\n            hasFraudProtection: function () {\n                return window.checkoutConfig.payment[this.getCode()].hasFraudProtection;\n            },\n\n            /**\n             * @returns {String}\n             */\n            getEnvironment: function () {\n                return window.checkoutConfig.payment[this.getCode()].environment;\n            },\n\n            /**\n             * @returns {String}\n             */\n            getKountMerchantId: function () {\n                return window.checkoutConfig.payment[this.getCode()].kountMerchantId;\n            },\n\n            /**\n             * Get data\n             *\n             * @returns {Object}\n             */\n            getData: function () {\n                var 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             * Set payment nonce\n             * @param {String} paymentMethodNonce\n             */\n            setPaymentMethodNonce: function (paymentMethodNonce) {\n                this.paymentMethodNonce = paymentMethodNonce;\n            },\n\n            /**\n             * Prepare data to place order\n             * @param {Object} data\n             */\n            beforePlaceOrder: function (data) {\n                this.setPaymentMethodNonce(data.nonce);\n                this.placeOrder();\n            },\n\n            /**\n             * Action to place order\n             * @param {String} key\n             */\n            placeOrder: function (key) {\n                var self = this;\n\n                if (key) {\n                    return self._super();\n                }\n                // place order on success validation\n                self.validatorManager.validate(self, function () {\n                    return self.placeOrder('parent');\n                });\n\n                return false;\n            }\n        });\n    }\n);\n","Magento_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*/\n/*global define*/\ndefine([\n    'jquery',\n    'underscore',\n    'Magento_Checkout/js/view/payment/default',\n    'Magento_Braintree/js/view/payment/adapter',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Vault/js/view/payment/vault-enabler',\n    'Magento_Checkout/js/action/create-billing-address',\n    'mage/translate'\n], function (\n    $,\n    _,\n    Component,\n    Braintree,\n    quote,\n    fullScreenLoader,\n    additionalValidators,\n    VaultEnabler,\n    createBillingAddress,\n    $t\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Braintree/payment/paypal',\n            code: 'braintree_paypal',\n            active: false,\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             * PayPal client configuration\n             * {Object}\n             */\n            clientConfig: {\n                dataCollector: {\n                    paypal: true\n                },\n\n                /**\n                 * Triggers when widget is loaded\n                 * @param {Object} checkout\n                 */\n                onReady: function (checkout) {\n                    Braintree.checkout = checkout;\n                    this.additionalData['device_data'] = checkout.deviceData;\n                    this.enableButton();\n                    Braintree.onReady();\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            imports: {\n                onActiveChange: 'active'\n            }\n        },\n\n        /**\n         * Set list of observable attributes\n         * @returns {exports.initObservable}\n         */\n        initObservable: function () {\n            var self = this;\n\n            this._super()\n                .observe(['active', 'isReviewRequired', 'customerEmail']);\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                }\n            });\n\n            quote.shippingAddress.subscribe(function () {\n                if (self.isActive()) {\n                    self.reInitPayPal();\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            var 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            // 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         * @param {String} paymentMethodNonce\n         */\n        setPaymentMethodNonce: function (paymentMethodNonce) {\n            this.paymentMethodNonce = paymentMethodNonce;\n        },\n\n        /**\n         * Update quote billing address\n         * @param {Object}customer\n         * @param {Object}address\n         */\n        setBillingAddress: function (customer, address) {\n            var billingAddress = {\n                street: [address.streetAddress],\n                city: address.locality,\n                postcode: address.postalCode,\n                countryId: address.countryCodeAlpha2,\n                email: customer.email,\n                firstname: customer.firstName,\n                lastname: customer.lastName,\n                telephone: customer.phone\n            };\n\n            billingAddress['region_code'] = address.region;\n            billingAddress = createBillingAddress(billingAddress);\n            quote.billingAddress(billingAddress);\n        },\n\n        /**\n         * Prepare data to place order\n         * @param {Object} data\n         */\n        beforePlaceOrder: function (data) {\n            this.setPaymentMethodNonce(data.nonce);\n\n            if ((this.isRequiredBillingAddress() || quote.billingAddress() === null) &&\n                typeof data.details.billingAddress !== 'undefined'\n            ) {\n                this.setBillingAddress(data.details, data.details.billingAddress);\n            }\n\n            if (this.isSkipOrderReview()) {\n                this.placeOrder();\n            } else {\n                this.customerEmail(data.details.email);\n                this.isReviewRequired(true);\n            }\n        },\n\n        /**\n         * Re-init PayPal Auth Flow\n         */\n        reInitPayPal: function () {\n            if (Braintree.checkout) {\n                Braintree.checkout.teardown(function () {\n                    Braintree.checkout = null;\n                });\n            }\n\n            this.disableButton();\n            this.clientConfig.paypal.amount = this.grandTotalAmount;\n            this.clientConfig.paypal.shippingAddressOverride = this.getShippingAddress();\n\n            Braintree.setConfig(this.clientConfig);\n            Braintree.setup();\n        },\n\n        /**\n         * Get locale\n         * @returns {String}\n         */\n        getLocale: function () {\n            return window.checkoutConfig.payment[this.getCode()].locale;\n        },\n\n        /**\n         * Is shipping address can be editable on PayPal side\n         * @returns {Boolean}\n         */\n        isAllowOverrideShippingAddress: function () {\n            return window.checkoutConfig.payment[this.getCode()].isAllowShippingAddressOverride;\n        },\n\n        /**\n         * Is billing address required from PayPal side\n         * @returns {Boolean}\n         */\n        isRequiredBillingAddress: function () {\n            return window.checkoutConfig.payment[this.getCode()].isRequiredBillingAddress;\n        },\n\n        /**\n         * Get configuration for PayPal\n         * @returns {Object}\n         */\n        getPayPalConfig: function () {\n            var totals = quote.totals(),\n                config = {},\n                isActiveVaultEnabler = this.isActiveVault();\n\n            config.paypal = {\n                container: 'paypal-container',\n                singleUse: !isActiveVaultEnabler,\n                headless: true,\n                amount: this.grandTotalAmount,\n                currency: totals['base_currency_code'],\n                locale: this.getLocale(),\n                enableShippingAddress: 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            config.paypal.shippingAddressOverride = this.getShippingAddress();\n\n            if (this.getMerchantName()) {\n                config.paypal.displayName = this.getMerchantName();\n            }\n\n            return config;\n        },\n\n        /**\n         * Get shipping address\n         * @returns {Object}\n         */\n        getShippingAddress: function () {\n            var address = quote.shippingAddress();\n\n            if (_.isNull(address.postcode) || _.isUndefined(address.postcode)) {\n                return {};\n            }\n\n            return {\n                recipientName: address.firstname + ' ' + address.lastname,\n                streetAddress: address.street[0],\n                locality: address.city,\n                countryCodeAlpha2: address.countryId,\n                postalCode: address.postcode,\n                region: address.regionCode,\n                phone: address.telephone,\n                editable: this.isAllowOverrideShippingAddress()\n            };\n        },\n\n        /**\n         * Get merchant name\n         * @returns {String}\n         */\n        getMerchantName: 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                }\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         * @returns {String}\n         */\n        getPaymentAcceptanceMarkSrc: function () {\n\n            return window.checkoutConfig.payment[this.getCode()].paymentAcceptanceMarkSrc;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getVaultCode: function () {\n            return window.checkoutConfig.payment[this.getCode()].vaultCode;\n        },\n\n        /**\n         * Check if need to skip order review\n         * @returns {Boolean}\n         */\n        isSkipOrderReview: function () {\n            return window.checkoutConfig.payment[this.getCode()].skipOrderReview;\n        },\n\n        /**\n         * Checks if vault is active\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();\n        },\n\n        /**\n         * Triggers when customer click \"Continue to PayPal\" button\n         */\n        payWithPayPal: function () {\n            if (!additionalValidators.validate()) {\n                return;\n            }\n\n            try {\n                Braintree.checkout.paypal.initAuthFlow();\n            } catch (e) {\n                this.messageContainer.addErrorMessage({\n                    message: $t('Payment ' + this.getTitle() + ' can\\'t be initialized.')\n                });\n            }\n        },\n\n        /**\n         * Get button title\n         * @returns {String}\n         */\n        getButtonTitle: function () {\n            return this.isSkipOrderReview() ? 'Pay with PayPal' : 'Continue to PayPal';\n        },\n\n        /**\n         * Get button id\n         * @returns {String}\n         */\n        getButtonId: function () {\n            return this.getCode() + (this.isSkipOrderReview() ? '_pay_with' : '_continue_to');\n        }\n    });\n});\n","Magento_Braintree/js/view/payment/method-renderer/hosted-fields.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n/*global define*/\n\ndefine([\n    'jquery',\n    'Magento_Braintree/js/view/payment/method-renderer/cc-form',\n    'Magento_Braintree/js/validator',\n    'Magento_Vault/js/view/payment/vault-enabler',\n    'mage/translate'\n], function ($, Component, validator, VaultEnabler, $t) {\n    'use strict';\n\n    return Component.extend({\n\n        defaults: {\n            template: 'Magento_Braintree/payment/form',\n            clientConfig: {\n\n                /**\n                 * {String}\n                 */\n                id: 'co-transparent-form-braintree'\n            },\n            isValidCardNumber: false\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         * Init config\n         */\n        initClientConfig: function () {\n            this._super();\n\n            // Hosted fields settings\n            this.clientConfig.hostedFields = this.getHostedFields();\n        },\n\n        /**\n         * @returns {Object}\n         */\n        getData: function () {\n            var data = this._super();\n\n            this.vaultEnabler.visitAdditionalData(data);\n\n            return data;\n        },\n\n        /**\n         * @returns {Boolean}\n         */\n        isVaultEnabled: function () {\n            return this.vaultEnabler.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                    },\n                    expirationMonth: {\n                        selector: self.getSelector('expirationMonth'),\n                        placeholder: $t('MM')\n                    },\n                    expirationYear: {\n                        selector: self.getSelector('expirationYear'),\n                        placeholder: $t('YY')\n                    }\n                };\n\n            if (self.hasVerification()) {\n                fields.cvv = {\n                    selector: self.getSelector('cc_cid')\n                };\n            }\n\n            /**\n             * Triggers on Hosted Field changes\n             * @param {Object} event\n             * @returns {Boolean}\n             */\n            fields.onFieldEvent = function (event) {\n                if (event.isEmpty === false) {\n                    self.validateCardType();\n                }\n\n                if (event.type !== 'fieldStateChange') {\n                    return false;\n                }\n\n                // Handle a change in validation or card type\n                if (event.target.fieldKey === 'number') {\n                    self.selectedCardType(null);\n                }\n\n                if (event.target.fieldKey === 'number' && event.card) {\n                    self.isValidCardNumber = event.isValid;\n                    self.selectedCardType(\n                        validator.getMageCardType(event.card.type, self.getCcAvailableTypes())\n                    );\n                }\n            };\n\n            return fields;\n        },\n\n        /**\n         * Validate current credit card type\n         * @returns {Boolean}\n         */\n        validateCardType: function () {\n            var $selector = $(this.getSelector('cc_number')),\n                invalidClass = 'braintree-hosted-fields-invalid';\n\n            $selector.removeClass(invalidClass);\n\n            if (this.selectedCardType() === null || !this.isValidCardNumber) {\n                $(this.getSelector('cc_number')).addClass(invalidClass);\n\n                return false;\n            }\n\n            return true;\n        },\n\n        /**\n         * Returns state of place order button\n         * @returns {Boolean}\n         */\n        isButtonActive: function () {\n            return this.isActive() && this.isPlaceOrderActionAllowed();\n        },\n\n        /**\n         * Trigger order placing\n         */\n        placeOrderClick: function () {\n            if (this.validateCardType()) {\n                this.isPlaceOrderActionAllowed(false);\n                $(this.getSelector('submit')).trigger('click');\n            }\n        },\n\n        /**\n         * @returns {String}\n         */\n        getVaultCode: function () {\n            return window.checkoutConfig.payment[this.getCode()].ccVaultCode;\n        }\n    });\n});\n","Magento_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*/\n/*global define*/\ndefine([\n    'jquery',\n    'Magento_Vault/js/view/payment/method-renderer/vault',\n    'Magento_Braintree/js/view/payment/adapter',\n    'Magento_Ui/js/model/messageList',\n    'Magento_Checkout/js/model/full-screen-loader'\n], function ($, VaultComponent, Braintree, globalMessageList, fullScreenLoader) {\n    'use strict';\n\n    return VaultComponent.extend({\n        defaults: {\n            template: 'Magento_Vault/payment/form',\n            modules: {\n                hostedFields: '${ $.parentName }.braintree'\n            }\n        },\n\n        /**\n         * Get last 4 digits of card\n         * @returns {String}\n         */\n        getMaskedCard: function () {\n            return this.details.maskedCC;\n        },\n\n        /**\n         * Get expiration date\n         * @returns {String}\n         */\n        getExpirationDate: function () {\n            return this.details.expirationDate;\n        },\n\n        /**\n         * Get card type\n         * @returns {String}\n         */\n        getCardType: function () {\n            return this.details.type;\n        },\n\n        /**\n         * Place order\n         */\n        placeOrder: function () {\n            var self = this;\n\n            /**\n             * Define onReady callback\n             */\n            Braintree.onReady = function () {\n                self.getPaymentMethodNonce();\n            };\n            self.hostedFields(function (formComponent) {\n                formComponent.initBraintree();\n            });\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.hostedFields(function (formComponent) {\n                        formComponent.setPaymentMethodNonce(response.paymentMethodNonce);\n                        formComponent.additionalData['public_hash'] = self.publicHash;\n                        formComponent.code = self.code;\n                        formComponent.messageContainer = self.messageContainer;\n                        formComponent.placeOrder();\n                    });\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","Magento_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*/\n/*global define*/\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: 'Magento_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","Magento_Theme/menu.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * Simple Navigation with replacing old handlers.\n *\n * @param {String} id - id of ul element with navigation lists\n * @param {Object} settings - object with settings\n */\n/**\n * global mainNav\n *\n * @deprecated\n * @see lib/web/mage/menu.js\n */\ndefine([\n    'prototype'\n], function () {\n    'use strict';\n\n    /**\n     * Main nav.\n     */\n    window.mainNav = function () {\n        var main = {\n            'obj_nav':   $(arguments[0]) || $('nav'),\n            settings:  {\n                'show_delay': 0,\n                'hide_delay': 0,\n                _ie6: /MSIE 6.+Win/.test(navigator.userAgent),\n                _ie7: /MSIE 7.+Win/.test(navigator.userAgent)\n            },\n\n            /**\n             * @param {Object} obj\n             * @param {*} level\n             */\n            init: function (obj, level) {\n                obj.lists = obj.childElements();\n                obj.lists.each(function (el, ind) {\n                    main.handlNavElement(el);\n\n                    if ((main.settings._ie6 || main.settings._ie7) && level) {\n                        main.ieFixZIndex(el, ind, obj.lists.size());\n                    }\n                });\n\n                if (main.settings._ie6 && !level) {\n                    document.execCommand('BackgroundImageCache', false, true);\n                }\n            },\n\n            /**\n             * @param {Object} list\n             */\n            handlNavElement: function (list) {\n                if (list !== undefined) {\n\n                    /**\n                     * On mouse over.\n                     */\n                    list.onmouseover = function () {\n                        main.fireNavEvent(this, true);\n                    };\n\n                    /**\n                     * On mouse out.\n                     */\n                    list.onmouseout = function () {\n                        main.fireNavEvent(this, false);\n                    };\n\n                    if (list.down('ul')) {\n                        main.init(list.down('ul'), true);\n                    }\n                }\n            },\n\n            /**\n             * @param {HTMLElement} el\n             * @param {*} i\n             * @param {*} l\n             */\n            ieFixZIndex: function (el, i, l) {\n                if (el.tagName.toString().toLowerCase().indexOf('iframe') == -1) { //eslint-disable-line eqeqeq\n                    el.style.zIndex = l - i;\n                } else {\n                    el.onmouseover = 'null';\n                    el.onmouseout = 'null';\n                }\n            },\n\n            /**\n             * @param {Object} elm\n             * @param {*} ev\n             */\n            fireNavEvent: function (elm, ev) {\n                if (ev) {\n                    elm.addClassName('over');\n                    elm.down('a').addClassName('over');\n\n                    if (elm.childElements()[1]) {\n                        main.show(elm.childElements()[1]);\n                    }\n                } else {\n                    elm.removeClassName('over');\n                    elm.down('a').removeClassName('over');\n\n                    if (elm.childElements()[1]) {\n                        main.hide(elm.childElements()[1]);\n                    }\n                }\n            },\n\n            /**\n             * @param {Object} subElm\n             */\n            show: function (subElm) {\n                if (subElm['hide_time_id']) {\n                    clearTimeout(subElm['hide_time_id']);\n                }\n                subElm['show_time_id'] = setTimeout(function () {\n                    if (!subElm.hasClassName('shown-sub')) {\n                        subElm.addClassName('shown-sub');\n                    }\n                }, main.settings['show_delay']);\n            },\n\n            /**\n             * @param {Object} subElm\n             */\n            hide: function (subElm) {\n                if (subElm['show_time_id']) {\n                    clearTimeout(subElm['show_time_id']);\n                }\n                subElm['hide_time_id'] = setTimeout(function () {\n                    if (subElm.hasClassName('shown-sub')) {\n                        subElm.removeClassName('shown-sub');\n                    }\n                }, main.settings['hide_delay']);\n            }\n\n        };\n\n        if (arguments[1]) {\n            main.settings = Object.extend(main.settings, arguments[1]);\n        }\n\n        if (main['obj_nav']) {\n            main.init(main['obj_nav'], false);\n        }\n    };\n\n    document.observe('dom:loaded', function () {\n        //run navigation without delays and with default id=\"#nav\"\n        //mainNav();\n\n        //run navigation with delays\n        window.mainNav('nav', {\n            'show_delay': '100',\n            'hide_delay': '100'\n        });\n    });\n});\n","Magento_Theme/js/responsive.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'matchMedia',\n    'mage/tabs',\n    'domReady!'\n], function ($, mediaCheck) {\n    'use strict';\n\n    mediaCheck({\n        media: '(min-width: 768px)',\n\n        /**\n         * Switch to Desktop Version.\n         */\n        entry: function () {\n            var galleryElement;\n\n            (function () {\n\n                var productInfoMain = $('.product-info-main'),\n                    productInfoAdditional = $('#product-info-additional');\n\n                if (productInfoAdditional.length) {\n                    productInfoAdditional.addClass('hidden');\n                    productInfoMain.removeClass('responsive');\n                }\n\n            })();\n\n            galleryElement = $('[data-role=media-gallery]');\n\n            if (galleryElement.length && galleryElement.data('mageZoom')) {\n                galleryElement.zoom('enable');\n            }\n\n            if (galleryElement.length && galleryElement.data('mageGallery')) {\n                galleryElement.gallery('option', 'disableLinks', true);\n                galleryElement.gallery('option', 'showNav', false);\n                galleryElement.gallery('option', 'showThumbs', true);\n            }\n        },\n\n        /**\n         * Switch to Mobile Version.\n         */\n        exit: function () {\n            var galleryElement;\n\n            $('.action.toggle.checkout.progress').on('click.gotoCheckoutProgress', function () {\n                var myWrapper = '#checkout-progress-wrapper';\n\n                scrollTo(myWrapper + ' .title');\n                $(myWrapper + ' .title').addClass('active');\n                $(myWrapper + ' .content').show();\n            });\n\n            $('body').on('click.checkoutProgress', '#checkout-progress-wrapper .title', function () {\n                $(this).toggleClass('active');\n                $('#checkout-progress-wrapper .content').toggle();\n            });\n\n            galleryElement = $('[data-role=media-gallery]');\n\n            setTimeout(function () {\n                if (galleryElement.length && galleryElement.data('mageZoom')) {\n                    galleryElement.zoom('disable');\n                }\n\n                if (galleryElement.length && galleryElement.data('mageGallery')) {\n                    galleryElement.gallery('option', 'disableLinks', false);\n                    galleryElement.gallery('option', 'showNav', true);\n                    galleryElement.gallery('option', 'showThumbs', false);\n                }\n            }, 2000);\n        }\n    });\n});\n","Magento_Theme/js/truncate.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * JQuery UI Widget declaration: 'mage.truncateOptions'\n *\n * @deprecated since version 2.2.0\n */\ndefine([\n    'jquery',\n    'jquery/ui'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.truncateOptions', {\n        options: {\n            detailsLink: 'a.details',\n            mouseEvents: 'mouseover mouseout',\n            truncatedFullValue: 'div.truncated.full.value'\n        },\n\n        /**\n         * Establish the event handler for mouse events on the appropriate elements.\n         *\n         * @private\n         */\n        _create: function () {\n            this.element.on(this.options.mouseEvents, $.proxy(this._toggleShow, this))\n                .find(this.options.detailsLink).on(this.options.mouseEvents, $.proxy(this._toggleShow, this));\n        },\n\n        /**\n         * Toggle the \"show\" class on the associated element.\n         *\n         * @private\n         * @param {jQuery.Event} event - Mouse over/out event.\n         */\n        _toggleShow: function (event) {\n            $(event.currentTarget).find(this.options.truncatedFullValue).toggleClass('show');\n        }\n    });\n});\n","Magento_Theme/js/theme.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/smart-keyboard-handler',\n    'mage/mage',\n    'mage/ie-class-fixer',\n    'domReady!'\n], function ($, keyboardHandler) {\n    'use strict';\n\n    if ($('body').hasClass('checkout-cart-index')) {\n        if ($('#co-shipping-method-form .fieldset.rates').length > 0 &&\n            $('#co-shipping-method-form .fieldset.rates :checked').length === 0\n        ) {\n            $('#block-shipping').on('collapsiblecreate', function () {\n                $('#block-shipping').collapsible('forceActivate');\n            });\n        }\n    }\n\n    $('.cart-summary').mage('sticky', {\n        container: '#maincontent'\n    });\n\n    $('.panel.header > .header.links').clone().appendTo('#store\\\\.links');\n\n    keyboardHandler.apply();\n});\n","Magento_Theme/js/row-builder.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * JQuery UI Widget declaration: 'mage.rowBuilder'\n *\n * @api\n */\ndefine([\n    'jquery',\n    'mage/template',\n    'jquery/ui'\n], function ($, mageTemplate) {\n    'use strict';\n\n    $.widget('mage.rowBuilder', {\n\n        /**\n         * options with default values for setting up the template\n         */\n        options: {\n            //Default template options\n            rowTemplate: '#template-registrant',\n            rowContainer: '#registrant-container',\n            //Row index used by the template rows.\n            rowIndex: 0,\n            //Row count: Should not be set externally\n            rowCount: 0,\n            rowParentElem: '<li></li>',\n            rowContainerClass: 'fields',\n            addRowBtn: '#add-registrant-button',\n            btnRemoveIdPrefix: 'btn-remove',\n            btnRemoveSelector: '.btn-remove',\n            rowIdPrefix: 'row',\n            //This class is added to rows added after the first one. Adds the dotted separator\n            additionalRowClass: 'add-row',\n\n            /*\n             This is provided during widget instantiation. eg :\n             formDataPost : {\"formData\":formData,\"templateFields\":['field1-name','field2-name'] }\n             -\"formData\" is the multi-dimensional array of form field values : [['a','b'],['c','b']]\n             received from the server and encoded\n             -\"templateFields\" are the input fields in the template with index suffixed after the field name\n             eg field1-name{index}\n             */\n            formDataPost: null,\n            //Default selectors for add element of a template\n            addEventSelector: 'button',\n            //Default selectors for remove markup elements of a template\n            remEventSelector: 'a',\n            //This option allows adding first row delete option and a row separator\n            hideFirstRowAddSeparator: true,\n            //Max rows - This option should be set when instantiating the widget\n            maxRows: 1000,\n            maxRowsMsg: '#max-registrant-message'\n        },\n\n        /**\n         * Initialize create\n         * @private\n         */\n        _create: function () {\n            this.rowTemplate = mageTemplate(this.options.rowTemplate);\n\n            this.options.rowCount = this.options.rowIndex = 0;\n\n            //On document ready related tasks\n            $($.proxy(this.ready, this));\n\n            //Binding template-wide events handlers for adding and removing rows\n            this.element.on(\n                'click',\n                this.options.addEventSelector + this.options.addRowBtn,\n                $.proxy(this.handleAdd, this)\n            );\n            this.element.on(\n                'click',\n                this.options.remEventSelector + this.options.btnRemoveSelector,\n                $.proxy(this.handleRemove, this)\n            );\n        },\n\n        /**\n         * Initialize template\n         * @public\n         */\n        ready: function () {\n            if (this.options.formDataPost &&\n                this.options.formDataPost.formData &&\n                this.options.formDataPost.formData.length\n            ) {\n                this.processFormDataArr(this.options.formDataPost);\n            } else if (this.options.rowIndex === 0 && this.options.maxRows !== 0) {\n                //If no form data , then add default row\n                this.addRow(0);\n            }\n        },\n\n        /**\n         * Process and loop through all row data to create preselected values. This is used for any error on submit.\n         * For complex implementations the inheriting widget can override this behavior\n         * @public\n         * @param {Object} formDataArr\n         */\n        processFormDataArr: function (formDataArr) {\n            var formData = formDataArr.formData,\n                templateFields = formDataArr.templateFields,\n                formRow,\n                i, j;\n\n            for (i = this.options.rowIndex = 0; i < formData.length; this.options.rowIndex = i++) {\n                this.addRow(i);\n\n                formRow = formData[i];\n\n                for (j = 0; j < formRow.length; j++) {\n                    this.setFieldById(templateFields[j] + i, formRow[j]);\n                }\n            }\n\n        },\n\n        /**\n         * Initialize and create markup for template row. Add it to the parent container.\n         * The template processing will substitute row index at all places marked with _index_ in the template\n         * using the template\n         * @public\n         * @param {Number} index - current index/count of the created template. This will be used as the id\n         * @return {*}\n         */\n        addRow: function (index) {\n            var row = $(this.options.rowParentElem),\n                tmpl;\n\n            row.addClass(this.options.rowContainerClass).attr('id', this.options.rowIdPrefix + index);\n\n            tmpl = this.rowTemplate({\n                data: {\n                    _index_: index\n                }\n            });\n\n            $(tmpl).appendTo(row);\n\n            $(this.options.rowContainer).append(row).trigger('contentUpdated');\n\n            row.addClass(this.options.additionalRowClass);\n\n            //Remove 'delete' link and additionalRowClass for first row\n            if (this.options.rowIndex === 0 && this.options.hideFirstRowAddSeparator) {\n                $('#' + this._esc(this.options.btnRemoveIdPrefix) + '0').remove();\n                $('#' + this._esc(this.options.rowIdPrefix) + '0').removeClass(this.options.additionalRowClass);\n            }\n\n            this.maxRowCheck(++this.options.rowCount);\n\n            return row;\n        },\n\n        /**\n         * Remove return item information row\n         * @public\n         * @param {*} rowIndex - return item information row index\n         * @return {Boolean}\n         */\n        removeRow: function (rowIndex) {\n            $('#' + this._esc(this.options.rowIdPrefix) + rowIndex).remove();\n            this.maxRowCheck(--this.options.rowCount);\n\n            return false;\n        },\n\n        /**\n         * Function to check if maximum rows are exceeded and render/hide maxMsg and Add btn\n         * @public\n         * @param {Number} rowIndex\n         */\n        maxRowCheck: function (rowIndex) {\n            var addRowBtn = $(this.options.addRowBtn),\n                maxRowMsg = $(this.options.maxRowsMsg);\n\n            //liIndex starts from 0\n            if (rowIndex >= this.options.maxRows) {\n                addRowBtn.hide();\n                maxRowMsg.show();\n            } else if (addRowBtn.is(':hidden')) {\n                addRowBtn.show();\n                maxRowMsg.hide();\n            }\n        },\n\n        /**\n         * Set the value on given element\n         * @public\n         * @param {String} domId\n         * @param {String} value\n         */\n        setFieldById: function (domId, value) {\n            var x = $('#' + this._esc(domId));\n\n            if (x.length) {\n\n                if (x.is(':checkbox')) {\n                    x.attr('checked', true);\n                } else if (x.is('option')) {\n                    x.attr('selected', 'selected');\n                } else {\n                    x.val(value);\n                }\n            }\n        },\n\n        /**\n         * Delegated handler for adding a row\n         * @public\n         * @return {Boolean}\n         */\n        handleAdd: function () {\n            this.addRow(++this.options.rowIndex);\n\n            return false;\n        },\n\n        /**\n         * Delegated handler for removing a selected row\n         * @public\n         * @param {Object} e - Native event object\n         * @return {Boolean}\n         */\n        handleRemove: function (e) {\n            this.removeRow($(e.currentTarget).closest('[id^=\"' + this.options.btnRemoveIdPrefix + '\"]')\n                .attr('id').replace(this.options.btnRemoveIdPrefix, ''));\n\n            return false;\n        },\n\n        /**\n         * Utility function to add escape chars for jquery selector strings\n         * @private\n         * @param {String} str - String to be processed\n         * @return {String}\n         */\n        _esc: function (str) {\n            return str ? str.replace(/([ ;&,.+*~\\':\"!\\^$\\[\\]()=>|\\/@])/g, '\\\\$1') : str;\n        }\n    });\n\n    return $.mage.rowBuilder;\n});\n","Magento_Theme/js/model/breadcrumb-list.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","Magento_Theme/js/view/add-home-breadcrumb.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* eslint-disable max-nested-callbacks, no-undef */\ndefine([\n    'jquery',\n    'Magento_Theme/js/model/breadcrumb-list',\n    'mage/translate'\n], function ($, breadcrumbList) {\n    'use strict';\n\n    /**\n     * @return {Object}\n     */\n    var homeCrumb = function () {\n        return {\n            name: 'home',\n            label: $.mage.__('Home'),\n            title: $.mage.__('Go to Home Page'),\n            link: BASE_URL || ''\n        };\n    };\n\n    return function (breadcrumb) {\n\n        breadcrumbList.unshift(homeCrumb());\n\n        return breadcrumb;\n    };\n});\n","Magento_Theme/js/view/breadcrumbs.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    'Magento_Theme/js/model/breadcrumb-list',\n    'text!Magento_Theme/templates/breadcrumbs.html',\n    'jquery/ui'\n], function ($, mageTemplate, breadcrumbList, tpl) {\n    'use strict';\n\n    /**\n     * Breadcrumb Widget.\n     */\n    $.widget('mage.breadcrumbs', {\n\n        /** @inheritdoc */\n        _init: function () {\n            this._super();\n            this._render();\n        },\n\n        /**\n         * Render breadcrumb.\n         *\n         * @private\n         */\n        _render: function () {\n            var html,\n                crumbs = breadcrumbList,\n                template = mageTemplate(tpl);\n\n            this._decorate(crumbs);\n\n            html = template({\n                'breadcrumbs': crumbs\n            });\n\n            if (html.length) {\n                $(this.element).html(html);\n            }\n        },\n\n        /**\n         * Decorate list.\n         *\n         * @param {Array} list\n         * @private\n         */\n        _decorate: function (list) {\n\n            if (list.length) {\n                list[0].first = true;\n            }\n\n            if (list.length > 1) {\n                list[list.length - 1].last = true;\n            }\n        }\n    });\n\n    return $.mage.breadcrumbs;\n});\n","Magento_Theme/js/view/messages.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'uiComponent',\n    'Magento_Customer/js/customer-data',\n    'underscore',\n    'jquery/jquery-storageapi'\n], function ($, Component, customerData, _) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            cookieMessages: [],\n            messages: []\n        },\n\n        /**\n         * Extends Component object by storage observable messages.\n         */\n        initialize: function () {\n            this._super();\n\n            this.cookieMessages = _.unique($.cookieStorage.get('mage-messages'), 'text');\n            this.messages = customerData.get('messages').extend({\n                disposableCustomerData: 'messages'\n            });\n\n            // Force to clean obsolete messages\n            if (!_.isEmpty(this.messages().messages)) {\n                customerData.set('messages', {});\n            }\n\n            $.cookieStorage.set('mage-messages', '');\n        }\n    });\n});\n","mage/decorate.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable strict */\n(function (factory) {\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery',\n            'mage/translate'\n        ], factory);\n    } else {\n        factory(jQuery);\n    }\n}(function ($) {\n    var methods = {\n        /**\n         * Decorate a list (e.g. a <ul> containing <li>) recursively if specified.\n         * @param {Boolean} isRecursive\n         */\n        list: function (isRecursive) {\n            return this.each(function () {\n                var list = $(this),\n                    items;\n\n                if (list.length > 0) {\n                    items = typeof isRecursive === undefined || isRecursive ?\n                        list.find('li') :\n                        list.children();\n                    items.decorate('generic', ['odd', 'even', 'last']);\n                }\n            });\n        },\n\n        /**\n         * Annotate a set of DOM elements with decorator classes.\n         * @param {Array} decoratorParams\n         */\n        generic: function (decoratorParams) {\n            var elements = $(this),\n                allSupportedParams;\n\n            if (elements) {\n                allSupportedParams = {\n                    even: 'odd', // Flip jQuery odd/even so that index 0 is odd.\n                    odd: 'even',\n                    last: 'last',\n                    first: 'first'\n                };\n\n                decoratorParams = decoratorParams || allSupportedParams;\n\n                $.each(decoratorParams, function (index, param) {\n                    if (param === 'even' || param === 'odd') {\n                        elements.filter(':' + param).removeClass('odd even').addClass(allSupportedParams[param]);\n                    } else {\n                        elements.filter(':' + param).addClass(allSupportedParams[param]);\n                    }\n                });\n            }\n\n            return this;\n        },\n\n        /**\n         * Decorate DOM elements in an HTML table with specified classes.\n         * @param {Object} instanceOptions\n         */\n        table: function (instanceOptions) {\n            return this.each(function () {\n                var table = $(this),\n                    options;\n\n                if (table.length > 0) {\n                    options = {\n                        'tbody': false,\n                        'tbody tr': ['odd', 'even', 'first', 'last'],\n                        'thead tr': ['first', 'last'],\n                        'tfoot tr': ['first', 'last'],\n                        'tr td': ['last']\n                    };\n\n                    $.extend(options, instanceOptions || {});\n\n                    $.each(options, function (key, value) {\n                        if (options[key]) {\n                            if (key === 'tr td') {\n                                $.each(table.find('tr'), function () {\n                                    $(this).find('td').decorate('generic', options['tr td']);\n                                });\n                            } else {\n                                table.find(key).decorate('generic', value);\n                            }\n                        }\n                    });\n                }\n            });\n        },\n\n        /**\n         * Annotate data list elements with CSS classes.\n         */\n        dataList: function () {\n            return this.each(function () {\n                var list = $(this);\n\n                if (list) {\n                    list.find('dt').decorate('generic', ['odd', 'even', 'last']);\n                    list.find('dd').decorate('generic', ['odd', 'even', 'last']);\n                }\n            });\n        }\n    };\n\n    /**\n     * @param {String} method\n     * @return {*}\n     */\n    $.fn.decorate = function (method) {\n        var message;\n\n        if (methods[method]) {\n            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n        } else if (typeof method === 'object' || !method) {\n            return methods.init.apply(this, arguments);\n        }\n\n        message = $.mage.__('Method %s does not exist on jQuery.decorate');\n        $.error(message.replace('%s', method));\n    };\n}));\n","mage/accordion.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/tabs'\n], function ($, tabs) {\n    'use strict';\n\n    $.widget('mage.accordion', tabs, {\n        options: {\n            active: [0],\n            multipleCollapsible: false,\n            openOnFocus: false\n        },\n\n        /**\n         * @private\n         */\n        _callCollapsible: function () {\n            var self = this,\n                disabled = false,\n                active = false;\n\n            if (typeof this.options.active === 'string') {\n                this.options.active = this.options.active.split(' ').map(function (item) {\n                    return parseInt(item, 10);\n                });\n            }\n\n            $.each(this.collapsibles, function (i) {\n                disabled = active = false;\n\n                if ($.inArray(i, self.options.disabled) !== -1) {\n                    disabled = true;\n                }\n\n                if ($.inArray(i, self.options.active) !== -1) {\n                    active = true;\n                }\n                self._instantiateCollapsible(this, i, active, disabled);\n            });\n        },\n\n        /**\n         * Overwrites default functionality to provide the option to activate/deactivate multiple sections simultaneous\n         * @param {*} action\n         * @param {*} index\n         * @private\n         */\n        _toggleActivate: function (action, index) {\n            var self = this;\n\n            if ($.isArray(index && this.options.multipleCollapsible)) {\n                $.each(index, function () {\n                    self.collapsibles.eq(this).collapsible(action);\n                });\n            } else if (index === undefined && this.options.multipleCollapsible) {\n                this.collapsibles.collapsible(action);\n            } else {\n                this._super(action, index);\n            }\n        },\n\n        /**\n         * If the Accordion allows multiple section to be active at the same time, if deep linking is used\n         * sections that don't contain the id from anchor shouldn't be closed, otherwise the accordion uses the\n         * tabs behavior\n         * @private\n         */\n        _handleDeepLinking: function () {\n            if (!this.options.multipleCollapsible) {\n                this._super();\n            }\n        },\n\n        /**\n         * Prevent default behavior that closes the other sections when one gets activated if the Accordion allows\n         * multiple sections simultaneous\n         * @private\n         */\n        _closeOthers: function () {\n            if (!this.options.multipleCollapsible) {\n                this._super();\n            }\n            $.each(this.collapsibles, function () {\n                $(this).on('beforeOpen', function () {\n                    var section = $(this);\n\n                    section.addClass('allow').prevAll().addClass('allow');\n                    section.nextAll().removeClass('allow');\n                });\n            });\n        }\n    });\n\n    return $.mage.accordion;\n});\n","mage/multiselect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'jquery',\n    'text!mage/multiselect.html',\n    'Magento_Ui/js/modal/alert',\n    'jquery/ui',\n    'jquery/editableMultiselect/js/jquery.multiselect'\n], function (_, $, searchTemplate, alert) {\n    'use strict';\n\n    $.widget('mage.multiselect2', {\n        options: {\n            mselectContainer: 'section.mselect-list',\n            mselectItemsWrapperClass: 'mselect-items-wrapper',\n            mselectCheckedClass: 'mselect-checked',\n            containerClass: 'paginated',\n            searchInputClass: 'admin__action-multiselect-search',\n            selectedItemsCountClass: 'admin__action-multiselect-items-selected',\n            currentPage: 1,\n            lastAppendValue: 0,\n            updateDelay: 1000,\n            optionsLoaded: false\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            $.fn.multiselect.call(this.element, this.options);\n        },\n\n        /** @inheritdoc */\n        _init: function () {\n            this.domElement = this.element.get(0);\n\n            this.$container = $(this.options.mselectContainer);\n            this.$wrapper = this.$container.find('.' + this.options.mselectItemsWrapperClass);\n            this.$item = this.$wrapper.find('div').first();\n            this.selectedValues = [];\n            this.values = {};\n\n            this.$container.addClass(this.options.containerClass).prepend(searchTemplate);\n            this.$input = this.$container.find('.' + this.options.searchInputClass);\n            this.$selectedCounter = this.$container.find('.' + this.options.selectedItemsCountClass);\n            this.filter = '';\n\n            if (this.domElement.options.length) {\n                this._setLastAppendOption(this.domElement.options[this.domElement.options.length - 1].value);\n            }\n\n            this._initElement();\n            this._events();\n        },\n\n        /**\n         * Leave only saved/selected options in select element.\n         *\n         * @private\n         */\n        _initElement: function () {\n            this.element.empty();\n            _.each(this.options.selectedValues, function (value) {\n                this._createSelectedOption({\n                    value: value,\n                    label: value\n                });\n            }, this);\n        },\n\n        /**\n         * Attach required events.\n         *\n         * @private\n         */\n        _events: function () {\n            var onKeyUp = _.debounce(this.onKeyUp, this.options.updateDelay);\n\n            _.bindAll(this, 'onScroll', 'onCheck', 'onOptionsChange');\n\n            this.$wrapper.on('scroll', this.onScroll);\n            this.$wrapper.on('change.mselectCheck', '[type=checkbox]', this.onCheck);\n            this.$input.on('keyup', _.bind(onKeyUp, this));\n            this.element.on('change.hiddenSelect', this.onOptionsChange);\n        },\n\n        /**\n         * Behaves multiselect scroll.\n         */\n        onScroll: function () {\n            var height = this.$wrapper.height(),\n                scrollHeight = this.$wrapper.prop('scrollHeight'),\n                scrollTop = Math.ceil(this.$wrapper.prop('scrollTop'));\n\n            if (!this.options.optionsLoaded && scrollHeight - height <= scrollTop) {\n                this.loadOptions();\n            }\n        },\n\n        /**\n         * Behaves keyup event on input search\n         */\n        onKeyUp: function () {\n            if (this.getSearchCriteria() === this.filter) {\n                return false;\n            }\n\n            this.setFilter();\n            this.clearMultiselectOptions();\n            this.setCurrentPage(0);\n            this.loadOptions();\n        },\n\n        /**\n         * Callback for select change event\n         */\n        onOptionsChange: function () {\n            this.selectedValues = _.map(this.domElement.options, function (option) {\n                this.values[option.value] = true;\n\n                return option.value;\n            }, this);\n\n            this._updateSelectedCounter();\n        },\n\n        /**\n         * Overrides native check behaviour.\n         *\n         * @param {Event} event\n         */\n        onCheck: function (event) {\n            var checkbox = event.target,\n                option = {\n                    value: checkbox.value,\n                    label: $(checkbox).parent('label').text()\n                };\n\n            checkbox.checked ? this._createSelectedOption(option) : this._removeSelectedOption(option);\n            event.stopPropagation();\n        },\n\n        /**\n         * Show error message.\n         *\n         * @param {String} message\n         */\n        onError: function (message) {\n            alert({\n                content: message\n            });\n        },\n\n        /**\n         * Updates current filter state.\n         */\n        setFilter: function () {\n            this.filter = this.getSearchCriteria() || '';\n        },\n\n        /**\n         * Reads search input value.\n         *\n         * @return {String}\n         */\n        getSearchCriteria: function () {\n            return $.trim(this.$input.val());\n        },\n\n        /**\n         * Load options data.\n         */\n        loadOptions: function () {\n            var nextPage = this.getCurrentPage() + 1;\n\n            this.$wrapper.trigger('processStart');\n            this.$input.prop('disabled', true);\n\n            $.get(this.options.nextPageUrl, {\n                p: nextPage,\n                s: this.filter\n            })\n            .done(function (response) {\n                if (response.success) {\n                    this.appendOptions(response.result);\n                    this.setCurrentPage(nextPage);\n                } else {\n                    this.onError(response.errorMessage);\n                }\n            }.bind(this))\n            .always(function () {\n                this.$wrapper.trigger('processStop');\n                this.$input.prop('disabled', false);\n\n                if (this.filter) {\n                    this.$input.focus();\n                }\n            }.bind(this));\n        },\n\n        /**\n         * Append loaded options\n         *\n         * @param {Array} options\n         */\n        appendOptions: function (options) {\n            var divOptions = [];\n\n            if (!options.length) {\n                return false;\n            }\n\n            if (this.isOptionsLoaded(options)) {\n                return;\n            }\n\n            options.forEach(function (option) {\n                if (!this.values[option.value]) {\n                    this.values[option.value] = true;\n                    option.selected = this._isOptionSelected(option);\n                    divOptions.push(this._createMultiSelectOption(option));\n                    this._setLastAppendOption(option.value);\n                }\n            }, this);\n\n            this.$wrapper.append(divOptions);\n        },\n\n        /**\n         * Clear multiselect options\n         */\n        clearMultiselectOptions: function () {\n            this._setLastAppendOption(0);\n            this.values = {};\n            this.$wrapper.empty();\n        },\n\n        /**\n         * Checks if all options are already loaded\n         *\n         * @return {Boolean}\n         */\n        isOptionsLoaded: function (options) {\n            this.options.optionsLoaded = this.options.lastAppendValue === options[options.length - 1].value;\n\n            return this.options.optionsLoaded;\n        },\n\n        /**\n         * Setter for current page.\n         *\n         * @param {Number} page\n         */\n        setCurrentPage: function (page) {\n            this.options.currentPage = page;\n        },\n\n        /**\n         * Getter for current page.\n         *\n         * @return {Number}\n         */\n        getCurrentPage: function () {\n            return this.options.currentPage;\n        },\n\n        /**\n         * Creates new selected option for select element\n         *\n         * @param {Object} option - option object\n         * @param {String} option.value - option value\n         * @param {String} option.label - option label\n         * @private\n         */\n        _createSelectedOption: function (option) {\n            var selectOption = new Option(option.label, option.value, false, true);\n\n            this.element.append(selectOption);\n            this.selectedValues.push(option.value);\n            this._updateSelectedCounter();\n\n            return selectOption;\n        },\n\n        /**\n         * Remove passed option from select element\n         *\n         * @param {Object} option - option object\n         * @param {String} option.value - option value\n         * @param {String} option.label - option label\n         * @return {Object} option\n         * @private\n         */\n        _removeSelectedOption: function (option) {\n            var unselectedOption = _.findWhere(this.domElement.options, {\n                value: option.value\n            });\n\n            if (!_.isUndefined(unselectedOption)) {\n                this.domElement.remove(unselectedOption.index);\n                this.selectedValues.splice(_.indexOf(this.selectedValues, option.value), 1);\n                this._updateSelectedCounter();\n            }\n\n            return unselectedOption;\n        },\n\n        /**\n         * Creates new DIV option for multiselect widget\n         *\n         * @param {Object} option - option object\n         * @param {String} option.value - option value\n         * @param {String} option.label - option label\n         * @param {Boolean} option.selected - is option selected\n         * @private\n         */\n        _createMultiSelectOption: function (option) {\n            var item = this.$item.clone(),\n                checkbox = item.find('input'),\n                isSelected = !!option.selected;\n\n            checkbox.val(option.value)\n                .prop('checked', isSelected)\n                .toggleClass(this.options.mselectCheckedClass, isSelected);\n\n            item.find('label > span').text(option.label);\n\n            return item;\n        },\n\n        /**\n         * Checks if passed option should be selected\n         *\n         * @param {Object} option - option object\n         * @param {String} option.value - option value\n         * @param {String} option.label - option label\n         * @param {Boolean} option.selected - is option selected\n         * @return {Boolean}\n         * @private\n         */\n        _isOptionSelected: function (option) {\n            return !!~this.selectedValues.indexOf(option.value);\n        },\n\n        /**\n         * Saves last added option value.\n         *\n         * @param {Number} value\n         * @private\n         */\n        _setLastAppendOption: function (value) {\n            this.options.lastAppendValue = value;\n        },\n\n        /**\n         * Updates counter of selected items.\n         *\n         * @private\n         */\n        _updateSelectedCounter: function () {\n            this.$selectedCounter.text(this.selectedValues.length);\n        }\n    });\n\n    return $.mage.multiselect2;\n});\n","mage/collapsible.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery/ui',\n    'jquery/jquery-storageapi',\n    'mage/mage'\n], function ($) {\n    'use strict';\n\n    var hideProps = {},\n        showProps = {};\n\n    hideProps.height =  'hide';\n    showProps.height =  'show';\n\n    $.widget('mage.collapsible', {\n        options: {\n            active: false,\n            disabled: false,\n            collapsible: true,\n            header: '[data-role=title]',\n            content: '[data-role=content]',\n            trigger: '[data-role=trigger]',\n            closedState: null,\n            openedState: null,\n            disabledState: null,\n            ajaxUrlElement: '[data-ajax=true]',\n            ajaxContent: false,\n            loadingClass: null,\n            saveState: false,\n            animate: false,\n            icons: {\n                activeHeader: null,\n                header: null\n            },\n            collateral: {\n                element: null,\n                openedState: null\n            }\n        },\n\n        /**\n         * @private\n         */\n        _create: function () {\n            this.storage = $.localStorage;\n            this.icons = false;\n\n            if (typeof this.options.icons === 'string') {\n                this.options.icons = $.parseJSON(this.options.icons);\n            }\n\n            this._processPanels();\n            this._processState();\n            this._refresh();\n\n            if (this.options.icons.header && this.options.icons.activeHeader) {\n                this._createIcons();\n                this.icons = true;\n            }\n\n            this.element.on('dimensionsChanged', function (e) {\n                if (e.target && e.target.classList.contains('active')) {\n                    this._scrollToTopIfVisible(e.target);\n                }\n            }.bind(this));\n\n            this._bind('click');\n            this._trigger('created');\n        },\n\n        /**\n         * @private\n         */\n        _refresh: function () {\n            this.trigger.attr('tabIndex', 0);\n\n            if (this.options.active && !this.options.disabled) {\n                if (this.options.openedState) {\n                    this.element.addClass(this.options.openedState);\n                }\n\n                if (this.options.collateral.element && this.options.collateral.openedState) {\n                    $(this.options.collateral.element).addClass(this.options.collateral.openedState);\n                }\n\n                if (this.options.ajaxContent) {\n                    this._loadContent();\n                }\n                // ARIA (updates aria attributes)\n                this.header.attr({\n                    'aria-selected': false\n                });\n            } else if (this.options.disabled) {\n                this.disable();\n            } else {\n                this.content.hide();\n\n                if (this.options.closedState) {\n                    this.element.addClass(this.options.closedState);\n                }\n            }\n        },\n\n        /**\n         * Processing the state:\n         *     If deep linking is used and the anchor is the id of the content or the content contains this id,\n         *     and the collapsible element is a nested one having collapsible parents, in order to see the content,\n         *     all the parents must be expanded.\n         * @private\n         */\n        _processState: function () {\n            var anchor = window.location.hash,\n                isValid = $.mage.isValidSelector(anchor),\n                urlPath = window.location.pathname.replace(/\\./g, ''),\n                state;\n\n            this.stateKey = encodeURIComponent(urlPath + this.element.attr('id'));\n\n            if (isValid &&\n                ($(this.content.find(anchor)).length > 0 || this.content.attr('id') === anchor.replace('#', ''))\n            ) {\n                this.element.parents('[data-collapsible=true]').collapsible('forceActivate');\n\n                if (!this.options.disabled) {\n                    this.options.active = true;\n\n                    if (this.options.saveState) { //eslint-disable-line max-depth\n                        this.storage.set(this.stateKey, true);\n                    }\n                }\n            } else if (this.options.saveState && !this.options.disabled) {\n                state = this.storage.get(this.stateKey);\n\n                if (typeof state === 'undefined' || state === null) {\n                    this.storage.set(this.stateKey, this.options.active);\n                } else if (state === true) {\n                    this.options.active = true;\n                } else if (state === false) {\n                    this.options.active = false;\n                }\n            }\n        },\n\n        /**\n         * @private\n         */\n        _createIcons: function () {\n            var icons = this.options.icons;\n\n            if (icons) {\n                $('<span>')\n                    .addClass(icons.header)\n                    .attr('data-role', 'icons')\n                    .prependTo(this.header);\n\n                if (this.options.active && !this.options.disabled) {\n                    this.header.children('[data-role=icons]')\n                        .removeClass(icons.header)\n                        .addClass(icons.activeHeader);\n                }\n            }\n        },\n\n        /**\n         * @private\n         */\n        _destroyIcons: function () {\n            this.header\n                .children('[data-role=icons]')\n                .remove();\n        },\n\n        /**\n         * @private\n         */\n        _destroy: function () {\n            var options = this.options;\n\n            this.element.removeAttr('data-collapsible');\n\n            this.trigger.removeAttr('tabIndex');\n\n            if (options.openedState) {\n                this.element.removeClass(options.openedState);\n            }\n\n            if (this.options.collateral.element && this.options.collateral.openedState) {\n                $(this.options.collateral.element).removeClass(this.options.collateral.openedState);\n            }\n\n            if (options.closedState) {\n                this.element.removeClass(options.closedState);\n            }\n\n            if (options.disabledState) {\n                this.element.removeClass(options.disabledState);\n            }\n\n            if (this.icons) {\n                this._destroyIcons();\n            }\n        },\n\n        /**\n         * @private\n         */\n        _processPanels: function () {\n            var headers, triggers;\n\n            this.element.attr('data-collapsible', 'true');\n\n            if (typeof this.options.header === 'object') {\n                this.header = this.options.header;\n            } else {\n                headers = this.element.find(this.options.header);\n\n                if (headers.length > 0) {\n                    this.header = headers.eq(0);\n                } else {\n                    this.header = this.element;\n                }\n            }\n\n            if (typeof this.options.content === 'object') {\n                this.content = this.options.content;\n            } else {\n                this.content = this.header.next(this.options.content).eq(0);\n            }\n\n            // ARIA (init aria attributes)\n            if (this.header.attr('id')) {\n                this.content.attr('aria-labelledby', this.header.attr('id'));\n            }\n\n            if (this.content.attr('id')) {\n                this.header.attr('aria-controls', this.content.attr('id'));\n            }\n\n            this.header\n                .attr({\n                    'role': 'tab',\n                    'aria-selected': this.options.active,\n                    'aria-expanded': this.options.active\n                });\n\n            // For collapsible widget only (not tabs or accordion)\n            if (this.header.parent().attr('role') !== 'presentation') {\n                this.header\n                    .parent()\n                    .attr('role', 'tablist');\n            }\n\n            this.content.attr({\n                'role': 'tabpanel',\n                'aria-hidden': !this.options.active\n            });\n\n            if (typeof this.options.trigger === 'object') {\n                this.trigger = this.options.trigger;\n            } else {\n                triggers = this.header.find(this.options.trigger);\n\n                if (triggers.length > 0) {\n                    this.trigger = triggers.eq(0);\n                } else {\n                    this.trigger = this.header;\n                }\n            }\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _keydown: function (event) {\n            var keyCode;\n\n            if (event.altKey || event.ctrlKey) {\n                return;\n            }\n\n            keyCode = $.ui.keyCode;\n\n            switch (event.keyCode) {\n                case keyCode.SPACE:\n                case keyCode.ENTER:\n                    this._eventHandler(event);\n                    break;\n            }\n\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _bind: function (event) {\n            var self = this;\n\n            this.events = {\n                keydown: '_keydown'\n            };\n\n            if (event) {\n                $.each(event.split(' '), function (index, eventName) {\n                    self.events[ eventName ] = '_eventHandler';\n                });\n            }\n            this._off(this.trigger);\n\n            if (!this.options.disabled) {\n                this._on(this.trigger, this.events);\n            }\n        },\n\n        /**\n         * Disable.\n         */\n        disable: function () {\n            this.options.disabled = true;\n            this._off(this.trigger);\n            this.forceDeactivate();\n\n            if (this.options.disabledState) {\n                this.element.addClass(this.options.disabledState);\n            }\n            this.trigger.attr('tabIndex', -1);\n        },\n\n        /**\n         * Enable.\n         */\n        enable: function () {\n            this.options.disabled = false;\n            this._on(this.trigger, this.events);\n            this.forceActivate();\n\n            if (this.options.disabledState) {\n                this.element.removeClass(this.options.disabledState);\n            }\n            this.trigger.attr('tabIndex', 0);\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _eventHandler: function (event) {\n\n            if (this.options.active && this.options.collapsible) {\n                this.deactivate();\n            } else {\n                this.activate();\n\n            }\n            event.preventDefault();\n\n        },\n\n        /**\n         * @param {*} prop\n         * @private\n         */\n        _animate: function (prop) {\n            var duration,\n                easing,\n                animate = this.options.animate;\n\n            if (typeof animate === 'number') {\n                duration = animate;\n            }\n\n            if (typeof animate === 'string') {\n                animate = $.parseJSON(animate);\n            }\n            duration = duration || animate.duration;\n            easing = animate.easing;\n            this.content.animate(prop, duration, easing);\n        },\n\n        /**\n         * Deactivate.\n         */\n        deactivate: function () {\n            if (this.options.animate) {\n                this._animate(hideProps);\n            } else {\n                this.content.hide();\n            }\n            this._close();\n        },\n\n        /**\n         * Force deactivate.\n         */\n        forceDeactivate: function () {\n            this.content.hide();\n            this._close();\n\n        },\n\n        /**\n         * @private\n         */\n        _close: function () {\n            this.options.active = false;\n\n            if (this.options.saveState) {\n                this.storage.set(this.stateKey, false);\n            }\n\n            if (this.options.openedState) {\n                this.element.removeClass(this.options.openedState);\n            }\n\n            if (this.options.collateral.element && this.options.collateral.openedState) {\n                $(this.options.collateral.element).removeClass(this.options.collateral.openedState);\n            }\n\n            if (this.options.closedState) {\n                this.element.addClass(this.options.closedState);\n            }\n\n            if (this.icons) {\n                this.header.children('[data-role=icons]')\n                    .removeClass(this.options.icons.activeHeader)\n                    .addClass(this.options.icons.header);\n            }\n\n            // ARIA (updates aria attributes)\n            this.header.attr({\n                'aria-selected': 'false',\n                'aria-expanded': 'false'\n            });\n            this.content.attr({\n                'aria-hidden': 'true'\n            });\n\n            this.element.trigger('dimensionsChanged', {\n                opened: false\n            });\n        },\n\n        /**\n         * Activate.\n         *\n         * @return void;\n         */\n        activate: function () {\n            if (this.options.disabled) {\n                return;\n            }\n\n            if (this.options.animate) {\n                this._animate(showProps);\n            } else {\n                this.content.show();\n            }\n            this._open();\n        },\n\n        /**\n         * Force activate.\n         */\n        forceActivate: function () {\n            if (!this.options.disabled) {\n                this.content.show();\n                this._open();\n            }\n        },\n\n        /**\n         * @private\n         */\n        _open: function () {\n            this.element.trigger('beforeOpen');\n            this.options.active = true;\n\n            if (this.options.ajaxContent) {\n                this._loadContent();\n            }\n\n            if (this.options.saveState) {\n                this.storage.set(this.stateKey, true);\n            }\n\n            if (this.options.openedState) {\n                this.element.addClass(this.options.openedState);\n            }\n\n            if (this.options.collateral.element && this.options.collateral.openedState) {\n                $(this.options.collateral.element).addClass(this.options.collateral.openedState);\n            }\n\n            if (this.options.closedState) {\n                this.element.removeClass(this.options.closedState);\n            }\n\n            if (this.icons) {\n                this.header.children('[data-role=icons]')\n                    .removeClass(this.options.icons.header)\n                    .addClass(this.options.icons.activeHeader);\n            }\n\n            // ARIA (updates aria attributes)\n            this.header.attr({\n                'aria-selected': 'true',\n                'aria-expanded': 'true'\n            });\n            this.content.attr({\n                'aria-hidden': 'false'\n            });\n\n            this.element.trigger('dimensionsChanged', {\n                opened: true\n            });\n        },\n\n        /**\n         * @private\n         */\n        _loadContent: function () {\n            var url = this.element.find(this.options.ajaxUrlElement).attr('href'),\n                that = this;\n\n            if (url) {\n                that.xhr = $.get({\n                    url: url,\n                    dataType: 'html'\n                }, function () {\n                });\n            }\n\n            if (that.xhr && that.xhr.statusText !== 'canceled') {\n                if (that.options.loadingClass) {\n                    that.element.addClass(that.options.loadingClass);\n                }\n                that.content.attr('aria-busy', 'true');\n                that.xhr.done(function (response) {\n                    setTimeout(function () {\n                        that.content.html(response);\n                    }, 1);\n                });\n                that.xhr.always(function (jqXHR, status) {\n                    setTimeout(function () {\n                        if (status === 'abort') {\n                            that.content.stop(false, true);\n                        }\n\n                        if (that.options.loadingClass) {\n                            that.element.removeClass(that.options.loadingClass);\n                        }\n                        that.content.removeAttr('aria-busy');\n\n                        if (jqXHR === that.xhr) {\n                            delete that.xhr;\n                        }\n                    }, 1);\n                });\n            }\n        },\n\n        /**\n         * @param {HTMLElement} elem\n         * @private\n         */\n        _scrollToTopIfVisible: function (elem) {\n            if (this._isElementOutOfViewport(elem)) {\n                elem.scrollIntoView();\n            }\n        },\n\n        /**\n         * @param {HTMLElement} elem\n         * @private\n         * @return {Boolean}\n         */\n        _isElementOutOfViewport: function (elem) {\n            var rect = elem.getBoundingClientRect();\n\n            return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;\n        }\n    });\n\n    return $.mage.collapsible;\n});\n","mage/cookies.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (factory) {\n    'use strict';\n\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery',\n            'mage/mage',\n            'jquery/jquery.cookie'\n        ], factory);\n    } else {\n        factory(jQuery);\n    }\n}(function ($) {\n    'use strict';\n\n    /**\n     * Helper for cookies manipulation\n     * @returns {CookieHelper}\n     * @constructor\n     */\n    var CookieHelper = function () {\n\n        /**\n         * Cookie default values.\n         * @type {Object}\n         */\n        this.defaults = {\n            expires: null,\n            path: '/',\n            domain: null,\n            secure: false,\n            lifetime: null\n        };\n\n        /**\n         * Calculate cookie expiration date based on its lifetime.\n         * @param {Object} options - Cookie option values\n         * @return {Date|null} Calculated cookie expiration date or null if no lifetime provided.\n         * @private\n         */\n        function lifetimeToExpires(options, defaults) {\n            var expires,\n                lifetime;\n\n            lifetime = options.lifetime || defaults.lifetime;\n\n            if (lifetime && lifetime > 0) {\n                expires = options.expires || new Date();\n\n                return new Date(expires.getTime() + lifetime * 1000);\n            }\n\n            return null;\n        }\n\n        /**\n         * Set a cookie's value by cookie name based on optional cookie options.\n         * @param {String} name - The name of the cookie.\n         * @param {String} value - The cookie's value.\n         * @param {Object} options - Optional options (e.g. lifetime, expires, path, etc.)\n         */\n        this.set = function (name, value, options) {\n            var expires,\n                path,\n                domain,\n                secure;\n\n            options = $.extend({}, this.defaults, options || {});\n            expires = lifetimeToExpires(options, this.defaults) || options.expires;\n            path = options.path;\n            domain = options.domain;\n            secure = options.secure;\n\n            document.cookie = name + '=' + encodeURIComponent(value) +\n                (expires ? '; expires=' + expires.toUTCString() :  '') +\n                (path ? '; path=' + path : '') +\n                (domain ? '; domain=' + domain : '') +\n                (secure ? '; secure' : '');\n        };\n\n        /**\n         * Get a cookie's value by cookie name.\n         * @param {String} name  - The name of the cookie.\n         * @return {(null|String)}\n         */\n        this.get = function (name) {\n            var arg = name + '=',\n                aLength = arg.length,\n                cookie = document.cookie,\n                cLength = cookie.length,\n                i = 0,\n                j = 0;\n\n            while (i < cLength) {\n                j = i + aLength;\n\n                if (cookie.substring(i, j) === arg) {\n                    return this.getCookieVal(j);\n                }\n                i = cookie.indexOf(' ', i) + 1;\n\n                if (i === 0) {\n                    break;\n                }\n            }\n\n            return null;\n        };\n\n        /**\n         * Clear a cookie's value by name.\n         * @param {String} name - The name of the cookie being cleared.\n         */\n        this.clear = function (name) {\n            if (this.get(name)) {\n                this.set(name, '', {\n                    expires: new Date('Jan 01 1970 00:00:01 GMT')\n                });\n            }\n        };\n\n        /**\n         * Return URI decoded cookie component value (e.g. expires, path, etc.) based on a\n         * numeric offset in the document's cookie value.\n         * @param {Number} offset - Offset into the document's cookie value.\n         * @return {String}\n         */\n        this.getCookieVal = function (offset) {\n            var cookie = document.cookie,\n                endstr = cookie.indexOf(';', offset);\n\n            if (endstr === -1) {\n                endstr = cookie.length;\n            }\n\n            return decodeURIComponent(cookie.substring(offset, endstr));\n        };\n\n        return this;\n    };\n\n    $.extend(true, $, {\n        mage: {\n            cookies: new CookieHelper()\n        }\n    });\n\n    return function (pageOptions) {\n        $.extend($.mage.cookies.defaults, pageOptions);\n        $.extend($.cookie.defaults, $.mage.cookies.defaults);\n    };\n}));\n","mage/sticky.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery/ui'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.sticky', {\n        options: {\n            /**\n             * Element selector, who's height will be used to restrict the\n             * maximum offsetTop position of the stuck element.\n             * Default uses document body.\n             * @type {String}\n             */\n            container: '',\n\n            /**\n             * Spacing in pixels above the stuck element\n             * @type {Number|Function} Number or Function that will return a Number\n             */\n            spacingTop: 0,\n\n            /**\n             * Allows postponing sticking, until element will go out of the\n             * screen for the number of pixels.\n             * @type {Number|Function} Number or Function that will return a Number\n             */\n            stickAfter: 0,\n\n            /**\n             * CSS class for active sticky state\n             * @type {String}\n             */\n            stickyClass: '_sticky'\n        },\n\n        /**\n         * Retrieve option value\n         * @param  {String} option\n         * @return {*}\n         * @private\n         */\n        _getOptionValue: function (option) {\n            var value = this.options[option] || 0;\n\n            if (typeof value === 'function') {\n                value = this.options[option]();\n            }\n\n            return value;\n        },\n\n        /**\n         * Bind handlers to scroll event\n         * @private\n         */\n        _create: function () {\n            $(window).on({\n                'scroll': $.proxy(this._stick, this),\n                'resize': $.proxy(this.reset, this)\n            });\n\n            this.element.on('dimensionsChanged', $.proxy(this.reset, this));\n\n            this.reset();\n        },\n\n        /**\n         * float Block on windowScroll\n         * @private\n         */\n        _stick: function () {\n            var offset,\n                isStatic,\n                stuck,\n                stickAfter;\n\n            isStatic = this.element.css('position') === 'static';\n\n            if (!isStatic && this.element.is(':visible')) {\n                offset = $(document).scrollTop() -\n                    this.parentOffset +\n                    this._getOptionValue('spacingTop');\n\n                offset = Math.max(0, Math.min(offset, this.maxOffset));\n\n                stuck = this.element.hasClass(this.options.stickyClass);\n                stickAfter = this._getOptionValue('stickAfter');\n\n                if (offset && !stuck && offset < stickAfter) {\n                    offset = 0;\n                }\n\n                this.element\n                    .toggleClass(this.options.stickyClass, offset > 0)\n                    .css('top', offset);\n            }\n        },\n\n        /**\n         * Defines maximum offset value of the element.\n         * @private\n         */\n        _calculateDimens: function () {\n            var $parent         = this.element.parent(),\n                topMargin       = parseInt(this.element.css('margin-top'), 10),\n                parentHeight    = $parent.height() - topMargin,\n                height          = this.element.innerHeight(),\n                maxScroll       = document.body.offsetHeight - window.innerHeight;\n\n            if (this.options.container.length > 0) {\n                maxScroll = $(this.options.container).height();\n            }\n\n            this.parentOffset   = $parent.offset().top + topMargin;\n            this.maxOffset      = maxScroll - this.parentOffset;\n\n            if (this.maxOffset + height >= parentHeight) {\n                this.maxOffset = parentHeight - height;\n            }\n\n            return this;\n        },\n\n        /**\n         * Facade method that palces sticky element where it should be.\n         */\n        reset: function () {\n            this._calculateDimens()\n                ._stick();\n        }\n    });\n\n    return $.mage.sticky;\n});\n","mage/dropdowns.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * @param {Object} options\n     */\n    $.fn.dropdown = function (options) {\n        var defaults = {\n                parent: null,\n                autoclose: true,\n                btnArrow: '.arrow',\n                menu: '[data-target=\"dropdown\"]',\n                activeClass: 'active'\n            },\n            actionElem = $(this),\n            self = this;\n\n        options = $.extend(defaults, options);\n        actionElem = $(this);\n        self = this;\n\n        /**\n         * @param {HTMLElement} elem\n         */\n        this.openDropdown = function (elem) {\n            elem\n                .addClass(options.activeClass)\n                .attr('aria-expanded', true)\n                .parent()\n                    .addClass(options.activeClass);\n\n            elem.parent()\n                .find(options.menu)\n                .attr('aria-hidden', false);\n\n            $(options.btnArrow, elem).text('-');\n        };\n\n        /**\n         * @param {HTMLElement} elem\n         */\n        this.closeDropdown = function (elem) {\n            elem.removeClass(options.activeClass)\n                .attr('aria-expanded', false)\n                .parent()\n                    .removeClass(options.activeClass);\n\n            elem.parent()\n                .find(options.menu)\n                .attr('aria-hidden', true);\n\n            $(options.btnArrow, elem).text('+');\n        };\n\n        /**\n         * Reset all dropdowns.\n         *\n         * @param {Object} param\n         */\n        this.reset = function (param) {\n            var params = param || {},\n                dropdowns = params.elems || actionElem;\n\n            dropdowns.each(function (index, elem) {\n                self.closeDropdown($(elem));\n            });\n        };\n\n        /* document Event bindings */\n        if (options.autoclose === true) {\n            $(document).on('click.hideDropdown', this.reset);\n            $(document).on('keyup.hideDropdown', function (e) {\n                var ESC_CODE = '27';\n\n                if (e.keyCode == ESC_CODE) { //eslint-disable-line eqeqeq\n                    self.reset();\n                }\n            });\n        }\n\n        if (options.events) {\n            $.each(options.events, function (index, event) {\n                $(document).on(event.name, event.selector, event.action);\n            });\n        }\n\n        return this.each(function () {\n            var elem = $(this),\n                parent = $(options.parent).length > 0 ? $(options.parent) : elem.parent(),\n                menu = $(options.menu, parent) || $('.dropdown-menu', parent);\n\n            // ARIA (adding aria attributes)\n            if (menu.length) {\n                elem.attr('aria-haspopup', true);\n            }\n\n            if (!elem.hasClass(options.activeClass)) {\n                elem.attr('aria-expanded', false);\n                menu.attr('aria-hidden', true);\n            } else {\n                elem.attr('aria-expanded', true);\n                menu.attr('aria-hidden', false);\n            }\n\n            if (!elem.is('a, button')) {\n                elem.attr('role', 'button');\n                elem.attr('tabindex', 0);\n            }\n\n            if (elem.attr('data-trigger-keypress-button')) {\n                elem.on('keypress', function (e) {\n                    var keyCode = e.keyCode || e.which,\n                        ENTER_CODE = 13;\n\n                    if (keyCode === ENTER_CODE) {\n                        e.preventDefault();\n                        elem.trigger('click.toggleDropdown');\n                    }\n                });\n            }\n\n            elem.on('click.toggleDropdown', function () {\n                var el = actionElem;\n\n                if (options.autoclose === true) {\n                    actionElem = $();\n                    $(document).trigger('click.hideDropdown');\n                    actionElem = el;\n                }\n\n                self[el.hasClass(options.activeClass) ? 'closeDropdown' : 'openDropdown'](elem);\n\n                return false;\n            });\n        });\n    };\n\n    return function (data, el) {\n        $(el).dropdown(data);\n    };\n});\n","mage/url.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable strict */\ndefine([], function () {\n    var baseUrl = '';\n\n    return {\n        /**\n         * @param {String} url\n         */\n        setBaseUrl: function (url) {\n            baseUrl = url;\n        },\n\n        /**\n         * @param {String} path\n         * @return {*}\n         */\n        build: function (path) {\n            if (path.indexOf(baseUrl) !== -1) {\n                return path;\n            }\n\n            return baseUrl + path;\n        }\n    };\n});\n","mage/storage.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery', 'mage/url'], function ($, urlBuilder) {\n    'use strict';\n\n    return {\n        /**\n         * Perform asynchronous GET request to server.\n         * @param {String} url\n         * @param {Boolean} global\n         * @param {String} contentType\n         * @returns {Deferred}\n         */\n        get: function (url, global, contentType) {\n            global = global === undefined ? true : global;\n            contentType = contentType || 'application/json';\n\n            return $.ajax({\n                url: urlBuilder.build(url),\n                type: 'GET',\n                global: global,\n                contentType: contentType\n            });\n        },\n\n        /**\n         * Perform asynchronous POST request to server.\n         * @param {String} url\n         * @param {String} data\n         * @param {Boolean} global\n         * @param {String} contentType\n         * @returns {Deferred}\n         */\n        post: function (url, data, global, contentType) {\n            global = global === undefined ? true : global;\n            contentType = contentType || 'application/json';\n\n            return $.ajax({\n                url: urlBuilder.build(url),\n                type: 'POST',\n                data: data,\n                global: global,\n                contentType: contentType\n            });\n        },\n\n        /**\n         * Perform asynchronous PUT request to server.\n         * @param {String} url\n         * @param {String} data\n         * @param {Boolean} global\n         * @param {String} contentType\n         * @returns {Deferred}\n         */\n        put: function (url, data, global, contentType) {\n            global = global === undefined ? true : global;\n            contentType = contentType || 'application/json';\n\n            return $.ajax({\n                url: urlBuilder.build(url),\n                type: 'PUT',\n                data: data,\n                global: global,\n                contentType: contentType\n            });\n        },\n\n        /**\n         * Perform asynchronous DELETE request to server.\n         * @param {String} url\n         * @param {Boolean} global\n         * @param {String} contentType\n         * @returns {Deferred}\n         */\n        delete: function (url, global, contentType) {\n            global = global === undefined ? true : global;\n            contentType = contentType || 'application/json';\n\n            return $.ajax({\n                url: urlBuilder.build(url),\n                type: 'DELETE',\n                global: global,\n                contentType: contentType\n            });\n        }\n    };\n});\n","mage/bootstrap.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/apply/main',\n    'Magento_Ui/js/lib/knockout/bootstrap'\n], function ($, mage) {\n    'use strict';\n\n    $.ajaxSetup({\n        cache: false\n    });\n\n    /**\n     * Init all components defined via data-mage-init attribute.\n     */\n    $(mage.apply);\n});\n","mage/layout.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\n/* eslint-disable strict */\ndefine(['underscore'], function (_) {\n    return {\n        /**\n         * @param {Object} config\n         */\n        build: function (config) {\n            var types = _.map(_.flatten(config), function (item) {\n                return item.type;\n            });\n\n            require(types, function () {});\n        }\n    };\n});\n","mage/loader.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    'jquery/ui',\n    'mage/translate'\n], function ($, mageTemplate) {\n    'use strict';\n\n    $.widget('mage.loader', {\n        loaderStarted: 0,\n        options: {\n            icon: '',\n            texts: {\n                loaderText: $.mage.__('Please wait...'),\n                imgAlt: $.mage.__('Loading...')\n            },\n            template:\n                '<div class=\"loading-mask\" data-role=\"loader\">' +\n                    '<div class=\"loader\">' +\n                        '<img alt=\"<%- data.texts.imgAlt %>\" src=\"<%- data.icon %>\">' +\n                        '<p><%- data.texts.loaderText %></p>' +\n                    '</div>' +\n                '</div>'\n\n        },\n\n        /**\n         * Loader creation\n         * @protected\n         */\n        _create: function () {\n            this._bind();\n        },\n\n        /**\n         * Bind on ajax events\n         * @protected\n         */\n        _bind: function () {\n            this._on({\n                'processStop': 'hide',\n                'processStart': 'show',\n                'show.loader': 'show',\n                'hide.loader': 'hide',\n                'contentUpdated.loader': '_contentUpdated'\n            });\n        },\n\n        /**\n         * Verify loader present after content updated\n         *\n         * This will be cleaned up by the task MAGETWO-11070\n         *\n         * @param {EventObject} e\n         * @private\n         */\n        _contentUpdated: function (e) {\n            this.show(e);\n        },\n\n        /**\n         * Show loader\n         */\n        show: function (e, ctx) {\n            this._render();\n            this.loaderStarted++;\n            this.spinner.show();\n\n            if (ctx) {\n                this.spinner\n                    .css({\n                        width: ctx.outerWidth(),\n                        height: ctx.outerHeight(),\n                        position: 'absolute'\n                    })\n                    .position({\n                        my: 'top left',\n                        at: 'top left',\n                        of: ctx\n                    });\n            }\n\n            return false;\n        },\n\n        /**\n         * Hide loader\n         */\n        hide: function () {\n            if (this.loaderStarted > 0) {\n                this.loaderStarted--;\n\n                if (this.loaderStarted === 0) {\n                    this.spinner.hide();\n                }\n            }\n\n            return false;\n        },\n\n        /**\n         * Render loader\n         * @protected\n         */\n        _render: function () {\n            var html;\n\n            if (!this.spinnerTemplate) {\n                this.spinnerTemplate = mageTemplate(this.options.template);\n\n                html = $(this.spinnerTemplate({\n                    data: this.options\n                }));\n\n                html.prependTo(this.element);\n\n                this.spinner = html;\n            }\n        },\n\n        /**\n         * Destroy loader\n         */\n        _destroy: function () {\n            this.spinner.remove();\n        }\n    });\n\n    /**\n     * This widget takes care of registering the needed loader listeners on the body\n     */\n    $.widget('mage.loaderAjax', {\n        options: {\n            defaultContainer: '[data-container=body]',\n            loadingClass: 'ajax-loading'\n        },\n\n        /**\n         * @private\n         */\n        _create: function () {\n            this._bind();\n            // There should only be one instance of this widget, and it should be attached\n            // to the body only. Having it on the page twice will trigger multiple processStarts.\n            if (window.console && !this.element.is(this.options.defaultContainer) && $.mage.isDevMode(undefined)) {\n                console.warn('This widget is intended to be attached to the body, not below.');\n            }\n        },\n\n        /**\n         * @private\n         */\n        _bind: function () {\n            $(document).on({\n                'ajaxSend': this._onAjaxSend.bind(this),\n                'ajaxComplete': this._onAjaxComplete.bind(this)\n            });\n        },\n\n        /**\n         * @param {Object} loaderContext\n         * @return {*}\n         * @private\n         */\n        _getJqueryObj: function (loaderContext) {\n            var ctx;\n\n            // Check to see if context is jQuery object or not.\n            if (loaderContext) {\n                if (loaderContext.jquery) {\n                    ctx = loaderContext;\n                } else {\n                    ctx = $(loaderContext);\n                }\n            } else {\n                ctx = $('[data-container=\"body\"]');\n            }\n\n            return ctx;\n        },\n\n        /**\n         * @param {jQuery.Event} e\n         * @param {Object} jqxhr\n         * @param {Object} settings\n         * @private\n         */\n        _onAjaxSend: function (e, jqxhr, settings) {\n            var ctx;\n\n            $(this.options.defaultContainer)\n                .addClass(this.options.loadingClass)\n                .attr({\n                    'aria-busy': true\n                });\n\n            if (settings && settings.showLoader) {\n                ctx = this._getJqueryObj(settings.loaderContext);\n                ctx.trigger('processStart');\n\n                // Check to make sure the loader is there on the page if not report it on the console.\n                // NOTE that this check should be removed before going live. It is just an aid to help\n                // in finding the uses of the loader that maybe broken.\n                if (window.console && !ctx.parents('[data-role=\"loader\"]').length) {\n                    console.warn('Expected to start loader but did not find one in the dom');\n                }\n            }\n        },\n\n        /**\n         * @param {jQuery.Event} e\n         * @param {Object} jqxhr\n         * @param {Object} settings\n         * @private\n         */\n        _onAjaxComplete: function (e, jqxhr, settings) {\n            $(this.options.defaultContainer)\n                .removeClass(this.options.loadingClass)\n                .attr('aria-busy', false);\n\n            if (settings && settings.showLoader) {\n                this._getJqueryObj(settings.loaderContext).trigger('processStop');\n            }\n        }\n\n    });\n\n    return {\n        loader: $.mage.loader,\n        loaderAjax: $.mage.loaderAjax\n    };\n});\n","mage/deletable-item.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\ndefine([\n    'jquery',\n    'jquery/ui'\n], function ($) {\n    'use strict';\n\n    /**\n     * This widget is used to tag a DOM element as deletable. By default, it will use the click event on the item with a\n     * data role of delete to trigger the deletion.\n     */\n    $.widget('mage.deletableItem', {\n        options: {\n            deleteEvent: 'click',\n            deleteSelector: '[data-role=\"delete\"]',\n            hiddenClass: 'no-display'\n        },\n\n        /**\n         * This method binds elements found in this widget.\n         */\n        _bind: function () {\n            var handlers = {};\n\n            // since the first handler is dynamic, generate the object using array notation\n            handlers[this.options.deleteEvent + ' ' + this.options.deleteSelector] = '_onDeleteClicked';\n            handlers.hideDelete = '_onHideDelete';\n            handlers.showDelete = '_onShowDelete';\n\n            this._on(handlers);\n        },\n\n        /**\n         * This method constructs a new widget.\n         */\n        _create: function () {\n            this._bind();\n        },\n\n        /**\n         * This method is to initialize the control\n         * @private\n         */\n        _init: function () {\n            this._onHideDelete(); // by default, hide the control\n        },\n\n        /**\n         * This method removes the entity from the DOM.\n         * @private\n         */\n        _onDeleteClicked: function (e) {\n            e.stopPropagation();\n            this.element.trigger('deleteItem');\n        },\n\n        /**\n         * This method hides the delete capability of this item (i.e. making it not deletable)\n         * @private\n         */\n        _onHideDelete: function () {\n            this.element.find(this.options.deleteSelector).addClass(this.options.hiddenClass);\n        },\n\n        /**\n         * This method shows the delete capability of this item (i.e. making it deletable)\n         * @private\n         */\n        _onShowDelete: function () {\n            this.element.find(this.options.deleteSelector).removeClass(this.options.hiddenClass);\n        }\n    });\n\n    return $.mage.deletableItem;\n});\n","mage/popup-window.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery/ui'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.popupWindow', {\n        options: {\n            centerBrowser: 0, // center window over browser window? {1 (YES) or 0 (NO)}. overrides top and left\n            centerScreen: 0, // center window over entire screen? {1 (YES) or 0 (NO)}. overrides top and left\n            height: 500, // sets the height in pixels of the window.\n            left: 0, // left position when the window appears.\n            location: 0, // determines whether the address bar is displayed {1 (YES) or 0 (NO)}.\n            menubar: 0, // determines whether the menu bar is displayed {1 (YES) or 0 (NO)}.\n            resizable: 0, // whether the window can be resized {1 (YES) or 0 (NO)}.\n            scrollbars: 0, // determines whether scrollbars appear on the window {1 (YES) or 0 (NO)}.\n            status: 0, // whether a status line appears at the bottom of the window {1 (YES) or 0 (NO)}.\n            width: 500, // sets the width in pixels of the window.\n            windowName: null, // name of window set from the name attribute of the element that invokes the click\n            windowURL: null, // url used for the popup\n            top: 0, // top position when the window appears.\n            toolbar: 0 // determines whether a toolbar is displayed {1 (YES) or 0 (NO)}.\n        },\n\n        /**\n         * @private\n         */\n        _create: function () {\n            this.element.on('click', $.proxy(this._openPopupWindow, this));\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _openPopupWindow: function (event) {\n            var element = $(event.target),\n                settings = this.options,\n                windowFeatures =\n                    'height=' + settings.height +\n                        ',width=' + settings.width +\n                        ',toolbar=' + settings.toolbar +\n                        ',scrollbars=' + settings.scrollbars +\n                        ',status=' + settings.status +\n                        ',resizable=' + settings.resizable +\n                        ',location=' + settings.location +\n                        ',menuBar=' + settings.menubar,\n                centeredX,\n                centeredY;\n\n            settings.windowName = settings.windowName || element.attr('name');\n            settings.windowURL = settings.windowURL || element.attr('href');\n\n            if (settings.centerBrowser) {\n                centeredY = window.screenY + ((window.outerHeight / 2 - settings.height / 2));\n                centeredX = window.screenX + ((window.outerWidth / 2 - settings.width / 2));\n                windowFeatures += ',left=' + centeredX + ',top=' + centeredY;\n            } else if (settings.centerScreen) {\n                centeredY = (screen.height - settings.height) / 2;\n                centeredX = (screen.width - settings.width) / 2;\n                windowFeatures += ',left=' + centeredX + ',top=' + centeredY;\n            } else {\n                windowFeatures += ',left=' + settings.left + ',top=' + settings.top;\n            }\n\n            window.open(settings.windowURL, settings.windowName, windowFeatures).focus();\n            event.preventDefault();\n        }\n    });\n\n    return $.mage.popupWindow;\n});\n","mage/smart-keyboard-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * @return {Object}\n     * @constructor\n     */\n    function KeyboardHandler() {\n        var body = $('body'),\n            focusState = false,\n            tabFocusClass = '_keyfocus',\n            productsGrid = '[data-container=\"product-grid\"]',\n            catalogProductsGrid = $(productsGrid),\n            CODE_TAB = 9;\n\n        /**\n         * Handle logic, when onTabKeyPress fired at first.\n         * Then it changes state.\n         */\n        function onFocusInHandler() {\n            focusState = true;\n            body.addClass(tabFocusClass)\n                .off('focusin.keyboardHandler', onFocusInHandler);\n        }\n\n        /**\n         * Handle logic to remove state after onTabKeyPress to normal.\n         */\n        function onClickHandler() {\n            focusState = false;\n            body.removeClass(tabFocusClass)\n                .off('click', onClickHandler);\n        }\n\n        /**\n         * Tab key onKeypress handler. Apply main logic:\n         *  - call differ actions onTabKeyPress and onClick\n         */\n        function smartKeyboardFocus() {\n            $(document).on('keydown keypress', function (event) {\n                if (event.which === CODE_TAB && !focusState) {\n                    body\n                        .on('focusin.keyboardHandler', onFocusInHandler)\n                        .on('click', onClickHandler);\n                }\n            });\n\n            // ARIA support for catalog grid products\n            if (catalogProductsGrid.length) {\n                body.on('focusin.gridProducts', productsGrid, function () {\n                    if (body.hasClass(tabFocusClass)) {\n                        $(this).addClass('active');\n                    }\n                });\n                body.on('focusout.gridProducts', productsGrid, function () {\n                    $(this).removeClass('active');\n                });\n            }\n        }\n\n        /**\n         * Attach smart focus on specific element.\n         * @param {jQuery} element\n         */\n        function handleFocus(element) {\n            element.on('focusin.emulateTabFocus', function () {\n                focusState = true;\n                body.addClass(tabFocusClass);\n                element.off();\n            });\n\n            element.on('focusout.emulateTabFocus', function () {\n                focusState = false;\n                body.removeClass(tabFocusClass);\n                element.off();\n            });\n        }\n\n        return {\n            apply: smartKeyboardFocus,\n            focus: handleFocus\n        };\n    }\n\n    return new KeyboardHandler;\n});\n","mage/validation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (factory) {\n    'use strict';\n\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery',\n            'moment',\n            'jquery/ui',\n            'jquery/validate',\n            'mage/translate'\n        ], factory);\n    } else {\n        factory(jQuery);\n    }\n}(function ($, moment) {\n    'use strict';\n\n    var creditCartTypes, rules, showLabel, originValidateDelegate;\n\n    $.extend(true, $, {\n        // @TODO: Move methods 'isEmpty', 'isEmptyNoTrim', 'parseNumber', 'stripHtml' in file with utility functions\n        mage: {\n            /**\n             * Check if string is empty with trim\n             * @param {String} value\n             */\n            isEmpty: function (value) {\n                return value === '' || value === undefined ||\n                    value == null || value.length === 0 || /^\\s+$/.test(value);\n            },\n\n            /**\n             * Check if string is empty no trim\n             * @param {String} value\n             */\n            isEmptyNoTrim: function (value) {\n                return value === '' || value == null || value.length === 0;\n            },\n\n            /**\n             * Checks if {value} is between numbers {from} and {to}\n             * @param {String} value\n             * @param {String} from\n             * @param {String} to\n             * @returns {Boolean}\n             */\n            isBetween: function (value, from, to) {\n                return ($.mage.isEmpty(from) || value >= $.mage.parseNumber(from)) &&\n                    ($.mage.isEmpty(to) || value <= $.mage.parseNumber(to));\n            },\n\n            /**\n             * Parse price string\n             * @param {String} value\n             */\n            parseNumber: function (value) {\n                var isDot, isComa;\n\n                if (typeof value !== 'string') {\n                    return parseFloat(value);\n                }\n                isDot = value.indexOf('.');\n                isComa = value.indexOf(',');\n\n                if (isDot !== -1 && isComa !== -1) {\n                    if (isComa > isDot) {\n                        value = value.replace('.', '').replace(',', '.');\n                    } else {\n                        value = value.replace(',', '');\n                    }\n                } else if (isComa !== -1) {\n                    value = value.replace(',', '.');\n                }\n\n                return parseFloat(value);\n            },\n\n            /**\n             * Removes HTML tags and space characters, numbers and punctuation.\n             *\n             * @param {String} value - Value being stripped.\n             * @return {String}\n             */\n            stripHtml: function (value) {\n                return value.replace(/<.[^<>]*?>/g, ' ').replace(/&nbsp;|&#160;/gi, ' ')\n                    .replace(/[0-9.(),;:!?%#$'\"_+=\\/-]*/g, '');\n            }\n        }\n    });\n\n    /**\n     * @param {String} name\n     * @param {*} method\n     * @param {*} message\n     * @param {*} dontSkip\n     */\n    $.validator.addMethod = function (name, method, message, dontSkip) {\n        $.validator.methods[name] = method;\n        $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];\n\n        if (method.length < 3 || dontSkip) {\n            $.validator.addClassRules(name, $.validator.normalizeRule(name));\n        }\n    };\n\n    /**\n     * Javascript object with credit card types\n     * 0 - regexp for card number\n     * 1 - regexp for cvn\n     * 2 - check or not credit card number trough Luhn algorithm by\n     */\n    creditCartTypes = {\n        'SO': [\n            new RegExp('^(6334[5-9]([0-9]{11}|[0-9]{13,14}))|(6767([0-9]{12}|[0-9]{14,15}))$'),\n            new RegExp('^([0-9]{3}|[0-9]{4})?$'),\n            true\n        ],\n        'SM': [\n            new RegExp('(^(5[0678])[0-9]{11,18}$)|(^(6[^05])[0-9]{11,18}$)|' +\n                '(^(601)[^1][0-9]{9,16}$)|(^(6011)[0-9]{9,11}$)|(^(6011)[0-9]{13,16}$)|' +\n                '(^(65)[0-9]{11,13}$)|(^(65)[0-9]{15,18}$)|(^(49030)[2-9]([0-9]{10}$|[0-9]{12,13}$))|' +\n                '(^(49033)[5-9]([0-9]{10}$|[0-9]{12,13}$))|(^(49110)[1-2]([0-9]{10}$|[0-9]{12,13}$))|' +\n                '(^(49117)[4-9]([0-9]{10}$|[0-9]{12,13}$))|(^(49118)[0-2]([0-9]{10}$|[0-9]{12,13}$))|' +\n                '(^(4936)([0-9]{12}$|[0-9]{14,15}$))'), new RegExp('^([0-9]{3}|[0-9]{4})?$'),\n            true\n        ],\n        'VI': [new RegExp('^4[0-9]{12}([0-9]{3})?$'), new RegExp('^[0-9]{3}$'), true],\n        'MC': [\n            new RegExp('^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$'),\n            new RegExp('^[0-9]{3}$'),\n            true\n        ],\n        'AE': [new RegExp('^3[47][0-9]{13}$'), new RegExp('^[0-9]{4}$'), true],\n        'DI': [new RegExp('^(6011(0|[2-4]|74|7[7-9]|8[6-9]|9)|6(4[4-9]|5))\\\\d*$'), new RegExp('^[0-9]{3}$'), true],\n        'JCB': [new RegExp('^35(2[8-9]|[3-8])\\\\d*$'), new RegExp('^[0-9]{3}$'), true],\n        'DN': [new RegExp('^(3(0[0-5]|095|6|[8-9]))\\\\d*$'), new RegExp('^[0-9]{3}$'), true],\n        'UN': [\n            new RegExp('^(622(1(2[6-9]|[3-9])|[3-8]|9([[0-1]|2[0-5]))|62[4-6]|628([2-8]))\\\\d*?$'),\n            new RegExp('^[0-9]{3}$'),\n            true\n        ],\n        'MI': [new RegExp('^(5(0|[6-9])|63|67(?!59|6770|6774))\\\\d*$'), new RegExp('^[0-9]{3}$'), true],\n        'MD': [new RegExp('^6759(?!24|38|40|6[3-9]|70|76)|676770|676774\\\\d*$'), new RegExp('^[0-9]{3}$'), true]\n    };\n\n    /**\n     * validate credit card number using mod10\n     * @param {String} s\n     * @return {Boolean}\n     */\n    function validateCreditCard(s) {\n        // remove non-numerics\n        var v = '0123456789',\n            w = '',\n            i, j, k, m, c, a, x;\n\n        for (i = 0; i < s.length; i++) {\n            x = s.charAt(i);\n\n            if (v.indexOf(x, 0) !== -1) {\n                w += x;\n            }\n        }\n        // validate number\n        j = w.length / 2;\n        k = Math.floor(j);\n        m = Math.ceil(j) - k;\n        c = 0;\n\n        for (i = 0; i < k; i++) {\n            a = w.charAt(i * 2 + m) * 2;\n            c += a > 9 ? Math.floor(a / 10 + a % 10) : a;\n        }\n\n        for (i = 0; i < k + m; i++) {\n            c += w.charAt(i * 2 + 1 - m) * 1;\n        }\n\n        return c % 10 === 0;\n    }\n\n    /**\n     * validate all table required inputs at once, using single hidden input\n     * @param {String} value\n     * @param {HTMLElement} element\n     *\n     * @return {Boolean}\n     */\n    function tableSingleValidation(value, element) {\n        var empty = $(element).closest('table')\n            .find('input.required-option:visible')\n            .filter(function (i, el) {\n                if ($(el).is('disabled')) {\n                    return $.mage.isEmpty(el.value);\n                }\n            })\n            .length;\n\n        return empty === 0;\n    }\n\n    /**\n     * Collection of validation rules including rules from additional-methods.js\n     * @type {Object}\n     */\n    rules = {\n        'max-words': [\n            function (value, element, params) {\n                return this.optional(element) || $.mage.stripHtml(value).match(/\\b\\w+\\b/g).length < params;\n            },\n            $.mage.__('Please enter {0} words or less.')\n        ],\n        'min-words': [\n            function (value, element, params) {\n                return this.optional(element) || $.mage.stripHtml(value).match(/\\b\\w+\\b/g).length >= params;\n            },\n            $.mage.__('Please enter at least {0} words.')\n        ],\n        'range-words': [\n            function (value, element, params) {\n                return this.optional(element) ||\n                    $.mage.stripHtml(value).match(/\\b\\w+\\b/g).length >= params[0] &&\n                    value.match(/bw+b/g).length < params[1];\n            },\n            $.mage.__('Please enter between {0} and {1} words.')\n        ],\n        'letters-with-basic-punc': [\n            function (value, element) {\n                return this.optional(element) || /^[a-z\\-.,()'\\\"\\s]+$/i.test(value);\n            },\n            $.mage.__('Letters or punctuation only please')\n        ],\n        'alphanumeric': [\n            function (value, element) {\n                return this.optional(element) || /^\\w+$/i.test(value);\n            },\n            $.mage.__('Letters, numbers, spaces or underscores only please')\n        ],\n        'letters-only': [\n            function (value, element) {\n                return this.optional(element) || /^[a-z]+$/i.test(value);\n            },\n            $.mage.__('Letters only please')\n        ],\n        'no-whitespace': [\n            function (value, element) {\n                return this.optional(element) || /^\\S+$/i.test(value);\n            },\n            $.mage.__('No white space please')\n        ],\n        'no-marginal-whitespace': [\n            function (value, element) {\n                return this.optional(element) || !/^\\s+|\\s+$/i.test(value);\n            },\n            $.mage.__('No marginal white space please')\n        ],\n        'zip-range': [\n            function (value, element) {\n                return this.optional(element) || /^90[2-5]-\\d{2}-\\d{4}$/.test(value);\n            },\n            $.mage.__('Your ZIP-code must be in the range 902xx-xxxx to 905-xx-xxxx')\n        ],\n        'integer': [\n            function (value, element) {\n                return this.optional(element) || /^-?\\d+$/.test(value);\n            },\n            $.mage.__('A positive or negative non-decimal number please')\n        ],\n        'vinUS': [\n            function (v) {\n                var i, n, d, f, cd, cdv, LL, VL, FL, rs;\n\n                /* eslint-disable max-depth */\n                if (v.length !== 17) {\n                    return false;\n                }\n\n                LL = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L',\n                    'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];\n                VL = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9];\n                FL = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2];\n                rs = 0;\n\n                for (i = 0; i < 17; i++) {\n                    f = FL[i];\n                    d = v.slice(i, i + 1);\n\n                    if (i === 8) {\n                        cdv = d;\n                    }\n\n                    if (!isNaN(d)) {\n                        d *= f;\n                    } else {\n                        for (n = 0; n < LL.length; n++) {\n                            if (d.toUpperCase() === LL[n]) {\n                                d = VL[n];\n                                d *= f;\n\n                                if (isNaN(cdv) && n === 8) {\n                                    cdv = LL[n];\n                                }\n                                break;\n                            }\n                        }\n                    }\n                    rs += d;\n                }\n\n                /* eslint-enable max-depth */\n                cd = rs % 11;\n\n                if (cd === 10) {\n                    cd = 'X';\n                }\n\n                if (cd === cdv) {\n                    return true;\n                }\n\n                return false;\n            },\n            $.mage.__('The specified vehicle identification number (VIN) is invalid.')\n        ],\n        'dateITA': [\n            function (value, element) {\n                var check = false,\n                    re = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/,\n                    adata, gg, mm, aaaa, xdata;\n\n                if (re.test(value)) {\n                    adata = value.split('/');\n                    gg = parseInt(adata[0], 10);\n                    mm = parseInt(adata[1], 10);\n                    aaaa = parseInt(adata[2], 10);\n                    xdata = new Date(aaaa, mm - 1, gg);\n\n                    if (xdata.getFullYear() === aaaa &&\n                        xdata.getMonth() === mm - 1 &&\n                        xdata.getDate() === gg\n                    ) {\n                        check = true;\n                    } else {\n                        check = false;\n                    }\n                } else {\n                    check = false;\n                }\n\n                return this.optional(element) || check;\n            },\n            $.mage.__('Please enter a correct date')\n        ],\n        'dateNL': [\n            function (value, element) {\n                return this.optional(element) || /^\\d\\d?[\\.\\/-]\\d\\d?[\\.\\/-]\\d\\d\\d?\\d?$/.test(value);\n            },\n            'Vul hier een geldige datum in.'\n        ],\n        'time': [\n            function (value, element) {\n                return this.optional(element) || /^([01]\\d|2[0-3])(:[0-5]\\d){0,2}$/.test(value);\n            },\n            $.mage.__('Please enter a valid time, between 00:00 and 23:59')\n        ],\n        'time12h': [\n            function (value, element) {\n                return this.optional(element) || /^((0?[1-9]|1[012])(:[0-5]\\d){0,2}(\\s[AP]M))$/i.test(value);\n            },\n            $.mage.__('Please enter a valid time, between 00:00 am and 12:00 pm')\n        ],\n        'phoneUS': [\n            function (phoneNumber, element) {\n                phoneNumber = phoneNumber.replace(/\\s+/g, '');\n\n                return this.optional(element) || phoneNumber.length > 9 &&\n                    phoneNumber.match(/^(1-?)?(\\([2-9]\\d{2}\\)|[2-9]\\d{2})-?[2-9]\\d{2}-?\\d{4}$/);\n            },\n            $.mage.__('Please specify a valid phone number')\n        ],\n        'phoneUK': [\n            function (phoneNumber, element) {\n                return this.optional(element) || phoneNumber.length > 9 &&\n                    phoneNumber.match(/^(\\(?(0|\\+44)[1-9]{1}\\d{1,4}?\\)?\\s?\\d{3,4}\\s?\\d{3,4})$/);\n            },\n            $.mage.__('Please specify a valid phone number')\n        ],\n        'mobileUK': [\n            function (phoneNumber, element) {\n                return this.optional(element) || phoneNumber.length > 9 &&\n                    phoneNumber.match(/^((0|\\+44)7\\d{3}\\s?\\d{6})$/);\n            },\n            $.mage.__('Please specify a valid mobile number')\n        ],\n        'stripped-min-length': [\n            function (value, element, param) {\n                return value.length >= param;\n            },\n            $.mage.__('Please enter at least {0} characters')\n        ],\n\n        /* detect chars that would require more than 3 bytes */\n        'validate-no-utf8mb4-characters': [\n            function (value) {\n                var validator = this,\n                    message = $.mage.__('Please remove invalid characters: {0}.'),\n                    matches = value.match(/(?:[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])/g),\n                    result = matches === null;\n\n                if (!result) {\n                    validator.charErrorMessage = message.replace('{0}', matches.join());\n                }\n\n                return result;\n            }, function () {\n                return this.charErrorMessage;\n            }\n        ],\n\n        /* eslint-disable max-len */\n        'email2': [\n            function (value, element) {\n                return this.optional(element) ||\n                    /^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?$/i.test(value);\n            },\n            $.validator.messages.email\n        ],\n        'url2': [\n            function (value, element) {\n                return this.optional(element) || /^(https?|ftp):\\/\\/(((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|[\\uE000-\\uF8FF]|\\/|\\?)*)?(\\#((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.test(value);\n            },\n            $.validator.messages.url\n        ],\n\n        /* eslint-enable max-len */\n        'credit-card-types': [\n            function (value, element, param) {\n                var validTypes;\n\n                if (/[^0-9-]+/.test(value)) {\n                    return false;\n                }\n                value = value.replace(/\\D/g, '');\n\n                validTypes = 0x0000;\n\n                if (param.mastercard) {\n                    validTypes |= 0x0001;\n                }\n\n                if (param.visa) {\n                    validTypes |= 0x0002;\n                }\n\n                if (param.amex) {\n                    validTypes |= 0x0004;\n                }\n\n                if (param.dinersclub) {\n                    validTypes |= 0x0008;\n                }\n\n                if (param.enroute) {\n                    validTypes |= 0x0010;\n                }\n\n                if (param.discover) {\n                    validTypes |= 0x0020;\n                }\n\n                if (param.jcb) {\n                    validTypes |= 0x0040;\n                }\n\n                if (param.unknown) {\n                    validTypes |= 0x0080;\n                }\n\n                if (param.all) {\n                    validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;\n                }\n\n                if (validTypes & 0x0001 && /^(51|52|53|54|55)/.test(value)) { //mastercard\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0002 && /^(4)/.test(value)) { //visa\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0004 && /^(34|37)/.test(value)) { //amex\n                    return value.length === 15;\n                }\n\n                if (validTypes & 0x0008 && /^(300|301|302|303|304|305|36|38)/.test(value)) { //dinersclub\n                    return value.length === 14;\n                }\n\n                if (validTypes & 0x0010 && /^(2014|2149)/.test(value)) { //enroute\n                    return value.length === 15;\n                }\n\n                if (validTypes & 0x0020 && /^(6011)/.test(value)) { //discover\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0040 && /^(3)/.test(value)) { //jcb\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0040 && /^(2131|1800)/.test(value)) { //jcb\n                    return value.length === 15;\n                }\n\n                if (validTypes & 0x0080) { //unknown\n                    return true;\n                }\n\n                return false;\n            },\n            $.mage.__('Please enter a valid credit card number.')\n        ],\n\n        /* eslint-disable max-len */\n        'ipv4': [\n            function (value, element) {\n                return this.optional(element) ||\n                    /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i.test(value);\n            },\n            $.mage.__('Please enter a valid IP v4 address.')\n        ],\n        'ipv6': [\n            function (value, element) {\n                return this.optional(element) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value);\n            },\n            $.mage.__('Please enter a valid IP v6 address.')\n        ],\n\n        /* eslint-enable max-len */\n        'pattern': [\n            function (value, element, param) {\n                return this.optional(element) || param.test(value);\n            },\n            $.mage.__('Invalid format.')\n        ],\n        'allow-container-className': [\n            function (element) {\n                if (element.type === 'radio' || element.type === 'checkbox') {\n                    return $(element).hasClass('change-container-classname');\n                }\n            },\n            ''\n        ],\n        'validate-no-html-tags': [\n            function (value) {\n                return !/<(\\/)?\\w+/.test(value);\n            },\n            $.mage.__('HTML tags are not allowed.')\n        ],\n        'validate-select': [\n            function (value) {\n                return value !== 'none' && value != null && value.length !== 0;\n            },\n            $.mage.__('Please select an option.')\n        ],\n        'validate-no-empty': [\n            function (value) {\n                return !$.mage.isEmpty(value);\n            },\n            $.mage.__('Empty Value.')\n        ],\n        'validate-alphanum-with-spaces': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z0-9 ]+$/.test(v);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or spaces only in this field.')\n        ],\n        'validate-data': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^[A-Za-z]+[A-Za-z0-9_]+$/.test(v);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.') //eslint-disable-line max-len\n        ],\n        'validate-street': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^[ \\w]{3,}([A-Za-z]\\.)?([ \\w]*\\#\\d+)?(\\r\\n| )[ \\w]{3,}/.test(v);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9), spaces and \"#\" in this field.')\n        ],\n        'validate-phoneStrict': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^(\\()?\\d{3}(\\))?(-|\\s)?\\d{3}(-|\\s)\\d{4}$/.test(v);\n            },\n            $.mage.__('Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.')\n        ],\n        'validate-phoneLax': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) ||\n                    /^((\\d[\\-. ]?)?((\\(\\d{3}\\))|\\d{3}))?[\\-. ]?\\d{3}[\\-. ]?\\d{4}$/.test(v);\n            },\n            $.mage.__('Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.')\n        ],\n        'validate-fax': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^(\\()?\\d{3}(\\))?(-|\\s)?\\d{3}(-|\\s)\\d{4}$/.test(v);\n            },\n            $.mage.__('Please enter a valid fax number (Ex: 123-456-7890).')\n        ],\n        'validate-email': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*@([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*\\.(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]){2,})$/i.test(v); //eslint-disable-line max-len\n            },\n            $.mage.__('Please enter a valid email address (Ex: johndoe@domain.com).')\n        ],\n        'validate-emailSender': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^[\\S ]+$/.test(v);\n            },\n            $.mage.__('Please enter a valid email address (Ex: johndoe@domain.com).')\n        ],\n        'validate-password': [\n            function (v) {\n                var pass;\n\n                if (v == null) {\n                    return false;\n                }\n                //strip leading and trailing spaces\n                pass = $.trim(v);\n\n                if (!pass.length) {\n                    return true;\n                }\n\n                return !(pass.length > 0 && pass.length < 6);\n            },\n            $.mage.__('Please enter 6 or more characters. Leading and trailing spaces will be ignored.')\n        ],\n        'validate-admin-password': [\n            function (v) {\n                var pass;\n\n                if (v == null) {\n                    return false;\n                }\n                pass = $.trim(v);\n                // strip leading and trailing spaces\n                if (pass.length === 0) {\n                    return true;\n                }\n\n                if (!/[a-z]/i.test(v) || !/[0-9]/.test(v)) {\n                    return false;\n                }\n\n                if (pass.length < 7) {\n                    return false;\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter 7 or more characters, using both numeric and alphabetic.')\n        ],\n        'validate-customer-password': [\n            function (v, elm) {\n                var validator = this,\n                    counter = 0,\n                    passwordMinLength = $(elm).data('password-min-length'),\n                    passwordMinCharacterSets = $(elm).data('password-min-character-sets'),\n                    pass = $.trim(v),\n                    result = pass.length >= passwordMinLength;\n\n                if (result === false) {\n                    validator.passwordErrorMessage = $.mage.__('Minimum length of this field must be equal or greater than %1 symbols. Leading and trailing spaces will be ignored.').replace('%1', passwordMinLength); //eslint-disable-line max-len\n\n                    return result;\n                }\n\n                if (pass.match(/\\d+/)) {\n                    counter++;\n                }\n\n                if (pass.match(/[a-z]+/)) {\n                    counter++;\n                }\n\n                if (pass.match(/[A-Z]+/)) {\n                    counter++;\n                }\n\n                if (pass.match(/[^a-zA-Z0-9]+/)) {\n                    counter++;\n                }\n\n                if (counter < passwordMinCharacterSets) {\n                    result = false;\n                    validator.passwordErrorMessage = $.mage.__('Minimum of different classes of characters in password is %1. Classes of characters: Lower Case, Upper Case, Digits, Special Characters.').replace('%1', passwordMinCharacterSets); //eslint-disable-line max-len\n                }\n\n                return result;\n            }, function () {\n                return this.passwordErrorMessage;\n            }\n        ],\n        'validate-url': [\n            function (v) {\n                if ($.mage.isEmptyNoTrim(v)) {\n                    return true;\n                }\n                v = (v || '').replace(/^\\s+/, '').replace(/\\s+$/, '');\n\n                return (/^(http|https|ftp):\\/\\/(([A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))(\\.[A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))*)(:(\\d+))?(\\/[A-Z0-9~](([A-Z0-9_~-]|\\.)*[A-Z0-9~]|))*\\/?(.*)?$/i).test(v); //eslint-disable-line max-len\n\n            },\n            $.mage.__('Please enter a valid URL. Protocol is required (http://, https:// or ftp://).')\n        ],\n        'validate-clean-url': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^(http|https|ftp):\\/\\/(([A-Z0-9][A-Z0-9_-]*)(\\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\\d+))?\\/?/i.test(v) || /^(www)((\\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\\d+))?\\/?/i.test(v); //eslint-disable-line max-len\n\n            },\n            $.mage.__('Please enter a valid URL. For example http://www.example.com or www.example.com.')\n        ],\n        'validate-xml-identifier': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^[A-Z][A-Z0-9_\\/-]*$/i.test(v);\n\n            },\n            $.mage.__('Please enter a valid XML-identifier (Ex: something_1, block5, id-4).')\n        ],\n        'validate-ssn': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^\\d{3}-?\\d{2}-?\\d{4}$/.test(v);\n\n            },\n            $.mage.__('Please enter a valid social security number (Ex: 123-45-6789).')\n        ],\n        'validate-zip-us': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /(^\\d{5}$)|(^\\d{5}-\\d{4}$)/.test(v);\n\n            },\n            $.mage.__('Please enter a valid zip code (Ex: 90602 or 90602-1234).')\n        ],\n        'validate-date-au': [\n            function (v) {\n                var regex, d;\n\n                if ($.mage.isEmptyNoTrim(v)) {\n                    return true;\n                }\n                regex = /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/;\n\n                if ($.mage.isEmpty(v) || !regex.test(v)) {\n                    return false;\n                }\n                d = new Date(v.replace(regex, '$2/$1/$3'));\n\n                return parseInt(RegExp.$2, 10) === 1 + d.getMonth() &&\n                    parseInt(RegExp.$1, 10) === d.getDate() &&\n                    parseInt(RegExp.$3, 10) === d.getFullYear();\n\n            },\n            $.mage.__('Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.')\n        ],\n        'validate-currency-dollar': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^\\$?\\-?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}\\d*(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$/.test(v); //eslint-disable-line max-len\n\n            },\n            $.mage.__('Please enter a valid $ amount. For example $100.00.')\n        ],\n        'validate-not-negative-number': [\n            function (v) {\n                if ($.mage.isEmptyNoTrim(v)) {\n                    return true;\n                }\n                v = $.mage.parseNumber(v);\n\n                return !isNaN(v) && v >= 0;\n\n            },\n            $.mage.__('Please enter a number 0 or greater in this field.')\n        ],\n        // validate-not-negative-number should be replaced in all places with this one and then removed\n        'validate-zero-or-greater': [\n            function (v) {\n                if ($.mage.isEmptyNoTrim(v)) {\n                    return true;\n                }\n                v = $.mage.parseNumber(v);\n\n                return !isNaN(v) && v >= 0;\n\n            },\n            $.mage.__('Please enter a number 0 or greater in this field.')\n        ],\n        'validate-greater-than-zero': [\n            function (v) {\n                if ($.mage.isEmptyNoTrim(v)) {\n                    return true;\n                }\n                v = $.mage.parseNumber(v);\n\n                return !isNaN(v) && v > 0;\n            },\n            $.mage.__('Please enter a number greater than 0 in this field.')\n        ],\n        'validate-css-length': [\n            function (v) {\n                if (v !== '') {\n                    return (/^[0-9]*\\.*[0-9]+(px|pc|pt|ex|em|mm|cm|in|%)?$/).test(v);\n                }\n\n                return true;\n            },\n            $.mage.__('Please input a valid CSS-length (Ex: 100px, 77pt, 20em, .5ex or 50%).')\n        ],\n        // Additional methods\n        'validate-number': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || !isNaN($.mage.parseNumber(v)) && /^\\s*-?\\d*(\\.\\d*)?\\s*$/.test(v);\n            },\n            $.mage.__('Please enter a valid number in this field.')\n        ],\n        'required-number': [\n            function (v) {\n                return !!v.length;\n            },\n            $.mage.__('Please enter a valid number in this field.')\n        ],\n        'validate-number-range': [\n            function (v, elm, param) {\n                var numValue, dataAttrRange, classNameRange, result, range, m, classes, ii;\n\n                if ($.mage.isEmptyNoTrim(v)) {\n                    return true;\n                }\n\n                numValue = $.mage.parseNumber(v);\n\n                if (isNaN(numValue)) {\n                    return false;\n                }\n\n                dataAttrRange = /^(-?[\\d.,]+)?-(-?[\\d.,]+)?$/;\n                classNameRange = /^number-range-(-?[\\d.,]+)?-(-?[\\d.,]+)?$/;\n                result = true;\n                range = param;\n\n                if (typeof range === 'string') {\n                    m = dataAttrRange.exec(range);\n\n                    if (m) {\n                        result = result && $.mage.isBetween(numValue, m[1], m[2]);\n                    } else {\n                        result = false;\n                    }\n                } else if (elm && elm.className) {\n                    classes = elm.className.split(' ');\n                    ii = classes.length;\n\n                    while (ii--) {\n                        range = classes[ii];\n                        m = classNameRange.exec(range);\n\n                        if (m) { //eslint-disable-line max-depth\n                            result = result && $.mage.isBetween(numValue, m[1], m[2]);\n                            break;\n                        }\n                    }\n                }\n\n                return result;\n            },\n            $.mage.__('The value is not within the specified range.'),\n            true\n        ],\n        'validate-digits': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || !/[^\\d]/.test(v);\n            },\n            $.mage.__('Please enter a valid number in this field.')\n        ],\n        'validate-forbidden-extensions': [\n            function (v, elem) {\n                var forbiddenExtensions = $(elem).attr('data-validation-params'),\n                    forbiddenExtensionsArray = forbiddenExtensions.split(','),\n                    extensionsArray = v.split(','),\n                    result = true;\n\n                this.validateExtensionsMessage = $.mage.__('Forbidden extensions has been used. Avoid usage of ') +\n                    forbiddenExtensions;\n\n                $.each(extensionsArray, function (key, extension) {\n                    if (forbiddenExtensionsArray.indexOf(extension) !== -1) {\n                        result = false;\n                    }\n                });\n\n                return result;\n            }, function () {\n                return this.validateExtensionsMessage;\n            }\n        ],\n        'validate-digits-range': [\n            function (v, elm, param) {\n                var numValue, dataAttrRange, classNameRange, result, range, m, classes, ii;\n\n                if ($.mage.isEmptyNoTrim(v)) {\n                    return true;\n                }\n\n                numValue = $.mage.parseNumber(v);\n\n                if (isNaN(numValue)) {\n                    return false;\n                }\n\n                dataAttrRange = /^(-?\\d+)?-(-?\\d+)?$/;\n                classNameRange = /^digits-range-(-?\\d+)?-(-?\\d+)?$/;\n                result = true;\n                range = param;\n\n                if (typeof range === 'string') {\n                    m = dataAttrRange.exec(range);\n\n                    if (m) {\n                        result = result && $.mage.isBetween(numValue, m[1], m[2]);\n                    } else {\n                        result = false;\n                    }\n                } else if (elm && elm.className) {\n                    classes = elm.className.split(' ');\n                    ii = classes.length;\n\n                    while (ii--) {\n                        range = classes[ii];\n                        m = classNameRange.exec(range);\n\n                        if (m) { //eslint-disable-line max-depth\n                            result = result && $.mage.isBetween(numValue, m[1], m[2]);\n                            break;\n                        }\n                    }\n                }\n\n                return result;\n            },\n            $.mage.__('The value is not within the specified range.'),\n            true\n        ],\n        'validate-range': [\n            function (v, elm) {\n                var minValue, maxValue, ranges, reRange, result, values,\n                    i, name, validRange, minValidRange, maxValidRange;\n\n                if ($.mage.isEmptyNoTrim(v)) {\n                    return true;\n                } else if ($.validator.methods['validate-digits'] && $.validator.methods['validate-digits'](v)) {\n                    minValue = maxValue = $.mage.parseNumber(v);\n                } else {\n                    ranges = /^(-?\\d+)?-(-?\\d+)?$/.exec(v);\n\n                    if (ranges) {\n                        minValue = $.mage.parseNumber(ranges[1]);\n                        maxValue = $.mage.parseNumber(ranges[2]);\n\n                        if (minValue > maxValue) { //eslint-disable-line max-depth\n                            return false;\n                        }\n                    } else {\n                        return false;\n                    }\n                }\n                reRange = /^range-(-?\\d+)?-(-?\\d+)?$/;\n                result = true;\n                values = $(elm).prop('class').split(' ');\n\n                for (i = values.length - 1; i >= 0; i--) {\n                    name = values[i];\n                    validRange = reRange.exec(name);\n\n                    if (validRange) {\n                        minValidRange = $.mage.parseNumber(validRange[1]);\n                        maxValidRange = $.mage.parseNumber(validRange[2]);\n                        result = result &&\n                        (isNaN(minValidRange) || minValue >= minValidRange) &&\n                        (isNaN(maxValidRange) || maxValue <= maxValidRange);\n                    }\n                }\n\n                return result;\n            },\n            $.mage.__('The value is not within the specified range.')\n        ],\n        'validate-alpha': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z]+$/.test(v);\n            },\n            $.mage.__('Please use letters only (a-z or A-Z) in this field.')\n        ],\n        'validate-code': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z]+[a-zA-Z0-9_]+$/.test(v);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.') //eslint-disable-line max-len\n        ],\n        'validate-alphanum': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^[a-zA-Z0-9]+$/.test(v);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z) or numbers (0-9) in this field. No spaces or other characters are allowed.') //eslint-disable-line max-len\n        ],\n        'validate-not-number-first': [\n            function (value) {\n                return $.mage.isEmptyNoTrim(value) || /^[^0-9-\\.].*$/.test(value.trim());\n            },\n            $.mage.__('First character must be letter.')\n        ],\n        'validate-date': [\n            function (value, params, additionalParams) {\n                var test = moment(value, additionalParams.dateFormat);\n\n                return $.mage.isEmptyNoTrim(value) || test.isValid();\n            },\n            $.mage.__('Please enter a valid date.')\n\n        ],\n        'validate-date-range': [\n            function (v, elm) {\n                var m = /\\bdate-range-(\\w+)-(\\w+)\\b/.exec(elm.className),\n                    currentYear, normalizedTime, dependentElements;\n\n                if (!m || m[2] === 'to' || $.mage.isEmptyNoTrim(v)) {\n                    return true;\n                }\n\n                currentYear = new Date().getFullYear() + '';\n\n                /**\n                 * @param {String} vd\n                 * @return {Number}\n                 */\n                normalizedTime = function (vd) {\n                    vd = vd.split(/[.\\/]/);\n\n                    if (vd[2] && vd[2].length < 4) {\n                        vd[2] = currentYear.substr(0, vd[2].length) + vd[2];\n                    }\n\n                    return new Date(vd.join('/')).getTime();\n                };\n\n                dependentElements = $(elm.form).find('.validate-date-range.date-range-' + m[1] + '-to');\n\n                return !dependentElements.length || $.mage.isEmptyNoTrim(dependentElements[0].value) ||\n                    normalizedTime(v) <= normalizedTime(dependentElements[0].value);\n            },\n            $.mage.__('Make sure the To Date is later than or the same as the From Date.')\n        ],\n        'validate-cpassword': [\n            function () {\n                var conf = $('#confirmation').length > 0 ? $('#confirmation') : $($('.validate-cpassword')[0]),\n                    pass = false,\n                    passwordElements, i, passwordElement;\n\n                if ($('#password')) {\n                    pass = $('#password');\n                }\n                passwordElements = $('.validate-password');\n\n                for (i = 0; i < passwordElements.length; i++) {\n                    passwordElement = $(passwordElements[i]);\n\n                    if (passwordElement.closest('form').attr('id') === conf.closest('form').attr('id')) {\n                        pass = passwordElement;\n                    }\n                }\n\n                if ($('.validate-admin-password').length) {\n                    pass = $($('.validate-admin-password')[0]);\n                }\n\n                return pass.val() === conf.val();\n            },\n            $.mage.__('Please make sure your passwords match.')\n        ],\n        'validate-identifier': [\n            function (v) {\n                return $.mage.isEmptyNoTrim(v) || /^[a-z0-9][a-z0-9_\\/-]+(\\.[a-z0-9_-]+)?$/.test(v);\n            },\n            $.mage.__('Please enter a valid URL Key (Ex: \"example-page\", \"example-page.html\" or \"anotherlevel/example-page\").') //eslint-disable-line max-len\n        ],\n        'validate-zip-international': [\n\n            /*function(v) {\n             // @TODO: Cleanup\n             return Validation.get('IsEmpty').test(v) ||\n             /(^[A-z0-9]{2,10}([\\s]{0,1}|[\\-]{0,1})[A-z0-9]{2,10}$)/.test(v);\n             }*/\n            function () {\n                return true;\n            },\n            $.mage.__('Please enter a valid zip code.')\n        ],\n        'validate-one-required': [\n            function (v, elm) {\n                var p = $(elm).parent(),\n                    options = p.find('input');\n\n                return options.map(function (el) {\n                        return $(el).val();\n                    }).length > 0;\n            },\n            $.mage.__('Please select one of the options above.')\n        ],\n        'validate-state': [\n            function (v) {\n                return v !== 0 || v === '';\n            },\n            $.mage.__('Please select State/Province.')\n        ],\n        'required-file': [\n            function (v, elm) {\n                var result = !$.mage.isEmptyNoTrim(v),\n                    ovId;\n\n                if (!result) {\n                    ovId = $('#' + $(elm).attr('id') + '_value');\n\n                    if (ovId.length > 0) {\n                        result = !$.mage.isEmptyNoTrim(ovId.val());\n                    }\n                }\n\n                return result;\n            },\n            $.mage.__('Please select a file.')\n        ],\n        'validate-ajax-error': [\n            function (v, element) {\n                element = $(element);\n                element.on('change.ajaxError', function () {\n                    element.removeClass('validate-ajax-error');\n                    element.off('change.ajaxError');\n                });\n\n                return !element.hasClass('validate-ajax-error');\n            },\n            ''\n        ],\n        'validate-optional-datetime': [\n            function (v, elm, param) {\n                var dateTimeParts = $('.datetime-picker[id^=\"options_' + param + '\"]'),\n                    hasWithValue = false,\n                    hasWithNoValue = false,\n                    pattern = /day_part$/i,\n                    i;\n\n                for (i = 0; i < dateTimeParts.length; i++) {\n                    if (!pattern.test($(dateTimeParts[i]).attr('id'))) {\n                        if ($(dateTimeParts[i]).val() === 's') { //eslint-disable-line max-depth\n                            hasWithValue = true;\n                        } else {\n                            hasWithNoValue = true;\n                        }\n                    }\n                }\n\n                return hasWithValue ^ hasWithNoValue;\n            },\n            $.mage.__('The field isn\\'t complete.')\n        ],\n        'validate-required-datetime': [\n            function (v, elm, param) {\n                var dateTimeParts = $('.datetime-picker[id^=\"options_' + param + '\"]'),\n                    i;\n\n                for (i = 0; i < dateTimeParts.length; i++) {\n                    if (dateTimeParts[i].value === '') {\n                        return false;\n                    }\n                }\n\n                return true;\n            },\n            $.mage.__('This is a required field.')\n        ],\n        'validate-one-required-by-name': [\n            function (v, elm, selector) {\n                var name = elm.name.replace(/([\\\\\"])/g, '\\\\$1'),\n                    container = this.currentForm;\n\n                selector = selector === true ? 'input[name=\"' + name + '\"]:checked' : selector;\n\n                return !!container.querySelectorAll(selector).length;\n            },\n            $.mage.__('Please select one of the options.')\n        ],\n        'less-than-equals-to': [\n            function (value, element, params) {\n                if ($.isNumeric($(params).val()) && $.isNumeric(value)) {\n                    this.lteToVal = $(params).val();\n\n                    return parseFloat(value) <= parseFloat($(params).val());\n                }\n\n                return true;\n            },\n            function () {\n                var message = $.mage.__('Please enter a value less than or equal to %s.');\n\n                return message.replace('%s', this.lteToVal);\n            }\n        ],\n        'greater-than-equals-to': [\n            function (value, element, params) {\n                if ($.isNumeric($(params).val()) && $.isNumeric(value)) {\n                    this.gteToVal = $(params).val();\n\n                    return parseFloat(value) >= parseFloat($(params).val());\n                }\n\n                return true;\n            },\n            function () {\n                var message = $.mage.__('Please enter a value greater than or equal to %s.');\n\n                return message.replace('%s', this.gteToVal);\n            }\n        ],\n        'validate-emails': [\n            function (value) {\n                var validRegexp, emails, i;\n\n                if ($.mage.isEmpty(value)) {\n                    return true;\n                }\n                validRegexp = /^([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*@([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*\\.(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]){2,})$/i; //eslint-disable-line max-len\n                emails = value.split(/[\\s\\n\\,]+/g);\n\n                for (i = 0; i < emails.length; i++) {\n                    if (!validRegexp.test(emails[i].trim())) {\n                        return false;\n                    }\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter valid email addresses, separated by commas. For example, johndoe@domain.com, johnsmith@domain.com.') //eslint-disable-line max-len\n        ],\n\n        'validate-cc-type-select': [\n\n            /**\n             * Validate credit card type matches credit card number\n             * @param {*} value - select credit card type\n             * @param {*} element - element contains the select box for credit card types\n             * @param {*} params - selector for credit card number\n             * @return {Boolean}\n             */\n            function (value, element, params) {\n                if (value && params && creditCartTypes[value]) {\n                    return creditCartTypes[value][0].test($(params).val().replace(/\\s+/g, ''));\n                }\n\n                return false;\n            },\n            $.mage.__('Card type does not match credit card number.')\n        ],\n        'validate-cc-number': [\n\n            /**\n             * Validate credit card number based on mod 10.\n             *\n             * @param {*} value - credit card number\n             * @return {Boolean}\n             */\n            function (value) {\n                if (value) {\n                    return validateCreditCard(value);\n                }\n\n                return false;\n            },\n            $.mage.__('Please enter a valid credit card number.')\n        ],\n        'validate-cc-type': [\n\n            /**\n             * Validate credit card number is for the correct credit card type.\n             *\n             * @param {String} value - credit card number\n             * @param {*} element - element contains credit card number\n             * @param {*} params - selector for credit card type\n             * @return {Boolean}\n             */\n            function (value, element, params) {\n                var ccType;\n\n                if (value && params) {\n                    ccType = $(params).val();\n                    value = value.replace(/\\s/g, '').replace(/\\-/g, '');\n\n                    if (creditCartTypes[ccType] && creditCartTypes[ccType][0]) {\n                        return creditCartTypes[ccType][0].test(value);\n                    } else if (creditCartTypes[ccType] && !creditCartTypes[ccType][0]) {\n                        return true;\n                    }\n                }\n\n                return false;\n            },\n            $.mage.__('Credit card number does not match credit card type.')\n        ],\n        'validate-cc-exp': [\n\n            /**\n             * Validate credit card expiration date, make sure it's within the year and not before current month.\n             *\n             * @param {*} value - month\n             * @param {*} element - element contains month\n             * @param {*} params - year selector\n             * @return {Boolean}\n             */\n            function (value, element, params) {\n                var isValid = false,\n                    month, year, currentTime, currentMonth, currentYear;\n\n                if (value && params) {\n                    month = value;\n                    year = $(params).val();\n                    currentTime = new Date();\n                    currentMonth = currentTime.getMonth() + 1;\n                    currentYear = currentTime.getFullYear();\n\n                    isValid = !year || year > currentYear || year == currentYear && month >= currentMonth; //eslint-disable-line\n                }\n\n                return isValid;\n            },\n            $.mage.__('Incorrect credit card expiration date.')\n        ],\n        'validate-cc-cvn': [\n\n            /**\n             * Validate credit card cvn based on credit card type.\n             *\n             * @param {*} value - credit card cvn\n             * @param {*} element - element contains credit card cvn\n             * @param {*} params - credit card type selector\n             * @return {*}\n             */\n            function (value, element, params) {\n                var ccType;\n\n                if (value && params) {\n                    ccType = $(params).val();\n\n                    if (creditCartTypes[ccType] && creditCartTypes[ccType][0]) {\n                        return creditCartTypes[ccType][1].test(value);\n                    }\n                }\n\n                return false;\n            },\n            $.mage.__('Please enter a valid credit card verification number.')\n        ],\n        'validate-cc-ukss': [\n\n            /**\n             * Validate Switch/Solo/Maestro issue number and start date is filled.\n             *\n             * @param {*} value - input field value\n             * @return {*}\n             */\n            function (value) {\n                return value;\n            },\n            $.mage.__('Please enter issue number or start date for switch/solo card type.')\n        ],\n        'validate-length': [\n            function (v, elm) {\n                var reMax = new RegExp(/^maximum-length-[0-9]+$/),\n                    reMin = new RegExp(/^minimum-length-[0-9]+$/),\n                    validator = this,\n                    result = true,\n                    length = 0;\n\n                $.each(elm.className.split(' '), function (index, name) {\n                    if (name.match(reMax) && result) {\n                        length = name.split('-')[2];\n                        result = v.length <= length;\n                        validator.validateMessage =\n                            $.mage.__('Please enter less or equal than %1 symbols.').replace('%1', length);\n                    }\n\n                    if (name.match(reMin) && result && !$.mage.isEmpty(v)) {\n                        length = name.split('-')[2];\n                        result = v.length >= length;\n                        validator.validateMessage =\n                            $.mage.__('Please enter more or equal than %1 symbols.').replace('%1', length);\n                    }\n                });\n\n                return result;\n            }, function () {\n                return this.validateMessage;\n            }\n        ],\n        'required-entry': [\n            function (value) {\n                return !$.mage.isEmpty(value);\n            }, $.mage.__('This is a required field.')\n        ],\n        'not-negative-amount': [\n            function (v) {\n                if (v.length) {\n                    return (/^\\s*\\d+([,.]\\d+)*\\s*%?\\s*$/).test(v);\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter positive number in this field.')\n        ],\n        'validate-per-page-value-list': [\n            function (v) {\n                var isValid = !$.mage.isEmpty(v),\n                    values = v.split(','),\n                    i;\n\n                for (i = 0; i < values.length; i++) {\n                    if (!/^[0-9]+$/.test(values[i])) {\n                        isValid = false;\n                    }\n                }\n\n                return isValid;\n            },\n            $.mage.__('Please enter a valid value, ex: 10,20,30')\n        ],\n        'validate-per-page-value': [\n            function (v, elm) {\n                var values;\n\n                if ($.mage.isEmpty(v)) {\n                    return false;\n                }\n                values = $('#' + elm.id + '_values').val().split(',');\n\n                return values.indexOf(v) !== -1;\n            },\n            $.mage.__('Please enter a valid value from list')\n        ],\n        'validate-new-password': [\n            function (v) {\n                if ($.validator.methods['validate-password'] && !$.validator.methods['validate-password'](v)) {\n                    return false;\n                }\n\n                if ($.mage.isEmpty(v) && v !== '') {\n                    return false;\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter 6 or more characters. Leading and trailing spaces will be ignored.')\n        ],\n        'required-if-not-specified': [\n            function (value, element, params) {\n                var valid = false,\n                    alternate = $(params),\n                    alternateValue;\n\n                if (alternate.length > 0) {\n                    valid = this.check(alternate);\n                    // if valid, it may be blank, so check for that\n                    if (valid) {\n                        alternateValue = alternate.val();\n\n                        if (typeof alternateValue == 'undefined' || alternateValue.length === 0) { //eslint-disable-line\n                            valid = false;\n                        }\n                    }\n                }\n\n                if (!valid) {\n                    valid = !this.optional(element);\n                }\n\n                return valid;\n            },\n            $.mage.__('This is a required field.')\n        ],\n        'required-if-all-sku-empty-and-file-not-loaded': [\n            function (value, element, params) {\n                var valid = false,\n                    alternate = $(params.specifiedId),\n                    alternateValue;\n\n                if (alternate.length > 0) {\n                    valid = this.check(alternate);\n                    // if valid, it may be blank, so check for that\n                    if (valid) {\n                        alternateValue = alternate.val();\n\n                        if (typeof alternateValue == 'undefined' || alternateValue.length === 0) { //eslint-disable-line\n                            valid = false;\n                        }\n                    }\n                }\n\n                if (!valid) {\n                    valid = !this.optional(element);\n                }\n\n                $('input[' + params.dataSku + '=true]').each(function () {\n                    if ($(this).val() !== '') {\n                        valid = true;\n                    }\n                });\n\n                return valid;\n            },\n            $.mage.__('Please enter valid SKU key.')\n        ],\n        'required-if-specified': [\n            function (value, element, params) {\n                var valid = true,\n                    dependent = $(params),\n                    dependentValue;\n\n                if (dependent.length > 0) {\n                    valid = this.check(dependent);\n                    // if valid, it may be blank, so check for that\n                    if (valid) {\n                        dependentValue = dependent.val();\n                        valid = typeof dependentValue != 'undefined' && dependentValue.length > 0;\n                    }\n                }\n\n                if (valid) {\n                    valid = !this.optional(element);\n                } else {\n                    valid = true; // dependent was not valid, so don't even check\n                }\n\n                return valid;\n            },\n            $.mage.__('This is a required field.')\n        ],\n        'required-number-if-specified': [\n            function (value, element, params) {\n                var valid = true,\n                    dependent = $(params),\n                    depeValue;\n\n                if (dependent.length) {\n                    valid = this.check(dependent);\n\n                    if (valid) {\n                        depeValue = dependent[0].value;\n                        valid = !!(depeValue && depeValue.length);\n                    }\n                }\n\n                return valid ? !!value.length : true;\n            },\n            $.mage.__('Please enter a valid number.')\n        ],\n        'datetime-validation': [\n            function (value, element) {\n                var isValid = true;\n\n                if ($(element).val().length === 0) {\n                    isValid = false;\n                    $(element).addClass('mage-error');\n                }\n\n                return isValid;\n            },\n            $.mage.__('This is required field')\n        ],\n        'required-text-swatch-entry': [\n            tableSingleValidation,\n            $.mage.__('Admin is a required field in each row.')\n        ],\n        'required-visual-swatch-entry': [\n            tableSingleValidation,\n            $.mage.__('Admin is a required field in each row.')\n        ],\n        'required-dropdown-attribute-entry': [\n            tableSingleValidation,\n            $.mage.__('Admin is a required field in each row.')\n        ],\n        'validate-item-quantity': [\n            function (value, element, params) {\n                var validator = this,\n                    result = false,\n                    // obtain values for validation\n                    qty = $.mage.parseNumber(value),\n                    isMinAllowedValid = typeof params.minAllowed === 'undefined' ||\n                        qty >= $.mage.parseNumber(params.minAllowed),\n                    isMaxAllowedValid = typeof params.maxAllowed === 'undefined' ||\n                        qty <= $.mage.parseNumber(params.maxAllowed),\n                    isQtyIncrementsValid = typeof params.qtyIncrements === 'undefined' ||\n                        qty % $.mage.parseNumber(params.qtyIncrements) === 0;\n\n                result = qty > 0;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('Please enter a quantity greater than 0.');//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                result = isMinAllowedValid;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('The fewest you may purchase is %1.').replace('%1', params.minAllowed);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                result = isMaxAllowedValid;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('The maximum you may purchase is %1.').replace('%1', params.maxAllowed);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                result = isQtyIncrementsValid;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('You can buy this product only in quantities of %1 at a time.').replace('%1', params.qtyIncrements);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                return result;\n            }, function () {\n                return this.itemQtyErrorMessage;\n            }\n        ],\n        'password-not-equal-to-user-name': [\n            function (value, element, params) {\n                if (typeof params === 'string') {\n                    return value.toLowerCase() !== params.toLowerCase();\n                }\n\n                return true;\n            },\n            $.mage.__('The password can\\'t be the same as the email address. Create a new password and try again.')\n        ]\n    };\n\n    $.each(rules, function (i, rule) {\n        rule.unshift(i);\n        $.validator.addMethod.apply($.validator, rule);\n    });\n    $.validator.addClassRules({\n        'required-option': {\n            required: true\n        },\n        'required-options-count': {\n            required: true\n        },\n        'validate-both-passwords': {\n            'validate-cpassword': true\n        }\n    });\n    $.validator.messages = $.extend($.validator.messages, {\n        required: $.mage.__('This is a required field.'),\n        remote: $.mage.__('Please fix this field.'),\n        email: $.mage.__('Please enter a valid email address.'),\n        url: $.mage.__('Please enter a valid URL.'),\n        date: $.mage.__('Please enter a valid date.'),\n        dateISO: $.mage.__('Please enter a valid date (ISO).'),\n        number: $.mage.__('Please enter a valid number.'),\n        digits: $.mage.__('Please enter only digits.'),\n        creditcard: $.mage.__('Please enter a valid credit card number.'),\n        equalTo: $.mage.__('Please enter the same value again.'),\n        maxlength: $.validator.format($.mage.__('Please enter no more than {0} characters.')),\n        minlength: $.validator.format($.mage.__('Please enter at least {0} characters.')),\n        rangelength: $.validator.format($.mage.__('Please enter a value between {0} and {1} characters long.')),\n        range: $.validator.format($.mage.__('Please enter a value between {0} and {1}.')),\n        max: $.validator.format($.mage.__('Please enter a value less than or equal to {0}.')),\n        min: $.validator.format($.mage.__('Please enter a value greater than or equal to {0}.'))\n    });\n\n    if ($.metadata) {\n        // Setting the type as html5 to enable data-validate attribute\n        $.metadata.setType('html5');\n    }\n\n    showLabel = $.validator.prototype.showLabel;\n    $.extend(true, $.validator.prototype, {\n        /**\n         * @param {*} element\n         * @param {*} message\n         */\n        showLabel: function (element, message) {\n            var label, elem;\n\n            showLabel.call(this, element, message);\n\n            // ARIA (adding aria-invalid & aria-describedby)\n            label = this.errorsFor(element);\n            elem = $(element);\n\n            if (!label.attr('id')) {\n                label.attr('id', this.idOrName(element) + '-error');\n            }\n            elem.attr('aria-invalid', 'true')\n                .attr('aria-describedby', label.attr('id'));\n        }\n    });\n\n    /**\n     * Validate form field without instantiating validate plug-in.\n     *\n     * @param {Element|String} element - DOM element or selector\n     * @return {Boolean} validation result\n     */\n    $.validator.validateElement = function (element) {\n        var form, validator, valid, classes;\n\n        element = $(element);\n        form = element.get(0).form;\n        validator = form ? $(form).data('validator') : null;\n\n        if (validator) {\n            return validator.element(element.get(0));\n        }\n        valid = true;\n        classes = element.prop('class').split(' ');\n        $.each(classes, $.proxy(function (i, className) {\n            if (this.methods[className] && !this.methods[className](element.val(), element.get(0))) {\n                valid = false;\n\n                return valid;\n            }\n        }, this));\n\n        return valid;\n    };\n\n    originValidateDelegate = $.fn.validateDelegate;\n\n    /**\n     * @return {*}\n     */\n    $.fn.validateDelegate = function () {\n        if (!this[0].form) {\n            return this;\n        }\n\n        return originValidateDelegate.apply(this, arguments);\n    };\n\n    /**\n     * Validate single element.\n     *\n     * @param {Element} element\n     * @param {Object} config\n     * @returns {*}\n     */\n    $.validator.validateSingleElement = function (element, config) {\n        var errors = {},\n            valid = true,\n            validateConfig = {\n                errorElement: 'label',\n                ignore: '.ignore-validate',\n                hideError: false\n            },\n            form, validator, classes, elementValue;\n\n        $.extend(validateConfig, config);\n        element = $(element).not(validateConfig.ignore);\n\n        if (!element.length) {\n            return true;\n        }\n\n        form = element.get(0).form;\n        validator = form ? $(form).data('validator') : null;\n\n        if (validator) {\n            return validator.element(element.get(0));\n        }\n\n        classes = element.prop('class').split(' ');\n        validator = element.parent().data('validator') ||\n            $.mage.validation(validateConfig, element.parent()).validate;\n\n        element.removeClass(validator.settings.errorClass);\n        validator.toHide = validator.toShow;\n        validator.hideErrors();\n        validator.toShow = validator.toHide = $([]);\n\n        $.each(classes, $.proxy(function (i, className) {\n            elementValue = element.val();\n\n            if (element.is(':checkbox') || element.is(':radio')) {\n                elementValue = element.is(':checked') || null;\n            }\n\n            if (this.methods[className] && !this.methods[className](elementValue, element.get(0))) {\n                valid = false;\n                errors[element.get(0).name] = this.messages[className];\n                validator.invalid[element.get(0).name] = true;\n\n                if (!validateConfig.hideError) {\n                    validator.showErrors(errors);\n                }\n\n                return valid;\n            }\n        }, this));\n\n        return valid;\n    };\n\n    $.widget('mage.validation', {\n        options: {\n            meta: 'validate',\n            onfocusout: false,\n            onkeyup: false,\n            onclick: false,\n            ignoreTitle: true,\n            errorClass: 'mage-error',\n            errorElement: 'div',\n\n            /**\n             * @param {*} error\n             * @param {*} element\n             */\n            errorPlacement: function (error, element) {\n                var errorPlacement = element,\n                    fieldWrapper;\n\n                // logic for date-picker error placement\n                if (element.hasClass('_has-datepicker')) {\n                    errorPlacement = element.siblings('button');\n                }\n                // logic for field wrapper\n                fieldWrapper = element.closest('.addon');\n\n                if (fieldWrapper.length) {\n                    errorPlacement = fieldWrapper.after(error);\n                }\n                //logic for checkboxes/radio\n                if (element.is(':checkbox') || element.is(':radio')) {\n                    errorPlacement = element.parents('.control').children().last();\n\n                    //fallback if group does not have .control parent\n                    if (!errorPlacement.length) {\n                        errorPlacement = element.siblings('label').last();\n                    }\n                }\n                //logic for control with tooltip\n                if (element.siblings('.tooltip').length) {\n                    errorPlacement = element.siblings('.tooltip');\n                }\n                errorPlacement.after(error);\n            }\n        },\n\n        /**\n         * Check if form pass validation rules without submit.\n         *\n         * @return boolean\n         */\n        isValid: function () {\n            return this.element.valid();\n        },\n\n        /**\n         * Remove validation error messages\n         */\n        clearError: function () {\n            if (arguments.length) {\n                $.each(arguments, $.proxy(function (index, item) {\n                    this.validate.prepareElement(item);\n                    this.validate.hideErrors();\n                }, this));\n            } else {\n                this.validate.resetForm();\n            }\n        },\n\n        /**\n         * Validation creation.\n         *\n         * @protected\n         */\n        _create: function () {\n            this.validate = this.element.validate(this.options);\n\n            // ARIA (adding aria-required attribute)\n            this.element\n                .find('.field.required')\n                .find('.control')\n                .find('input, select, textarea')\n                .attr('aria-required', 'true');\n\n            this._listenFormValidate();\n        },\n\n        /**\n         * Validation listening.\n         * @protected\n         */\n        _listenFormValidate: function () {\n            $('form').on('invalid-form.validate', this.listenFormValidateHandler);\n        },\n\n        /**\n         * Handle form validation. Focus on first invalid form field.\n         *\n         * @param {jQuery.Event} event\n         * @param {Object} validation\n         */\n        listenFormValidateHandler:  function (event, validation) {\n            var firstActive = $(validation.errorList[0].element || []),\n                lastActive = $(validation.findLastActive() ||\n                    validation.errorList.length && validation.errorList[0].element || []),\n                parent, windowHeight, successList;\n\n            if (lastActive.is(':hidden')) {\n                parent = lastActive.parent();\n                windowHeight = $(window).height();\n                $('html, body').animate({\n                    scrollTop: parent.offset().top - windowHeight / 2\n                });\n            }\n\n            // ARIA (removing aria attributes if success)\n            successList = validation.successList;\n\n            if (successList.length) {\n                $.each(successList, function () {\n                    $(this)\n                        .removeAttr('aria-describedby')\n                        .removeAttr('aria-invalid');\n                });\n            }\n\n            if (firstActive.length) {\n                $('html, body').animate({\n                    scrollTop: firstActive.offset().top\n                });\n                firstActive.focus();\n            }\n        }\n    });\n\n    return $.mage.validation;\n}));\n","mage/tooltip.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\ndefine([\n    'jquery',\n    'jquery/ui'\n], function ($) {\n    'use strict';\n\n    //Widget Wrapper\n    $.widget('mage.tooltip', $.ui.tooltip, {});\n\n    return $.mage.tooltip;\n});\n","mage/item-table.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\ndefine([\n    'jquery',\n    'mage/template',\n    'jquery/ui'\n], function ($, mageTemplate) {\n    'use strict';\n\n    $.widget('mage.itemTable', {\n        options: {\n            addBlock: '[data-template=\"add-block\"]',\n            addBlockData: {},\n            addEvent: 'click',\n            addSelector: '[data-role=\"add\"]',\n            itemsSelector: '[data-container=\"items\"]',\n            keepLastRow: true\n        },\n\n        /**\n         * This method adds a new instance of the block to the items.\n         * @private\n         */\n        _add: function () {\n            var hideShowDelete,\n                deletableItems,\n                addedBlock;\n\n            // adding a new row, so increment the count to give each row a unique index\n            this.rowIndex++;\n\n            // make sure the block data has the rowIndex\n            this.options.addBlockData.rowIndex = this.rowIndex;\n\n            // render the form\n            addedBlock = $(this.addBlockTmpl({\n                data: this.options.addBlockData\n            }));\n\n            // add the row to the item block\n            this.element.find(this.options.itemsSelector).append(addedBlock);\n\n            // initialize all mage content\n            addedBlock.trigger('contentUpdated');\n\n            // determine all existing items in the collection\n            deletableItems = this._getDeletableItems();\n\n            // for the most part, show the delete mechanism, except in the case where there is only one it should not\n            // be deleted\n            hideShowDelete = 'showDelete';\n\n            if (this.options.keepLastRow && deletableItems.length === 1) {\n                hideShowDelete = 'hideDelete';\n            }\n\n            // loop through each control and perform that action on the deletable item\n            $.each(deletableItems, function (index) {\n                $(deletableItems[index]).trigger(hideShowDelete);\n            });\n        },\n\n        /**\n         * This method binds elements found in this widget.\n         * @private\n         */\n        _bind: function () {\n            var handlers = {};\n\n            // since the first handler is dynamic, generate the object using array notation\n            handlers[this.options.addEvent + ' ' + this.options.addSelector] = '_add';\n            handlers.deleteItem = '_onDeleteItem';\n\n            this._on(handlers);\n        },\n\n        /**\n         * This method constructs a new widget.\n         * @private\n         */\n        _create: function () {\n            this._bind();\n\n            this.addBlockTmpl = mageTemplate(this.options.addBlock);\n\n            // nothing in the table, so indicate that\n            this.rowIndex = -1;\n\n            // make sure the block data is an object\n            if (this.options.addBlockData == null || typeof this.options.addBlockData !== 'object') {\n                // reset the block data to an empty object\n                this.options.addBlockData = {};\n            }\n\n            // add the first row to the table\n            this._add();\n        },\n\n        /**\n         * This method returns the list of widgets associated with deletable items from the container (direct children\n         * only).\n         * @private\n         */\n        _getDeletableItems: function () {\n            return this.element.find(this.options.itemsSelector + '> .deletableItem');\n        },\n\n        /**\n         * This method removes the item associated with the message.\n         * @private\n         */\n        _onDeleteItem: function (e) {\n            var deletableItems;\n\n            // parent elements don't need to see this event\n            e.stopPropagation();\n\n            // remove the deletable item\n            $(e.target).remove();\n\n            if (this.options.keepLastRow) {\n                // determine if there is only one element remaining, in which case, disable the delete mechanism on it\n                deletableItems = this._getDeletableItems();\n\n                if (deletableItems.length === 1) {\n                    $(deletableItems[0]).trigger('hideDelete');\n                }\n            }\n        }\n    });\n\n    return $.mage.itemTable;\n});\n","mage/terms.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * @param {*} args\n     */\n    $.fn.terms = function (args) {\n\n        // default\n        var defaults = {\n                start: 0,\n                wrapper: '',\n                showAnchor: '',\n                effects: 'slide'\n            },\n            options = $.extend(defaults, args);\n\n        this.each(function () {\n            var obj = $(this),\n                wrapper = options.wrapper !== '' ? '> ' + options.wrapper : '',\n                switches = $(wrapper + '> [data-section=\"title\"] > [data-toggle=\"switch\"]', obj),\n                terms = $(wrapper + '> [data-section=\"content\"]', obj),\n                t = switches.length,\n                marginTop = $(switches[0]).closest('[data-section=\"title\"]').css('position') == 'absolute' ? 0 : null, //eslint-disable-line\n                title,\n                current,\n\n                /**\n                 * @param {*} item\n                 */\n                showItem = function (item) {\n                    if (item != current && !$(switches[item]).closest('[data-section=\"title\"]').hasClass('disabled')) { //eslint-disable-line\n                        $(switches).closest('[data-section=\"title\"]').removeClass('active');\n\n                        if (options.wrapper !== '') {\n                            $(switches).parent().parent().removeClass('active');\n                        }\n                        $(terms).removeClass('active');\n                        $(switches[item]).closest('[data-section=\"title\"]').addClass('active');\n\n                        if (options.wrapper !== '') {\n                            $(switches[current]).parent().parent().addClass('active');\n                        }\n                        $(terms[item]).addClass('active');\n                        current = item;\n                    } else if (\n                        // Check if this is accordion width as criteria for now\n                        (obj.attr('data-sections') == 'accordion' || $(switches[item]).closest('[data-section=\"title\"]').css('width') == obj.css('width')) && //eslint-disable-line\n                        item == current && !$(switches[item]).closest('[data-section=\"title\"]').hasClass('disabled') //eslint-disable-line\n                    ) {\n                        $(switches).closest('[data-section=\"title\"]').removeClass('active');\n\n                        if (options.wrapper !== '') {\n                            $(switches).parent().parent().removeClass('active');\n                        }\n                        $(terms).removeClass('active');\n                        current = -1;\n                    }\n                },\n\n                /**\n                 * Init.\n                 */\n                init = function () {\n                    var linksList, i, classes, dataSection, itemHref, itemClass, fromUrl;\n\n                    if (t > 0) {\n                        if ($(switches[0]).closest('[data-section=\"title\"]').css('display') == 'table-cell') { //eslint-disable-line\n                            obj.addClass('adjusted');\n\n                            if (obj[0].tagName == 'DL') { //eslint-disable-line eqeqeq, max-depth\n                                linksList = $('<dd>');\n                            } else {\n                                linksList = $('<div>');\n                            }\n                            linksList.addClass('sections-nav');\n                            obj.prepend(linksList);\n\n                            for (i = 0; i < t; i++) { //eslint-disable-line max-depth\n                                title = $(switches[i]).html();\n                                classes = $(switches[i]).closest('[data-section=\"title\"]').attr('class');\n                                dataSection = $(switches[i]).closest('[data-section=\"title\"]').attr('data-section');\n                                itemHref = $(switches[i]).attr('href');\n                                itemClass = $(switches[i]).attr('class');\n                                $(switches[i]).parent('[data-section=\"title\"]').hide();\n                                switches[i] = $('<a/>', {\n                                    href: itemHref,\n                                    'class': itemClass,\n                                    html: title\n                                }).appendTo(linksList);\n                                $(switches[i]).wrap(\n                                    '<strong class=\"' + classes + '\" data-section=\"' + dataSection + '\" />'\n                                );\n                            }\n                        }\n                        $(switches).each(function (ind, el) {\n                            $(el).click(function (event) {\n                                event.preventDefault();\n                                showItem(ind);\n                            });\n\n                            if (marginTop !== null) {\n                                $(el).closest('[data-section=\"title\"]').css({\n                                    'top': marginTop + 'px'\n                                });\n                                marginTop += $(el).closest('[data-section=\"title\"]').outerHeight(true);\n                                obj.css({\n                                    'min-height': marginTop + 'px'\n                                });\n                            }\n                        });\n\n                        fromUrl = false;\n\n                        if (window.location.hash.length > 0) {\n                            $(terms).each(function (ind, el) {\n                                if ('#info-' + $(el).attr('id') == window.location.hash) { //eslint-disable-line eqeqeq\n                                    showItem(ind);\n                                    $('html, body').animate({\n                                        scrollTop: $(switches[ind]).offset().top\n                                    }, 700);\n                                    fromUrl = true;\n                                }\n                            });\n                        }\n\n                        if (fromUrl === false) {\n                            if (options.start % 1 === 0) { //eslint-disable-line max-depth\n                                current = options.start + 1;\n                                showItem(options.start);\n                            } else {\n                                $(terms).each(function (ind, el) {\n                                    if ($(el).attr('id') == options.start) { //eslint-disable-line eqeqeq\n                                        current = ind + 1;\n                                        showItem(ind);\n                                        $('html, body').animate({\n                                            scrollTop: $(switches[ind]).offset().top\n                                        }, 700);\n                                    }\n                                });\n                            }\n                        }\n                    }\n                };\n\n            init();\n        });\n    };\n\n    return function (data, el) {\n        $(el).terms(data);\n    };\n});\n","mage/dropdown.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery/ui',\n    'mage/translate'\n], function ($) {\n    'use strict';\n\n    var timer = null;\n\n    /**\n     * Dropdown Widget - this widget is a wrapper for the jQuery UI Dialog\n     */\n    $.widget('mage.dropdownDialog', $.ui.dialog, {\n        options: {\n            triggerEvent: 'click',\n            triggerClass: null,\n            parentClass: null,\n            triggerTarget: null,\n            defaultDialogClass: 'mage-dropdown-dialog',\n            dialogContentClass: null,\n            shadowHinter: null,\n            closeOnMouseLeave: true,\n            closeOnClickOutside: true,\n            minHeight: null,\n            minWidth: null,\n            width: null,\n            modal: false,\n            timeout: null,\n            autoOpen: false,\n            createTitleBar: false,\n            autoPosition: false,\n            autoSize: false,\n            draggable: false,\n            resizable: false,\n            bodyClass: '',\n            buttons: [\n                {\n                    'class': 'action close',\n                    'text': $.mage.__('Close'),\n\n                    /**\n                     * Click action.\n                     */\n                    'click': function () {\n                        $(this).dropdownDialog('close');\n                    }\n                }\n            ]\n        },\n\n        /**\n         * extend default functionality to bind the opener for dropdown\n         * @private\n         */\n        _create: function () {\n            var _self = this;\n\n            this._super();\n            this.uiDialog.addClass(this.options.defaultDialogClass);\n\n            if (_self.options.triggerTarget) {\n                $(_self.options.triggerTarget).on(_self.options.triggerEvent, function (event) {\n                    event.preventDefault();\n                    event.stopPropagation();\n\n                    if (!_self._isOpen) {\n                        $('.' + _self.options.defaultDialogClass + ' > .ui-dialog-content').dropdownDialog('close');\n                        _self.open();\n                    } else {\n                        _self.close(event);\n                    }\n                });\n            }\n\n            if (_self.options.shadowHinter) {\n                _self.hinter = $('<div class=\"' + _self.options.shadowHinter + '\"/>');\n                _self.element.append(_self.hinter);\n            }\n        },\n\n        /**\n         * Extend default functionality to close the dropdown\n         * with custom delay on mouse out and also to close when clicking outside\n         */\n        open: function () {\n            var _self = this;\n\n            this._super();\n\n            if (_self.options.dialogContentClass) {\n                _self.element.addClass(_self.options.dialogContentClass);\n            }\n\n            if (_self.options.closeOnMouseLeave) {\n\n                this._mouseEnter(_self.uiDialog);\n                this._mouseLeave(_self.uiDialog);\n\n                if (_self.options.triggerTarget) {\n                    this._mouseLeave($(_self.options.triggerTarget));\n                }\n            }\n\n            if (_self.options.closeOnClickOutside) {\n                $('body').on('click.outsideDropdown', function (event) {\n                    if (_self._isOpen && !$(event.target).closest('.ui-dialog').length) {\n                        if (timer) {\n                            clearTimeout(timer);\n                        }\n                        _self.close(event);\n                    }\n                });\n            }\n            // adding the class on the opener and parent element for dropdown\n            if (_self.options.triggerClass) {\n                $(_self.options.triggerTarget).addClass(_self.options.triggerClass);\n            }\n\n            if (_self.options.parentClass) {\n                $(_self.options.appendTo).addClass(_self.options.parentClass);\n            }\n\n            if (_self.options.bodyClass) {\n                $('body').addClass(_self.options.bodyClass);\n            }\n\n            if (_self.options.shadowHinter) {\n                _self._setShadowHinterPosition();\n            }\n        },\n\n        /**\n         * extend default functionality to reset the timer and remove the active class for opener\n         */\n        close: function () {\n            this._super();\n\n            if (this.options.dialogContentClass) {\n                this.element.removeClass(this.options.dialogContentClass);\n            }\n\n            if (this.options.triggerClass) {\n                $(this.options.triggerTarget).removeClass(this.options.triggerClass);\n            }\n\n            if (this.options.parentClass) {\n                $(this.options.appendTo).removeClass(this.options.parentClass);\n            }\n\n            if (this.options.bodyClass) {\n                $('body').removeClass(this.options.bodyClass);\n            }\n\n            if (timer) {\n                clearTimeout(timer);\n            }\n\n            if (this.options.triggerTarget) {\n                $(this.options.triggerTarget).off('mouseleave');\n            }\n            this.uiDialog.off('mouseenter');\n            this.uiDialog.off('mouseleave');\n            $('body').off('click.outsideDropdown');\n        },\n\n        /**\n         * _setShadowHinterPosition\n         * @private\n         */\n        _setShadowHinterPosition: function () {\n            var _self = this,\n                offset;\n\n            offset = _self.options.position.of.offset().left -\n                _self.element.offset().left +\n                _self.options.position.of.outerWidth() / 2;\n            offset = isNaN(offset) ? 0 : Math.floor(offset);\n            _self.hinter.css('left', offset);\n        },\n\n        /**\n         * @private\n         */\n        _position: function () {\n            if (this.options.autoPosition) {\n                this._super();\n            }\n        },\n\n        /**\n         * @private\n         */\n        _createTitlebar: function () {\n            if (this.options.createTitleBar) {\n                this._super();\n            } else {\n                // the title bar close button is referenced\n                // in _focusTabbable function, so to prevent errors it must be declared\n                this.uiDialogTitlebarClose = $('<div>');\n            }\n        },\n\n        /**\n         * @private\n         */\n        _size: function () {\n            if (this.options.autoSize) {\n                this._super();\n            }\n        },\n\n        /**\n         * @param {Object} handler\n         * @private\n         */\n        _mouseLeave: function (handler) {\n            var _self = this;\n\n            handler.on('mouseleave', function (event) {\n                event.stopPropagation();\n\n                if (_self._isOpen) {\n                    if (timer) {\n                        clearTimeout(timer);\n                    }\n                    timer = setTimeout(function (e) {\n                        _self.close(e);\n                    }, _self.options.timeout);\n                }\n            });\n        },\n\n        /**\n         * @param {Object} handler\n         * @private\n         */\n        _mouseEnter: function (handler) {\n            handler.on('mouseenter', function (event) {\n                event.stopPropagation();\n\n                if (timer) {\n                    clearTimeout(timer);\n                }\n            });\n        },\n\n        /**\n         * @param {String} key\n         * @param {*} value\n         * @private\n         */\n        _setOption: function (key, value) {\n            this._super(key, value);\n\n            if (key === 'triggerTarget') {\n                this.options.triggerTarget = value;\n            }\n        }\n    });\n\n    return $.mage.dropdownDialog;\n});\n","mage/mage.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (root, factory) {\n    'use strict';\n\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery',\n            'mage/apply/main'\n        ], factory);\n    } else {\n        factory(root.jQuery);\n    }\n}(this, function ($, mage) {\n    'use strict';\n\n    /**\n     * Main namespace for Magento extensions\n     * @type {Object}\n     */\n    $.mage = $.mage || {};\n\n    /**\n     * Plugin mage, initialize components on elements\n     * @param {String} name - Components' path.\n     * @param {Object} config - Components' config.\n     * @returns {JQuery} Chainable.\n     */\n    $.fn.mage = function (name, config) {\n        config = config || {};\n\n        this.each(function (index, el) {\n            mage.applyFor(el, config, name);\n        });\n\n        return this;\n    };\n\n    $.extend($.mage, {\n        /**\n         * Handle all components declared via data attribute\n         * @return {Object} $.mage\n         */\n        init: function () {\n            mage.apply();\n\n            return this;\n        },\n\n        /**\n         * Method handling redirects and page refresh\n         * @param {String} url - redirect URL\n         * @param {(undefined|String)} type - 'assign', 'reload', 'replace'\n         * @param {(undefined|Number)} timeout - timeout in milliseconds before processing the redirect or reload\n         * @param {(undefined|Boolean)} forced - true|false used for 'reload' only\n         */\n        redirect: function (url, type, timeout, forced) {\n            var _redirect;\n\n            forced  = !!forced;\n            timeout = timeout || 0;\n            type    = type || 'assign';\n\n            /**\n             * @private\n             */\n            _redirect = function () {\n                window.location[type](type === 'reload' ? forced : url);\n            };\n\n            timeout ? setTimeout(_redirect, timeout) : _redirect();\n        },\n\n        /**\n         * Checks if provided string is a valid selector.\n         * @param {String} selector - Selector to check.\n         * @returns {Boolean}\n         */\n        isValidSelector: function (selector) {\n            try {\n                document.querySelector(selector);\n\n                return true;\n            } catch (e) {\n                return false;\n            }\n        }\n    });\n\n    /**\n     * Init components inside of dynamically updated elements\n     */\n    $('body').on('contentUpdated', function () {\n        if (mage) {\n            mage.apply();\n        }\n    });\n\n    return $.mage;\n}));\n","mage/translate-inline.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (root, factory) {\n    'use strict';\n\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery',\n            'mage/template',\n            'jquery/ui',\n            'mage/translate'\n        ], factory);\n    } else {\n        factory(root.jQuery, root.mageTemplate);\n    }\n}(this, function ($, mageTemplate) {\n    'use strict';\n\n    $.widget('mage.translateInline', $.ui.dialog, {\n        options: {\n            translateForm: {\n                template: '#translate-form-template',\n                data: {\n                    id: 'translate-inline-form',\n                    message: 'Please refresh the page to see your changes after submitting this form.'\n                }\n            },\n            autoOpen: false,\n            translateArea: null,\n            modal: true,\n            dialogClass: 'popup-window',\n            width: '75%',\n            title: $.mage.__('Translate'),\n            height: 470,\n            position: {\n                my: 'left top',\n                at: 'center top',\n                of: 'body'\n            },\n            buttons: [{\n                text: $.mage.__('Submit'),\n                'class': 'action-primary',\n\n                /**\n                 * Click\n                 */\n                click: function () {\n                    $(this).translateInline('submit');\n                }\n            },\n            {\n                text: $.mage.__('Close'),\n                'class': 'action-close',\n\n                /**\n                 * Click.\n                 */\n                click: function () {\n                    $(this).translateInline('close');\n                }\n            }],\n\n            /**\n             * Open.\n             */\n            open: function () {\n                var topMargin;\n\n                $(this).closest('.ui-dialog').addClass('ui-dialog-active');\n                topMargin = jQuery(this).closest('.ui-dialog').children('.ui-dialog-titlebar').outerHeight() + 45;\n                jQuery(this).closest('.ui-dialog').css('margin-top', topMargin);\n            },\n\n            /**\n             * Close.\n             */\n            close: function () {\n                $(this).closest('.ui-dialog').removeClass('ui-dialog-active');\n            }\n        },\n\n        /**\n         * Translate Inline creation\n         * @protected\n         */\n        _create: function () {\n            this.tmpl = mageTemplate(this.options.translateForm.template);\n            (this.options.translateArea && $(this.options.translateArea).length ?\n                $(this.options.translateArea) :\n                this.element.closest('body'))\n                    .on('edit.editTrigger', $.proxy(this._onEdit, this));\n            this._super();\n        },\n\n        /**\n         * @param {*} templateData\n         * @return {*|jQuery|HTMLElement}\n         * @private\n         */\n        _prepareContent: function (templateData) {\n            var data = $.extend({\n                items: templateData,\n                escape: $.mage.escapeHTML\n            }, this.options.translateForm.data);\n\n            this.data = data;\n\n            return $(this.tmpl({\n                data: data\n            }));\n        },\n\n        /**\n         * Render translation form and open dialog\n         * @param {Object} e - object\n         * @protected\n         */\n        _onEdit: function (e) {\n            this.target = e.target;\n            this.element.html(this._prepareContent($(e.target).data('translate')));\n            this.open(e);\n        },\n\n        /**\n         * Submit.\n         */\n        submit: function () {\n            if (this.formIsSubmitted) {\n                return;\n            }\n            this._formSubmit();\n        },\n\n        /**\n         * Send ajax request on form submit\n         * @protected\n         */\n        _formSubmit: function () {\n            var parameters;\n\n            this.formIsSubmitted = true;\n            parameters = $.param({\n                area: this.options.area\n            }) + '&' + $('#' + this.options.translateForm.data.id).serialize();\n\n            $.ajax({\n                url: this.options.ajaxUrl,\n                type: 'POST',\n                data: parameters,\n                loaderContext: this.element,\n                showLoader: true\n            }).complete($.proxy(this._formSubmitComplete, this));\n        },\n\n        /**\n         * @param {Object} response\n         * @private\n         */\n        _formSubmitComplete: function (response) {\n            this.close();\n            this.formIsSubmitted = false;\n            this._updatePlaceholder(response.responseJSON[this.data.items[0].original]);\n        },\n\n        /**\n         * @param {*} newValue\n         * @private\n         */\n        _updatePlaceholder: function (newValue) {\n            var target = jQuery(this.target);\n\n            target.data('translate')[0].shown = newValue;\n            target.data('translate')[0].translated = newValue;\n            target.html(newValue);\n        },\n\n        /**\n         * Destroy translateInline\n         */\n        destroy: function () {\n            this.element.off('.editTrigger');\n            this._super();\n        }\n    });\n    // @TODO move the \"escapeHTML\" method into the file with global utility functions\n    $.extend(true, $, {\n        mage: {\n            /**\n             * @param {String} str\n             * @return {Boolean}\n             */\n            escapeHTML: function (str) {\n                return str ?\n                    jQuery('<div/>').text(str).html().replace(/\"/g, '&quot;') :\n                    false;\n            }\n        }\n    });\n\n    return $.mage.translateInline;\n}));\n","mage/redirect-url.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery/ui'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.redirectUrl', {\n        options: {\n            event: 'click',\n            url: undefined\n        },\n\n        /**\n         * This method binds elements found in this widget.\n         * @private\n         */\n        _bind: function () {\n            var handlers = {};\n\n            handlers[this.options.event] = '_onEvent';\n            this._on(handlers);\n        },\n\n        /**\n         * This method constructs a new widget.\n         * @private\n         */\n        _create: function () {\n            this._bind();\n        },\n\n        /**\n         * This method set the url for the redirect.\n         * @private\n         */\n        _onEvent: function () {\n            if (this.options.url) {\n                location.href = this.options.url;\n            } else {\n                location.href = this.element.val();\n            }\n        }\n    });\n\n    return $.mage.redirectUrl;\n});\n","mage/dataPost.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    'Magento_Ui/js/modal/confirm',\n    'jquery/ui'\n], function ($, mageTemplate, uiConfirm) {\n    'use strict';\n\n    $.widget('mage.dataPost', {\n        options: {\n            formTemplate: '<form action=\"<%- data.action %>\" method=\"post\">' +\n            '<% _.each(data.data, function(value, index) { %>' +\n            '<input name=\"<%- index %>\" value=\"<%- value %>\">' +\n            '<% }) %></form>',\n            postTrigger: ['a[data-post]', 'button[data-post]', 'span[data-post]'],\n            formKeyInputSelector: 'input[name=\"form_key\"]'\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            this._bind();\n        },\n\n        /** @inheritdoc */\n        _bind: function () {\n            var events = {};\n\n            $.each(this.options.postTrigger, function (index, value) {\n                events['click ' + value] = '_postDataAction';\n            });\n\n            this._on(events);\n        },\n\n        /**\n         * Handler for click.\n         *\n         * @param {Object} e\n         * @private\n         */\n        _postDataAction: function (e) {\n            var params = $(e.currentTarget).data('post');\n\n            e.preventDefault();\n            this.postData(params);\n        },\n\n        /**\n         * Data post action.\n         *\n         * @param {Object} params\n         */\n        postData: function (params) {\n            var formKey = $(this.options.formKeyInputSelector).val(),\n                $form, input;\n\n            if (formKey) {\n                params.data['form_key'] = formKey;\n            }\n\n            $form = $(mageTemplate(this.options.formTemplate, {\n                data: params\n            }));\n\n            if (params.files) {\n                $form[0].enctype = 'multipart/form-data';\n                $.each(params.files, function (key, files) {\n                    if (files instanceof FileList) {\n                        input = document.createElement('input');\n                        input.type = 'file';\n                        input.name = key;\n                        input.files = files;\n                        $form[0].appendChild(input);\n                    }\n                });\n            }\n\n            if (params.data.confirmation) {\n                uiConfirm({\n                    content: params.data.confirmationMessage,\n                    actions: {\n                        /** @inheritdoc */\n                        confirm: function () {\n                            $form.appendTo('body').hide().submit();\n                        }\n                    }\n                });\n            } else {\n                $form.appendTo('body').hide().submit();\n            }\n        }\n    });\n\n    $(document).dataPost();\n\n    return $.mage.dataPost;\n});\n","mage/toggle.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery/ui'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.toggleAdvanced', {\n        options: {\n            baseToggleClass: 'active' // Class used to be toggled on clicked element\n        },\n\n        /**\n         * Toggle creation\n         * @private\n         */\n        _create: function () {\n            this.beforeCreate();\n            this._bindCore();\n            this.afterCreate();\n        },\n\n        /**\n         *  Core bound events & setup\n         * @protected\n         */\n        _bindCore: function () {\n            var widget = this;\n\n            this.element.on('click', $.proxy(function (e) {\n                widget._onClick();\n                e.preventDefault();\n            }, this));\n        },\n\n        /**\n         * Binding Click event\n         *\n         * @protected\n         */\n        _onClick: function () {\n            this._prepareOptions();\n            this._toggleSelectors();\n        },\n\n        /**\n         * Method used to look for data attributes to override default options\n         *\n         * @protected\n         */\n        _prepareOptions: function () {\n            this.options.baseToggleClass = this.element.data('base-toggle-class') ?\n                this.element.data('base-toggle-class') : this.options.baseToggleClass;\n        },\n\n        /**\n         * Method responsible for hiding and revealing specified DOM elements\n         * Toggle the class on clicked element\n         *\n         * @protected\n         */\n        _toggleSelectors: function () {\n            this.element.toggleClass(this.options.baseToggleClass);\n        },\n\n        /**\n         * Method used to inject 3rd party functionality before create\n         * @public\n         */\n        beforeCreate: function () {},\n\n        /**\n         * Method used to inject 3rd party functionality after create\n         * @public\n         */\n        afterCreate: function () {}\n    });\n\n    // Extension for mage.toggle - Adding selectors support for other DOM elements we wish to toggle\n    $.widget('mage.toggleAdvanced', $.mage.toggleAdvanced, {\n\n        options: {\n            selectorsToggleClass: 'hidden',    // Class used to be toggled on selectors DOM elements\n            toggleContainers: null\n        },\n\n        /**\n         * Method responsible for hiding and revealing specified DOM elements\n         * If data-toggle-selectors attribute is present - toggle will be done on these selectors\n         * Otherwise we toggle the class on clicked element\n         *\n         * @protected\n         * @override\n         */\n        _toggleSelectors: function () {\n            this._super();\n\n            if (this.options.toggleContainers) {\n                $(this.options.toggleContainers).toggleClass(this.options.selectorsToggleClass);\n            } else {\n                this.element.toggleClass(this.options.baseToggleClass);\n            }\n        },\n\n        /**\n         * Method used to look for data attributes to override default options\n         *\n         * @protected\n         * @override\n         */\n        _prepareOptions: function () {\n            this.options.selectorsToggleClass = this.element.data('selectors-toggle-class') ?\n                this.element.data('selectors-toggle-class') : this.options.selectorsToggleClass;\n            this.options.toggleContainers = this.element.data('toggle-selectors') ?\n                this.element.data('toggle-selectors') : this.options.toggleContainers;\n            this._super();\n        }\n    });\n\n    // Extension for mage.toggle - Adding label toggle\n    $.widget('mage.toggleAdvanced', $.mage.toggleAdvanced, {\n\n        options: {\n            newLabel: null,             // Text of the new label to be used on toggle\n            curLabel: null,             // Text of the old label to be used on toggle\n            currentLabelElement: null   // Current label container\n        },\n\n        /**\n         * Binding Click event\n         *\n         * @protected\n         * @override\n         */\n        _onClick: function () {\n            this._super();\n            this._toggleLabel();\n        },\n\n        /**\n         * Method responsible for replacing clicked element labels\n         * @protected\n         */\n        _toggleLabel: function () {\n            var cachedLabel, currentLabelSelector;\n\n            if (this.options.newLabel) {\n                cachedLabel = this.options.newLabel;\n                currentLabelSelector = this.options.currentLabelElement ?\n                        $(this.options.currentLabelElement) : this.element;\n\n                this.element.data('toggle-label', this.options.curLabel);\n                currentLabelSelector.html(this.options.newLabel);\n\n                this.options.curLabel = this.options.newLabel;\n                this.options.newLabel = cachedLabel;\n            }\n        },\n\n        /**\n         * Method used to look for data attributes to override default options\n         *\n         * @protected\n         * @override\n         */\n        _prepareOptions: function () {\n            this.options.newLabel = this.element.data('toggle-label') ?\n                this.element.data('toggle-label') : this.options.newLabel;\n\n            this.options.currentLabelElement = this.element.data('current-label-el') ?\n                this.element.data('current-label-el') : this.options.currentLabelElement;\n\n            if (!this.options.currentLabelElement) {\n                this.options.currentLabelElement = this.element;\n            }\n\n            this.options.curLabel = $(this.options.currentLabelElement).html();\n\n            this._super();\n        }\n    });\n\n    return $.mage.toggleAdvanced;\n});\n","mage/trim-input.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.trimInput', {\n        options: {\n            cache: {}\n        },\n\n        /**\n         * Widget initialization\n         * @private\n         */\n        _create: function () {\n            this.options.cache.input = $(this.element);\n            this._bind();\n        },\n\n        /**\n         * Event binding, will monitor change, keyup and paste events.\n         * @private\n         */\n        _bind: function () {\n            if (this.options.cache.input.length) {\n                this._on(this.options.cache.input, {\n                    'change': this._trimInput,\n                    'keyup': this._trimInput,\n                    'paste': this._trimInput\n                });\n            }\n        },\n\n        /**\n         * Trim value\n         * @private\n         */\n        _trimInput: function () {\n            var input = this._getInputValue().trim();\n\n            this.options.cache.input.val(input);\n        },\n\n        /**\n         * Get input value\n         * @returns {*}\n         * @private\n         */\n        _getInputValue: function () {\n            return this.options.cache.input.val();\n        }\n    });\n\n    return $.mage.trimInput;\n});\n","mage/menu.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'matchMedia',\n    'jquery/ui',\n    'jquery/jquery.mobile.custom',\n    'mage/translate'\n], function ($, mediaCheck) {\n    'use strict';\n\n    /**\n     * Menu Widget - this widget is a wrapper for the jQuery UI Menu\n     */\n    $.widget('mage.menu', $.ui.menu, {\n        options: {\n            responsive: false,\n            expanded: false,\n            showDelay: 42,\n            hideDelay: 300,\n            delay: 0,\n            mediaBreakpoint: '(max-width: 768px)'\n        },\n\n        /**\n         * @private\n         */\n        _create: function () {\n            var self = this;\n\n            this.delay = this.options.delay;\n\n            this._super();\n            $(window).on('resize', function () {\n                self.element.find('.submenu-reverse').removeClass('submenu-reverse');\n            });\n        },\n\n        /**\n         * @private\n         */\n        _init: function () {\n            this._super();\n\n            if (this.options.expanded === true) {\n                this.isExpanded();\n            }\n\n            if (this.options.responsive === true) {\n                mediaCheck({\n                    media: this.options.mediaBreakpoint,\n                    entry: $.proxy(function () {\n                        this._toggleMobileMode();\n                    }, this),\n                    exit: $.proxy(function () {\n                        this._toggleDesktopMode();\n                    }, this)\n                });\n            }\n\n            this._assignControls()._listen();\n            this._setActiveMenu();\n        },\n\n        /**\n         * @return {Object}\n         * @private\n         */\n        _assignControls: function () {\n            this.controls = {\n                toggleBtn: $('[data-action=\"toggle-nav\"]'),\n                swipeArea: $('.nav-sections')\n            };\n\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _listen: function () {\n            var controls = this.controls,\n                toggle = this.toggle;\n\n            controls.toggleBtn.off('click');\n            controls.toggleBtn.on('click', toggle.bind(this));\n            controls.swipeArea.off('swipeleft');\n            controls.swipeArea.on('swipeleft', toggle.bind(this));\n        },\n\n        /**\n         * Toggle.\n         */\n        toggle: function () {\n            var html = $('html');\n\n            if (html.hasClass('nav-open')) {\n                html.removeClass('nav-open');\n                setTimeout(function () {\n                    html.removeClass('nav-before-open');\n                }, this.options.hideDelay);\n            } else {\n                html.addClass('nav-before-open');\n                setTimeout(function () {\n                    html.addClass('nav-open');\n                }, this.options.showDelay);\n            }\n        },\n\n        /**\n         * Tries to figure out the active category for current page and add appropriate classes:\n         *  - 'active' class for active category\n         *  - 'has-active' class for all parents of active category\n         *\n         *  First, checks whether current URL is URL of category page,\n         *  otherwise tries to retrieve category URL in case of current URL is product view page URL\n         *  which has category tree path in it.\n         *\n         * @return void\n         * @private\n         */\n        _setActiveMenu: function () {\n            var currentUrl = window.location.href.split('?')[0];\n\n            if (!this._setActiveMenuForCategory(currentUrl)) {\n                this._setActiveMenuForProduct(currentUrl);\n            }\n        },\n\n        /**\n         * Looks for category with provided URL and adds 'active' CSS class to it if it was not set before.\n         * If menu item has parent categories, sets 'has-active' class to all af them.\n         *\n         * @param {String} url - possible category URL\n         * @returns {Boolean} - true if active category was founded by provided URL, otherwise return false\n         * @private\n         */\n        _setActiveMenuForCategory: function (url) {\n            var activeCategoryLink = this.element.find('a[href=\"' + url + '\"]'),\n                classes,\n                classNav;\n\n            if (!activeCategoryLink || !activeCategoryLink.hasClass('ui-corner-all')) {\n\n                //category was not found by provided URL\n                return false;\n            } else if (!activeCategoryLink.parent().hasClass('active')) {\n                activeCategoryLink.parent().addClass('active');\n                classes = activeCategoryLink.parent().attr('class');\n                classNav = classes.match(/(nav\\-)[0-9]+(\\-[0-9]+)+/gi);\n\n                if (classNav) {\n                    this._setActiveParent(classNav[0]);\n                }\n            }\n\n            return true;\n        },\n\n        /**\n         * Sets 'has-active' CSS class to all parent categories which have part of provided class in childClassName\n         *\n         * @example\n         *  childClassName - 'nav-1-2-3'\n         *  CSS class 'has-active' will be added to categories have 'nav-1-2' and 'nav-1' classes\n         *\n         * @param {String} childClassName - Class name of active category <li> element\n         * @return void\n         * @private\n         */\n        _setActiveParent: function (childClassName) {\n            var parentElement,\n                parentClass = childClassName.substr(0, childClassName.lastIndexOf('-'));\n\n            if (parentClass.lastIndexOf('-') !== -1) {\n                parentElement = this.element.find('.' + parentClass);\n\n                if (parentElement) {\n                    parentElement.addClass('has-active');\n                }\n                this._setActiveParent(parentClass);\n            }\n        },\n\n        /**\n         * Tries to retrieve category URL from current URL and mark this category as active\n         * @see _setActiveMenuForCategory(url)\n         *\n         * @example\n         *  currentUrl - http://magento.com/category1/category12/product.html,\n         *  category URLs has extensions .phtml - http://magento.com/category1.phtml\n         *  method sets active category which has URL http://magento.com/category1/category12.phtml\n         *\n         * @param {String} currentUrl - current page URL without parameters\n         * @return void\n         * @private\n         */\n        _setActiveMenuForProduct: function (currentUrl) {\n            var categoryUrlExtension,\n                lastUrlSection,\n                possibleCategoryUrl,\n                //retrieve first category URL to know what extension is used for category URLs\n                firstCategoryUrl = this.element.find('> li a').attr('href');\n\n            if (firstCategoryUrl) {\n                lastUrlSection = firstCategoryUrl.substr(firstCategoryUrl.lastIndexOf('/'));\n                categoryUrlExtension = lastUrlSection.lastIndexOf('.') !== -1 ?\n                    lastUrlSection.substr(lastUrlSection.lastIndexOf('.')) : '';\n\n                possibleCategoryUrl = currentUrl.substr(0, currentUrl.lastIndexOf('/')) + categoryUrlExtension;\n                this._setActiveMenuForCategory(possibleCategoryUrl);\n            }\n        },\n\n        /**\n         * Add class for expanded option.\n         */\n        isExpanded: function () {\n            var subMenus = this.element.find(this.options.menus),\n                expandedMenus = subMenus.find(this.options.menus);\n\n            expandedMenus.addClass('expanded');\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _activate: function (event) {\n            window.location.href = this.active.find('> a').attr('href');\n            this.collapseAll(event);\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _keydown: function (event) {\n            var match, prev, character, skip, regex,\n                preventDefault = true;\n\n            /* eslint-disable max-depth */\n            /**\n             * @param {String} value\n             */\n            function escape(value) {\n                return value.replace(/[\\-\\[\\]{}()*+?.,\\\\\\^$|#\\s]/g, '\\\\$&');\n            }\n\n            if (this.active.closest(this.options.menus).attr('aria-expanded') != 'true') { //eslint-disable-line eqeqeq\n\n                switch (event.keyCode) {\n                    case $.ui.keyCode.PAGE_UP:\n                        this.previousPage(event);\n                        break;\n\n                    case $.ui.keyCode.PAGE_DOWN:\n                        this.nextPage(event);\n                        break;\n\n                    case $.ui.keyCode.HOME:\n                        this._move('first', 'first', event);\n                        break;\n\n                    case $.ui.keyCode.END:\n                        this._move('last', 'last', event);\n                        break;\n\n                    case $.ui.keyCode.UP:\n                        this.previous(event);\n                        break;\n\n                    case $.ui.keyCode.DOWN:\n                        if (this.active && !this.active.is('.ui-state-disabled')) {\n                            this.expand(event);\n                        }\n                        break;\n\n                    case $.ui.keyCode.LEFT:\n                        this.previous(event);\n                        break;\n\n                    case $.ui.keyCode.RIGHT:\n                        this.next(event);\n                        break;\n\n                    case $.ui.keyCode.ENTER:\n                    case $.ui.keyCode.SPACE:\n                        this._activate(event);\n                        break;\n\n                    case $.ui.keyCode.ESCAPE:\n                        this.collapse(event);\n                        break;\n                    default:\n                        preventDefault = false;\n                        prev = this.previousFilter || '';\n                        character = String.fromCharCode(event.keyCode);\n                        skip = false;\n\n                        clearTimeout(this.filterTimer);\n\n                        if (character === prev) {\n                            skip = true;\n                        } else {\n                            character = prev + character;\n                        }\n\n                        regex = new RegExp('^' + escape(character), 'i');\n                        match = this.activeMenu.children('.ui-menu-item').filter(function () {\n                            return regex.test($(this).children('a').text());\n                        });\n                        match = skip && match.index(this.active.next()) !== -1 ?\n                            this.active.nextAll('.ui-menu-item') :\n                            match;\n\n                        // If no matches on the current filter, reset to the last character pressed\n                        // to move down the menu to the first item that starts with that character\n                        if (!match.length) {\n                            character = String.fromCharCode(event.keyCode);\n                            regex = new RegExp('^' + escape(character), 'i');\n                            match = this.activeMenu.children('.ui-menu-item').filter(function () {\n                                return regex.test($(this).children('a').text());\n                            });\n                        }\n\n                        if (match.length) {\n                            this.focus(event, match);\n\n                            if (match.length > 1) {\n                                this.previousFilter = character;\n                                this.filterTimer = this._delay(function () {\n                                    delete this.previousFilter;\n                                }, 1000);\n                            } else {\n                                delete this.previousFilter;\n                            }\n                        } else {\n                            delete this.previousFilter;\n                        }\n                }\n            } else {\n                switch (event.keyCode) {\n                    case $.ui.keyCode.DOWN:\n                        this.next(event);\n                        break;\n\n                    case $.ui.keyCode.UP:\n                        this.previous(event);\n                        break;\n\n                    case $.ui.keyCode.RIGHT:\n                        if (this.active && !this.active.is('.ui-state-disabled')) {\n                            this.expand(event);\n                        }\n                        break;\n\n                    case $.ui.keyCode.ENTER:\n                    case $.ui.keyCode.SPACE:\n                        this._activate(event);\n                        break;\n\n                    case $.ui.keyCode.LEFT:\n                    case $.ui.keyCode.ESCAPE:\n                        this.collapse(event);\n                        break;\n                    default:\n                        preventDefault = false;\n                        prev = this.previousFilter || '';\n                        character = String.fromCharCode(event.keyCode);\n                        skip = false;\n\n                        clearTimeout(this.filterTimer);\n\n                        if (character === prev) {\n                            skip = true;\n                        } else {\n                            character = prev + character;\n                        }\n\n                        regex = new RegExp('^' + escape(character), 'i');\n                        match = this.activeMenu.children('.ui-menu-item').filter(function () {\n                            return regex.test($(this).children('a').text());\n                        });\n                        match = skip && match.index(this.active.next()) !== -1 ?\n                            this.active.nextAll('.ui-menu-item') :\n                            match;\n\n                        // If no matches on the current filter, reset to the last character pressed\n                        // to move down the menu to the first item that starts with that character\n                        if (!match.length) {\n                            character = String.fromCharCode(event.keyCode);\n                            regex = new RegExp('^' + escape(character), 'i');\n                            match = this.activeMenu.children('.ui-menu-item').filter(function () {\n                                return regex.test($(this).children('a').text());\n                            });\n                        }\n\n                        if (match.length) {\n                            this.focus(event, match);\n\n                            if (match.length > 1) {\n                                this.previousFilter = character;\n                                this.filterTimer = this._delay(function () {\n                                    delete this.previousFilter;\n                                }, 1000);\n                            } else {\n                                delete this.previousFilter;\n                            }\n                        } else {\n                            delete this.previousFilter;\n                        }\n                }\n            }\n\n            /* eslint-enable max-depth */\n            if (preventDefault) {\n                event.preventDefault();\n            }\n        },\n\n        /**\n         * @private\n         */\n        _toggleMobileMode: function () {\n            var subMenus;\n\n            $(this.element).off('mouseenter mouseleave');\n            this._on({\n\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                'click .ui-menu-item:has(a)': function (event) {\n                    var target;\n\n                    event.preventDefault();\n                    target = $(event.target).closest('.ui-menu-item');\n                    target.get(0).scrollIntoView();\n\n                    if (!target.hasClass('level-top') || !target.has('.ui-menu').length) {\n                        window.location.href = target.find('> a').attr('href');\n                    }\n                },\n\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                'click .ui-menu-item:has(.ui-state-active)': function (event) {\n                    this.collapseAll(event, true);\n                }\n            });\n\n            subMenus = this.element.find('.level-top');\n            $.each(subMenus, $.proxy(function (index, item) {\n                var category = $(item).find('> a span').not('.ui-menu-icon').text(),\n                    categoryUrl = $(item).find('> a').attr('href'),\n                    menu = $(item).find('> .ui-menu');\n\n                this.categoryLink = $('<a>')\n                    .attr('href', categoryUrl)\n                    .text($.mage.__('All ') + category);\n\n                this.categoryParent = $('<li>')\n                    .addClass('ui-menu-item all-category')\n                    .html(this.categoryLink);\n\n                if (menu.find('.all-category').length === 0) {\n                    menu.prepend(this.categoryParent);\n                }\n\n            }, this));\n        },\n\n        /**\n         * @private\n         */\n        _toggleDesktopMode: function () {\n            var categoryParent, html;\n\n            $(this.element).off('click mousedown mouseenter mouseleave');\n            this._on({\n\n                /**\n                 * Prevent focus from sticking to links inside menu after clicking\n                 * them (focus should always stay on UL during navigation).\n                 */\n                'mousedown .ui-menu-item > a': function (event) {\n                    event.preventDefault();\n                },\n\n                /**\n                 * Prevent focus from sticking to links inside menu after clicking\n                 * them (focus should always stay on UL during navigation).\n                 */\n                'click .ui-state-disabled > a': function (event) {\n                    event.preventDefault();\n                },\n\n                /**\n                 * @param {jQuer.Event} event\n                 */\n                'click .ui-menu-item:has(a)': function (event) {\n                    var target = $(event.target).closest('.ui-menu-item');\n\n                    if (!this.mouseHandled && target.not('.ui-state-disabled').length) {\n                        this.select(event);\n\n                        // Only set the mouseHandled flag if the event will bubble, see #9469.\n                        if (!event.isPropagationStopped()) {\n                            this.mouseHandled = true;\n                        }\n\n                        // Open submenu on click\n                        if (target.has('.ui-menu').length) {\n                            this.expand(event);\n                        } else if (!this.element.is(':focus') &&\n                            $(this.document[0].activeElement).closest('.ui-menu').length\n                        ) {\n                            // Redirect focus to the menu\n                            this.element.trigger('focus', [true]);\n\n                            // If the active item is on the top level, let it stay active.\n                            // Otherwise, blur the active item since it is no longer visible.\n                            if (this.active && this.active.parents('.ui-menu').length === 1) { //eslint-disable-line\n                                clearTimeout(this.timer);\n                            }\n                        }\n                    }\n                },\n\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                'mouseenter .ui-menu-item': function (event) {\n                    var target = $(event.currentTarget),\n                        submenu = this.options.menus,\n                        ulElement,\n                        ulElementWidth,\n                        width,\n                        targetPageX,\n                        rightBound;\n\n                    if (target.has(submenu)) {\n                        ulElement = target.find(submenu);\n                        ulElementWidth = ulElement.outerWidth(true);\n                        width = target.outerWidth() * 2;\n                        targetPageX = target.offset().left;\n                        rightBound = $(window).width();\n\n                        if (ulElementWidth + width + targetPageX > rightBound) {\n                            ulElement.addClass('submenu-reverse');\n                        }\n\n                        if (targetPageX - ulElementWidth < 0) {\n                            ulElement.removeClass('submenu-reverse');\n                        }\n                    }\n\n                    // Remove ui-state-active class from siblings of the newly focused menu item\n                    // to avoid a jump caused by adjacent elements both having a class with a border\n                    target.siblings().children('.ui-state-active').removeClass('ui-state-active');\n                    this.focus(event, target);\n                },\n\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                'mouseleave': function (event) {\n                    this.collapseAll(event, true);\n                },\n\n                /**\n                 * Mouse leave.\n                 */\n                'mouseleave .ui-menu': 'collapseAll'\n            });\n\n            categoryParent = this.element.find('.all-category');\n            html = $('html');\n\n            categoryParent.remove();\n\n            if (html.hasClass('nav-open')) {\n                html.removeClass('nav-open');\n                setTimeout(function () {\n                    html.removeClass('nav-before-open');\n                }, this.options.hideDelay);\n            }\n        },\n\n        /**\n         * @param {*} handler\n         * @param {Number} delay\n         * @return {Number}\n         * @private\n         */\n        _delay: function (handler, delay) {\n            var instance = this,\n\n                /**\n                 * @return {*}\n                 */\n                handlerProxy = function () {\n                    return (typeof handler === 'string' ? instance[handler] : handler).apply(instance, arguments);\n                };\n\n            return setTimeout(handlerProxy, delay || 0);\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         */\n        expand: function (event) {\n            var newItem = this.active &&\n                this.active\n                    .children('.ui-menu')\n                    .children('.ui-menu-item')\n                    .first();\n\n            if (newItem && newItem.length) {\n                if (newItem.closest('.ui-menu').is(':visible') &&\n                    newItem.closest('.ui-menu').has('.all-categories')\n                ) {\n                    return;\n                }\n\n                // remove the active state class from the siblings\n                this.active.siblings().children('.ui-state-active').removeClass('ui-state-active');\n\n                this._open(newItem.parent());\n\n                // Delay so Firefox will not hide activedescendant change in expanding submenu from AT\n                this._delay(function () {\n                    this.focus(event, newItem);\n                });\n            }\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         */\n        select: function (event) {\n            var ui;\n\n            this.active = this.active || $(event.target).closest('.ui-menu-item');\n\n            if (this.active.is('.all-category')) {\n                this.active = $(event.target).closest('.ui-menu-item');\n            }\n            ui = {\n                item: this.active\n            };\n\n            if (!this.active.has('.ui-menu').length) {\n                this.collapseAll(event, true);\n            }\n            this._trigger('select', event, ui);\n        }\n    });\n\n    $.widget('mage.navigation', $.mage.menu, {\n        options: {\n            responsiveAction: 'wrap', //option for responsive handling\n            maxItems: null, //option to set max number of menu items\n            container: '#menu', //container to check against navigation length\n            moreText: $.mage.__('more'),\n            breakpoint: 768\n        },\n\n        /**\n         * @private\n         */\n        _init: function () {\n            var that, responsive;\n\n            this._super();\n\n            that = this;\n            responsive = this.options.responsiveAction;\n\n            this.element\n                .addClass('ui-menu-responsive')\n                .attr('responsive', 'main');\n\n            this.setupMoreMenu();\n            this.setMaxItems();\n\n            //check responsive option\n            if (responsive == 'onResize') { //eslint-disable-line eqeqeq\n                $(window).on('resize', function () {\n                    if ($(window).width() > that.options.breakpoint) {\n                        that._responsive();\n                        $('[responsive=more]').show();\n                    } else {\n                        that.element.children().show();\n                        $('[responsive=more]').hide();\n                    }\n                });\n            } else if (responsive == 'onReload') { //eslint-disable-line eqeqeq\n                this._responsive();\n            }\n        },\n\n        /**\n         * Setup more menu.\n         */\n        setupMoreMenu: function () {\n            var moreListItems = this.element.children().clone(),\n                moreLink = $('<a>' + this.options.moreText + '</a>');\n\n            moreListItems.hide();\n\n            moreLink.attr('href', '#');\n\n            this.moreItemsList = $('<ul>')\n                .append(moreListItems);\n\n            this.moreListContainer = $('<li>')\n                .append(moreLink)\n                .append(this.moreItemsList);\n\n            this.responsiveMenu = $('<ul>')\n                .addClass('ui-menu-more')\n                .attr('responsive', 'more')\n                .append(this.moreListContainer)\n                .menu({\n                    position: {\n                        my: 'right top',\n                        at: 'right bottom'\n                    }\n                })\n                .insertAfter(this.element);\n        },\n\n        /**\n         * @private\n         */\n        _responsive: function () {\n            var container = $(this.options.container),\n                containerSize = container.width(),\n                width = 0,\n                items = this.element.children('li'),\n                more = $('.ui-menu-more > li > ul > li a');\n\n            items = items.map(function () {\n                var item = {};\n\n                item.item = $(this);\n                item.itemSize = $(this).outerWidth();\n\n                return item;\n            });\n\n            $.each(items, function (index) {\n                var itemText = items[index].item\n                    .find('a:first')\n                    .text();\n\n                width += parseInt(items[index].itemSize, null); //eslint-disable-line radix\n\n                if (width < containerSize) {\n                    items[index].item.show();\n\n                    more.each(function () {\n                        var text = $(this).text();\n\n                        if (text === itemText) {\n                            $(this).parent().hide();\n                        }\n                    });\n                } else if (width > containerSize) {\n                    items[index].item.hide();\n\n                    more.each(function () {\n                        var text = $(this).text();\n\n                        if (text === itemText) {\n                            $(this).parent().show();\n                        }\n                    });\n                }\n            });\n        },\n\n        /**\n         * Set max items.\n         */\n        setMaxItems: function () {\n            var items = this.element.children('li'),\n                itemsCount = items.length,\n                maxItems = this.options.maxItems,\n                overflow = itemsCount - maxItems,\n                overflowItems = items.slice(overflow);\n\n            overflowItems.hide();\n\n            overflowItems.each(function () {\n                var itemText = $(this).find('a:first').text();\n\n                $(this).hide();\n\n                $('.ui-menu-more > li > ul > li a').each(function () {\n                    var text = $(this).text();\n\n                    if (text === itemText) {\n                        $(this).parent().show();\n                    }\n                });\n            });\n        }\n    });\n\n    return {\n        menu: $.mage.menu,\n        navigation: $.mage.navigation\n    };\n});\n","mage/calendar.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/*eslint max-depth: 0*/\n(function (factory) {\n    'use strict';\n\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery',\n            'jquery/ui',\n            'jquery/jquery-ui-timepicker-addon'\n        ], factory);\n    } else {\n        factory(window.jQuery);\n    }\n}(function ($) {\n    'use strict';\n\n    var calendarBasePrototype,\n        datepickerPrototype = $.datepicker.constructor.prototype;\n\n    $.datepicker.markerClassName = '_has-datepicker';\n\n    /**\n     * Extend JQuery date picker prototype with store local time methods\n     */\n    $.extend(datepickerPrototype, {\n        /**\n         * Get date/time according to store settings.\n         * We use serverTimezoneOffset (in seconds) instead of serverTimezoneSeconds\n         * in order to have ability to know actual store time even if page hadn't been reloaded\n         * @returns {Date}\n         */\n        _getTimezoneDate: function (options) {\n            // local time in ms\n            var ms = Date.now();\n\n            options = options || $.calendarConfig || {};\n\n            // Adjust milliseconds according to store timezone offset,\n            // mind the GMT zero offset\n            if (typeof options.serverTimezoneOffset !== 'undefined') {\n                // Make UTC time and add store timezone offset in seconds\n                ms += new Date().getTimezoneOffset() * 60 * 1000 + options.serverTimezoneOffset * 1000;\n            } else if (typeof options.serverTimezoneSeconds !== 'undefined') {\n                //Set milliseconds according to client local timezone offset\n                ms = (options.serverTimezoneSeconds + new Date().getTimezoneOffset() * 60) * 1000;\n            }\n\n            return new Date(ms);\n        },\n\n        /**\n         * Set date/time according to store settings.\n         * @param {String|Object} target - the target input field or division or span\n         */\n        _setTimezoneDateDatepicker: function (target) {\n            this._setDateDatepicker(target, this._getTimezoneDate());\n        }\n    });\n\n    /**\n     * Widget calendar\n     */\n    $.widget('mage.calendar', {\n        options: {\n            autoComplete: true\n        },\n\n        /**\n         * Merge global options with options passed to widget invoke\n         * @protected\n         */\n        _create: function () {\n            this._enableAMPM();\n            this.options = $.extend(\n                {},\n                $.calendarConfig ? $.calendarConfig : {},\n                this.options.showsTime ? {\n                    showTime: true,\n                    showHour: true,\n                    showMinute: true\n                } : {},\n                this.options\n            );\n            this._initPicker(this.element);\n            this._overwriteGenerateHtml();\n        },\n\n        /**\n         * Get picker name\n         * @protected\n         */\n        _picker: function () {\n            return this.options.showsTime ? 'datetimepicker' : 'datepicker';\n        },\n\n        /**\n         * Fix for Timepicker - Set ampm option for Timepicker if timeformat contains string 'tt'\n         * @protected\n         */\n        _enableAMPM: function () {\n            if (this.options.timeFormat && this.options.timeFormat.indexOf('tt') >= 0) {\n                this.options.ampm = true;\n            }\n        },\n\n        /**\n         * Wrapper for overwrite jQuery UI datepicker function.\n         */\n        _overwriteGenerateHtml: function () {\n            /**\n             * Overwrite jQuery UI datepicker function.\n             * Reason: magento date could be set before calendar show\n             * but local date will be styled as current in original _generateHTML\n             *\n             * @param {Object} inst - instance datepicker.\n             * @return {String} html template\n             */\n            $.datepicker.constructor.prototype._generateHTML = function (inst) {\n                var today = this._getTimezoneDate(),\n                    isRTL = this._get(inst, 'isRTL'),\n                    showButtonPanel = this._get(inst, 'showButtonPanel'),\n                    hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'),\n                    navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'),\n                    numMonths = this._getNumberOfMonths(inst),\n                    showCurrentAtPos = this._get(inst, 'showCurrentAtPos'),\n                    stepMonths = this._get(inst, 'stepMonths'),\n                    isMultiMonth = parseInt(numMonths[0], 10) !== 1 || parseInt(numMonths[1], 10) !== 1,\n                    currentDate = this._daylightSavingAdjust(!inst.currentDay ? new Date(9999, 9, 9) :\n                        new Date(inst.currentYear, inst.currentMonth, inst.currentDay)),\n                    minDate = this._getMinMaxDate(inst, 'min'),\n                    maxDate = this._getMinMaxDate(inst, 'max'),\n                    drawMonth = inst.drawMonth - showCurrentAtPos,\n                    drawYear = inst.drawYear,\n                    maxDraw,\n                    prevText = this._get(inst, 'prevText'),\n                    prev,\n                    nextText = this._get(inst, 'nextText'),\n                    next,\n                    currentText = this._get(inst, 'currentText'),\n                    gotoDate,\n                    controls,\n                    buttonPanel,\n                    firstDay,\n                    showWeek = this._get(inst, 'showWeek'),\n                    dayNames = this._get(inst, 'dayNames'),\n                    dayNamesMin = this._get(inst, 'dayNamesMin'),\n                    monthNames = this._get(inst, 'monthNames'),\n                    monthNamesShort =  this._get(inst, 'monthNamesShort'),\n                    beforeShowDay = this._get(inst, 'beforeShowDay'),\n                    showOtherMonths = this._get(inst, 'showOtherMonths'),\n                    selectOtherMonths = this._get(inst, 'selectOtherMonths'),\n                    defaultDate = this._getDefaultDate(inst),\n                    html = '',\n                    row = 0,\n                    col = 0,\n                    selectedDate,\n                    cornerClass = ' ui-corner-all',\n                    group = '',\n                    calender = '',\n                    dow = 0,\n                    thead,\n                    day,\n                    daysInMonth,\n                    leadDays,\n                    curRows,\n                    numRows,\n                    printDate,\n                    dRow = 0,\n                    tbody,\n                    daySettings,\n                    otherMonth,\n                    unselectable;\n\n                if (drawMonth < 0) {\n                    drawMonth += 12;\n                    drawYear--;\n                }\n\n                if (maxDate) {\n                    maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),\n                        maxDate.getMonth() - numMonths[0] * numMonths[1] + 1, maxDate.getDate()));\n                    maxDraw = minDate && maxDraw < minDate ? minDate : maxDraw;\n\n                    while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {\n                        drawMonth--;\n\n                        if (drawMonth < 0) {\n                            drawMonth = 11;\n                            drawYear--;\n\n                        }\n                    }\n                }\n                inst.drawMonth = drawMonth;\n                inst.drawYear = drawYear;\n                prevText = !navigationAsDateFormat ? prevText : this.formatDate(prevText,\n                    this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),\n                    this._getFormatConfig(inst));\n                prev = this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?\n                    '<a class=\"ui-datepicker-prev ui-corner-all\" data-handler=\"prev\" data-event=\"click\"' +\n                    ' title=\"' + prevText + '\">' +\n                    '<span class=\"ui-icon ui-icon-circle-triangle-' + (isRTL ? 'e' : 'w') + '\">' +\n                    '' + prevText + '</span></a>'\n                    : hideIfNoPrevNext ? ''\n                        :   '<a class=\"ui-datepicker-prev ui-corner-all ui-state-disabled\" title=\"' +\n                            '' + prevText + '\"><span class=\"ui-icon ui-icon-circle-triangle-' +\n                            '' + (isRTL ? 'e' : 'w') + '\">' + prevText + '</span></a>';\n                nextText = !navigationAsDateFormat ?\n                    nextText\n                    :   this.formatDate(nextText,\n                        this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),\n                        this._getFormatConfig(inst));\n                next = this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?\n                    '<a class=\"ui-datepicker-next ui-corner-all\" data-handler=\"next\" data-event=\"click\"' +\n                    'title=\"' + nextText + '\"><span class=\"ui-icon ui-icon-circle-triangle-' +\n                    '' + (isRTL ? 'w' : 'e') + '\">' + nextText + '</span></a>'\n                    : hideIfNoPrevNext ? ''\n                        :   '<a class=\"ui-datepicker-next ui-corner-all ui-state-disabled\" title=\"' + nextText + '\">' +\n                            '<span class=\"ui-icon ui-icon-circle-triangle-' + (isRTL ? 'w' : 'e') + '\">' + nextText +\n                            '</span></a>';\n                gotoDate = this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today;\n                currentText = !navigationAsDateFormat ? currentText :\n                    this.formatDate(currentText, gotoDate, this._getFormatConfig(inst));\n                controls = !inst.inline ?\n                    '<button type=\"button\" class=\"ui-datepicker-close ui-state-default ui-priority-primary ' +\n                    'ui-corner-all\" data-handler=\"hide\" data-event=\"click\">' +\n                    this._get(inst, 'closeText') + '</button>'\n                    : '';\n                buttonPanel = showButtonPanel ?\n                    '<div class=\"ui-datepicker-buttonpane ui-widget-content\">' + (isRTL ? controls : '') +\n                    (this._isInRange(inst, gotoDate) ? '<button type=\"button\" class=\"ui-datepicker-current ' +\n                    'ui-state-default ui-priority-secondary ui-corner-all\" data-handler=\"today\" data-event=\"click\"' +\n                    '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';\n                firstDay = parseInt(this._get(inst, 'firstDay'), 10);\n                firstDay = isNaN(firstDay) ? 0 : firstDay;\n\n                for (row = 0; row < numMonths[0]; row++) {\n                    this.maxRows = 4;\n\n                    for (col = 0; col < numMonths[1]; col++) {\n                        selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));\n\n                        calender = '';\n\n                        if (isMultiMonth) {\n                            calender += '<div class=\"ui-datepicker-group';\n\n                            if (numMonths[1] > 1) {\n                                switch (col) {\n                                    case 0: calender += ' ui-datepicker-group-first';\n                                        cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left');\n                                        break;\n\n                                    case numMonths[1] - 1: calender += ' ui-datepicker-group-last';\n                                        cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right');\n                                        break;\n\n                                    default: calender += ' ui-datepicker-group-middle'; cornerClass = '';\n                                }\n                            }\n                            calender += '\">';\n                        }\n                        calender += '<div class=\"ui-datepicker-header ' +\n                            'ui-widget-header ui-helper-clearfix' + cornerClass + '\">' +\n                            (/all|left/.test(cornerClass) && parseInt(row, 10) === 0 ? isRTL ? next : prev : '') +\n                            (/all|right/.test(cornerClass) && parseInt(row, 10) === 0 ? isRTL ? prev : next : '') +\n                            this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,\n                            row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers\n                            '</div><table class=\"ui-datepicker-calendar\"><thead>' +\n                            '<tr>';\n                        thead = showWeek ?\n                            '<th class=\"ui-datepicker-week-col\">' + this._get(inst, 'weekHeader') + '</th>' : '';\n\n                        for (dow = 0; dow < 7; dow++) { // days of the week\n                            day = (dow + firstDay) % 7;\n                            thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ?\n                                ' class=\"ui-datepicker-week-end\"' : '') + '>' +\n                                '<span title=\"' + dayNames[day] + '\">' + dayNamesMin[day] + '</span></th>';\n                        }\n                        calender += thead + '</tr></thead><tbody>';\n                        daysInMonth = this._getDaysInMonth(drawYear, drawMonth);\n\n                        if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {\n                            inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);\n                        }\n                        leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;\n                        curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate\n                        numRows = isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows;\n                        this.maxRows = numRows;\n                        printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));\n\n                        for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows\n                            calender += '<tr>';\n                            tbody = !showWeek ? '' : '<td class=\"ui-datepicker-week-col\">' +\n                            this._get(inst, 'calculateWeek')(printDate) + '</td>';\n\n                            for (dow = 0; dow < 7; dow++) { // create date picker days\n                                daySettings = beforeShowDay ?\n                                    beforeShowDay.apply(inst.input ? inst.input[0] : null, [printDate]) : [true, ''];\n                                otherMonth = printDate.getMonth() !== drawMonth;\n                                unselectable = otherMonth && !selectOtherMonths || !daySettings[0] ||\n                                minDate && printDate < minDate || maxDate && printDate > maxDate;\n                                tbody += '<td class=\"' +\n                                ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends\n                                (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months\n                                (printDate.getTime() === selectedDate.getTime() &&\n                                drawMonth === inst.selectedMonth && inst._keyEvent || // user pressed key\n                                defaultDate.getTime() === printDate.getTime() &&\n                                defaultDate.getTime() === selectedDate.getTime() ?\n                                    // or defaultDate is current printedDate and defaultDate is selectedDate\n                                ' ' + this._dayOverClass : '') + // highlight selected day\n                                (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled' : '') +\n                                (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates\n                                (printDate.getTime() === currentDate.getTime() ? ' ' + this._currentClass : '') +\n                                (printDate.getDate() === today.getDate() && printDate.getMonth() === today.getMonth() &&\n                                printDate.getYear() === today.getYear() ? ' ui-datepicker-today' : '')) + '\"' +\n                                ((!otherMonth || showOtherMonths) && daySettings[2] ?\n                                ' title=\"' + daySettings[2] + '\"' : '') + // cell title\n                                (unselectable ? '' : ' data-handler=\"selectDay\" data-event=\"click\" data-month=\"' +\n                                '' + printDate.getMonth() + '\" data-year=\"' + printDate.getFullYear() + '\"') + '>' +\n                                (otherMonth && !showOtherMonths ? '&#xa0;' : // display for other months\n                                    unselectable ? '<span class=\"ui-state-default\">' + printDate.getDate() + '</span>'\n                                        : '<a class=\"ui-state-default' +\n                                    (printDate.getTime() === today.getTime() ? ' ' : '') +\n                                    (printDate.getTime() === currentDate.getTime() ? ' ui-state-active' : '') +\n                                    (otherMonth ? ' ui-priority-secondary' : '') +\n                                    '\" href=\"#\">' + printDate.getDate() + '</a>') + '</td>';\n                                printDate.setDate(printDate.getDate() + 1);\n                                printDate = this._daylightSavingAdjust(printDate);\n                            }\n                            calender += tbody + '</tr>';\n                        }\n                        drawMonth++;\n\n                        if (drawMonth > 11) {\n                            drawMonth = 0;\n                            drawYear++;\n                        }\n                        calender += '</tbody></table>' + (isMultiMonth ? '</div>' +\n                        (numMonths[0] > 0 && col === numMonths[1] - 1 ? '<div class=\"ui-datepicker-row-break\"></div>'\n                            : '') : '');\n                        group += calender;\n                    }\n                    html += group;\n                }\n                html += buttonPanel + ($.ui.ie6 && !inst.inline ?\n                    '<iframe src=\"javascript:false;\" class=\"ui-datepicker-cover\" frameborder=\"0\"></iframe>' : '');\n                inst._keyEvent = false;\n\n                return html;\n            };\n        },\n\n        /**\n         * Set current date if the date is not set\n         * @protected\n         * @param {Object} element\n         */\n        _setCurrentDate: function (element) {\n            if (!element.val()) {\n                element[this._picker()]('setTimezoneDate').val('');\n            }\n        },\n\n        /**\n         * Init Datetimepicker\n         * @protected\n         * @param {Object} element\n         */\n        _initPicker: function (element) {\n            var picker = element[this._picker()](this.options),\n                pickerButtonText = picker.next('.ui-datepicker-trigger')\n                    .find('img')\n                    .attr('title');\n\n            picker.next('.ui-datepicker-trigger')\n                .addClass('v-middle')\n                .text('') // Remove jQuery UI datepicker generated image\n                .append('<span>' + pickerButtonText + '</span>');\n\n            $(element).attr('autocomplete', this.options.autoComplete ? 'on' : 'off');\n\n            this._setCurrentDate(element);\n        },\n\n        /**\n         * destroy instance of datetimepicker\n         */\n        _destroy: function () {\n            this.element[this._picker()]('destroy');\n            this._super();\n        },\n\n        /**\n         * Method is kept for backward compatibility and unit-tests acceptance\n         * see \\mage\\calendar\\calendar-test.js\n         * @return {Object} date\n         */\n        getTimezoneDate: function () {\n            return datepickerPrototype._getTimezoneDate.call(this, this.options);\n        }\n    });\n\n    calendarBasePrototype = $.mage.calendar.prototype;\n\n    /**\n     * Extension for Calendar - date and time format convert functionality\n     * @var {Object}\n     */\n    $.widget('mage.calendar', $.extend({}, calendarBasePrototype,\n            /** @lends {$.mage.calendar.prototype} */ {\n                /**\n                 * key - backend format, value - jquery format\n                 * @type {Object}\n                 * @private\n                 */\n                dateTimeFormat: {\n                    date: {\n                        'EEEE': 'DD',\n                        'EEE': 'D',\n                        'EE': 'D',\n                        'E': 'D',\n                        'D': 'o',\n                        'MMMM': 'MM',\n                        'MMM': 'M',\n                        'MM': 'mm',\n                        'M': 'mm',\n                        'yyyy': 'yy',\n                        'y': 'yy',\n                        'Y': 'yy',\n                        'yy': 'yy' // Always long year format on frontend\n                    },\n                    time: {\n                        'a': 'TT'\n                    }\n                },\n\n                /**\n                 * Add Date and Time converting to _create method\n                 * @protected\n                 */\n                _create: function () {\n                    if (this.options.dateFormat) {\n                        this.options.dateFormat = this._convertFormat(this.options.dateFormat, 'date');\n                    }\n\n                    if (this.options.timeFormat) {\n                        this.options.timeFormat = this._convertFormat(this.options.timeFormat, 'time');\n                    }\n                    calendarBasePrototype._create.apply(this, arguments);\n                },\n\n                /**\n                 * Converting date or time format\n                 * @protected\n                 * @param {String} format\n                 * @param {String} type\n                 * @return {String}\n                 */\n                _convertFormat: function (format, type) {\n                    var symbols = format.match(/([a-z]+)/ig),\n                        separators = format.match(/([^a-z]+)/ig),\n                        self = this,\n                        convertedFormat = '';\n\n                    if (symbols) {\n                        $.each(symbols, function (key, val) {\n                            convertedFormat +=\n                                (self.dateTimeFormat[type][val] || val) +\n                                (separators[key] || '');\n                        });\n                    }\n\n                    return convertedFormat;\n                }\n            })\n    );\n\n    /**\n     * Widget dateRange\n     * @extends $.mage.calendar\n     */\n    $.widget('mage.dateRange', $.mage.calendar, {\n\n        /**\n         * creates two instances of datetimepicker for date range selection\n         * @protected\n         */\n        _initPicker: function () {\n            var from,\n                to;\n\n            if (this.options.from && this.options.to) {\n                from = this.element.find('#' + this.options.from.id);\n                to = this.element.find('#' + this.options.to.id);\n                this.options.onSelect = $.proxy(function (selectedDate) {\n                    to[this._picker()]('option', 'minDate', selectedDate);\n                }, this);\n                $.mage.calendar.prototype._initPicker.call(this, from);\n                from.on('change', $.proxy(function () {\n                    to[this._picker()]('option', 'minDate', from[this._picker()]('getDate'));\n                }, this));\n                this.options.onSelect = $.proxy(function (selectedDate) {\n                    from[this._picker()]('option', 'maxDate', selectedDate);\n                }, this);\n                $.mage.calendar.prototype._initPicker.call(this, to);\n                to.on('change', $.proxy(function () {\n                    from[this._picker()]('option', 'maxDate', to[this._picker()]('getDate'));\n                }, this));\n            }\n        },\n\n        /**\n         * destroy two instances of datetimepicker\n         */\n        _destroy: function () {\n            if (this.options.from) {\n                this.element.find('#' + this.options.from.id)[this._picker()]('destroy');\n            }\n\n            if (this.options.to) {\n                this.element.find('#' + this.options.to.id)[this._picker()]('destroy');\n            }\n            this._super();\n        }\n    });\n\n    // Overrides the \"today\" button functionality to select today's date when clicked.\n    $.datepicker._gotoTodayOriginal = $.datepicker._gotoToday;\n\n    /**\n     * overwrite jQuery UI _showDatepicker function for proper HTML generation conditions.\n     *\n     */\n    $.datepicker._showDatepickerOriginal = $.datepicker._showDatepicker;\n\n    /**\n     * Triggers original method showDataPicker for rendering calendar\n     * @param {HTMLObject} input\n     * @private\n     */\n    $.datepicker._showDatepicker = function (input) {\n        if (!input.disabled) {\n            $.datepicker._showDatepickerOriginal.call(this, input);\n        }\n    };\n\n    /**\n     * _gotoToday\n     * @param {Object} el\n     */\n    $.datepicker._gotoToday = function (el) {\n        //Set date/time according to timezone offset\n        $(el).datepicker('setTimezoneDate')\n            // To ensure that user can re-select date field without clicking outside it first.\n            .blur().trigger('change');\n    };\n\n    return {\n        dateRange:  $.mage.dateRange,\n        calendar:   $.mage.calendar\n    };\n}));\n","mage/common.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'domReady!'\n], function ($) {\n    'use strict';\n\n    /* Form with auto submit feature */\n    $('form[data-auto-submit=\"true\"]').submit();\n\n    //Add form keys.\n    $(document).on(\n        'submit',\n        'form',\n        function (e) {\n            var formKeyElement,\n                form = $(e.target),\n                formKey = $('input[name=\"form_key\"]').val();\n\n            if (formKey && !form.find('input[name=\"form_key\"]').length && form[0].method !== 'get') {\n                formKeyElement = document.createElement('input');\n                formKeyElement.setAttribute('type', 'hidden');\n                formKeyElement.setAttribute('name', 'form_key');\n                formKeyElement.setAttribute('value', formKey);\n                formKeyElement.setAttribute('auto-added-form-key', '1');\n                form.get(0).appendChild(formKeyElement);\n            }\n        }\n    );\n});\n","mage/fieldset-controls.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\ndefine([\n    'jquery',\n    'jquery/ui'\n], function ($) {\n    'use strict';\n\n    /**\n     * This widget will allow a control with the fieldsetResetControl widget attached to reset a set of input fields.\n     * The input fields to reset are defined by the inputSelector selector. The widget will store a clone of the fields\n     * on create, and on trigger of fieldsetReset event it resets the defined fields. The event is triggered by the\n     * reset control widget.\n     *\n     * For inputs of type file, the whole dom element is replaced as changing the value is a security violation\n     * For inputs of type checkbox or radio, the checked attribute is added or removed as appropriate\n     * For all others the jquery .val method is used to update to value to the original.\n     */\n    $.widget('mage.fieldsetControls', {\n        original: undefined,\n        options: {\n            inputSelector: '[data-reset=\"true\"]'\n        },\n\n        /**\n         * @private\n         */\n        _create: function () {\n            this.original = this.element.find(this.options.inputSelector).clone(true);\n            this._bind();\n        },\n\n        /**\n         * @private\n         */\n        _bind: function () {\n            this._on({\n                'fieldsetReset': '_onReset'\n            });\n        },\n\n        /**\n         * @param {jQuery.Event} e\n         * @private\n         */\n        _onReset: function (e) {\n            var items;\n\n            e.stopPropagation();\n            // find all the ones we have to remove\n            items = this.element.find(this.options.inputSelector);\n            // loop over replacing each one.\n            items.each($.proxy(function (index, item) {\n                if ($(item).attr('type') == 'file') { //eslint-disable-line eqeqeq\n                    // Replace the current one we found with a clone of the original saved earlier\n                    $(item).replaceWith($(this.original[index]).clone(true));\n                } else if ($(item).attr('type') == 'checkbox' || $(item).attr('type') == 'radio') { //eslint-disable-line\n                    // Return to original state.\n                    if ($(this.original[index]).attr('checked') === undefined) {\n                        $(item).removeAttr('checked');\n                    } else {\n                        $(item).attr('checked', $(this.original[index]).attr('checked'));\n                    }\n                } else {\n                    // Replace the value with the original\n                    $(item).val($(this.original[index]).val());\n                }\n            }, this));\n        }\n    });\n\n    $.widget('mage.fieldsetResetControl', {\n        /**\n         * @private\n         */\n        _create: function () {\n            this._bind();\n        },\n\n        /**\n         * @private\n         */\n        _bind: function () {\n            this._on({\n                click: '_onClick'\n            });\n        },\n\n        /**\n         * @param {jQuery.Event} e\n         * @private\n         */\n        _onClick: function (e) {\n            e.stopPropagation();\n            $(this.element).trigger('fieldsetReset');\n        }\n    });\n\n    return {\n        fieldsetControls: $.mage.fieldsetControls,\n        fieldsetResetControl: $.mage.fieldsetResetControl\n    };\n});\n","mage/translate.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable strict */\n(function (factory) {\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery',\n            'mage/mage'\n        ], factory);\n    } else {\n        factory(jQuery);\n    }\n}(function ($) {\n    $.extend(true, $, {\n        mage: {\n            translate: (function () {\n                /**\n                 * Key-value translations storage\n                 * @type {Object}\n                 * @private\n                 */\n                var _data = {};\n\n                /**\n                 * Add new translation (two string parameters) or several translations (object)\n                 */\n                this.add = function () {\n                    if (arguments.length > 1) {\n                        _data[arguments[0]] = arguments[1];\n                    } else if (typeof arguments[0] === 'object') {\n                        $.extend(_data, arguments[0]);\n                    }\n                };\n\n                /**\n                 * Make a translation with parsing (to handle case when _data represents tuple)\n                 * @param {String} text\n                 * @return {String}\n                 */\n                this.translate = function (text) {\n                    return _data[text] ? _data[text] : text;\n                };\n\n                return this;\n            }())\n        }\n    });\n    $.mage.__ = $.proxy($.mage.translate.translate, $.mage.translate);\n\n    return $.mage.__;\n}));\n","mage/ie-class-fixer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable strict */\n(function () {\n    var userAgent = navigator.userAgent, // user agent identifier\n        html = document.documentElement, // html tag\n        gap = ''; // gap between classes\n\n    if (html.className) { // check if neighbour class exist in html tag\n        gap = ' ';\n    } // end if\n\n    if (userAgent.match(/Trident.*rv[ :]*11\\./)) { // Special case for IE11\n        html.className += gap + 'ie11';\n    } // end if\n\n})();\n","mage/template.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (root, factory) {\n    'use strict';\n\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'underscore'\n        ], factory);\n    } else {\n        root.mageTemplate = factory(root._);\n    }\n}(this, function (_) {\n    'use strict';\n\n    /**\n     * Checks if provided string is a valid DOM selector.\n     *\n     * @param {String} selector - Selector to be checked.\n     * @returns {Boolean}\n     */\n    function isSelector(selector) {\n        try {\n            document.querySelector(selector);\n\n            return true;\n        } catch (e) {\n            return false;\n        }\n    }\n\n    /**\n     * Unescapes characters used in underscore templates.\n     *\n     * @param {String} str - String to be processed.\n     * @returns {String}\n     */\n    function unescape(str) {\n        return str.replace(/&lt;%|%3C%/g, '<%').replace(/%&gt;|%%3E/g, '%>');\n    }\n\n    /**\n     * If 'tmpl' is a valid selector, returns target node's innerHTML if found.\n     * Else, returns empty string and emits console warning.\n     * If 'tmpl' is not a selector, returns 'tmpl' as is.\n     *\n     * @param {String} tmpl\n     * @returns {String}\n     */\n    function getTmplString(tmpl) {\n        if (isSelector(tmpl)) {\n            tmpl = document.querySelector(tmpl);\n\n            if (tmpl) {\n                tmpl = tmpl.innerHTML.trim();\n            } else {\n                console.warn('No template was found by selector: ' + tmpl);\n\n                tmpl = '';\n            }\n        }\n\n        return unescape(tmpl);\n    }\n\n    /**\n     * Compiles or renders template provided either\n     * by selector or by the template string.\n     *\n     * @param {String} tmpl - Template string or selector.\n     * @param {(Object|Array|Function)} [data] - Data object with which to render template.\n     * @returns {String|Function}\n     */\n    return function (tmpl, data) {\n        var render;\n\n        tmpl   = getTmplString(tmpl);\n        render = _.template(tmpl);\n\n        return !_.isUndefined(data) ?\n            render(data) :\n            render;\n    };\n}));\n","mage/polyfill.js":"try {\n    if (!window.localStorage || !window.sessionStorage) {\n        throw new Error();\n    }\n\n    localStorage.setItem('storage_test', 1);\n    localStorage.removeItem('storage_test');\n} catch (e) {\n    (function () {\n        'use strict';\n\n        /**\n         * Returns a storage object to shim local or sessionStorage\n         * @param {String} type - either 'local' or 'session'\n         */\n        var Storage = function (type) {\n            var data;\n\n            /**\n             * Creates a cookie\n             * @param {String} name\n             * @param {String} value\n             * @param {Integer} days\n             */\n            function createCookie(name, value, days) {\n                var date, expires;\n\n                if (days) {\n                    date = new Date();\n                    date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);\n                    expires = '; expires=' + date.toGMTString();\n                } else {\n                    expires = '';\n                }\n                document.cookie = name + '=' + value + expires + '; path=/';\n            }\n\n            /**\n             * Reads value of a cookie\n             * @param {String} name\n             */\n            function readCookie(name) {\n                var nameEQ = name + '=',\n                    ca = document.cookie.split(';'),\n                    i = 0,\n                    c;\n\n                for (i = 0; i < ca.length; i++) {\n                    c = ca[i];\n\n                    while (c.charAt(0) === ' ') {\n                        c = c.substring(1, c.length);\n                    }\n\n                    if (c.indexOf(nameEQ) === 0) {\n                        return c.substring(nameEQ.length, c.length);\n                    }\n                }\n\n                return null;\n            }\n\n            /**\n             * Returns cookie name based upon the storage type.\n             * If this is session storage, the function returns a unique cookie per tab\n             */\n            function getCookieName() {\n\n                if (type !== 'session') {\n                    return 'localstorage';\n                }\n\n                if (!window.name) {\n                    window.name = new Date().getTime();\n                }\n\n                return 'sessionStorage' + window.name;\n            }\n\n            /**\n             * Sets storage cookie to a data object\n             * @param {Object} dataObject\n             */\n            function setData(dataObject) {\n                data = encodeURIComponent(JSON.stringify(dataObject));\n                createCookie(getCookieName(), data, 365);\n            }\n\n            /**\n             * Clears value of cookie data\n             */\n            function clearData() {\n                createCookie(getCookieName(), '', 365);\n            }\n\n            /**\n             * @returns value of cookie data\n             */\n            function getData() {\n                var dataResponse = readCookie(getCookieName());\n\n                return dataResponse ? JSON.parse(decodeURIComponent(dataResponse)) : {};\n            }\n\n            data = getData();\n\n            return {\n                length: 0,\n\n                /**\n                 * Clears data from storage\n                 */\n                clear: function () {\n                    data = {};\n                    this.length = 0;\n                    clearData();\n                },\n\n                /**\n                 * Gets an item from storage\n                 * @param {String} key\n                 */\n                getItem: function (key) {\n                    return data[key] === undefined ? null : data[key];\n                },\n\n                /**\n                 * Gets an item by index from storage\n                 * @param {Integer} i\n                 */\n                key: function (i) {\n                    var ctr = 0,\n                        k;\n\n                    for (k in data) {\n\n                        if (data.hasOwnProperty(k)) {\n\n                            // eslint-disable-next-line max-depth\n                            if (ctr.toString() === i.toString()) {\n                                return k;\n                            }\n                            ctr++;\n                        }\n                    }\n\n                    return null;\n                },\n\n                /**\n                 * Removes an item from storage\n                 * @param {String} key\n                 */\n                removeItem: function (key) {\n                    delete data[key];\n                    this.length--;\n                    setData(data);\n                },\n\n                /**\n                 * Sets an item from storage\n                 * @param {String} key\n                 * @param {String} value\n                 */\n                setItem: function (key, value) {\n                    data[key] = value.toString();\n                    this.length++;\n                    setData(data);\n                }\n            };\n        };\n\n        window.localStorage.prototype = window.localStorage = new Storage('local');\n        window.sessionStorage.prototype = window.sessionStorage = new Storage('session');\n    })();\n}\n","mage/edit-trigger.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\n(function (root, factory) {\n    'use strict';\n\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery',\n            'mage/template',\n            'jquery/ui'\n        ], factory);\n    } else {\n        factory(root.jQuery, root.mageTemplate);\n    }\n}(this, function ($, mageTemplate) {\n    'use strict';\n\n    var editTriggerPrototype;\n\n    $.widget('mage.editTrigger', {\n        options: {\n            img: '',\n            alt: '[TR]',\n            template: '#translate-inline-icon',\n            zIndex: 2000,\n            editSelector: '[data-translate]',\n            delay: 2000,\n            offsetTop: -3,\n            singleElement: true\n        },\n\n        /**\n         * editTriger creation\n         * @protected\n         */\n        _create: function () {\n            this.tmpl = mageTemplate(this.options.template);\n            this._initTrigger();\n            this._bind();\n        },\n\n        /**\n         * @return {Object}\n         * @private\n         */\n        _getCss: function () {\n            return {\n                position: 'absolute',\n                cursor: 'pointer',\n                display: 'none',\n                'z-index': this.options.zIndex\n            };\n        },\n\n        /**\n         * @param {*} appendTo\n         * @return {*|jQuery}\n         * @private\n         */\n        _createTrigger: function (appendTo) {\n            var tmpl = this.tmpl({\n                data: this.options\n            });\n\n            return $(tmpl)\n                .css(this._getCss())\n                .data('role', 'edit-trigger-element')\n                .appendTo(appendTo);\n        },\n\n        /**\n         * @private\n         */\n        _initTrigger: function () {\n            this.trigger = this._createTrigger($('body'));\n        },\n\n        /**\n         * Bind on mousemove event\n         * @protected\n         */\n        _bind: function () {\n            this.trigger.on('click.' + this.widgetName, $.proxy(this._onClick, this));\n            this.element.on('mousemove.' + this.widgetName, $.proxy(this._onMouseMove, this));\n        },\n\n        /**\n         * Show editTriger\n         */\n        show: function () {\n            if (this.trigger.is(':hidden')) {\n                this.trigger.show();\n            }\n        },\n\n        /**\n         * Hide editTriger\n         */\n        hide: function () {\n            this.currentTarget = null;\n\n            if (this.trigger && this.trigger.is(':visible')) {\n                this.trigger.hide();\n            }\n        },\n\n        /**\n         * Set editTriger position\n         * @protected\n         */\n        _setPosition: function (el) {\n            var offset = el.offset();\n\n            this.trigger.css({\n                top: offset.top + el.outerHeight() + this.options.offsetTop,\n                left: offset.left\n            });\n        },\n\n        /**\n         * Show/hide trigger on mouse move.\n         *\n         * @param {jQuery.Event} e\n         * @protected\n         */\n        _onMouseMove: function (e) {\n            var target = $(e.target),\n                inner = target.find(this.options.editSelector);\n\n            if ($(e.target).is('button') && inner.length) {\n                target = inner;\n            } else if (!target.is(this.trigger) && !target.is(this.options.editSelector)) {\n                target = target.parents(this.options.editSelector).first();\n            }\n\n            if (target.length) {\n                if (!target.is(this.trigger)) {\n                    this._setPosition(target);\n                    this.currentTarget = target;\n                }\n                this.show();\n            } else {\n                this.hide();\n            }\n        },\n\n        /**\n         * Trigger event \"edit\" on element for translate.\n         *\n         * @param {jQuery.Event} e\n         * @protected\n         */\n        _onClick: function (e) {\n            e.preventDefault();\n            e.stopImmediatePropagation();\n            $(this.currentTarget).trigger('edit.' + this.widgetName);\n            this.hide(true);\n        },\n\n        /**\n         * Destroy editTriger\n         */\n        destroy: function () {\n            this.trigger.remove();\n            this.element.off('.' + this.widgetName);\n\n            return $.Widget.prototype.destroy.call(this);\n        }\n    });\n\n    /**\n     * Extention for widget editTrigger - hide trigger with delay\n     */\n    editTriggerPrototype = $.mage.editTrigger.prototype;\n\n    $.widget('mage.editTrigger', $.extend({}, editTriggerPrototype, {\n        /**\n         * Added clear timeout on trigger show\n         */\n        show: function () {\n            editTriggerPrototype.show.apply(this, arguments);\n\n            if (this.options.delay) {\n                this._clearTimer();\n            }\n        },\n\n        /**\n         * Added setTimeout on trigger hide\n         */\n        hide: function (immediate) {\n            if (!immediate && this.options.delay) {\n                if (!this.timer) {\n                    this.timer = setTimeout($.proxy(function () {\n                        editTriggerPrototype.hide.apply(this, arguments);\n                        this._clearTimer();\n                    }, this), this.options.delay);\n                }\n            } else {\n                editTriggerPrototype.hide.apply(this, arguments);\n            }\n        },\n\n        /**\n         * Clear timer\n         * @protected\n         */\n        _clearTimer: function () {\n            if (this.timer) {\n                clearTimeout(this.timer);\n                this.timer = null;\n            }\n        }\n    }));\n\n    return $.mage.editTrigger;\n}));\n","mage/tabs.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery/ui',\n    'mage/mage',\n    'mage/collapsible'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.tabs', {\n        options: {\n            active: 0,\n            disabled: [],\n            openOnFocus: true,\n            collapsible: false,\n            collapsibleElement: '[data-role=collapsible]',\n            header: '[data-role=title]',\n            content: '[data-role=content]',\n            trigger: '[data-role=trigger]',\n            closedState: null,\n            openedState: null,\n            disabledState: null,\n            ajaxUrlElement: '[data-ajax=true]',\n            ajaxContent: false,\n            loadingClass: null,\n            saveState: false,\n            animate: false,\n            icons: {\n                activeHeader: null,\n                header: null\n            }\n        },\n\n        /**\n         * @private\n         */\n        _create: function () {\n            if (typeof this.options.disabled === 'string') {\n                this.options.disabled = this.options.disabled.split(' ').map(function (item) {\n                    return parseInt(item, 10);\n                });\n            }\n            this._processPanels();\n            this._handleDeepLinking();\n            this._processTabIndex();\n            this._closeOthers();\n            this._bind();\n        },\n\n        /**\n         * @private\n         */\n        _destroy: function () {\n            $.each(this.collapsibles, function () {\n                $(this).collapsible('destroy');\n            });\n        },\n\n        /**\n         * If deep linking is used, all sections must be closed but the one that contains the anchor.\n         * @private\n         */\n        _handleDeepLinking: function () {\n            var self = this,\n                anchor = window.location.hash,\n                isValid = $.mage.isValidSelector(anchor),\n                anchorId = anchor.replace('#', '');\n\n            if (anchor && isValid) {\n                $.each(self.contents, function (i) {\n                    if ($(this).attr('id') === anchorId) {\n                        self.collapsibles.not(self.collapsibles.eq(i)).collapsible('forceDeactivate');\n\n                        return false;\n                    }\n                });\n            }\n        },\n\n        /**\n         * When the widget gets instantiated, the first tab that is not disabled receive focusable property\n         * All tabs receive tabIndex 0\n         * @private\n         */\n        _processTabIndex: function () {\n            var self = this;\n\n            self.triggers.attr('tabIndex', 0);\n            $.each(this.collapsibles, function (i) {\n                self.triggers.attr('tabIndex', 0);\n                self.triggers.eq(i).attr('tabIndex', 0);\n            });\n        },\n\n        /**\n         * Prepare the elements for instantiating the collapsible widget\n         * @private\n         */\n        _processPanels: function () {\n            this.contents = this.element.find(this.options.content);\n\n            this.collapsibles = this.element.find(this.options.collapsibleElement);\n\n            this.collapsibles\n                .attr('role', 'presentation')\n                .parent()\n                .attr('role', 'tablist');\n\n            this.headers = this.element.find(this.options.header);\n\n            if (this.headers.length === 0) {\n                this.headers = this.collapsibles;\n            }\n            this.triggers = this.element.find(this.options.trigger);\n\n            if (this.triggers.length === 0) {\n                this.triggers = this.headers;\n            }\n            this._callCollapsible();\n        },\n\n        /**\n         * Setting the disabled and active tabs and calling instantiation of collapsible\n         * @private\n         */\n        _callCollapsible: function () {\n            var self = this,\n                disabled = false,\n                active = false;\n\n            $.each(this.collapsibles, function (i) {\n                disabled = active = false;\n\n                if ($.inArray(i, self.options.disabled) !== -1) {\n                    disabled = true;\n                }\n\n                if (i === self.options.active) {\n                    active = true;\n                }\n                self._instantiateCollapsible(this, i, active, disabled);\n            });\n        },\n\n        /**\n         * Instantiate collapsible.\n         *\n         * @param {HTMLElement} element\n         * @param {Number} index\n         * @param {*} active\n         * @param {*} disabled\n         * @private\n         */\n        _instantiateCollapsible: function (element, index, active, disabled) {\n            $(element).collapsible(\n                $.extend({}, this.options, {\n                    active: active,\n                    disabled: disabled,\n                    header: this.headers.eq(index),\n                    content: this.contents.eq(index),\n                    trigger: this.triggers.eq(index)\n                })\n            );\n        },\n\n        /**\n         * Adding callback to close others tabs when one gets opened\n         * @private\n         */\n        _closeOthers: function () {\n            var self = this;\n\n            $.each(this.collapsibles, function () {\n                $(this).on('beforeOpen', function () {\n                    self.collapsibles.not(this).collapsible('forceDeactivate');\n                });\n            });\n        },\n\n        /**\n         * @param {*} index\n         */\n        activate: function (index) {\n            this._toggleActivate('activate', index);\n        },\n\n        /**\n         * @param {*} index\n         */\n        deactivate: function (index) {\n            this._toggleActivate('deactivate', index);\n        },\n\n        /**\n         * @param {*} action\n         * @param {*} index\n         * @private\n         */\n        _toggleActivate: function (action, index) {\n            this.collapsibles.eq(index).collapsible(action);\n        },\n\n        /**\n         * @param {*} index\n         */\n        disable: function (index) {\n            this._toggleEnable('disable', index);\n        },\n\n        /**\n         * @param {*} index\n         */\n        enable: function (index) {\n            this._toggleEnable('enable', index);\n        },\n\n        /**\n         * @param {*} action\n         * @param {*} index\n         * @private\n         */\n        _toggleEnable: function (action, index) {\n            var self = this;\n\n            if ($.isArray(index)) {\n                $.each(index, function () {\n                    self.collapsibles.eq(this).collapsible(action);\n                });\n            } else if (index === undefined) {\n                this.collapsibles.collapsible(action);\n            } else {\n                this.collapsibles.eq(index).collapsible(action);\n            }\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _keydown: function (event) {\n            var self = this,\n                keyCode, toFocus, toFocusIndex, enabledTriggers, length, currentIndex, nextToFocus;\n\n            if (event.altKey || event.ctrlKey) {\n                return;\n            }\n            keyCode = $.ui.keyCode;\n            toFocus = false;\n            enabledTriggers = [];\n\n            $.each(this.triggers, function () {\n                if (!self.collapsibles.eq(self.triggers.index($(this))).collapsible('option', 'disabled')) {\n                    enabledTriggers.push(this);\n                }\n            });\n            length = $(enabledTriggers).length;\n            currentIndex = $(enabledTriggers).index(event.target);\n\n            /**\n             * @param {String} direction\n             * @return {*}\n             */\n            nextToFocus = function (direction) {\n                if (length > 0) {\n                    if (direction === 'right') {\n                        toFocusIndex = (currentIndex + 1) % length;\n                    } else {\n                        toFocusIndex = (currentIndex + length - 1) % length;\n                    }\n\n                    return enabledTriggers[toFocusIndex];\n                }\n\n                return event.target;\n            };\n\n            switch (event.keyCode) {\n                case keyCode.RIGHT:\n                case keyCode.DOWN:\n                    toFocus = nextToFocus('right');\n                    break;\n\n                case keyCode.LEFT:\n                case keyCode.UP:\n                    toFocus = nextToFocus('left');\n                    break;\n\n                case keyCode.HOME:\n                    toFocus = enabledTriggers[0];\n                    break;\n\n                case keyCode.END:\n                    toFocus = enabledTriggers[length - 1];\n                    break;\n            }\n\n            if (toFocus) {\n                toFocusIndex = this.triggers.index(toFocus);\n                $(event.target).attr('tabIndex', -1);\n                $(toFocus).attr('tabIndex', 0);\n                toFocus.focus();\n\n                if (this.options.openOnFocus) {\n                    this.activate(toFocusIndex);\n                }\n                event.preventDefault();\n            }\n        },\n\n        /**\n         * @private\n         */\n        _bind: function () {\n            var events = {\n                keydown: '_keydown'\n            };\n\n            this._off(this.triggers);\n            this._on(this.triggers, events);\n        }\n    });\n\n    return $.mage.tabs;\n});\n","mage/dialog.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\ndefine([\n    'jquery',\n    'jquery/ui'\n], function ($) {\n    'use strict';\n\n    /**\n     * Dialog Widget - this widget is a wrapper for the jQuery UI Dialog\n     */\n    $.widget('mage.dialog', $.ui.dialog, {});\n\n    return $.mage.dialog;\n});\n","mage/gallery/gallery.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'fotorama/fotorama',\n    'underscore',\n    'matchMedia',\n    'mage/template',\n    'text!mage/gallery/gallery.html',\n    'uiClass',\n    'mage/translate'\n], function ($, fotorama, _, mediaCheck, template, galleryTpl, Class, $t) {\n    'use strict';\n\n    /**\n     * Retrieves index if the main item.\n     * @param {Array.<Object>} data - Set of gallery items.\n     */\n    var getMainImageIndex = function (data) {\n            var mainIndex;\n\n            if (_.every(data, function (item) {\n                    return _.isObject(item);\n                })\n            ) {\n                mainIndex = _.findIndex(data, function (item) {\n                    return item.isMain;\n                });\n            }\n\n            return mainIndex > 0 ? mainIndex : 0;\n        },\n\n        /**\n         * Helper for parse translate property\n         *\n         * @param {Element} el - el that to parse\n         * @returns {Array} - array of properties.\n         */\n        getTranslate = function (el) {\n            var slideTransform = $(el).attr('style').split(';');\n\n            slideTransform = $.map(slideTransform, function (style) {\n                style = style.trim();\n\n                if (style.startsWith('transform: translate3d')) {\n                    return style.match(/transform: translate3d\\((.+)px,(.+)px,(.+)px\\)/);\n                }\n\n                return false;\n            });\n\n            return slideTransform.filter(Boolean);\n        },\n\n        /**\n         * @param {*} str\n         * @return {*}\n         * @private\n         */\n        _toNumber = function (str) {\n            var type = typeof str;\n\n            if (type === 'string') {\n                return parseInt(str); //eslint-disable-line radix\n            }\n\n            return str;\n        };\n\n    return Class.extend({\n\n        defaults: {\n            settings: {},\n            config: {},\n            startConfig: {}\n        },\n\n        /**\n         * Checks if device has touch interface.\n         * @return {Boolean} The result of searching touch events on device.\n         */\n        isTouchEnabled: (function () {\n            return 'ontouchstart' in document.documentElement;\n        })(),\n\n        /**\n         * Initializes gallery.\n         * @param {Object} config - Gallery configuration.\n         * @param {String} element - String selector of gallery DOM element.\n         */\n        initialize: function (config, element) {\n            var self = this;\n\n            this._super();\n\n            _.bindAll(this,\n                '_focusSwitcher'\n            );\n\n            /*turn off arrows for touch devices*/\n            if (this.isTouchEnabled) {\n                config.options.arrows = false;\n\n                if (config.fullscreen) {\n                    config.fullscreen.arrows = false;\n                }\n            }\n\n            config.options.width = _toNumber(config.options.width);\n            config.options.height = _toNumber(config.options.height);\n            config.options.thumbwidth = _toNumber(config.options.thumbwidth);\n            config.options.thumbheight = _toNumber(config.options.thumbheight);\n\n            config.options.swipe = true;\n            this.config = config;\n\n            this.settings = {\n                $element: $(element),\n                $pageWrapper: $('body>.page-wrapper'),\n                currentConfig: config,\n                defaultConfig: _.clone(config),\n                fullscreenConfig: _.clone(config.fullscreen),\n                breakpoints: config.breakpoints,\n                activeBreakpoint: {},\n                fotoramaApi: null,\n                isFullscreen: false,\n                api: null,\n                data: _.clone(config.data)\n            };\n            config.options.ratio = config.options.width / config.options.height;\n            config.options.height = null;\n\n            $.extend(true, this.startConfig, config);\n\n            this.initGallery();\n            this.initApi();\n            this.setupBreakpoints();\n            this.initFullscreenSettings();\n\n            this.settings.$element.on('mouseup', '.fotorama__stage__frame', function () {\n                if (\n                    !$(this).parents('.fotorama__shadows--left, .fotorama__shadows--right').length &&\n                    !$(this).hasClass('fotorama-video-container')\n                ) {\n                    self.openFullScreen();\n                }\n            });\n\n            if (this.isTouchEnabled && this.settings.isFullscreen) {\n                this.settings.$element.on('tap', '.fotorama__stage__frame', function () {\n                    var translate = getTranslate($(this).parents('.fotorama__stage__shaft'));\n\n                    if (translate[1] === '0' && !$(this).hasClass('fotorama-video-container')) {\n                        self.openFullScreen();\n                        self.settings.$pageWrapper.hide();\n                    }\n                });\n            }\n        },\n\n        /**\n         * Open gallery fullscreen\n         */\n        openFullScreen: function () {\n            this.settings.api.fotorama.requestFullScreen();\n            this.settings.$fullscreenIcon.css({\n                opacity: 1,\n                visibility: 'visible',\n                display: 'block'\n            });\n        },\n\n        /**\n         * Gallery fullscreen settings.\n         */\n        initFullscreenSettings: function () {\n            var settings = this.settings,\n                self = this;\n\n            settings.$gallery = this.settings.$element.find('[data-gallery-role=\"gallery\"]');\n            settings.$fullscreenIcon = this.settings.$element.find('[data-gallery-role=\"fotorama__fullscreen-icon\"]');\n            settings.focusableStart = this.settings.$element.find('[data-gallery-role=\"fotorama__focusable-start\"]');\n            settings.focusableEnd = this.settings.$element.find('[data-gallery-role=\"fotorama__focusable-end\"]');\n            settings.closeIcon = this.settings.$element.find('[data-gallery-role=\"fotorama__fullscreen-icon\"]');\n            settings.fullscreenConfig.swipe = true;\n\n            settings.$gallery.on('fotorama:fullscreenenter', function () {\n                settings.closeIcon.show();\n                settings.focusableStart.attr('tabindex', '0');\n                settings.focusableEnd.attr('tabindex', '0');\n                settings.focusableStart.bind('focusin', self._focusSwitcher);\n                settings.focusableEnd.bind('focusin', self._focusSwitcher);\n                settings.api.updateOptions(settings.defaultConfig.options, true);\n                settings.api.updateOptions(settings.fullscreenConfig, true);\n\n                if (!_.isEqual(settings.activeBreakpoint, {}) && settings.breakpoints) {\n                    settings.api.updateOptions(settings.activeBreakpoint.options, true);\n                }\n                settings.isFullscreen = true;\n            });\n\n            settings.$gallery.on('fotorama:fullscreenexit', function () {\n                settings.closeIcon.hide();\n                settings.focusableStart.attr('tabindex', '-1');\n                settings.focusableEnd.attr('tabindex', '-1');\n                settings.api.updateOptions(settings.defaultConfig.options, true);\n                settings.focusableStart.unbind('focusin', this._focusSwitcher);\n                settings.focusableEnd.unbind('focusin', this._focusSwitcher);\n                settings.closeIcon.hide();\n\n                if (!_.isEqual(settings.activeBreakpoint, {}) && settings.breakpoints) {\n                    settings.api.updateOptions(settings.activeBreakpoint.options, true);\n                }\n                settings.isFullscreen = false;\n                settings.$element.data('gallery').updateOptions({\n                    swipe: true\n                });\n            });\n        },\n\n        /**\n         * Switcher focus.\n         */\n        _focusSwitcher: function (e) {\n            var target = $(e.target),\n                settings = this.settings;\n\n            if (target.is(settings.focusableStart)) {\n                this._setFocus('start');\n            } else if (target.is(settings.focusableEnd)) {\n                this._setFocus('end');\n            }\n        },\n\n        /**\n         * Set focus to element.\n         * @param {String} position - can be \"start\" and \"end\"\n         *      positions.\n         *      If position is \"end\" - sets focus to first\n         *      focusable element in modal window scope.\n         *      If position is \"start\" - sets focus to last\n         *      focusable element in modal window scope\n         */\n        _setFocus: function (position) {\n            var settings = this.settings,\n                focusableElements,\n                infelicity;\n\n            if (position === 'end') {\n                settings.$gallery.find(settings.closeIcon).focus();\n            } else if (position === 'start') {\n                infelicity = 3; //Constant for find last focusable element\n                focusableElements = settings.$gallery.find(':focusable');\n                focusableElements.eq(focusableElements.length - infelicity).focus();\n            }\n        },\n\n        /**\n         * Initializes gallery with configuration options.\n         */\n        initGallery: function () {\n            var breakpoints = {},\n                settings = this.settings,\n                config = this.config,\n                tpl = template(galleryTpl, {\n                    next: $t('Next'),\n                    previous: $t('Previous')\n                }),\n                mainImageIndex;\n\n            if (settings.breakpoints) {\n                _.each(_.values(settings.breakpoints), function (breakpoint) {\n                    var conditions;\n\n                    _.each(_.pairs(breakpoint.conditions), function (pair) {\n                        conditions = conditions ? conditions + ' and (' + pair[0] + ': ' + pair[1] + ')' :\n                        '(' + pair[0] + ': ' + pair[1] + ')';\n                    });\n                    breakpoints[conditions] = breakpoint.options;\n                });\n                settings.breakpoints = breakpoints;\n            }\n\n            _.extend(config, config.options);\n            config.options = undefined;\n\n            config.click = false;\n            config.breakpoints = null;\n            settings.currentConfig = config;\n            settings.$element.html(tpl);\n            settings.$element.removeClass('_block-content-loading');\n            settings.$elementF = $(settings.$element.children()[0]);\n            settings.$elementF.fotorama(config);\n            settings.fotoramaApi = settings.$elementF.data('fotorama');\n            $.extend(true, config, this.startConfig);\n\n            mainImageIndex = getMainImageIndex(config.data);\n\n            if (mainImageIndex) {\n                this.settings.fotoramaApi.show({\n                    index: mainImageIndex,\n                    time: 0\n                });\n            }\n        },\n\n        /**\n         * Creates breakpoints for gallery.\n         */\n        setupBreakpoints: function () {\n            var pairs,\n                settings = this.settings,\n                config = this.config,\n                startConfig = this.startConfig,\n                isTouchEnabled = this.isTouchEnabled;\n\n            if (_.isObject(settings.breakpoints)) {\n                pairs = _.pairs(settings.breakpoints);\n                _.each(pairs, function (pair) {\n                    mediaCheck({\n                        media: pair[0],\n\n                        /**\n                         * Is triggered when breakpoint enties.\n                         */\n                        entry: function () {\n                            $.extend(true, config, _.clone(startConfig));\n\n                            settings.api.updateOptions(settings.defaultConfig.options, true);\n\n                            if (settings.isFullscreen) {\n                                settings.api.updateOptions(settings.fullscreenConfig, true);\n                            }\n\n                            if (isTouchEnabled) {\n                                settings.breakpoints[pair[0]].options.arrows = false;\n\n                                if (settings.breakpoints[pair[0]].options.fullscreen) {\n                                    settings.breakpoints[pair[0]].options.fullscreen.arrows = false;\n                                }\n                            }\n\n                            settings.api.updateOptions(settings.breakpoints[pair[0]].options, true);\n                            $.extend(true, config, settings.breakpoints[pair[0]]);\n                            settings.activeBreakpoint = settings.breakpoints[pair[0]];\n                        },\n\n                        /**\n                         * Is triggered when breakpoint exits.\n                         */\n                        exit: function () {\n                            $.extend(true, config, _.clone(startConfig));\n                            settings.api.updateOptions(settings.defaultConfig.options, true);\n\n                            if (settings.isFullscreen) {\n                                settings.api.updateOptions(settings.fullscreenConfig, true);\n                            }\n                            settings.activeBreakpoint = {};\n                        }\n                    });\n                });\n            }\n        },\n\n        /**\n         * Creates gallery's API.\n         */\n        initApi: function () {\n            var settings = this.settings,\n                config = this.config,\n                api = {\n\n                    /**\n                     * Contains fotorama's API methods.\n                     */\n                    fotorama: settings.fotoramaApi,\n\n                    /**\n                     * Displays the last image on preview.\n                     */\n                    last: function () {\n                        settings.fotoramaApi.show('>>');\n                    },\n\n                    /**\n                     * Displays the first image on preview.\n                     */\n                    first: function () {\n                        settings.fotoramaApi.show('<<');\n                    },\n\n                    /**\n                     * Displays previous element on preview.\n                     */\n                    prev: function () {\n                        settings.fotoramaApi.show('<');\n                    },\n\n                    /**\n                     * Displays next element on preview.\n                     */\n                    next: function () {\n                        settings.fotoramaApi.show('>');\n                    },\n\n                    /**\n                     * Displays image with appropriate count number on preview.\n                     * @param {Number} index - Number of image that should be displayed.\n                     */\n                    seek: function (index) {\n                        if (_.isNumber(index) && index !== 0) {\n\n                            if (index > 0) {\n                                index -= 1;\n                            }\n                            settings.fotoramaApi.show(index);\n                        }\n                    },\n\n                    /**\n                     * Updates gallery with new set of options.\n                     * @param {Object} configuration - Standart gallery configuration object.\n                     * @param {Boolean} isInternal - Is this function called via breakpoints.\n                     */\n                    updateOptions: function (configuration, isInternal) {\n\n                        var $selectable = $('a[href], area[href], input, select, ' +\n                                'textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]')\n                                .not('[tabindex=-1], [disabled], :hidden'),\n                            $focus = $(':focus'),\n                            index;\n\n                        if (_.isObject(configuration)) {\n\n                            //Saves index of focus\n                            $selectable.each(function (number) {\n                                if ($(this).is($focus)) {\n                                    index = number;\n                                }\n                            });\n\n                            if (this.isTouchEnabled) {\n                                configuration.arrows = false;\n                            }\n                            configuration.click = false;\n                            configuration.breakpoints = null;\n\n                            if (!isInternal) {\n                                !_.isEqual(settings.activeBreakpoint, {} && settings.brekpoints) ?\n                                    $.extend(true, settings.activeBreakpoint.options, configuration) :\n\n                                    settings.isFullscreen ?\n                                        $.extend(true, settings.fullscreenConfig, configuration) :\n                                        $.extend(true, settings.defaultConfig.options, configuration);\n\n                            }\n                            $.extend(true, settings.currentConfig.options, configuration);\n                            settings.fotoramaApi.setOptions(settings.currentConfig.options);\n\n                            if (_.isNumber(index)) {\n                                $selectable.eq(index).focus();\n                            }\n                        }\n                    },\n\n                    /**\n                     * Updates gallery with specific set of items.\n                     * @param {Array.<Object>} data - Set of gallery items to update.\n                     */\n                    updateData: function (data) {\n                        var mainImageIndex;\n\n                        if (_.isArray(data)) {\n                            settings.fotoramaApi.load(data);\n                            mainImageIndex = getMainImageIndex(data);\n\n                            if (mainImageIndex) {\n                                settings.fotoramaApi.show({\n                                    index: mainImageIndex,\n                                    time: 0\n                                });\n                            }\n\n                            $.extend(false, settings, {\n                                data: data,\n                                defaultConfig: data\n                            });\n                            $.extend(false, config, {\n                                data: data\n                            });\n                        }\n                    },\n\n                    /**\n                     * Returns current images list\n                     *\n                     * @returns {Array}\n                     */\n                    returnCurrentImages: function () {\n                        var images = [];\n\n                        _.each(this.fotorama.data, function (item) {\n                            images.push(_.omit(item, '$navThumbFrame', '$navDotFrame', '$stageFrame', 'labelledby'));\n                        });\n\n                        return images;\n                    },\n\n                    /**\n                     * Updates gallery data partially by index\n                     * @param {Number} index - Index of image in data array to be updated.\n                     * @param {Object} item - Standart gallery image object.\n                     *\n                     */\n                    updateDataByIndex: function (index, item) {\n                        settings.fotoramaApi.spliceByIndex(index, item);\n                    }\n                };\n\n            settings.$element.data('gallery', api);\n            settings.api = settings.$element.data('gallery');\n            settings.$element.trigger('gallery:loaded');\n        }\n    });\n});\n","mage/apply/scripts.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'jquery'\n], function (_, $) {\n    'use strict';\n\n    var scriptSelector = 'script[type=\"text/x-magento-init\"]',\n        dataAttr = 'data-mage-init',\n        virtuals = [];\n\n    /**\n     * Adds components to the virtual list.\n     *\n     * @param {Object} components\n     */\n    function addVirtual(components) {\n        virtuals.push({\n            el: false,\n            data: components\n        });\n    }\n\n    /**\n     * Merges provided data with a current data\n     * of a elements' \"data-mage-init\" attribute.\n     *\n     * @param {Object} components - Object with components and theirs configuration.\n     * @param {HTMLElement} elem - Element whose data should be modified.\n     */\n    function setData(components, elem) {\n        var data = elem.getAttribute(dataAttr);\n\n        data = data ? JSON.parse(data) : {};\n        _.each(components, function (obj, key) {\n            if (_.has(obj, 'mixins')) {\n                data[key] = data[key] || {};\n                data[key].mixins = data[key].mixins || [];\n                data[key].mixins = data[key].mixins.concat(obj.mixins);\n                delete obj.mixins;\n            }\n        });\n\n        data = $.extend(true, data, components);\n        data = JSON.stringify(data);\n        elem.setAttribute(dataAttr, data);\n    }\n\n    /**\n     * Search for the elements by privded selector and extends theirs data.\n     *\n     * @param {Object} components - Object with components and theirs configuration.\n     * @param {String} selector - Selector for the elements.\n     */\n    function processElems(components, selector) {\n        var elems,\n            iterator;\n\n        if (selector === '*') {\n            addVirtual(components);\n\n            return;\n        }\n\n        elems = document.querySelectorAll(selector);\n        iterator = setData.bind(null, components);\n\n        _.toArray(elems).forEach(iterator);\n    }\n\n    /**\n     * Parses content of a provided script node.\n     * Note: node will be removed from DOM.\n     *\n     * @param {HTMLScriptElement} node - Node to be processed.\n     * @returns {Object}\n     */\n    function getNodeData(node) {\n        var data = node.textContent;\n\n        node.parentNode.removeChild(node);\n\n        return JSON.parse(data);\n    }\n\n    /**\n     * Parses 'script' tags with a custom type attribute and moves it's data\n     * to a 'data-mage-init' attribute of an element found by provided selector.\n     * Note: All found script nodes will be removed from DOM.\n     *\n     * @returns {Array} An array of components not assigned to the specific element.\n     *\n     * @example Sample declaration.\n     *      <script type=\"text/x-magento-init\">\n     *          {\n     *              \"body\": {\n     *                  \"path/to/component\": {\"foo\": \"bar\"}\n     *              }\n     *          }\n     *      </script>\n     *\n     * @example Providing data without selector.\n     *      {\n     *          \"*\": {\n     *              \"path/to/component\": {\"bar\": \"baz\"}\n     *          }\n     *      }\n     */\n    return function () {\n        var nodes = document.querySelectorAll(scriptSelector);\n\n        _.toArray(nodes)\n            .map(getNodeData)\n            .forEach(function (item) {\n                _.each(item, processElems);\n            });\n\n        return virtuals.splice(0, virtuals.length);\n    };\n});\n","mage/apply/main.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'jquery',\n    './scripts'\n], function (_, $, processScripts) {\n    'use strict';\n\n    var dataAttr = 'data-mage-init',\n        nodeSelector = '[' + dataAttr + ']';\n\n    /**\n     * Initializes components assigned to a specified element via data-* attribute.\n     *\n     * @param {HTMLElement} el - Element to initialize components with.\n     * @param {Object|String} config - Initial components' config.\n     * @param {String} component - Components' path.\n     */\n    function init(el, config, component) {\n        require([component], function (fn) {\n\n            if (typeof fn === 'object') {\n                fn = fn[component].bind(fn);\n            }\n\n            if (_.isFunction(fn)) {\n                fn(config, el);\n            } else if ($(el)[component]) {\n                $(el)[component](config);\n            }\n        }, function (error) {\n            if ('console' in window && typeof window.console.error === 'function') {\n                console.error(error);\n            }\n\n            return true;\n        });\n    }\n\n    /**\n     * Parses elements 'data-mage-init' attribute as a valid JSON data.\n     * Note: data-mage-init attribute will be removed.\n     *\n     * @param {HTMLElement} el - Element whose attribute should be parsed.\n     * @returns {Object}\n     */\n    function getData(el) {\n        var data = el.getAttribute(dataAttr);\n\n        el.removeAttribute(dataAttr);\n\n        return {\n            el: el,\n            data: JSON.parse(data)\n        };\n    }\n\n    return {\n        /**\n         * Initializes components assigned to HTML elements via [data-mage-init].\n         *\n         * @example Sample 'data-mage-init' declaration.\n         *      data-mage-init='{\"path/to/component\": {\"foo\": \"bar\"}}'\n         */\n        apply: function (context) {\n            var virtuals = processScripts(!context ? document : context),\n                nodes = document.querySelectorAll(nodeSelector);\n\n            _.toArray(nodes)\n                .map(getData)\n                .concat(virtuals)\n                .forEach(function (itemContainer) {\n                    var element = itemContainer.el;\n\n                    _.each(itemContainer.data, function (obj, key) {\n                            if (obj.mixins) {\n                                require(obj.mixins, function () { //eslint-disable-line max-nested-callbacks\n                                    var i, len;\n\n                                    for (i = 0, len = arguments.length; i < len; i++) {\n                                        $.extend(\n                                            true,\n                                            itemContainer.data[key],\n                                            arguments[i](itemContainer.data[key], element)\n                                        );\n                                    }\n\n                                    delete obj.mixins;\n                                    init.call(null, element, obj, key);\n                                });\n                            } else {\n                                init.call(null, element, obj, key);\n                            }\n\n                        }\n                    );\n\n                });\n        },\n        applyFor: init\n    };\n});\n","mage/app/config.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\n/* eslint-disable strict */\ndefine([], function () {\n    return {\n        /**\n         * Get base url.\n         */\n        getBaseUrl: function () {\n            return this.values.baseUrl;\n        },\n\n        /**\n         * Get form key.\n         */\n        getFormKey: function () {\n            return this.values.formKey;\n        }\n    };\n});\n","mage/requirejs/baseUrlResolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Sample configuration:\n *\n require.config({\n        \"config\": {\n            \"baseUrlInterceptor\": {\n                \"Magento_Ui/js/lib/knockout/bindings/collapsible.js\": \"../../../../frontend/Magento/luma/en_US/\"\n            }\n        }\n    });\n */\n\n/* global jsSuffixRegExp */\n/* eslint-disable max-depth */\ndefine('baseUrlInterceptor', [\n    'module'\n], function (module) {\n    'use strict';\n\n    /**\n     * RequireJS Context object\n     */\n    var ctx = require.s.contexts._,\n\n        /**\n         * Original function\n         *\n         * @type {Function}\n         */\n        origNameToUrl = ctx.nameToUrl,\n\n        /**\n         * Original function\n         *\n         * @type {Function}\n         */\n        newContextConstr = require.s.newContext;\n\n    /**\n     * Remove dots from URL\n     *\n     * @param {Array} ary\n     */\n    function trimDots(ary) {\n        var i, part, length = ary.length;\n\n        for (i = 0; i < length; i++) {\n            part = ary[i];\n\n            if (part === '.') {\n                ary.splice(i, 1);\n                i -= 1;\n            } else if (part === '..') {\n                if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {\n                    //End of the line. Keep at least one non-dot\n                    //path segment at the front so it can be mapped\n                    //correctly to disk. Otherwise, there is likely\n                    //no path mapping for a path starting with '..'.\n                    //This can still fail, but catches the most reasonable\n                    //uses of ..\n                    break;\n                } else if (i > 0) {\n                    ary.splice(i - 1, 2);\n                    i -= 2;\n                }\n            }\n        }\n    }\n\n    /**\n     * Normalize URL string (remove '/../')\n     *\n     * @param {String} name\n     * @param {String} baseName\n     * @param {Object} applyMap\n     * @param {Object} localContext\n     * @returns {*}\n     */\n    function normalize(name, baseName, applyMap, localContext) {\n        var lastIndex,\n            baseParts = baseName && baseName.split('/'),\n            normalizedBaseParts = baseParts;\n\n        //Adjust any relative paths.\n        if (name && name.charAt(0) === '.') {\n            //If have a base name, try to normalize against it,\n            //otherwise, assume it is a top-level require that will\n            //be relative to baseUrl in the end.\n            if (baseName) {\n                //Convert baseName to array, and lop off the last part,\n                //so that . matches that 'directory' and not name of the baseName's\n                //module. For instance, baseName of 'one/two/three', maps to\n                //'one/two/three.js', but we want the directory, 'one/two' for\n                //this normalization.\n                normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);\n                name = name.split('/');\n                lastIndex = name.length - 1;\n\n                // If wanting node ID compatibility, strip .js from end\n                // of IDs. Have to do this here, and not in nameToUrl\n                // because node allows either .js or non .js to map\n                // to same file.\n                if (localContext.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {\n                    name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');\n                }\n\n                name = normalizedBaseParts.concat(name);\n                trimDots(name);\n                name = name.join('/');\n            } else if (name.indexOf('./') === 0) {\n                // No baseName, so this is ID is resolved relative\n                // to baseUrl, pull off the leading dot.\n                name = name.substring(2);\n            }\n        }\n\n        return name;\n    }\n\n    /**\n     * Get full url.\n     *\n     * @param {Object} context\n     * @param {String} url\n     * @return {String}\n     */\n    function getUrl(context, url) {\n        var baseUrl = context.config.baseUrl,\n            newConfig = context.config,\n            modulePath = url.replace(baseUrl, ''),\n            newBaseUrl,\n            rewrite = module.config()[modulePath];\n\n        if (!rewrite) {\n            return url;\n        }\n\n        newBaseUrl = normalize(rewrite, baseUrl, undefined, newConfig);\n\n        return newBaseUrl + modulePath;\n    }\n\n    /**\n     * Replace original function.\n     *\n     * @returns {*}\n     */\n    ctx.nameToUrl = function () {\n        return getUrl(ctx, origNameToUrl.apply(ctx, arguments));\n    };\n\n    /**\n     * Replace original function.\n     *\n     * @return {*}\n     */\n    require.s.newContext = function () {\n        var newCtx = newContextConstr.apply(require.s, arguments),\n            newOrigNameToUrl = newCtx.nameToUrl;\n\n        /**\n         * New implementation of native function.\n         *\n         * @returns {String}\n         */\n        newCtx.nameToUrl = function () {\n            return getUrl(newCtx, newOrigNameToUrl.apply(newCtx, arguments));\n        };\n\n        return newCtx;\n    };\n});\n\nrequire(['baseUrlInterceptor'], function () {\n    'use strict';\n\n});\n","mage/requirejs/text.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* inspired by http://github.com/requirejs/text */\n/*global XMLHttpRequest, XDomainRequest */\n\ndefine(['module'], function (module) {\n    'use strict';\n\n    var xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n        bodyRegExp = /<body[^>]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n        stripReg = /!strip$/i,\n        defaultConfig = module.config && module.config() || {};\n\n    /**\n     * Strips <?xml ...?> declarations so that external SVG and XML documents can be\n     * added to a document without worry.\n     * Also, if the string is an HTML document, only the part inside the body tag is returned.\n     *\n     * @param {String} external\n     * @returns {String}\n     */\n    function stripContent(external) {\n        var matches;\n\n        if (!external) {\n            return '';\n        }\n\n        matches = external.match(bodyRegExp);\n        external = matches ?\n            matches[1] :\n            external.replace(xmlRegExp, '');\n\n        return external;\n    }\n\n    /**\n     * Checks that url match current location\n     *\n     * @param {String} url\n     * @returns {Boolean}\n     */\n    function sameDomain(url) {\n        var uProtocol, uHostName, uPort,\n            xdRegExp = /^([\\w:]+)?\\/\\/([^\\/\\\\]+)/i,\n            location = window.location,\n            match = xdRegExp.exec(url);\n\n        if (!match) {\n            return true;\n        }\n        uProtocol = match[1];\n        uHostName = match[2];\n\n        uHostName = uHostName.split(':');\n        uPort = uHostName[1] || '';\n        uHostName = uHostName[0];\n\n        return (!uProtocol || uProtocol === location.protocol) &&\n            (!uHostName || uHostName.toLowerCase() === location.hostname.toLowerCase()) &&\n            (!uPort && !uHostName || uPort === location.port);\n    }\n\n    /**\n     * @returns {XMLHttpRequest|XDomainRequest|null}\n     */\n    function createRequest(url) {\n        var xhr = new XMLHttpRequest();\n\n        if (!sameDomain(url) && typeof XDomainRequest !== 'undefined') {\n            xhr = new XDomainRequest();\n        }\n\n        return xhr;\n    }\n\n    /**\n     * XHR requester. Returns value to callback.\n     *\n     * @param {String} url\n     * @param {Function} callback\n     * @param {Function} fail\n     * @param {Object} headers\n     */\n    function getContent(url, callback, fail, headers) {\n        var xhr = createRequest(url),\n            header;\n\n        xhr.open('GET', url);\n\n        /*eslint-disable max-depth */\n        if ('setRequestHeader' in xhr && headers) {\n            for (header in headers) {\n                if (headers.hasOwnProperty(header)) {\n                    xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n                }\n            }\n        }\n\n        /**\n         * @inheritdoc\n         */\n        xhr.onreadystatechange = function () {\n            var status, err;\n\n            //Do not explicitly handle errors, those should be\n            //visible via console output in the browser.\n            if (xhr.readyState === 4) {\n                status = xhr.status || 0;\n\n                if (status > 399 && status < 600) {\n                    //An http 4xx or 5xx error. Signal an error.\n                    err = new Error(url + ' HTTP status: ' + status);\n                    err.xhr = xhr;\n\n                    if (fail) {\n                        fail(err);\n                    }\n                } else {\n                    callback(xhr.responseText);\n\n                    if (defaultConfig.onXhrComplete) {\n                        defaultConfig.onXhrComplete(xhr, url);\n                    }\n                }\n            }\n        };\n\n        /*eslint-enable max-depth */\n\n        if (defaultConfig.onXhr) {\n            defaultConfig.onXhr(xhr, url);\n        }\n\n        xhr.send();\n    }\n\n    /**\n     * Main method used by RequireJs.\n     *\n     * @param {String} name - has format: some.module.filext!strip\n     * @param {Function} req\n     * @param {Function|undefined} onLoad\n     */\n    function loadContent(name, req, onLoad) {\n\n        var toStrip = stripReg.test(name),\n            url = req.toUrl(name.replace(stripReg, '')),\n            headers = defaultConfig.headers;\n\n        getContent(url, function (content) {\n                content = toStrip ? stripContent(content) : content;\n                onLoad(content);\n            }, onLoad.error, headers);\n    }\n\n    return {\n        load: loadContent,\n        get: getContent\n    };\n});\n","mage/requirejs/resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'domReady!'\n], function (_) {\n    'use strict';\n\n    var context = require.s.contexts._,\n        execCb = context.execCb,\n        registry = context.registry,\n        callbacks = [],\n        retries = 10,\n        updateDelay = 1,\n        ready,\n        update;\n\n    /**\n     * Checks if provided callback already exists in the callbacks list.\n     *\n     * @param {Object} callback - Callback object to be checked.\n     * @returns {Boolean}\n     */\n    function isSubscribed(callback) {\n        return !!_.findWhere(callbacks, callback);\n    }\n\n    /**\n     * Checks if provided module is rejected during load.\n     *\n     * @param {Object} module - Module to be checked.\n     * @return {Boolean}\n     */\n    function isRejected(module) {\n        return registry[module.id] && (registry[module.id].inited || registry[module.id].error);\n    }\n\n    /**\n     * Checks if provided module has unresolved dependencies.\n     *\n     * @param {Object} module - Module to be checked.\n     * @returns {Boolean}\n     */\n    function isPending(module) {\n        if (!module.depCount) {\n            return false;\n        }\n\n        return module.depCount > _.filter(module.depMaps, isRejected).length;\n    }\n\n    /**\n     * Checks if requirejs's registry object contains pending modules.\n     *\n     * @returns {Boolean}\n     */\n    function hasPending() {\n        return _.some(registry, isPending);\n    }\n\n    /**\n     * Checks if 'resolver' module is in ready\n     * state and that there are no pending modules.\n     *\n     * @returns {Boolean}\n     */\n    function isReady() {\n        return ready && !hasPending();\n    }\n\n    /**\n     * Invokes provided callback handler.\n     *\n     * @param {Object} callback\n     */\n    function invoke(callback) {\n        callback.handler.call(callback.ctx);\n    }\n\n    /**\n     * Sets 'resolver' module to a ready state\n     * and invokes pending callbacks.\n     */\n    function resolve() {\n        ready = true;\n\n        callbacks.splice(0).forEach(invoke);\n    }\n\n    /**\n     * Drops 'ready' flag and runs the update process.\n     */\n    function tick() {\n        ready = false;\n\n        update(retries);\n    }\n\n    /**\n     * Adds callback which will be invoked\n     * when all of the pending modules are initiated.\n     *\n     * @param {Function} handler - 'Ready' event handler function.\n     * @param {Object} [ctx] - Optional context with which handler\n     *      will be invoked.\n     */\n    function subscribe(handler, ctx) {\n        var callback = {\n            handler: handler,\n            ctx: ctx\n        };\n\n        if (!isSubscribed(callback)) {\n            callbacks.push(callback);\n\n            if (isReady()) {\n                _.defer(tick);\n            }\n        }\n    }\n\n    /**\n     * Checks for all modules to be initiated\n     * and invokes pending callbacks if it's so.\n     *\n     * @param {Number} [retry] - Number of retries\n     *      that will be used to repeat the 'update' function\n     *      invokation in case if there are no pending requests.\n     */\n    update = _.debounce(function (retry) {\n        if (!hasPending()) {\n            retry ? update(--retry) : resolve();\n        }\n    }, updateDelay);\n\n    /**\n     * Overrides requirejs's original 'execCb' method\n     * in order to track pending modules.\n     *\n     * @returns {*} Result of original method call.\n     */\n    context.execCb = function () {\n        var exported = execCb.apply(context, arguments);\n\n        tick();\n\n        return exported;\n    };\n\n    return subscribe;\n});\n","mage/view/composite.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\n/* eslint-disable strict */\ndefine(['jquery'], function ($) {\n    return function () {\n        var renderedChildren = {},\n            children = {};\n\n        return {\n            /**\n             * @param {*} child\n             * @param {String} key\n             */\n            addChild: function (child, key) {\n                children[key] = child;\n            },\n\n            /**\n             * @param {*} root\n             */\n            render: function (root) {\n                $.each(children, function (key, child) {\n                    var childRoot = $('<div>');\n\n                    renderedChildren[key] = child.render(childRoot);\n                    root.append(childRoot);\n                });\n            }\n        };\n    };\n});\n","mage/validation/url.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        /**\n         * Redirects to the url if it is considered safe\n         *\n         * @param {String} path - url to be redirected to\n         */\n        redirect: function (path) {\n            path = this.sanitize(path);\n\n            if (this.validate(path)) {\n                window.location.href = path;\n            }\n        },\n\n        /**\n         * Validates url\n         *\n         * @param {Object} path - url to be validated\n         * @returns {Boolean}\n         */\n        validate: function (path) {\n            var hostname = window.location.hostname;\n\n            if (path.indexOf(hostname) === -1 ||\n                path.indexOf('javascript:') !== -1 ||\n                path.indexOf('vbscript:') !== -1) {\n                return false;\n            }\n\n            return true;\n        },\n\n        /**\n         * Sanitize url, replacing disallowed chars\n         *\n         * @param {String} path - url to be normalized\n         * @returns {String}\n         */\n        sanitize: function (path) {\n            return path.replace('[^-A-Za-z0-9+&@#/%?=~_|!:,.;\\(\\)]', '');\n        }\n    };\n});\n","mage/validation/validation.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function (factory) {\n    'use strict';\n\n    if (typeof define === 'function' && define.amd) {\n        define([\n            'jquery',\n            'mage/validation',\n            'mage/translate'\n        ], factory);\n    } else {\n        factory(jQuery);\n    }\n}(function ($) {\n    'use strict';\n\n    $.each({\n        'validate-grouped-qty': [\n            function (value, element, params) {\n                var result = false,\n                    total = 0;\n\n                $(params).find('input[data-validate*=\"validate-grouped-qty\"]').each(function (i, e) {\n                    var val = $(e).val(),\n                        valInt;\n\n                    if (val && val.length > 0) {\n                        result = true;\n                        valInt = parseFloat(val) || 0;\n\n                        if (valInt >= 0) {\n                            total += valInt;\n                        } else {\n                            result = false;\n\n                            return result;\n                        }\n                    }\n                });\n\n                return result && total > 0;\n            },\n            $.mage.__('Please specify the quantity of product(s).')\n        ],\n        'validate-one-checkbox-required-by-name': [\n            function (value, element, params) {\n                var checkedCount = 0,\n                    container;\n\n                if (element.type === 'checkbox') {\n                    $('[name=\"' + element.name + '\"]').each(function () {\n                        if ($(this).is(':checked')) {\n                            checkedCount += 1;\n\n                            return false;\n                        }\n                    });\n                }\n                container = '#' + params;\n\n                if (checkedCount > 0) {\n                    $(container).removeClass('validation-failed');\n                    $(container).addClass('validation-passed');\n\n                    return true;\n                }\n                $(container).addClass('validation-failed');\n                $(container).removeClass('validation-passed');\n\n                return false;\n            },\n            $.mage.__('Please select one of the options.')\n        ],\n        'validate-date-between': [\n            function (value, element, params) {\n                var minDate = new Date(params[0]),\n                    maxDate = new Date(params[1]),\n                    inputDate = new Date(element.value),\n                    message;\n\n                minDate.setHours(0);\n                maxDate.setHours(0);\n\n                if (inputDate >= minDate && inputDate <= maxDate) {\n                    return true;\n                }\n                message = $.mage.__('Please enter a date between %min and %max.');\n                this.dateBetweenErrorMessage = message.replace('%min', minDate).replace('%max', maxDate);\n\n                return false;\n            },\n            function () {\n                return this.dateBetweenErrorMessage;\n            }\n        ],\n        'validate-dob': [\n            function (val, element, params) {\n                var dob = $(element).parents('.customer-dob'),\n                    dayVal, monthVal, yearVal, dobLength, day, month, year, curYear,\n                    validYearMessage, validateDayInMonth, validDateMessage, today, dateEntered;\n\n                $(dob).find('.' + this.settings.errorClass).removeClass(this.settings.errorClass);\n                dayVal = $(dob).find(params[0]).find('input:text').val();\n                monthVal = $(dob).find(params[1]).find('input:text').val();\n                yearVal = $(dob).find(params[2]).find('input:text').val();\n                dobLength = dayVal.length + monthVal.length + yearVal.length;\n\n                if (params[3] && dobLength === 0) {\n                    this.dobErrorMessage = $.mage.__('This is a required field.');\n\n                    return false;\n                }\n\n                if (!params[3] && dobLength === 0) {\n                    return true;\n                }\n                day = parseInt(dayVal, 10) || 0;\n                month = parseInt(monthVal, 10) || 0;\n                year = parseInt(yearVal, 10) || 0;\n                curYear = (new Date()).getFullYear();\n\n                if (!day || !month || !year) {\n                    this.dobErrorMessage = $.mage.__('Please enter a valid full date.');\n\n                    return false;\n                }\n\n                if (month < 1 || month > 12) {\n                    this.dobErrorMessage = $.mage.__('Please enter a valid month (1-12).');\n\n                    return false;\n                }\n\n                if (year < 1900 || year > curYear) {\n                    validYearMessage = $.mage.__('Please enter a valid year (1900-%1).');\n                    this.dobErrorMessage = validYearMessage.replace('%1', curYear.toString());\n\n                    return false;\n                }\n                validateDayInMonth = new Date(year, month, 0).getDate();\n\n                if (day < 1 || day > validateDayInMonth) {\n                    validDateMessage = $.mage.__('Please enter a valid day (1-%1).');\n                    this.dobErrorMessage = validDateMessage.replace('%1', validateDayInMonth.toString());\n\n                    return false;\n                }\n                today = new Date();\n                dateEntered = new Date();\n                dateEntered.setFullYear(year, month - 1, day);\n\n                if (dateEntered > today) {\n                    this.dobErrorMessage = $.mage.__('Please enter a date from the past.');\n\n                    return false;\n                }\n\n                day = day % 10 === day ? '0' + day : day;\n                month = month % 10 === month ? '0' + month : month;\n                $(element).val(month + '/' + day + '/' + year);\n\n                return true;\n            },\n            function () {\n                return this.dobErrorMessage;\n            }\n        ]\n    }, function (i, rule) {\n        rule.unshift(i);\n        $.validator.addMethod.apply($.validator, rule);\n    });\n}));\n","mage/utils/wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * Utility methods used to wrap and extend functions.\n *\n * @example Usage of a 'wrap' method with arguments delegation.\n *      var multiply = function (a, b) {\n *          return a * b;\n *      };\n *\n *      multiply = module.wrap(multiply, function (orig) {\n *          return 'Result is: ' + orig();\n *      });\n *\n *      multiply(2, 2);\n *      => 'Result is: 4'\n *\n * @example Usage of 'wrapSuper' method.\n *      var multiply = function (a, b) {\n *         return a * b;\n *      };\n *\n *      var obj = {\n *          multiply: module.wrapSuper(multiply, function () {\n *              return 'Result is: ' + this._super();\n *          });\n *      };\n *\n *      obj.multiply(2, 2);\n *      => 'Result is: 4'\n */\ndefine([\n    'underscore'\n], function (_) {\n    'use strict';\n\n    /**\n     * Checks if string has a '_super' substring.\n     */\n    var superReg = /\\b_super\\b/;\n\n    return {\n\n        /**\n         * Wraps target function with a specified wrapper, which will receive\n         * reference to the original function as a first argument.\n         *\n         * @param {Function} target - Function to be wrapped.\n         * @param {Function} wrapper - Wrapper function.\n         * @returns {Function} Wrapper function.\n         */\n        wrap: function (target, wrapper) {\n            if (!_.isFunction(target) || !_.isFunction(wrapper)) {\n                return wrapper;\n            }\n\n            return function () {\n                var args    = _.toArray(arguments),\n                    ctx     = this,\n                    _super;\n\n                /**\n                 * Function that will be passed to the wrapper.\n                 * If no arguments will be passed to it, then the original\n                 * function will be called with an arguments of a wrapper function.\n                 */\n                _super = function () {\n                    var superArgs = arguments.length ? arguments : args.slice(1);\n\n                    return target.apply(ctx, superArgs);\n                };\n\n                args.unshift(_super);\n\n                return wrapper.apply(ctx, args);\n            };\n        },\n\n        /**\n         * Wraps the incoming function to implement support of the '_super' method.\n         *\n         * @param {Function} target - Function to be wrapped.\n         * @param {Function} wrapper - Wrapper function.\n         * @returns {Function} Wrapped function.\n         */\n        wrapSuper: function (target, wrapper) {\n            if (!this.hasSuper(wrapper) || !_.isFunction(target)) {\n                return wrapper;\n            }\n\n            return function () {\n                var _super  = this._super,\n                    args    = arguments,\n                    result;\n\n                /**\n                 * Temporary define '_super' method which\n                 * contains call to the original function.\n                 */\n                this._super = function () {\n                    var superArgs = arguments.length ? arguments : args;\n\n                    return target.apply(this, superArgs);\n                };\n\n                result = wrapper.apply(this, args);\n\n                this._super = _super;\n\n                return result;\n            };\n        },\n\n        /**\n         * Checks wether the incoming method contains calls of the '_super' method.\n         *\n         * @param {Function} fn - Function to be checked.\n         * @returns {Boolean}\n         */\n        hasSuper: function (fn) {\n            return _.isFunction(fn) && superReg.test(fn);\n        },\n\n        /**\n         * Extends target object with provided extenders.\n         * If property in target and extender objects is a function,\n         * then it will be wrapped using 'wrap' method.\n         *\n         * @param {Object} target - Object to be extended.\n         * @param {...Object} extenders - Multiple extenders objects.\n         * @returns {Object} Modified target object.\n         */\n        extend: function (target) {\n            var extenders = _.toArray(arguments).slice(1),\n                iterator = this._extend.bind(this, target);\n\n            extenders.forEach(iterator);\n\n            return target;\n        },\n\n        /**\n         * Same as the 'extend' method, but operates only on one extender object.\n         *\n         * @private\n         * @param {Object} target\n         * @param {Object} extender\n         */\n        _extend: function (target, extender) {\n            _.each(extender, function (value, key) {\n                target[key] = this.wrap(target[key], extender[key]);\n            }, this);\n        }\n    };\n});\n","mage/utils/arrays.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    './strings'\n], function (_, utils) {\n    'use strict';\n\n    /**\n     * Defines index of an item in a specified container.\n     *\n     * @param {*} item - Item whose index should be defined.\n     * @param {Array} container - Container upon which to perform search.\n     * @returns {Number}\n     */\n    function getIndex(item, container) {\n        var index = container.indexOf(item);\n\n        if (~index) {\n            return index;\n        }\n\n        return _.findIndex(container, function (value) {\n            return value && value.name === item;\n        });\n    }\n\n    return {\n        /**\n         * Facade method to remove/add value from/to array\n         * without creating a new instance.\n         *\n         * @param {Array} arr - Array to be modified.\n         * @param {*} value - Value to add/remove.\n         * @param {Boolean} add - Flag that specfies operation.\n         * @returns {Utils} Chainable.\n         */\n        toggle: function (arr, value, add) {\n            return add ?\n                this.add(arr, value) :\n                this.remove(arr, value);\n        },\n\n        /**\n         * Removes the incoming value from array in case\n         * without creating a new instance of it.\n         *\n         * @param {Array} arr - Array to be modified.\n         * @param {*} value - Value to be removed.\n         * @returns {Utils} Chainable.\n         */\n        remove: function (arr, value) {\n            var index = arr.indexOf(value);\n\n            if (~index) {\n                arr.splice(index, 1);\n            }\n\n            return this;\n        },\n\n        /**\n         * Adds the incoming value to array if\n         * it's not alredy present in there.\n         *\n         * @param {Array} arr - Array to be modifed.\n         * @param {...*} arguments - Values to be added.\n         * @returns {Utils} Chainable.\n         */\n        add: function (arr) {\n            var values = _.toArray(arguments).slice(1);\n\n            values.forEach(function (value) {\n                if (!~arr.indexOf(value)) {\n                    arr.push(value);\n                }\n            });\n\n            return this;\n        },\n\n        /**\n         * Inserts specified item into container at a specified position.\n         *\n         * @param {*} item - Item to be inserted into container.\n         * @param {Array} container - Container of items.\n         * @param {*} [position=-1] - Position at which item should be inserted.\n         *      Position can represent:\n         *          - specific index in container\n         *          - item which might already be present in container\n         *          - structure with one of these properties: after, before\n         * @returns {Boolean|*}\n         *      - true if element has changed its' position\n         *      - false if nothing has changed\n         *      - inserted value if it wasn't present in container\n         */\n        insert: function (item, container, position) {\n            var currentIndex = getIndex(item, container),\n                newIndex,\n                target;\n\n            if (typeof position === 'undefined') {\n                position = -1;\n            } else if (typeof position === 'string') {\n                position = isNaN(+position) ? position : +position;\n            }\n\n            newIndex = position;\n\n            if (~currentIndex) {\n                target = container.splice(currentIndex, 1)[0];\n\n                if (typeof item === 'string') {\n                    item = target;\n                }\n            }\n\n            if (typeof position !== 'number') {\n                target = position.after || position.before || position;\n\n                newIndex = getIndex(target, container);\n\n                if (~newIndex && (position.after || newIndex >= currentIndex)) {\n                    newIndex++;\n                }\n            }\n\n            if (newIndex < 0) {\n                newIndex += container.length + 1;\n            }\n\n            container[newIndex] ?\n                container.splice(newIndex, 0, item) :\n                container[newIndex] = item;\n\n            return !~currentIndex ? item : currentIndex !== newIndex;\n        },\n\n        /**\n         * @param {Array} elems\n         * @param {Number} offset\n         * @return {Number|*}\n         */\n        formatOffset: function (elems, offset) {\n            if (utils.isEmpty(offset)) {\n                offset = -1;\n            }\n\n            offset = +offset;\n\n            if (offset < 0) {\n                offset += elems.length + 1;\n            }\n\n            return offset;\n        }\n    };\n});\n","mage/utils/compare.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'mage/utils/objects'\n], function (_, utils) {\n    'use strict';\n\n    var result = [];\n\n    /**\n     * Checks if all of the provided arrays contains equal values.\n     *\n     * @param {(Boolean|Array)} [keepOrder=false]\n     * @param {Array} target\n     * @returns {Boolean}\n     */\n    function equalArrays(keepOrder, target) {\n        var args = _.toArray(arguments),\n            arrays;\n\n        if (!Array.isArray(keepOrder)) {\n            arrays      = args.slice(2);\n        } else {\n            target      = keepOrder;\n            keepOrder   = false;\n            arrays      = args.slice(1);\n        }\n\n        if (!arrays.length) {\n            return true;\n        }\n\n        return arrays.every(function (array) {\n            if (array === target) {\n                return true;\n            } else if (array.length !== target.length) {\n                return false;\n            } else if (!keepOrder) {\n                return !_.difference(target, array).length;\n            }\n\n            return array.every(function (value, index) {\n                return target.indexOf(value) === index;\n            });\n        });\n    }\n\n    /**\n     * Checks if two values are different.\n     *\n     * @param {*} a - First value.\n     * @param {*} b - Second value.\n     * @returns {Boolean}\n     */\n    function isDifferent(a, b) {\n        var oldIsPrimitive = utils.isPrimitive(a);\n\n        if (Array.isArray(a) && Array.isArray(b)) {\n            return !equalArrays(true, a, b);\n        }\n\n        return oldIsPrimitive ? a !== b : true;\n    }\n\n    /**\n     * @param {String} prefix\n     * @param {String} part\n     */\n    function getPath(prefix, part) {\n        return prefix ? prefix + '.' + part : part;\n    }\n\n    /**\n     * Checks if object has own specified property.\n     *\n     * @param {*} obj - Value to be checked.\n     * @param {String} key - Key of the property.\n     * @returns {Boolean}\n     */\n    function hasOwn(obj, key) {\n        return Object.prototype.hasOwnProperty.call(obj, key);\n    }\n\n    /**\n     * @param {Array} changes\n     */\n    function getContainers(changes) {\n        var containers  = {},\n            indexed     = _.indexBy(changes, 'path');\n\n        _.each(indexed, function (change, name) {\n            var path;\n\n            name.split('.').forEach(function (part) {\n                path = getPath(path, part);\n\n                if (path in indexed) {\n                    return;\n                }\n\n                (containers[path] = containers[path] || []).push(change);\n            });\n        });\n\n        return containers;\n    }\n\n    /**\n     * @param {String} path\n     * @param {String} name\n     * @param {String} type\n     * @param {String} newValue\n     * @param {String} oldValue\n     */\n    function addChange(path, name, type, newValue, oldValue) {\n        var data;\n\n        data = {\n            path: path,\n            name: name,\n            type: type\n        };\n\n        if (type !== 'remove') {\n            data.value = newValue;\n            data.oldValue = oldValue;\n        } else {\n            data.oldValue = newValue;\n        }\n\n        result.push(data);\n    }\n\n    /**\n     * @param {String} ns\n     * @param {String} name\n     * @param {String} type\n     * @param {String} iterator\n     * @param {String} placeholder\n     */\n    function setAll(ns, name, type, iterator, placeholder) {\n        var key;\n\n        if (arguments.length > 4) {\n            type === 'add' ?\n                addChange(ns, name, 'update', iterator, placeholder) :\n                addChange(ns, name, 'update', placeholder, iterator);\n        } else {\n            addChange(ns, name, type, iterator);\n        }\n\n        if (!utils.isObject(iterator)) {\n            return;\n        }\n\n        for (key in iterator) {\n            if (hasOwn(iterator, key)) {\n                setAll(getPath(ns, key), key, type, iterator[key]);\n            }\n        }\n    }\n\n    /*eslint-disable max-depth*/\n    /**\n     * @param {Object} old\n     * @param {Object} current\n     * @param {String} ns\n     * @param {String} name\n     */\n    function compare(old, current, ns, name) {\n        var key,\n            oldIsObj = utils.isObject(old),\n            newIsObj = utils.isObject(current);\n\n        if (oldIsObj && newIsObj) {\n            for (key in old) {\n                if (hasOwn(old, key) && !hasOwn(current, key)) {\n                    setAll(getPath(ns, key), key, 'remove', old[key]);\n                }\n            }\n\n            for (key in current) {\n                if (hasOwn(current, key)) {\n                    hasOwn(old, key) ?\n                        compare(old[key], current[key], getPath(ns, key), key) :\n                        setAll(getPath(ns, key), key, 'add', current[key]);\n                }\n            }\n        } else if (oldIsObj) {\n            setAll(ns, name, 'remove', old, current);\n        } else if (newIsObj) {\n            setAll(ns, name, 'add', current, old);\n        } else if (isDifferent(old, current)) {\n            addChange(ns, name, 'update', current, old);\n        }\n    }\n\n    /*eslint-enable max-depth*/\n\n    return {\n\n        /**\n         *\n         * @returns {Object}\n         */\n        compare: function () {\n            var changes;\n\n            compare.apply(null, arguments);\n\n            changes = result.splice(0);\n\n            return {\n                containers: getContainers(changes),\n                changes: changes,\n                equal: !changes.length\n            };\n        },\n\n        equalArrays: equalArrays\n    };\n});\n","mage/utils/strings.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    var jsonRe = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/;\n\n    return {\n\n        /**\n         * Attempts to convert string to one of the primitive values,\n         * or to parse it as a valid json object.\n         *\n         * @param {String} str - String to be processed.\n         * @returns {*}\n         */\n        castString: function (str) {\n            try {\n                str = str === 'true' ? true :\n                    str === 'false' ? false :\n                        str === 'null' ? null :\n                            +str + '' === str ? +str :\n                                jsonRe.test(str) ? JSON.parse(str) :\n                                    str;\n            } catch (e) {\n            }\n\n            return str;\n        },\n\n        /**\n         * Splits string by separator if it's possible,\n         * otherwise returns the incoming value.\n         *\n         * @param {(String|Array|*)} str - String to split.\n         * @param {String} [separator=' '] - Seperator based on which to split the string.\n         * @returns {Array|*} Splitted string or the incoming value.\n         */\n        stringToArray: function (str, separator) {\n            separator = separator || ' ';\n\n            return typeof str === 'string' ?\n                str.split(separator) :\n                str;\n        },\n\n        /**\n         * Converts the incoming string which consists\n         * of a specified delimiters into a format commonly used in form elements.\n         *\n         * @param {String} name - The incoming string.\n         * @param {String} [separator='.']\n         * @returns {String} Serialized string.\n         *\n         * @example\n         *      utils.serializeName('one.two.three');\n         *      => 'one[two][three]';\n         */\n        serializeName: function (name, separator) {\n            var result;\n\n            separator = separator || '.';\n            name = name.split(separator);\n\n            result = name.shift();\n\n            name.forEach(function (part) {\n                result += '[' + part + ']';\n            });\n\n            return result;\n        },\n\n        /**\n         * Checks wether the incoming value is not empty,\n         * e.g. not 'null' or 'undefined'\n         *\n         * @param {*} value - Value to check.\n         * @returns {Boolean}\n         */\n        isEmpty: function (value) {\n            return value === '' || _.isUndefined(value) || _.isNull(value);\n        },\n\n        /**\n         * Adds 'prefix' to the 'part' value if it was provided.\n         *\n         * @param {String} prefix\n         * @param {String} part\n         * @returns {String}\n         */\n        fullPath: function (prefix, part) {\n            return prefix ? prefix + '.' + part : part;\n        },\n\n        /**\n         * Splits incoming string and returns its' part specified by offset.\n         *\n         * @param {String} parts\n         * @param {Number} [offset]\n         * @param {String} [delimiter=.]\n         * @returns {String}\n         */\n        getPart: function (parts, offset, delimiter) {\n            delimiter = delimiter || '.';\n            parts = parts.split(delimiter);\n            offset = this.formatOffset(parts, offset);\n\n            parts.splice(offset, 1);\n\n            return parts.join(delimiter) || '';\n        },\n\n        /**\n         * Converts nameThroughCamelCase to name-through-minus\n         *\n         * @param {String} string\n         * @returns {String}\n         */\n        camelCaseToMinus: function camelCaseToMinus(string) {\n            return ('' + string)\n                .split('')\n                .map(function (symbol, index) {\n                    return index ?\n                        symbol.toUpperCase() === symbol ?\n                        '-' + symbol.toLowerCase() :\n                            symbol :\n                        symbol.toLowerCase();\n                })\n                .join('');\n        },\n\n        /**\n         * Converts name-through-minus to nameThroughCamelCase\n         *\n         * @param {String} string\n         * @returns {String}\n         */\n        minusToCamelCase: function minusToCamelCase(string) {\n            return ('' + string)\n                .split('-')\n                .map(function (part, index) {\n                    return index ? part.charAt(0).toUpperCase() + part.slice(1) : part;\n                })\n                .join('');\n        }\n    };\n});\n","mage/utils/main.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(function (require) {\n    'use strict';\n\n    var utils = {},\n        _ = require('underscore');\n\n    return _.extend(\n        utils,\n        require('./arrays'),\n        require('./compare'),\n        require('./misc'),\n        require('./objects'),\n        require('./strings'),\n        require('./template')\n    );\n});\n","mage/utils/template.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-shadow */\n\ndefine([\n    'jquery',\n    'underscore',\n    'mage/utils/objects',\n    'mage/utils/strings'\n], function ($, _, utils, stringUtils) {\n    'use strict';\n\n    var tmplSettings = _.templateSettings,\n        interpolate = /\\$\\{([\\s\\S]+?)\\}/g,\n        opener = '${',\n        template,\n        hasStringTmpls;\n\n    /**\n     * Identifies whether ES6 templates are supported.\n     */\n    hasStringTmpls = (function () {\n        var testString = 'var foo = \"bar\"; return `${ foo }` === foo';\n\n        try {\n            return Function(testString)();\n        } catch (e) {\n            return false;\n        }\n    })();\n\n    if (hasStringTmpls) {\n\n        /*eslint-disable no-unused-vars, no-eval*/\n        /**\n         * Evaluates template string using ES6 templates.\n         *\n         * @param {String} tmpl - Template string.\n         * @param {Object} $ - Data object used in a template.\n         * @returns {String} Compiled template.\n         */\n        template = function (tmpl, $) {\n            return eval('`' + tmpl + '`');\n        };\n\n        /*eslint-enable no-unused-vars, no-eval*/\n    } else {\n\n        /**\n         * Fallback function used when ES6 templates are not supported.\n         * Uses underscore templates renderer.\n         *\n         * @param {String} tmpl - Template string.\n         * @param {Object} data - Data object used in a template.\n         * @returns {String} Compiled template.\n         */\n        template = function (tmpl, data) {\n            var cached = tmplSettings.interpolate;\n\n            tmplSettings.interpolate = interpolate;\n\n            tmpl = _.template(tmpl, {\n                variable: '$'\n            })(data);\n\n            tmplSettings.interpolate = cached;\n\n            return tmpl;\n        };\n    }\n\n    /**\n     * Checks if provided value contains template syntax.\n     *\n     * @param {*} value - Value to be checked.\n     * @returns {Boolean}\n     */\n    function isTemplate(value) {\n        return typeof value === 'string' &&\n            value.indexOf(opener) !== -1 &&\n            // the below pattern almost always indicates an accident which should not cause template evaluation\n            // refuse to evaluate\n            value.indexOf('${{') === -1;\n    }\n\n    /**\n     * Iteratively processes provided string\n     * until no templates syntax will be found.\n     *\n     * @param {String} tmpl - Template string.\n     * @param {Object} data - Data object used in a template.\n     * @param {Boolean} [castString=false] - Flag that indicates whether template\n     *      should be casted after evaluation to a value of another type or\n     *      that it should be leaved as a string.\n     * @returns {*} Compiled template.\n     */\n    function render(tmpl, data, castString) {\n        var last = tmpl;\n\n        while (~tmpl.indexOf(opener)) {\n            tmpl = template(tmpl, data);\n\n            if (tmpl === last) {\n                break;\n            }\n\n            last = tmpl;\n        }\n\n        return castString ?\n            stringUtils.castString(tmpl) :\n            tmpl;\n    }\n\n    return {\n\n        /**\n         * Applies provided data to the template.\n         *\n         * @param {Object|String} tmpl\n         * @param {Object} [data] - Data object to match with template.\n         * @param {Boolean} [castString=false] - Flag that indicates whether template\n         *      should be casted after evaluation to a value of another type or\n         *      that it should be leaved as a string.\n         * @returns {*}\n         *\n         * @example Template defined as a string.\n         *      var source = { foo: 'Random Stuff', bar: 'Some' };\n         *\n         *      utils.template('${ $.bar } ${ $.foo }', source);\n         *      => 'Some Random Stuff';\n         *\n         * @example Template defined as an object.\n         *      var tmpl = {\n         *              key: {'${ $.$data.bar }': '${ $.$data.foo }'},\n         *              foo: 'bar',\n         *              x1: 2, x2: 5,\n         *              delta: '${ $.x2 - $.x1 }',\n         *              baz: 'Upper ${ $.foo.toUpperCase() }'\n         *      };\n         *\n         *      utils.template(tmpl, source);\n         *      => {\n         *          key: {'Some': 'Random Stuff'},\n         *          foo: 'bar',\n         *          x1: 2, x2: 5,\n         *          delta: 3,\n         *          baz: 'Upper BAR'\n         *      };\n         */\n        template: function (tmpl, data, castString, dontClone) {\n            if (typeof tmpl === 'string') {\n                return render(tmpl, data, castString);\n            }\n\n            if (!dontClone) {\n                tmpl = utils.copy(tmpl);\n            }\n\n            tmpl.$data = data || {};\n\n            /**\n             * Template iterator function.\n             */\n            _.each(tmpl, function iterate(value, key, list) {\n                if (key === '$data') {\n                    return;\n                }\n\n                if (isTemplate(key)) {\n                    delete list[key];\n\n                    key = render(key, tmpl);\n                    list[key] = value;\n                }\n\n                if (isTemplate(value)) {\n                    list[key] = render(value, tmpl, castString);\n                } else if ($.isPlainObject(value) || Array.isArray(value)) {\n                    _.each(value, iterate);\n                }\n            });\n\n            delete tmpl.$data;\n\n            return tmpl;\n        }\n    };\n});\n","mage/utils/misc.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'jquery',\n    'FormData'\n], function (_, $) {\n    'use strict';\n\n    var defaultAttributes,\n        ajaxSettings,\n        map;\n\n    defaultAttributes = {\n        method: 'post',\n        enctype: 'multipart/form-data'\n    };\n\n    ajaxSettings = {\n        default: {\n            method: 'POST',\n            cache: false,\n            processData: false,\n            contentType: false\n        },\n        simple: {\n            method: 'POST',\n            dataType: 'json'\n        }\n    };\n\n    map = {\n        'D': 'DDD',\n        'dd': 'DD',\n        'd': 'D',\n        'EEEE': 'dddd',\n        'EEE': 'ddd',\n        'e': 'd',\n        'yyyy': 'YYYY',\n        'yy': 'YY',\n        'y': 'YYYY',\n        'a': 'A'\n    };\n\n    return {\n\n        /**\n         * Generates a unique identifier.\n         *\n         * @param {Number} [size=7] - Length of a resulting identifier.\n         * @returns {String}\n         */\n        uniqueid: function (size) {\n            var code = Math.random() * 25 + 65 | 0,\n                idstr = String.fromCharCode(code);\n\n            size = size || 7;\n\n            while (idstr.length < size) {\n                code = Math.floor(Math.random() * 42 + 48);\n\n                if (code < 58 || code > 64) {\n                    idstr += String.fromCharCode(code);\n                }\n            }\n\n            return idstr;\n        },\n\n        /**\n         * Limits function call.\n         *\n         * @param {Object} owner\n         * @param {String} target\n         * @param {Number} limit\n         */\n        limit: function (owner, target, limit) {\n            var fn = owner[target];\n\n            owner[target] = _.debounce(fn.bind(owner), limit);\n        },\n\n        /**\n         * Converts mage date format to a moment.js format.\n         *\n         * @param {String} mageFormat\n         * @returns {String}\n         */\n        normalizeDate: function (mageFormat) {\n            var result = mageFormat;\n\n            _.each(map, function (moment, mage) {\n                result = result.replace(mage, moment);\n            });\n\n            return result;\n        },\n\n        /**\n         * Puts provided value in range of min and max parameters.\n         *\n         * @param {Number} value - Value to be located.\n         * @param {Number} min - Min value.\n         * @param {Number} max - Max value.\n         * @returns {Number}\n         */\n        inRange: function (value, min, max) {\n            return Math.min(Math.max(min, value), max);\n        },\n\n        /**\n         * Serializes and sends data via POST request.\n         *\n         * @param {Object} options - Options object that consists of\n         *      a 'url' and 'data' properties.\n         * @param {Object} attrs - Attributes that will be added to virtual form.\n         */\n        submit: function (options, attrs) {\n            var form        = document.createElement('form'),\n                data        = this.serialize(options.data),\n                attributes  = _.extend({}, defaultAttributes, attrs || {});\n\n            if (!attributes.action) {\n                attributes.action = options.url;\n            }\n\n            data['form_key'] = window.FORM_KEY;\n\n            _.each(attributes, function (value, name) {\n                form.setAttribute(name, value);\n            });\n\n            data = _.map(\n                data,\n                function (value, name) {\n                    return '<input type=\"hidden\" ' +\n                        'name=\"' + _.escape(name) + '\" ' +\n                        'value=\"' + _.escape(value) + '\"' +\n                        ' />';\n                }\n            ).join('');\n\n            form.insertAdjacentHTML('afterbegin', data);\n            document.body.appendChild(form);\n\n            form.submit();\n        },\n\n        /**\n         * Serializes and sends data via AJAX POST request.\n         *\n         * @param {Object} options - Options object that consists of\n         *      a 'url' and 'data' properties.\n         * @param {Object} config\n         */\n        ajaxSubmit: function (options, config) {\n            var t = new Date().getTime(),\n                settings;\n\n            options.data['form_key'] = window.FORM_KEY;\n            options.data = this.prepareFormData(options.data, config.ajaxSaveType);\n            settings = _.extend({}, ajaxSettings[config.ajaxSaveType], options || {});\n\n            if (!config.ignoreProcessEvents) {\n                $('body').trigger('processStart');\n            }\n\n            return $.ajax(settings)\n                .done(function (data) {\n                    if (config.response) {\n                        data.t = t;\n                        config.response.data(data);\n                        config.response.status(undefined);\n                        config.response.status(!data.error);\n                    }\n                })\n                .fail(function () {\n                    config.response.status(undefined);\n                    config.response.status(false);\n                    config.response.data({\n                        error: true,\n                        messages: 'Something went wrong.',\n                        t: t\n                    });\n                })\n                .always(function () {\n                    if (!config.ignoreProcessEvents) {\n                        $('body').trigger('processStop');\n                    }\n                });\n        },\n\n        /**\n         * Creates FormData object and append this data.\n         *\n         * @param {Object} data\n         * @param {String} type\n         * @returns {FormData}\n         */\n        prepareFormData: function (data, type) {\n            var formData;\n\n            if (type === 'default') {\n                formData = new FormData();\n                _.each(this.serialize(data), function (val, name) {\n                    formData.append(name, val);\n                });\n            } else if (type === 'simple') {\n                formData = this.serialize(data);\n            }\n\n            return formData;\n        },\n\n        /**\n         * Filters data object. Finds properties with suffix\n         * and sets their values to properties with the same name without suffix.\n         *\n         * @param {Object} data - The data object that should be filtered\n         * @param {String} suffix - The string by which data object should be filtered\n         * @param {String} separator - The string that is separator between property and suffix\n         *\n         * @returns {Object} Filtered data object\n         */\n        filterFormData: function (data, suffix, separator) {\n            data = data || {};\n            suffix = suffix || 'prepared-for-send';\n            separator = separator || '-';\n\n            _.each(data, function (value, key) {\n                if (_.isObject(value) && !value.length) {\n                    this.filterFormData(value, suffix, separator);\n                } else if (_.isString(key) && ~key.indexOf(suffix)) {\n                    data[key.split(separator)[0]] = value;\n                    delete data[key];\n                }\n            }, this);\n\n            return data;\n        },\n\n        /**\n         * Replaces symbol codes with their unescaped counterparts.\n         *\n         * @param {String} data\n         *\n         * @returns {String}\n         */\n        unescape: function (data) {\n            var unescaped = _.unescape(data),\n                mapCharacters = {\n                    '&#039;': '\\''\n                };\n\n            _.each(mapCharacters, function (value, key) {\n                unescaped = unescaped.replace(key, value);\n            });\n\n            return unescaped;\n        },\n\n        /**\n         * Converts PHP IntlFormatter format to moment format.\n         *\n         * @param {String} format - PHP format\n         * @returns {String} - moment compatible formatting\n         */\n        convertToMomentFormat: function (format) {\n            var newFormat;\n\n            newFormat = format.replace(/yyyy|yy|y/, 'YYYY'); // replace the year\n            newFormat = newFormat.replace(/dd|d/g, 'DD'); // replace the date\n\n            return newFormat;\n        },\n\n        /**\n         * Get Url Parameters.\n         *\n         * @param {String} url - Url string\n         * @returns {Object}\n         */\n        getUrlParameters: function (url) {\n            var params = {},\n                queries = url.split('?'),\n                temp,\n                i,\n                l;\n\n            if (!queries[1]) {\n                return params;\n            }\n\n            queries = queries[1].split('&');\n\n            for (i = 0, l = queries.length; i < l; i++) {\n                temp = queries[i].split('=');\n\n                if (temp[1]) {\n                    params[temp[0]] = decodeURIComponent(temp[1].replace(/\\+/g, '%20'));\n                } else {\n                    params[temp[0]] = '';\n                }\n            }\n\n            return params;\n        }\n    };\n});\n","mage/utils/objects.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    'underscore'\n], function (ko, $, _) {\n    'use strict';\n\n    var primitives = [\n        'undefined',\n        'boolean',\n        'number',\n        'string'\n    ];\n\n    /**\n     * Sets nested property of a specified object.\n     * @private\n     *\n     * @param {Object} parent - Object to look inside for the properties.\n     * @param {Array} path - Splitted path the property.\n     * @param {*} value - Value of the last property in 'path' array.\n     * returns {*} New value for the property.\n     */\n    function setNested(parent, path, value) {\n        var last = path.pop(),\n            len = path.length,\n            pi = 0,\n            part = path[pi];\n\n        for (; pi < len; part = path[++pi]) {\n            if (!_.isObject(parent[part])) {\n                parent[part] = {};\n            }\n\n            parent = parent[part];\n        }\n\n        if (typeof parent[last] === 'function') {\n            parent[last](value);\n        } else {\n            parent[last] = value;\n        }\n\n        return value;\n    }\n\n    /**\n     * Retrieves value of a nested property.\n     * @private\n     *\n     * @param {Object} parent - Object to look inside for the properties.\n     * @param {Array} path - Splitted path the property.\n     * @returns {*} Value of the property.\n     */\n    function getNested(parent, path) {\n        var exists = true,\n            len = path.length,\n            pi = 0;\n\n        for (; pi < len && exists; pi++) {\n            parent = parent[path[pi]];\n\n            if (typeof parent === 'undefined') {\n                exists = false;\n            }\n        }\n\n        if (exists) {\n            if (ko.isObservable(parent)) {\n                parent = parent();\n            }\n\n            return parent;\n        }\n    }\n\n    /**\n     * Removes property from a specified object.\n     * @private\n     *\n     * @param {Object} parent - Object from which to remove property.\n     * @param {Array} path - Splitted path to the property.\n     */\n    function removeNested(parent, path) {\n        var field = path.pop();\n\n        parent = getNested(parent, path);\n\n        if (_.isObject(parent)) {\n            delete parent[field];\n        }\n    }\n\n    return {\n\n        /**\n         * Retrieves or defines objects' property by a composite path.\n         *\n         * @param {Object} data - Container for the properties specified in path.\n         * @param {String} path - Objects' properties divided by dots.\n         * @param {*} [value] - New value for the last property.\n         * @returns {*} Returns value of the last property in chain.\n         *\n         * @example\n         *      utils.nested({}, 'one.two', 3);\n         *      => { one: {two: 3} }\n         */\n        nested: function (data, path, value) {\n            var action = arguments.length > 2 ? setNested : getNested;\n\n            path = path ? path.split('.') : [];\n\n            return action(data, path, value);\n        },\n\n        /**\n         * Removes nested property from an object.\n         *\n         * @param {Object} data - Data source.\n         * @param {String} path - Path to the property e.g. 'one.two.three'\n         */\n        nestedRemove: function (data, path) {\n            path = path.split('.');\n\n            removeNested(data, path);\n        },\n\n        /**\n         * Flattens objects' nested properties.\n         *\n         * @param {Object} data - Object to flatten.\n         * @param {String} [separator='.'] - Objects' keys separator.\n         * @returns {Object} Flattened object.\n         *\n         * @example Example with a default separator.\n         *      utils.flatten({one: { two: { three: 'value'} }});\n         *      => { 'one.two.three': 'value' };\n         *\n         * @example Example with a custom separator.\n         *      utils.flatten({one: { two: { three: 'value'} }}, '=>');\n         *      => {'one=>two=>three': 'value'};\n         */\n        flatten: function (data, separator, parent, result) {\n            separator = separator || '.';\n            result = result || {};\n\n            _.each(data, function (node, name) {\n                if (parent) {\n                    name = parent + separator + name;\n                }\n\n                typeof node === 'object' ?\n                    this.flatten(node, separator, name, result) :\n                    result[name] = node;\n\n            }, this);\n\n            return result;\n        },\n\n        /**\n         * Opposite operation of the 'flatten' method.\n         *\n         * @param {Object} data - Previously flattened object.\n         * @param {String} [separator='.'] - Keys separator.\n         * @returns {Object} Object with nested properties.\n         *\n         * @example Example using custom separator.\n         *      utils.unflatten({'one=>two': 'value'}, '=>');\n         *      => {\n         *          one: { two: 'value' }\n         *      };\n         */\n        unflatten: function (data, separator) {\n            var result = {};\n\n            separator = separator || '.';\n\n            _.each(data, function (value, nodes) {\n                nodes = nodes.split(separator);\n\n                setNested(result, nodes, value);\n            });\n\n            return result;\n        },\n\n        /**\n         * Same operation as 'flatten' method,\n         * but returns objects' keys wrapped in '[]'.\n         *\n         * @param {Object} data - Object that should be serialized.\n         * @returns {Object} Serialized data.\n         *\n         * @example\n         *      utils.serialize({one: { two: { three: 'value'} }});\n         *      => { 'one[two][three]': 'value' }\n         */\n        serialize: function (data) {\n            var result = {};\n\n            data = this.flatten(data);\n\n            _.each(data, function (value, keys) {\n                keys = this.serializeName(keys);\n                value = _.isUndefined(value) ? '' : value;\n\n                result[keys] = value;\n            }, this);\n\n            return result;\n        },\n\n        /**\n         * Performs deep extend of specified objects.\n         *\n         * @returns {Object|Array} Extended object.\n         */\n        extend: function () {\n            var args = _.toArray(arguments);\n\n            args.unshift(true);\n\n            return $.extend.apply($, args);\n        },\n\n        /**\n         * Performs a deep clone of a specified object.\n         *\n         * @param {(Object|Array)} data - Data that should be copied.\n         * @returns {Object|Array} Cloned object.\n         */\n        copy: function (data) {\n            var result = data,\n                isArray = Array.isArray(data),\n                placeholder;\n\n            if (this.isObject(data) || isArray) {\n                placeholder = isArray ? [] : {};\n                result = this.extend(placeholder, data);\n            }\n\n            return result;\n        },\n\n        /**\n         * Performs a deep clone of a specified object.\n         * Doesn't save links to original object.\n         *\n         * @param {*} original - Object to clone\n         * @returns {*}\n         */\n        hardCopy: function (original) {\n            if (original === null || typeof original !== 'object') {\n                return original;\n            }\n\n            return JSON.parse(JSON.stringify(original));\n        },\n\n        /**\n         * Removes specified nested properties from the target object.\n         *\n         * @param {Object} target - Object whose properties should be removed.\n         * @param {(...String|Array|Object)} list - List that specifies properties to be removed.\n         * @returns {Object} Modified object.\n         *\n         * @example Basic usage\n         *      var obj = {a: {b: 2}, c: 'a'};\n         *\n         *      omit(obj, 'a.b');\n         *      => {'a.b': 2};\n         *      obj => {a: {}, c: 'a'};\n         *\n         * @example Various syntaxes that would return same result\n         *      omit(obj, ['a.b', 'c']);\n         *      omit(obj, 'a.b', 'c');\n         *      omit(obj, {'a.b': true, 'c': true});\n         */\n        omit: function (target, list) {\n            var removed = {},\n                ignored = list;\n\n            if (this.isObject(list)) {\n                ignored = [];\n\n                _.each(list, function (value, key) {\n                    if (value) {\n                        ignored.push(key);\n                    }\n                });\n            } else if (_.isString(list)) {\n                ignored = _.toArray(arguments).slice(1);\n            }\n\n            _.each(ignored, function (path) {\n                var value = this.nested(target, path);\n\n                if (!_.isUndefined(value)) {\n                    removed[path] = value;\n\n                    this.nestedRemove(target, path);\n                }\n            }, this);\n\n            return removed;\n        },\n\n        /**\n         * Checks if provided value is a plain object.\n         *\n         * @param {*} value - Value to be checked.\n         * @returns {Boolean}\n         */\n        isObject: function (value) {\n            var objProto = Object.prototype;\n\n            return typeof value == 'object' ?\n            objProto.toString.call(value) === '[object Object]' :\n                false;\n        },\n\n        /**\n         *\n         * @param {*} value\n         * @returns {Boolean}\n         */\n        isPrimitive: function (value) {\n            return value === null || ~primitives.indexOf(typeof value);\n        },\n\n        /**\n         * Iterates over obj props/array elems recursively, applying action to each one\n         *\n         * @param {Object|Array} data - Data to be iterated.\n         * @param {Function} action - Callback to be called with each item as an argument.\n         * @param {Number} [maxDepth=7] - Max recursion depth.\n         */\n        forEachRecursive: function (data, action, maxDepth) {\n            maxDepth = typeof maxDepth === 'number' && !isNaN(maxDepth) ? maxDepth - 1 : 7;\n\n            if (!_.isFunction(action) || _.isFunction(data) || maxDepth < 0) {\n                return;\n            }\n\n            if (!_.isObject(data)) {\n                action(data);\n\n                return;\n            }\n\n            _.each(data, function (value) {\n                this.forEachRecursive(value, action, maxDepth);\n            }, this);\n\n            action(data);\n        },\n\n        /**\n         * Maps obj props/array elems recursively\n         *\n         * @param {Object|Array} data - Data to be iterated.\n         * @param {Function} action - Callback to transform each item.\n         * @param {Number} [maxDepth=7] - Max recursion depth.\n         *\n         * @returns {Object|Array}\n         */\n        mapRecursive: function (data, action, maxDepth) {\n            var newData;\n\n            maxDepth = typeof maxDepth === 'number' && !isNaN(maxDepth) ? maxDepth - 1 : 7;\n\n            if (!_.isFunction(action) || _.isFunction(data) || maxDepth < 0) {\n                return data;\n            }\n\n            if (!_.isObject(data)) {\n                return action(data);\n            }\n\n            if (_.isArray(data)) {\n                newData = _.map(data, function (item) {\n                    return this.mapRecursive(item, action, maxDepth);\n                }, this);\n\n                return action(newData);\n            }\n\n            newData = _.mapObject(data, function (val, key) {\n                if (data.hasOwnProperty(key)) {\n                    return this.mapRecursive(val, action, maxDepth);\n                }\n\n                return val;\n            }, this);\n\n            return action(newData);\n        },\n\n        /**\n         * Removes empty(in common sence) obj props/array elems\n         *\n         * @param {*} data - Data to be cleaned.\n         * @returns {*}\n         */\n        removeEmptyValues: function (data) {\n            if (!_.isObject(data)) {\n                return data;\n            }\n\n            if (_.isArray(data)) {\n                return data.filter(function (item) {\n                    return !this.isEmptyObj(item);\n                }, this);\n            }\n\n            return _.omit(data, this.isEmptyObj.bind(this));\n        },\n\n        /**\n         * Checks that argument of any type is empty in common sence:\n         * empty string, string with spaces only, object without own props, empty array, null or undefined\n         *\n         * @param {*} val - Value to be checked.\n         * @returns {Boolean}\n         */\n        isEmptyObj: function (val) {\n\n            return _.isObject(val) && _.isEmpty(val) ||\n            this.isEmpty(val) ||\n            val && val.trim && this.isEmpty(val.trim());\n        }\n    };\n});\n","Magento_CheckoutAgreements/js/model/place-order-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/utils/wrapper',\n    'Magento_CheckoutAgreements/js/model/agreements-assigner'\n], function ($, wrapper, agreementsAssigner) {\n    'use strict';\n\n    return function (placeOrderAction) {\n\n        /** Override default place order action and add agreement_ids to request */\n        return wrapper.wrap(placeOrderAction, function (originalAction, paymentData, messageContainer) {\n            agreementsAssigner(paymentData);\n\n            return originalAction(paymentData, messageContainer);\n        });\n    };\n});\n","Magento_CheckoutAgreements/js/model/agreement-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/validation'\n], function ($) {\n    'use strict';\n\n    var checkoutConfig = window.checkoutConfig,\n        agreementsConfig = checkoutConfig ? checkoutConfig.checkoutAgreements : {},\n        agreementsInputPath = '.payment-method._active div.checkout-agreements input';\n\n    return {\n        /**\n         * Validate checkout agreements\n         *\n         * @returns {Boolean}\n         */\n        validate: function (hideError) {\n            var isValid = true;\n\n            if (!agreementsConfig.isEnabled || $(agreementsInputPath).length === 0) {\n                return true;\n            }\n\n            $(agreementsInputPath).each(function (index, element) {\n                if (!$.validator.validateSingleElement(element, {\n                    errorElement: 'div',\n                    hideError: hideError || false\n                })) {\n                    isValid = false;\n                }\n            });\n\n            return isValid;\n        }\n    };\n});\n","Magento_CheckoutAgreements/js/model/agreements-modal.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/modal',\n    'mage/translate'\n], function ($, modal, $t) {\n    'use strict';\n\n    return {\n        modalWindow: null,\n\n        /**\n         * Create popUp window for provided element.\n         *\n         * @param {HTMLElement} element\n         */\n        createModal: function (element) {\n            var options;\n\n            this.modalWindow = element;\n            options = {\n                'type': 'popup',\n                'modalClass': 'agreements-modal',\n                'responsive': true,\n                'innerScroll': true,\n                'trigger': '.show-modal',\n                'buttons': [\n                    {\n                        text: $t('Close'),\n                        class: 'action secondary action-hide-popup',\n\n                        /** @inheritdoc */\n                        click: function () {\n                            this.closeModal();\n                        }\n                    }\n                ]\n            };\n            modal(options, $(this.modalWindow));\n        },\n\n        /** Show login popup window */\n        showModal: function () {\n            $(this.modalWindow).modal('openModal');\n        }\n    };\n});\n","Magento_CheckoutAgreements/js/model/agreements-assigner.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/*global alert*/\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    var agreementsConfig = window.checkoutConfig.checkoutAgreements;\n\n    /** Override default place order action and add agreement_ids to request */\n    return function (paymentData) {\n        var agreementForm,\n            agreementData,\n            agreementIds;\n\n        if (!agreementsConfig.isEnabled) {\n            return;\n        }\n\n        agreementForm = $('.payment-method._active div[data-role=checkout-agreements] input');\n        agreementData = agreementForm.serializeArray();\n        agreementIds = [];\n\n        agreementData.forEach(function (item) {\n            agreementIds.push(item.value);\n        });\n\n        if (paymentData['extension_attributes'] === undefined) {\n            paymentData['extension_attributes'] = {};\n        }\n\n        paymentData['extension_attributes']['agreement_ids'] = agreementIds;\n    };\n});\n","Magento_CheckoutAgreements/js/model/set-payment-information-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*global alert*/\ndefine([\n    'jquery',\n    'mage/utils/wrapper',\n    'Magento_CheckoutAgreements/js/model/agreements-assigner'\n], function ($, wrapper, agreementsAssigner) {\n    'use strict';\n\n    return function (placeOrderAction) {\n\n        /** Override place-order-mixin for set-payment-information action as they differs only by method signature */\n        return wrapper.wrap(placeOrderAction, function (originalAction, messageContainer, paymentData) {\n            agreementsAssigner(paymentData);\n\n            return originalAction(messageContainer, paymentData);\n        });\n    };\n});\n","Magento_CheckoutAgreements/js/view/agreement-validation.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/payment/additional-validators',\n    'Magento_CheckoutAgreements/js/model/agreement-validator'\n], function (Component, additionalValidators, agreementValidator) {\n    'use strict';\n\n    additionalValidators.registerValidator(agreementValidator);\n\n    return Component.extend({});\n});\n","Magento_CheckoutAgreements/js/view/checkout-agreements.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_CheckoutAgreements/js/model/agreements-modal'\n], function (ko, $, Component, agreementsModal) {\n    'use strict';\n\n    var checkoutConfig = window.checkoutConfig,\n        agreementManualMode = 1,\n        agreementsConfig = checkoutConfig ? checkoutConfig.checkoutAgreements : {};\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_CheckoutAgreements/checkout/checkout-agreements'\n        },\n        isVisible: agreementsConfig.isEnabled,\n        agreements: agreementsConfig.agreements,\n        modalTitle: ko.observable(null),\n        modalContent: ko.observable(null),\n        modalWindow: null,\n\n        /**\n         * Checks if agreement required\n         *\n         * @param {Object} element\n         */\n        isAgreementRequired: function (element) {\n            return element.mode == agreementManualMode; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * Show agreement content in modal\n         *\n         * @param {Object} element\n         */\n        showContent: function (element) {\n            this.modalTitle(element.checkboxText);\n            this.modalContent(element.content);\n            agreementsModal.showModal();\n        },\n\n        /**\n         * build a unique id for the term checkbox\n         *\n         * @param {Object} context - the ko context\n         * @param {Number} agreementId\n         */\n        getCheckboxId: function (context, agreementId) {\n            var paymentMethodName = '',\n                paymentMethodRenderer = context.$parents[1];\n\n            // corresponding payment method fetched from parent context\n            if (paymentMethodRenderer) {\n                // item looks like this: {title: \"Check / Money order\", method: \"checkmo\"}\n                paymentMethodName = paymentMethodRenderer.item ?\n                  paymentMethodRenderer.item.method : '';\n            }\n\n            return 'agreement_' + paymentMethodName + '_' + agreementId;\n        },\n\n        /**\n         * Init modal window for rendered element\n         *\n         * @param {Object} element\n         */\n        initModal: function (element) {\n            agreementsModal.createModal(element);\n        }\n    });\n});\n","Magento_OfflinePayments/js/view/payment/offline-payments.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/payment/renderer-list'\n], function (Component, rendererList) {\n    'use strict';\n\n    rendererList.push(\n        {\n            type: 'checkmo',\n            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/checkmo-method'\n        },\n        {\n            type: 'banktransfer',\n            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/banktransfer-method'\n        },\n        {\n            type: 'cashondelivery',\n            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method'\n        },\n        {\n            type: 'purchaseorder',\n            component: 'Magento_OfflinePayments/js/view/payment/method-renderer/purchaseorder-method'\n        }\n    );\n\n    /** Add view logic here if needed */\n    return Component.extend({});\n});\n","Magento_OfflinePayments/js/view/payment/method-renderer/checkmo-method.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'Magento_Checkout/js/view/payment/default'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_OfflinePayments/payment/checkmo'\n        },\n\n        /**\n         * Returns send check to info.\n         *\n         * @return {*}\n         */\n        getMailingAddress: function () {\n            return window.checkoutConfig.payment.checkmo.mailingAddress;\n        },\n\n        /**\n         * Returns payable to info.\n         *\n         * @return {*}\n         */\n        getPayableTo: function () {\n            return window.checkoutConfig.payment.checkmo.payableTo;\n        }\n    });\n});\n","Magento_OfflinePayments/js/view/payment/method-renderer/banktransfer-method.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'ko',\n    'Magento_Checkout/js/view/payment/default'\n], function (ko, Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_OfflinePayments/payment/banktransfer'\n        },\n\n        /**\n         * Get value of instruction field.\n         * @returns {String}\n         */\n        getInstructions: function () {\n            return window.checkoutConfig.payment.instructions[this.item.method];\n        }\n    });\n});\n","Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'Magento_Checkout/js/view/payment/default'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_OfflinePayments/payment/cashondelivery'\n        },\n\n        /**\n         * Returns payment method instructions.\n         *\n         * @return {*}\n         */\n        getInstructions: function () {\n            return window.checkoutConfig.payment.instructions[this.item.method];\n        }\n    });\n});\n","Magento_OfflinePayments/js/view/payment/method-renderer/purchaseorder-method.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'Magento_Checkout/js/view/payment/default',\n    'jquery',\n    'mage/validation'\n], function (Component, $) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_OfflinePayments/payment/purchaseorder-form',\n            purchaseOrderNumber: ''\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super()\n                .observe('purchaseOrderNumber');\n\n            return this;\n        },\n\n        /**\n         * @return {Object}\n         */\n        getData: function () {\n            return {\n                method: this.item.method,\n                'po_number': this.purchaseOrderNumber(),\n                'additional_data': null\n            };\n        },\n\n        /**\n         * @return {jQuery}\n         */\n        validate: function () {\n            var form = 'form[data-role=purchaseorder-form]';\n\n            return $(form).validation() && $(form).validation('isValid');\n        }\n    });\n});\n","Amazon_Login/js/amazon-logout.js":"/**\n * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n * You may not use this file except in compliance with the License.\n * A copy of the License is located at\n *\n *  http://aws.amazon.com/apache2.0\n *\n * or in the \"license\" file accompanying this file. This file is distributed\n * on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either\n * express or implied. See the License for the specific language governing\n * permissions and limitations under the License.\n */\n\ndefine([\n    'jquery',\n    'amazonCore',\n    'jquery/ui',\n    'mage/cookies'\n], function ($, core) {\n    'use strict';\n\n    $.widget('amazon.AmazonLogout', {\n        options: {\n            onInit: false\n        },\n\n        /**\n         * Create Amazon Logout Widget\n         * @private\n         */\n        _create: function () {\n            if (this.options.onInit) {\n                core.AmazonLogout(); //logout amazon user on init\n                $.mage.cookies.clear('amazon_Login_accessToken');\n            }\n        },\n\n        /**\n         * Logs out a user if called directly\n         * @private\n         */\n        _logoutAmazonUser: function () {\n            core.AmazonLogout();\n            $.mage.cookies.clear('amazon_Login_accessToken');\n        }\n    });\n\n    return $.amazon.AmazonLogout;\n});\n","Amazon_Login/js/amazon-csrf.js":"/**\n * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n * You may not use this file except in compliance with the License.\n * A copy of the License is located at\n *\n *  http://aws.amazon.com/apache2.0\n *\n * or in the \"license\" file accompanying this file. This file is distributed\n * on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either\n * express or implied. See the License for the specific language governing\n * permissions and limitations under the License.\n */\n\ndefine([\n    'sjcl',\n    'jquery',\n    'mage/cookies'\n], function (sjcl, $) {\n    'use strict';\n\n    return {\n        options: {\n            wordsLength: 8,\n            cookieName: 'amazon-csrf-state'\n        },\n\n        /**\n         * Create random string for Amazon CSRF cookie\n         */\n        generateNewValue: function () {\n            var randomString = sjcl.codec.base64.fromBits(sjcl.random.randomWords(this.options.wordsLength));\n\n            $.mage.cookies.set(this.options.cookieName, randomString);\n\n            return randomString;\n        },\n\n        /**\n         * Check if Amazon CSRF cookie is valid and clear cookie\n         * @param {String} stateString\n         * @returns {Boolean}\n         */\n        isValid: function (stateString) {\n            var isValid = $.mage.cookies.get(this.options.cookieName) === stateString;\n\n            this.clear(); // always clear nonce when validating\n\n            return isValid;\n        },\n\n        /**\n         * Clear Amazon CSRF cookie\n         */\n        clear: function () {\n            $.mage.cookies.clear(this.options.cookieName);\n        }\n    };\n});\n","Amazon_Login/js/amazon-redirect.js":"/**\n * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n * You may not use this file except in compliance with the License.\n * A copy of the License is located at\n *\n *  http://aws.amazon.com/apache2.0\n *\n * or in the \"license\" file accompanying this file. This file is distributed\n * on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either\n * express or implied. See the License for the specific language governing\n * permissions and limitations under the License.\n */\n\ndefine([\n    'jquery',\n    'amazonCore',\n    'amazonPaymentConfig',\n    'amazonCsrf',\n    'Magento_Customer/js/customer-data',\n    'mage/loader',\n    'jquery/ui',\n    'mage/cookies'\n], function ($, amazonCore, amazonPaymentConfig, amazonCsrf, customerData) {\n    'use strict';\n\n    var self;\n\n    $.widget('amazon.AmazonRedirect', {\n\n        /**\n         * @private\n         */\n        _create: function () {\n\n            self = this;\n            // start the loading animation. WIll en on redirect, no explicit stop here\n            $('body').trigger('processStart');\n\n            //verify nonce first\n            this.redirectOnInvalidState();\n\n            // we don't have the customer's consent or invalid request\n            this.redirectOnRequestWithError();\n            this.setAuthStateCookies();\n            amazonCore.amazonDefined.subscribe(function () {\n                //only set this on the redirect page\n                amazon.Login.setUseCookie(true); //eslint-disable-line no-undef\n                amazonCore.verifyAmazonLoggedIn().then(function (loggedIn) {\n                    if (loggedIn) {\n                        self.redirect();\n                    } else {\n                        window.location = amazonPaymentConfig.getValue('customerLoginPageUrl');\n                    }\n                }, function(error) {\n                    $('body').trigger('processStop');\n                    customerData.set('messages', {\n                        messages: [{\n                            type: 'error',\n                            text: error\n                        }]\n                    });\n                });\n            }, this);\n        },\n\n        /**\n         * getURLParamater from URL for access OAuth Token\n         * @param {String} name\n         * @param {String} source\n         * @returns {String|Null}\n         */\n        getURLParameter: function (name, source) {\n            return decodeURIComponent((new RegExp('[?|&|#]' + name + '=' +\n                    '([^&]+?)(&|#|;|$)').exec(source) || [,''])[1].replace(\n                        /\\+/g,\n                        '%20'\n                    )) || null;\n        },\n\n        /**\n         * Set State Cache Auth Cookies if they aren't already set\n         * @returns {Boolean}\n         */\n        setAuthStateCookies: function () {\n            var token = this.getURLParameter('access_token', location.hash);\n\n            if (typeof token === 'string' && token.match(/^Atza/)) {\n                $.mage.cookies.set('amazon_Login_accessToken', token);\n            }\n\n            return true;\n        },\n\n        /**\n         * Redirect user to correct controller which logs them into M2 via Amazon hash\n         */\n        redirect: function () {\n            window.location = amazonPaymentConfig.getValue('redirectUrl') + '?access_token=' +\n                this.getURLParameter('access_token', location.hash);\n        },\n\n        /**\n         * Redirect user on invalid state\n         */\n        redirectOnInvalidState: function () {\n            var state = this.getURLParameter('state', location.hash);\n\n            if (!state || !amazonCsrf.isValid(state)) {\n                window.location = amazonPaymentConfig.getValue('customerLoginPageUrl');\n            }\n        },\n\n        /**\n         * Redirect user on request error\n         */\n        redirectOnRequestWithError: function () {\n            if (this.getURLParameter('error', window.location)) {\n                window.location = amazonPaymentConfig.getValue('customerLoginPageUrl');\n            }\n        }\n    });\n\n    return $.amazon.AmazonRedirect;\n});\n","Amazon_Login/js/view/login-button-wrapper.js":"/**\n * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n * You may not use this file except in compliance with the License.\n * A copy of the License is located at\n *\n *  http://aws.amazon.com/apache2.0\n *\n * or in the \"license\" file accompanying this file. This file is distributed\n * on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either\n * express or implied. See the License for the specific language governing\n * permissions and limitations under the License.\n */\n\ndefine(['uiRegistry', 'Amazon_Login/js/view/login-button', 'uiComponent'], function(registry, login, component) {\n    'use strict';\n    var amazonPayment = registry.get('amazonPayment');\n\n    if (amazonPayment !== undefined && amazonPayment.allowAmLoginLoading === true) {\n        return login;\n    }\n    return component;\n});\n","Amazon_Login/js/view/login-button.js":"/**\n * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\").\n * You may not use this file except in compliance with the License.\n * A copy of the License is located at\n *\n *  http://aws.amazon.com/apache2.0\n *\n * or in the \"license\" file accompanying this file. This file is distributed\n * on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either\n * express or implied. See the License for the specific language governing\n * permissions and limitations under the License.\n */\n\ndefine(\n    [\n        'jquery',\n        'uiComponent',\n        'ko',\n        'Magento_Customer/js/model/customer',\n        'Amazon_Payment/js/model/storage',\n        'amazonPaymentConfig'\n    ],\n    function (\n        $,\n        Component,\n        ko,\n        customer,\n        amazonStorage,\n        amazonPaymentConfig\n    ) {\n        'use strict';\n\n        return Component.extend({\n            defaults: {\n                template: 'Amazon_Login/login-button'\n            },\n            isCustomerLoggedIn: customer.isLoggedIn,\n            isAmazonAccountLoggedIn: amazonStorage.isAmazonAccountLoggedIn,\n            isLwaVisible: ko.observable(amazonPaymentConfig.getValue('isLwaEnabled')),\n\n            /**\n             * Initialize login button\n             */\n            initialize: function () {\n                this._super();\n            }\n        });\n    }\n);\n","Magento_ConfigurableProduct/js/configurable.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'mage/template',\n    'mage/translate',\n    'priceUtils',\n    'priceBox',\n    'jquery/ui',\n    'jquery/jquery.parsequery'\n], function ($, _, mageTemplate, $t, priceUtils) {\n    'use strict';\n\n    $.widget('mage.configurable', {\n        options: {\n            superSelector: '.super-attribute-select',\n            selectSimpleProduct: '[name=\"selected_configurable_option\"]',\n            priceHolderSelector: '.price-box',\n            spConfig: {},\n            state: {},\n            priceFormat: {},\n            optionTemplate: '<%- data.label %>' +\n            '<% if (typeof data.finalPrice.value !== \"undefined\") { %>' +\n            ' <%- data.finalPrice.formatted %>' +\n            '<% } %>',\n            mediaGallerySelector: '[data-gallery-role=gallery-placeholder]',\n            mediaGalleryInitial: null,\n            slyOldPriceSelector: '.sly-old-price',\n            normalPriceLabelSelector: '.normal-price .price-label',\n\n            /**\n             * Defines the mechanism of how images of a gallery should be\n             * updated when user switches between configurations of a product.\n             *\n             * As for now value of this option can be either 'replace' or 'prepend'.\n             *\n             * @type {String}\n             */\n            gallerySwitchStrategy: 'replace',\n            tierPriceTemplateSelector: '#tier-prices-template',\n            tierPriceBlockSelector: '[data-role=\"tier-price-block\"]',\n            tierPriceTemplate: ''\n        },\n\n        /**\n         * Creates widget\n         * @private\n         */\n        _create: function () {\n            // Initial setting of various option values\n            this._initializeOptions();\n\n            // Override defaults with URL query parameters and/or inputs values\n            this._overrideDefaults();\n\n            // Change events to check select reloads\n            this._setupChangeEvents();\n\n            // Fill state\n            this._fillState();\n\n            // Setup child and prev/next settings\n            this._setChildSettings();\n\n            // Setup/configure values to inputs\n            this._configureForValues();\n\n            $(this.element).trigger('configurable.initialized');\n        },\n\n        /**\n         * Initialize tax configuration, initial settings, and options values.\n         * @private\n         */\n        _initializeOptions: function () {\n            var options = this.options,\n                gallery = $(options.mediaGallerySelector),\n                priceBoxOptions = $(this.options.priceHolderSelector).priceBox('option').priceConfig || null;\n\n            if (priceBoxOptions && priceBoxOptions.optionTemplate) {\n                options.optionTemplate = priceBoxOptions.optionTemplate;\n            }\n\n            if (priceBoxOptions && priceBoxOptions.priceFormat) {\n                options.priceFormat = priceBoxOptions.priceFormat;\n            }\n            options.optionTemplate = mageTemplate(options.optionTemplate);\n            options.tierPriceTemplate = $(this.options.tierPriceTemplateSelector).html();\n\n            options.settings = options.spConfig.containerId ?\n                $(options.spConfig.containerId).find(options.superSelector) :\n                $(options.superSelector);\n\n            options.values = options.spConfig.defaultValues || {};\n            options.parentImage = $('[data-role=base-image-container] img').attr('src');\n\n            this.inputSimpleProduct = this.element.find(options.selectSimpleProduct);\n\n            gallery.data('gallery') ?\n                this._onGalleryLoaded(gallery) :\n                gallery.on('gallery:loaded', this._onGalleryLoaded.bind(this, gallery));\n\n        },\n\n        /**\n         * Override default options values settings with either URL query parameters or\n         * initialized inputs values.\n         * @private\n         */\n        _overrideDefaults: function () {\n            var hashIndex = window.location.href.indexOf('#');\n\n            if (hashIndex !== -1) {\n                this._parseQueryParams(window.location.href.substr(hashIndex + 1));\n            }\n\n            if (this.options.spConfig.inputsInitialized) {\n                this._setValuesByAttribute();\n            }\n        },\n\n        /**\n         * Parse query parameters from a query string and set options values based on the\n         * key value pairs of the parameters.\n         * @param {*} queryString - URL query string containing query parameters.\n         * @private\n         */\n        _parseQueryParams: function (queryString) {\n            var queryParams = $.parseQuery({\n                query: queryString\n            });\n\n            $.each(queryParams, $.proxy(function (key, value) {\n                this.options.values[key] = value;\n            }, this));\n        },\n\n        /**\n         * Override default options values with values based on each element's attribute\n         * identifier.\n         * @private\n         */\n        _setValuesByAttribute: function () {\n            this.options.values = {};\n            $.each(this.options.settings, $.proxy(function (index, element) {\n                var attributeId;\n\n                if (element.value) {\n                    attributeId = element.id.replace(/[a-z]*/, '');\n                    this.options.values[attributeId] = element.value;\n                }\n            }, this));\n        },\n\n        /**\n         * Set up .on('change') events for each option element to configure the option.\n         * @private\n         */\n        _setupChangeEvents: function () {\n            $.each(this.options.settings, $.proxy(function (index, element) {\n                $(element).on('change', this, this._configure);\n            }, this));\n        },\n\n        /**\n         * Iterate through the option settings and set each option's element configuration,\n         * attribute identifier. Set the state based on the attribute identifier.\n         * @private\n         */\n        _fillState: function () {\n            $.each(this.options.settings, $.proxy(function (index, element) {\n                var attributeId = element.id.replace(/[a-z]*/, '');\n\n                if (attributeId && this.options.spConfig.attributes[attributeId]) {\n                    element.config = this.options.spConfig.attributes[attributeId];\n                    element.attributeId = attributeId;\n                    this.options.state[attributeId] = false;\n                }\n            }, this));\n        },\n\n        /**\n         * Set each option's child settings, and next/prev option setting. Fill (initialize)\n         * an option's list of selections as needed or disable an option's setting.\n         * @private\n         */\n        _setChildSettings: function () {\n            var childSettings = [],\n                settings = this.options.settings,\n                index = settings.length,\n                option;\n\n            while (index--) {\n                option = settings[index];\n\n                if (index) {\n                    option.disabled = true;\n                } else {\n                    this._fillSelect(option);\n                }\n\n                _.extend(option, {\n                    childSettings: childSettings.slice(),\n                    prevSetting: settings[index - 1],\n                    nextSetting: settings[index + 1]\n                });\n\n                childSettings.push(option);\n            }\n        },\n\n        /**\n         * Setup for all configurable option settings. Set the value of the option and configure\n         * the option, which sets its state, and initializes the option's choices, etc.\n         * @private\n         */\n        _configureForValues: function () {\n            if (this.options.values) {\n                this.options.settings.each($.proxy(function (index, element) {\n                    var attributeId = element.attributeId;\n\n                    element.value = this.options.values[attributeId] || '';\n                    this._configureElement(element);\n                }, this));\n            }\n        },\n\n        /**\n         * Event handler for configuring an option.\n         * @private\n         * @param {Object} event - Event triggered to configure an option.\n         */\n        _configure: function (event) {\n            event.data._configureElement(this);\n        },\n\n        /**\n         * Configure an option, initializing it's state and enabling related options, which\n         * populates the related option's selection and resets child option selections.\n         * @private\n         * @param {*} element - The element associated with a configurable option.\n         */\n        _configureElement: function (element) {\n            this.simpleProduct = this._getSimpleProductId(element);\n\n            if (element.value) {\n                this.options.state[element.config.id] = element.value;\n\n                if (element.nextSetting) {\n                    element.nextSetting.disabled = false;\n                    this._fillSelect(element.nextSetting);\n                    this._resetChildren(element.nextSetting);\n                } else {\n                    if (!!document.documentMode) { //eslint-disable-line\n                        this.inputSimpleProduct.val(element.options[element.selectedIndex].config.allowedProducts[0]);\n                    } else {\n                        this.inputSimpleProduct.val(element.selectedOptions[0].config.allowedProducts[0]);\n                    }\n                }\n            } else {\n                this._resetChildren(element);\n            }\n\n            this._reloadPrice();\n            this._displayRegularPriceBlock(this.simpleProduct);\n            this._displayTierPriceBlock(this.simpleProduct);\n            this._displayNormalPriceLabel();\n            this._changeProductImage();\n        },\n\n        /**\n         * Change displayed product image according to chosen options of configurable product\n         *\n         * @private\n         */\n        _changeProductImage: function () {\n            var images,\n                initialImages = this.options.mediaGalleryInitial,\n                galleryObject = $(this.options.mediaGallerySelector).data('gallery');\n\n            if (!galleryObject) {\n                return;\n            }\n\n            images = this.options.spConfig.images[this.simpleProduct];\n\n            if (images) {\n                images = this._sortImages(images);\n\n                if (this.options.gallerySwitchStrategy === 'prepend') {\n                    images = images.concat(initialImages);\n                }\n\n                images = $.extend(true, [], images);\n                images = this._setImageIndex(images);\n\n                galleryObject.updateData(images);\n\n                $(this.options.mediaGallerySelector).AddFotoramaVideoEvents({\n                    selectedOption: this.simpleProduct,\n                    dataMergeStrategy: this.options.gallerySwitchStrategy\n                });\n            } else {\n                galleryObject.updateData(initialImages);\n                $(this.options.mediaGallerySelector).AddFotoramaVideoEvents();\n            }\n\n        },\n\n        /**\n         * Sorting images array\n         *\n         * @private\n         */\n        _sortImages: function (images) {\n            return _.sortBy(images, function (image) {\n                return image.position;\n            });\n        },\n\n        /**\n         * Set correct indexes for image set.\n         *\n         * @param {Array} images\n         * @private\n         */\n        _setImageIndex: function (images) {\n            var length = images.length,\n                i;\n\n            for (i = 0; length > i; i++) {\n                images[i].i = i + 1;\n            }\n\n            return images;\n        },\n\n        /**\n         * For a given option element, reset all of its selectable options. Clear any selected\n         * index, disable the option choice, and reset the option's state if necessary.\n         * @private\n         * @param {*} element - The element associated with a configurable option.\n         */\n        _resetChildren: function (element) {\n            if (element.childSettings) {\n                _.each(element.childSettings, function (set) {\n                    set.selectedIndex = 0;\n                    set.disabled = true;\n                });\n\n                if (element.config) {\n                    this.options.state[element.config.id] = false;\n                }\n            }\n        },\n\n        /**\n         * Populates an option's selectable choices.\n         * @private\n         * @param {*} element - Element associated with a configurable option.\n         */\n        _fillSelect: function (element) {\n            var attributeId = element.id.replace(/[a-z]*/, ''),\n                options = this._getAttributeOptions(attributeId),\n                prevConfig,\n                index = 1,\n                allowedProducts,\n                i,\n                j,\n                basePrice = parseFloat(this.options.spConfig.prices.basePrice.amount),\n                optionFinalPrice,\n                optionPriceDiff,\n                optionPrices = this.options.spConfig.optionPrices,\n                allowedProductMinPrice;\n\n            this._clearSelect(element);\n            element.options[0] = new Option('', '');\n            element.options[0].innerHTML = this.options.spConfig.chooseText;\n            prevConfig = false;\n\n            if (element.prevSetting) {\n                prevConfig = element.prevSetting.options[element.prevSetting.selectedIndex];\n            }\n\n            if (options) {\n                for (i = 0; i < options.length; i++) {\n                    allowedProducts = [];\n                    optionPriceDiff = 0;\n\n                    /* eslint-disable max-depth */\n                    if (prevConfig) {\n                        for (j = 0; j < options[i].products.length; j++) {\n                            // prevConfig.config can be undefined\n                            if (prevConfig.config &&\n                                prevConfig.config.allowedProducts &&\n                                prevConfig.config.allowedProducts.indexOf(options[i].products[j]) > -1) {\n                                allowedProducts.push(options[i].products[j]);\n                            }\n                        }\n                    } else {\n                        allowedProducts = options[i].products.slice(0);\n\n                        if (typeof allowedProducts[0] !== 'undefined' &&\n                            typeof optionPrices[allowedProducts[0]] !== 'undefined') {\n                            allowedProductMinPrice = this._getAllowedProductWithMinPrice(allowedProducts);\n                            optionFinalPrice = parseFloat(optionPrices[allowedProductMinPrice].finalPrice.amount);\n                            optionPriceDiff = optionFinalPrice - basePrice;\n\n                            if (optionPriceDiff !== 0) {\n                                options[i].label = options[i].label + ' ' + priceUtils.formatPrice(\n                                    optionPriceDiff,\n                                    this.options.priceFormat,\n                                    true);\n                            }\n                        }\n                    }\n\n                    if (allowedProducts.length > 0) {\n                        options[i].allowedProducts = allowedProducts;\n                        element.options[index] = new Option(this._getOptionLabel(options[i]), options[i].id);\n\n                        if (typeof options[i].price !== 'undefined') {\n                            element.options[index].setAttribute('price', options[i].price);\n                        }\n\n                        element.options[index].config = options[i];\n                        index++;\n                    }\n\n                    /* eslint-enable max-depth */\n                }\n            }\n        },\n\n        /**\n         * Generate the label associated with a configurable option. This includes the option's\n         * label or value and the option's price.\n         * @private\n         * @param {*} option - A single choice among a group of choices for a configurable option.\n         * @return {String} The option label with option value and price (e.g. Black +1.99)\n         */\n        _getOptionLabel: function (option) {\n            return option.label;\n        },\n\n        /**\n         * Removes an option's selections.\n         * @private\n         * @param {*} element - The element associated with a configurable option.\n         */\n        _clearSelect: function (element) {\n            var i;\n\n            for (i = element.options.length - 1; i >= 0; i--) {\n                element.remove(i);\n            }\n        },\n\n        /**\n         * Retrieve the attribute options associated with a specific attribute Id.\n         * @private\n         * @param {Number} attributeId - The id of the attribute whose configurable options are sought.\n         * @return {Object} Object containing the attribute options.\n         */\n        _getAttributeOptions: function (attributeId) {\n            if (this.options.spConfig.attributes[attributeId]) {\n                return this.options.spConfig.attributes[attributeId].options;\n            }\n        },\n\n        /**\n         * Reload the price of the configurable product incorporating the prices of all of the\n         * configurable product's option selections.\n         */\n        _reloadPrice: function () {\n            $(this.options.priceHolderSelector).trigger('updatePrice', this._getPrices());\n        },\n\n        /**\n         * Get product various prices\n         * @returns {{}}\n         * @private\n         */\n        _getPrices: function () {\n            var prices = {},\n                elements = _.toArray(this.options.settings),\n                allowedProduct;\n\n            _.each(elements, function (element) {\n                var selected = element.options[element.selectedIndex],\n                    config = selected && selected.config,\n                    priceValue = {};\n\n                if (config && config.allowedProducts.length === 1) {\n                    priceValue = this._calculatePrice(config);\n                } else if (element.value) {\n                    allowedProduct = this._getAllowedProductWithMinPrice(config.allowedProducts);\n                    priceValue = this._calculatePrice({\n                        'allowedProducts': [\n                            allowedProduct\n                        ]\n                    });\n                }\n\n                if (!_.isEmpty(priceValue)) {\n                    prices.prices = priceValue;\n                }\n            }, this);\n\n            return prices;\n        },\n\n        /**\n         * Get product with minimum price from selected options.\n         *\n         * @param {Array} allowedProducts\n         * @returns {String}\n         * @private\n         */\n        _getAllowedProductWithMinPrice: function (allowedProducts) {\n            var optionPrices = this.options.spConfig.optionPrices,\n                product = {},\n                optionMinPrice, optionFinalPrice;\n\n            _.each(allowedProducts, function (allowedProduct) {\n                optionFinalPrice = parseFloat(optionPrices[allowedProduct].finalPrice.amount);\n\n                if (_.isEmpty(product) || optionFinalPrice < optionMinPrice) {\n                    optionMinPrice = optionFinalPrice;\n                    product = allowedProduct;\n                }\n            }, this);\n\n            return product;\n        },\n\n        /**\n         * Returns prices for configured products\n         *\n         * @param {*} config - Products configuration\n         * @returns {*}\n         * @private\n         */\n        _calculatePrice: function (config) {\n            var displayPrices = $(this.options.priceHolderSelector).priceBox('option').prices,\n                newPrices = this.options.spConfig.optionPrices[_.first(config.allowedProducts)];\n\n            _.each(displayPrices, function (price, code) {\n                if (newPrices[code]) {\n                    displayPrices[code].amount = newPrices[code].amount - displayPrices[code].amount;\n                }\n            });\n\n            return displayPrices;\n        },\n\n        /**\n         * Returns Simple product Id\n         *  depending on current selected option.\n         *\n         * @private\n         * @param {HTMLElement} element\n         * @returns {String|undefined}\n         */\n        _getSimpleProductId: function (element) {\n            // TODO: Rewrite algorithm. It should return ID of\n            //        simple product based on selected options.\n            var allOptions = element.config.options,\n                value = element.value,\n                config;\n\n            config = _.filter(allOptions, function (option) {\n                return option.id === value;\n            });\n            config = _.first(config);\n\n            return _.isEmpty(config) ?\n                undefined :\n                _.first(config.allowedProducts);\n\n        },\n\n        /**\n         * Show or hide regular price block\n         *\n         * @param {*} optionId\n         * @private\n         */\n        _displayRegularPriceBlock: function (optionId) {\n            var shouldBeShown = true;\n\n            _.each(this.options.settings, function (element) {\n                if (element.value === '') {\n                    shouldBeShown = false;\n                }\n            });\n\n            if (shouldBeShown &&\n                this.options.spConfig.optionPrices[optionId].oldPrice.amount !==\n                this.options.spConfig.optionPrices[optionId].finalPrice.amount\n            ) {\n                $(this.options.slyOldPriceSelector).show();\n            } else {\n                $(this.options.slyOldPriceSelector).hide();\n            }\n\n            $(document).trigger('updateMsrpPriceBlock',\n                [\n                    optionId,\n                    this.options.spConfig.optionPrices\n                ]\n            );\n        },\n\n        /**\n         * Show or hide normal price label\n         *\n         * @private\n         */\n        _displayNormalPriceLabel: function () {\n            var shouldBeShown = false;\n\n            _.each(this.options.settings, function (element) {\n                if (element.value === '') {\n                    shouldBeShown = true;\n                }\n            });\n\n            if (shouldBeShown) {\n                $(this.options.normalPriceLabelSelector).show();\n            } else {\n                $(this.options.normalPriceLabelSelector).hide();\n            }\n        },\n\n        /**\n         * Callback which fired after gallery gets initialized.\n         *\n         * @param {HTMLElement} element - DOM element associated with gallery.\n         */\n        _onGalleryLoaded: function (element) {\n            var galleryObject = element.data('gallery');\n\n            this.options.mediaGalleryInitial = galleryObject.returnCurrentImages();\n        },\n\n        /**\n         * Show or hide tier price block\n         *\n         * @param {*} optionId\n         * @private\n         */\n        _displayTierPriceBlock: function (optionId) {\n            var options, tierPriceHtml;\n\n            if (typeof optionId != 'undefined' &&\n                this.options.spConfig.optionPrices[optionId].tierPrices != [] // eslint-disable-line eqeqeq\n            ) {\n                options = this.options.spConfig.optionPrices[optionId];\n\n                if (this.options.tierPriceTemplate) {\n                    tierPriceHtml = mageTemplate(this.options.tierPriceTemplate, {\n                        'tierPrices': options.tierPrices,\n                        '$t': $t,\n                        'currencyFormat': this.options.spConfig.currencyFormat,\n                        'priceUtils': priceUtils\n                    });\n                    $(this.options.tierPriceBlockSelector).html(tierPriceHtml).show();\n                }\n            } else {\n                $(this.options.tierPriceBlockSelector).hide();\n            }\n        }\n    });\n\n    return $.mage.configurable;\n});\n","Magento_ConfigurableProduct/js/catalog-add-to-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\nrequire([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * Add selected configurable attributes to redirect url\n     *\n     * @see Magento_Catalog/js/catalog-add-to-cart\n     */\n    $('body').on('catalogCategoryAddToCartRedirect', function (event, data) {\n        $(data.form).find('select[name*=\"super\"]').each(function (index, item) {\n            data.redirectParameters.push(item.config.id + '=' + $(item).val());\n        });\n    });\n});\n","Magento_ConfigurableProduct/js/options-updater.js":"define([\n    'jquery',\n    'underscore',\n    'Magento_Customer/js/customer-data'\n], function ($, _, customerData) {\n    'use strict';\n\n    var selectors = {\n        formSelector: '#product_addtocart_form',\n        productIdSelector: '#product_addtocart_form [name=\"product\"]',\n        itemIdSelector: '#product_addtocart_form [name=\"item\"]'\n    },\n    cartData = customerData.get('cart'),\n    productId = $(selectors.productIdSelector).val(),\n    itemId = $(selectors.itemIdSelector).val(),\n\n    /**\n    * set productOptions according to cart data from customer-data\n    *\n    * @param {Object} data - cart data from customer-data\n    * @returns {Boolean} - whether the new options differ from previous\n    */\n    setProductOptions = function (data) {\n        var changedProductOptions;\n\n        if (!(data && data.items && data.items.length && productId)) {\n            return false;\n        }\n        changedProductOptions = _.find(data.items, function (item) {\n            if (item['item_id'] === itemId) {\n                return item['product_id'] === productId;\n            }\n        });\n        changedProductOptions = changedProductOptions && changedProductOptions.options &&\n            changedProductOptions.options.reduce(function (obj, val) {\n                obj[val['option_id']] = val['option_value'];\n\n                return obj;\n            }, {});\n\n        if (JSON.stringify(this.productOptions || {}) === JSON.stringify(changedProductOptions || {})) {\n            return false;\n        }\n\n        this.productOptions = changedProductOptions;\n\n        return true;\n    },\n\n    /**\n    * Listens to update of cart data or options initialization and update selected option according to customer data\n    *\n    */\n    listen = function () {\n        cartData.subscribe(function (updateCartData) {\n            if (this.setProductOptions(updateCartData)) {\n                this.updateOptions();\n            }\n        }.bind(this));\n        $(selectors.formSelector).on(this.eventName, function () {\n            this.setProductOptions(cartData());\n            this.updateOptions();\n        }.bind(this));\n    },\n\n    /**\n    * Updater constructor function\n    *\n    */\n    Updater = function (eventName, updateOptionsCallback) {\n        if (this instanceof Updater) {\n            this.eventName = eventName;\n            this.updateOptions = updateOptionsCallback;\n            this.productOptions = {};\n        }\n    };\n\n    Updater.prototype.setProductOptions = setProductOptions;\n    Updater.prototype.listen = listen;\n\n    return Updater;\n});\n","Magento_ConfigurableProduct/js/configurable-customer-data.js":"require([\n    'jquery',\n    'Magento_ConfigurableProduct/js/options-updater'\n], function ($, Updater) {\n    'use strict';\n\n    var selectors = {\n            formSelector: '#product_addtocart_form'\n        },\n        configurableWidgetName = 'mageConfigurable',\n        widgetInitEvent = 'configurable.initialized',\n\n    /**\n    * Sets all configurable attribute's selected values\n    */\n    updateConfigurableOptions = function () {\n        var configurableWidget = $(selectors.formSelector).data(configurableWidgetName);\n\n        if (!configurableWidget) {\n            return;\n        }\n        configurableWidget.options.values = this.productOptions || {};\n        configurableWidget._configureForValues();\n    },\n    updater = new Updater(widgetInitEvent, updateConfigurableOptions);\n\n    updater.listen();\n});\n"}
}});