Your IP : 216.73.216.52


Current Path : /proc/thread-self/cwd/static/frontend/Magento/blank/it_IT/js/bundle/
Upload File :
Current File : //proc/thread-self/cwd/static/frontend/Magento/blank/it_IT/js/bundle/bundle2.js

require.config({"config": {
        "jsbuild":{"knockoutjs/knockout.js":"/*!\n * Knockout JavaScript library v3.5.1\n * (c) The Knockout.js team - http://knockoutjs.com/\n * License: MIT (http://www.opensource.org/licenses/mit-license.php)\n */\n\n(function(){\n    var DEBUG=true;\n    (function(undefined){\n        // (0, eval)('this') is a robust way of getting a reference to the global object\n        // For details, see http://stackoverflow.com/questions/14119988/return-this-0-evalthis/14120023#14120023\n        var window = this || (0, eval)('this'),\n            document = window['document'],\n            navigator = window['navigator'],\n            jQueryInstance = window[\"jQuery\"],\n            JSON = window[\"JSON\"];\n\n        if (!jQueryInstance && typeof jQuery !== \"undefined\") {\n            jQueryInstance = jQuery;\n        }\n        (function(factory) {\n            // Support three module loading scenarios\n            if (typeof define === 'function' && define['amd']) {\n                // [1] AMD anonymous module\n                define(['exports', 'require'], factory);\n            } else if (typeof exports === 'object' && typeof module === 'object') {\n                // [2] CommonJS/Node.js\n                factory(module['exports'] || exports);  // module.exports is for Node.js\n            } else {\n                // [3] No module loader (plain <script> tag) - put directly in global namespace\n                factory(window['ko'] = {});\n            }\n        }(function(koExports, amdRequire){\n// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).\n// In the future, the following \"ko\" variable may be made distinct from \"koExports\" so that private objects are not externally reachable.\n            var ko = typeof koExports !== 'undefined' ? koExports : {};\n// Google Closure Compiler helpers (used only to make the minified file smaller)\n            ko.exportSymbol = function(koPath, object) {\n                var tokens = koPath.split(\".\");\n\n                // In the future, \"ko\" may become distinct from \"koExports\" (so that non-exported objects are not reachable)\n                // At that point, \"target\" would be set to: (typeof koExports !== \"undefined\" ? koExports : ko)\n                var target = ko;\n\n                for (var i = 0; i < tokens.length - 1; i++)\n                    target = target[tokens[i]];\n                target[tokens[tokens.length - 1]] = object;\n            };\n            ko.exportProperty = function(owner, publicName, object) {\n                owner[publicName] = object;\n            };\n            ko.version = \"3.5.1\";\n\n            ko.exportSymbol('version', ko.version);\n// For any options that may affect various areas of Knockout and aren't directly associated with data binding.\n            ko.options = {\n                'deferUpdates': false,\n                'useOnlyNativeEvents': false,\n                'foreachHidesDestroyed': false\n            };\n\n//ko.exportSymbol('options', ko.options);   // 'options' isn't minified\n            ko.utils = (function () {\n                var hasOwnProperty = Object.prototype.hasOwnProperty;\n\n                function objectForEach(obj, action) {\n                    for (var prop in obj) {\n                        if (hasOwnProperty.call(obj, prop)) {\n                            action(prop, obj[prop]);\n                        }\n                    }\n                }\n\n                function extend(target, source) {\n                    if (source) {\n                        for(var prop in source) {\n                            if(hasOwnProperty.call(source, prop)) {\n                                target[prop] = source[prop];\n                            }\n                        }\n                    }\n                    return target;\n                }\n\n                function setPrototypeOf(obj, proto) {\n                    obj.__proto__ = proto;\n                    return obj;\n                }\n\n                var canSetPrototype = ({ __proto__: [] } instanceof Array);\n                var canUseSymbols = !DEBUG && typeof Symbol === 'function';\n\n                // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)\n                var knownEvents = {}, knownEventTypesByEventName = {};\n                var keyEventTypeName = (navigator && /Firefox\\/2/i.test(navigator.userAgent)) ? 'KeyboardEvent' : 'UIEvents';\n                knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];\n                knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];\n                objectForEach(knownEvents, function(eventType, knownEventsForType) {\n                    if (knownEventsForType.length) {\n                        for (var i = 0, j = knownEventsForType.length; i < j; i++)\n                            knownEventTypesByEventName[knownEventsForType[i]] = eventType;\n                    }\n                });\n                var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406\n\n                // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)\n                // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.\n                // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.\n                // If there is a future need to detect specific versions of IE10+, we will amend this.\n                var ieVersion = document && (function() {\n                    var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');\n\n                    // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment\n                    while (\n                        div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',\n                            iElems[0]\n                        ) {}\n                    return version > 4 ? version : undefined;\n                }());\n                var isIe6 = ieVersion === 6,\n                    isIe7 = ieVersion === 7;\n\n                function isClickOnCheckableElement(element, eventType) {\n                    if ((ko.utils.tagNameLower(element) !== \"input\") || !element.type) return false;\n                    if (eventType.toLowerCase() != \"click\") return false;\n                    var inputType = element.type;\n                    return (inputType == \"checkbox\") || (inputType == \"radio\");\n                }\n\n                // For details on the pattern for changing node classes\n                // see: https://github.com/knockout/knockout/issues/1597\n                var cssClassNameRegex = /\\S+/g;\n\n                var jQueryEventAttachName;\n\n                function toggleDomNodeCssClass(node, classNames, shouldHaveClass) {\n                    var addOrRemoveFn;\n                    if (classNames) {\n                        if (typeof node.classList === 'object') {\n                            addOrRemoveFn = node.classList[shouldHaveClass ? 'add' : 'remove'];\n                            ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {\n                                addOrRemoveFn.call(node.classList, className);\n                            });\n                        } else if (typeof node.className['baseVal'] === 'string') {\n                            // SVG tag .classNames is an SVGAnimatedString instance\n                            toggleObjectClassPropertyString(node.className, 'baseVal', classNames, shouldHaveClass);\n                        } else {\n                            // node.className ought to be a string.\n                            toggleObjectClassPropertyString(node, 'className', classNames, shouldHaveClass);\n                        }\n                    }\n                }\n\n                function toggleObjectClassPropertyString(obj, prop, classNames, shouldHaveClass) {\n                    // obj/prop is either a node/'className' or a SVGAnimatedString/'baseVal'.\n                    var currentClassNames = obj[prop].match(cssClassNameRegex) || [];\n                    ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {\n                        ko.utils.addOrRemoveItem(currentClassNames, className, shouldHaveClass);\n                    });\n                    obj[prop] = currentClassNames.join(\" \");\n                }\n\n                return {\n                    fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],\n\n                    arrayForEach: function (array, action, actionOwner) {\n                        for (var i = 0, j = array.length; i < j; i++) {\n                            action.call(actionOwner, array[i], i, array);\n                        }\n                    },\n\n                    arrayIndexOf: typeof Array.prototype.indexOf == \"function\"\n                        ? function (array, item) {\n                            return Array.prototype.indexOf.call(array, item);\n                        }\n                        : function (array, item) {\n                            for (var i = 0, j = array.length; i < j; i++) {\n                                if (array[i] === item)\n                                    return i;\n                            }\n                            return -1;\n                        },\n\n                    arrayFirst: function (array, predicate, predicateOwner) {\n                        for (var i = 0, j = array.length; i < j; i++) {\n                            if (predicate.call(predicateOwner, array[i], i, array))\n                                return array[i];\n                        }\n                        return undefined;\n                    },\n\n                    arrayRemoveItem: function (array, itemToRemove) {\n                        var index = ko.utils.arrayIndexOf(array, itemToRemove);\n                        if (index > 0) {\n                            array.splice(index, 1);\n                        }\n                        else if (index === 0) {\n                            array.shift();\n                        }\n                    },\n\n                    arrayGetDistinctValues: function (array) {\n                        var result = [];\n                        if (array) {\n                            ko.utils.arrayForEach(array, function(item) {\n                                if (ko.utils.arrayIndexOf(result, item) < 0)\n                                    result.push(item);\n                            });\n                        }\n                        return result;\n                    },\n\n                    arrayMap: function (array, mapping, mappingOwner) {\n                        var result = [];\n                        if (array) {\n                            for (var i = 0, j = array.length; i < j; i++)\n                                result.push(mapping.call(mappingOwner, array[i], i));\n                        }\n                        return result;\n                    },\n\n                    arrayFilter: function (array, predicate, predicateOwner) {\n                        var result = [];\n                        if (array) {\n                            for (var i = 0, j = array.length; i < j; i++)\n                                if (predicate.call(predicateOwner, array[i], i))\n                                    result.push(array[i]);\n                        }\n                        return result;\n                    },\n\n                    arrayPushAll: function (array, valuesToPush) {\n                        if (valuesToPush instanceof Array)\n                            array.push.apply(array, valuesToPush);\n                        else\n                            for (var i = 0, j = valuesToPush.length; i < j; i++)\n                                array.push(valuesToPush[i]);\n                        return array;\n                    },\n\n                    addOrRemoveItem: function(array, value, included) {\n                        var existingEntryIndex = ko.utils.arrayIndexOf(ko.utils.peekObservable(array), value);\n                        if (existingEntryIndex < 0) {\n                            if (included)\n                                array.push(value);\n                        } else {\n                            if (!included)\n                                array.splice(existingEntryIndex, 1);\n                        }\n                    },\n\n                    canSetPrototype: canSetPrototype,\n\n                    extend: extend,\n\n                    setPrototypeOf: setPrototypeOf,\n\n                    setPrototypeOfOrExtend: canSetPrototype ? setPrototypeOf : extend,\n\n                    objectForEach: objectForEach,\n\n                    objectMap: function(source, mapping, mappingOwner) {\n                        if (!source)\n                            return source;\n                        var target = {};\n                        for (var prop in source) {\n                            if (hasOwnProperty.call(source, prop)) {\n                                target[prop] = mapping.call(mappingOwner, source[prop], prop, source);\n                            }\n                        }\n                        return target;\n                    },\n\n                    emptyDomNode: function (domNode) {\n                        while (domNode.firstChild) {\n                            ko.removeNode(domNode.firstChild);\n                        }\n                    },\n\n                    moveCleanedNodesToContainerElement: function(nodes) {\n                        // Ensure it's a real array, as we're about to reparent the nodes and\n                        // we don't want the underlying collection to change while we're doing that.\n                        var nodesArray = ko.utils.makeArray(nodes);\n                        var templateDocument = (nodesArray[0] && nodesArray[0].ownerDocument) || document;\n\n                        var container = templateDocument.createElement('div');\n                        for (var i = 0, j = nodesArray.length; i < j; i++) {\n                            container.appendChild(ko.cleanNode(nodesArray[i]));\n                        }\n                        return container;\n                    },\n\n                    cloneNodes: function (nodesArray, shouldCleanNodes) {\n                        for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {\n                            var clonedNode = nodesArray[i].cloneNode(true);\n                            newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);\n                        }\n                        return newNodesArray;\n                    },\n\n                    setDomNodeChildren: function (domNode, childNodes) {\n                        ko.utils.emptyDomNode(domNode);\n                        if (childNodes) {\n                            for (var i = 0, j = childNodes.length; i < j; i++)\n                                domNode.appendChild(childNodes[i]);\n                        }\n                    },\n\n                    replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {\n                        var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;\n                        if (nodesToReplaceArray.length > 0) {\n                            var insertionPoint = nodesToReplaceArray[0];\n                            var parent = insertionPoint.parentNode;\n                            for (var i = 0, j = newNodesArray.length; i < j; i++)\n                                parent.insertBefore(newNodesArray[i], insertionPoint);\n                            for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {\n                                ko.removeNode(nodesToReplaceArray[i]);\n                            }\n                        }\n                    },\n\n                    fixUpContinuousNodeArray: function(continuousNodeArray, parentNode) {\n                        // Before acting on a set of nodes that were previously outputted by a template function, we have to reconcile\n                        // them against what is in the DOM right now. It may be that some of the nodes have already been removed, or that\n                        // new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been\n                        // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.\n                        // So, this function translates the old \"map\" output array into its best guess of the set of current DOM nodes.\n                        //\n                        // Rules:\n                        //   [A] Any leading nodes that have been removed should be ignored\n                        //       These most likely correspond to memoization nodes that were already removed during binding\n                        //       See https://github.com/knockout/knockout/pull/440\n                        //   [B] Any trailing nodes that have been remove should be ignored\n                        //       This prevents the code here from adding unrelated nodes to the array while processing rule [C]\n                        //       See https://github.com/knockout/knockout/pull/1903\n                        //   [C] We want to output a continuous series of nodes. So, ignore any nodes that have already been removed,\n                        //       and include any nodes that have been inserted among the previous collection\n\n                        if (continuousNodeArray.length) {\n                            // The parent node can be a virtual element; so get the real parent node\n                            parentNode = (parentNode.nodeType === 8 && parentNode.parentNode) || parentNode;\n\n                            // Rule [A]\n                            while (continuousNodeArray.length && continuousNodeArray[0].parentNode !== parentNode)\n                                continuousNodeArray.splice(0, 1);\n\n                            // Rule [B]\n                            while (continuousNodeArray.length > 1 && continuousNodeArray[continuousNodeArray.length - 1].parentNode !== parentNode)\n                                continuousNodeArray.length--;\n\n                            // Rule [C]\n                            if (continuousNodeArray.length > 1) {\n                                var current = continuousNodeArray[0], last = continuousNodeArray[continuousNodeArray.length - 1];\n                                // Replace with the actual new continuous node set\n                                continuousNodeArray.length = 0;\n                                while (current !== last) {\n                                    continuousNodeArray.push(current);\n                                    current = current.nextSibling;\n                                }\n                                continuousNodeArray.push(last);\n                            }\n                        }\n                        return continuousNodeArray;\n                    },\n\n                    setOptionNodeSelectionState: function (optionNode, isSelected) {\n                        // IE6 sometimes throws \"unknown error\" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.\n                        if (ieVersion < 7)\n                            optionNode.setAttribute(\"selected\", isSelected);\n                        else\n                            optionNode.selected = isSelected;\n                    },\n\n                    stringTrim: function (string) {\n                        return string === null || string === undefined ? '' :\n                            string.trim ?\n                                string.trim() :\n                                string.toString().replace(/^[\\s\\xa0]+|[\\s\\xa0]+$/g, '');\n                    },\n\n                    stringStartsWith: function (string, startsWith) {\n                        string = string || \"\";\n                        if (startsWith.length > string.length)\n                            return false;\n                        return string.substring(0, startsWith.length) === startsWith;\n                    },\n\n                    domNodeIsContainedBy: function (node, containedByNode) {\n                        if (node === containedByNode)\n                            return true;\n                        if (node.nodeType === 11)\n                            return false; // Fixes issue #1162 - can't use node.contains for document fragments on IE8\n                        if (containedByNode.contains)\n                            return containedByNode.contains(node.nodeType !== 1 ? node.parentNode : node);\n                        if (containedByNode.compareDocumentPosition)\n                            return (containedByNode.compareDocumentPosition(node) & 16) == 16;\n                        while (node && node != containedByNode) {\n                            node = node.parentNode;\n                        }\n                        return !!node;\n                    },\n\n                    domNodeIsAttachedToDocument: function (node) {\n                        return ko.utils.domNodeIsContainedBy(node, node.ownerDocument.documentElement);\n                    },\n\n                    anyDomNodeIsAttachedToDocument: function(nodes) {\n                        return !!ko.utils.arrayFirst(nodes, ko.utils.domNodeIsAttachedToDocument);\n                    },\n\n                    tagNameLower: function(element) {\n                        // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.\n                        // Possible future optimization: If we know it's an element from an XHTML document (not HTML),\n                        // we don't need to do the .toLowerCase() as it will always be lower case anyway.\n                        return element && element.tagName && element.tagName.toLowerCase();\n                    },\n\n                    catchFunctionErrors: function (delegate) {\n                        return ko['onError'] ? function () {\n                            try {\n                                return delegate.apply(this, arguments);\n                            } catch (e) {\n                                ko['onError'] && ko['onError'](e);\n                                throw e;\n                            }\n                        } : delegate;\n                    },\n\n                    setTimeout: function (handler, timeout) {\n                        return setTimeout(ko.utils.catchFunctionErrors(handler), timeout);\n                    },\n\n                    deferError: function (error) {\n                        setTimeout(function () {\n                            ko['onError'] && ko['onError'](error);\n                            throw error;\n                        }, 0);\n                    },\n\n                    registerEventHandler: function (element, eventType, handler) {\n                        var wrappedHandler = ko.utils.catchFunctionErrors(handler);\n\n                        var mustUseAttachEvent = eventsThatMustBeRegisteredUsingAttachEvent[eventType];\n                        if (!ko.options['useOnlyNativeEvents'] && !mustUseAttachEvent && jQueryInstance) {\n                            if (!jQueryEventAttachName) {\n                                jQueryEventAttachName = (typeof jQueryInstance(element)['on'] == 'function') ? 'on' : 'bind';\n                            }\n                            jQueryInstance(element)[jQueryEventAttachName](eventType, wrappedHandler);\n                        } else if (!mustUseAttachEvent && typeof element.addEventListener == \"function\")\n                            element.addEventListener(eventType, wrappedHandler, false);\n                        else if (typeof element.attachEvent != \"undefined\") {\n                            var attachEventHandler = function (event) { wrappedHandler.call(element, event); },\n                                attachEventName = \"on\" + eventType;\n                            element.attachEvent(attachEventName, attachEventHandler);\n\n                            // IE does not dispose attachEvent handlers automatically (unlike with addEventListener)\n                            // so to avoid leaks, we have to remove them manually. See bug #856\n                            ko.utils.domNodeDisposal.addDisposeCallback(element, function() {\n                                element.detachEvent(attachEventName, attachEventHandler);\n                            });\n                        } else\n                            throw new Error(\"Browser doesn't support addEventListener or attachEvent\");\n                    },\n\n                    triggerEvent: function (element, eventType) {\n                        if (!(element && element.nodeType))\n                            throw new Error(\"element must be a DOM node when calling triggerEvent\");\n\n                        // For click events on checkboxes and radio buttons, jQuery toggles the element checked state *after* the\n                        // event handler runs instead of *before*. (This was fixed in 1.9 for checkboxes but not for radio buttons.)\n                        // IE doesn't change the checked state when you trigger the click event using \"fireEvent\".\n                        // In both cases, we'll use the click method instead.\n                        var useClickWorkaround = isClickOnCheckableElement(element, eventType);\n\n                        if (!ko.options['useOnlyNativeEvents'] && jQueryInstance && !useClickWorkaround) {\n                            jQueryInstance(element)['trigger'](eventType);\n                        } else if (typeof document.createEvent == \"function\") {\n                            if (typeof element.dispatchEvent == \"function\") {\n                                var eventCategory = knownEventTypesByEventName[eventType] || \"HTMLEvents\";\n                                var event = document.createEvent(eventCategory);\n                                event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);\n                                element.dispatchEvent(event);\n                            }\n                            else\n                                throw new Error(\"The supplied element doesn't support dispatchEvent\");\n                        } else if (useClickWorkaround && element.click) {\n                            element.click();\n                        } else if (typeof element.fireEvent != \"undefined\") {\n                            element.fireEvent(\"on\" + eventType);\n                        } else {\n                            throw new Error(\"Browser doesn't support triggering events\");\n                        }\n                    },\n\n                    unwrapObservable: function (value) {\n                        return ko.isObservable(value) ? value() : value;\n                    },\n\n                    peekObservable: function (value) {\n                        return ko.isObservable(value) ? value.peek() : value;\n                    },\n\n                    toggleDomNodeCssClass: toggleDomNodeCssClass,\n\n                    setTextContent: function(element, textContent) {\n                        var value = ko.utils.unwrapObservable(textContent);\n                        if ((value === null) || (value === undefined))\n                            value = \"\";\n\n                        // We need there to be exactly one child: a text node.\n                        // If there are no children, more than one, or if it's not a text node,\n                        // we'll clear everything and create a single text node.\n                        var innerTextNode = ko.virtualElements.firstChild(element);\n                        if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {\n                            ko.virtualElements.setDomNodeChildren(element, [element.ownerDocument.createTextNode(value)]);\n                        } else {\n                            innerTextNode.data = value;\n                        }\n\n                        ko.utils.forceRefresh(element);\n                    },\n\n                    setElementName: function(element, name) {\n                        element.name = name;\n\n                        // Workaround IE 6/7 issue\n                        // - https://github.com/SteveSanderson/knockout/issues/197\n                        // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/\n                        if (ieVersion <= 7) {\n                            try {\n                                var escapedName = element.name.replace(/[&<>'\"]/g, function(r){ return \"&#\" + r.charCodeAt(0) + \";\"; });\n                                element.mergeAttributes(document.createElement(\"<input name='\" + escapedName + \"'/>\"), false);\n                            }\n                            catch(e) {} // For IE9 with doc mode \"IE9 Standards\" and browser mode \"IE9 Compatibility View\"\n                        }\n                    },\n\n                    forceRefresh: function(node) {\n                        // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209\n                        if (ieVersion >= 9) {\n                            // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container\n                            var elem = node.nodeType == 1 ? node : node.parentNode;\n                            if (elem.style)\n                                elem.style.zoom = elem.style.zoom;\n                        }\n                    },\n\n                    ensureSelectElementIsRenderedCorrectly: function(selectElement) {\n                        // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.\n                        // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)\n                        // Also fixes IE7 and IE8 bug that causes selects to be zero width if enclosed by 'if' or 'with'. (See issue #839)\n                        if (ieVersion) {\n                            var originalWidth = selectElement.style.width;\n                            selectElement.style.width = 0;\n                            selectElement.style.width = originalWidth;\n                        }\n                    },\n\n                    range: function (min, max) {\n                        min = ko.utils.unwrapObservable(min);\n                        max = ko.utils.unwrapObservable(max);\n                        var result = [];\n                        for (var i = min; i <= max; i++)\n                            result.push(i);\n                        return result;\n                    },\n\n                    makeArray: function(arrayLikeObject) {\n                        var result = [];\n                        for (var i = 0, j = arrayLikeObject.length; i < j; i++) {\n                            result.push(arrayLikeObject[i]);\n                        };\n                        return result;\n                    },\n\n                    createSymbolOrString: function(identifier) {\n                        return canUseSymbols ? Symbol(identifier) : identifier;\n                    },\n\n                    isIe6 : isIe6,\n                    isIe7 : isIe7,\n                    ieVersion : ieVersion,\n\n                    getFormFields: function(form, fieldName) {\n                        var fields = ko.utils.makeArray(form.getElementsByTagName(\"input\")).concat(ko.utils.makeArray(form.getElementsByTagName(\"textarea\")));\n                        var isMatchingField = (typeof fieldName == 'string')\n                            ? function(field) { return field.name === fieldName }\n                            : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate\n                        var matches = [];\n                        for (var i = fields.length - 1; i >= 0; i--) {\n                            if (isMatchingField(fields[i]))\n                                matches.push(fields[i]);\n                        };\n                        return matches;\n                    },\n\n                    parseJson: function (jsonString) {\n                        if (typeof jsonString == \"string\") {\n                            jsonString = ko.utils.stringTrim(jsonString);\n                            if (jsonString) {\n                                if (JSON && JSON.parse) // Use native parsing where available\n                                    return JSON.parse(jsonString);\n                                return (new Function(\"return \" + jsonString))(); // Fallback on less safe parsing for older browsers\n                            }\n                        }\n                        return null;\n                    },\n\n                    stringifyJson: function (data, replacer, space) {   // replacer and space are optional\n                        if (!JSON || !JSON.stringify)\n                            throw new Error(\"Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js\");\n                        return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);\n                    },\n\n                    postJson: function (urlOrForm, data, options) {\n                        options = options || {};\n                        var params = options['params'] || {};\n                        var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;\n                        var url = urlOrForm;\n\n                        // If we were given a form, use its 'action' URL and pick out any requested field values\n                        if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === \"form\")) {\n                            var originalForm = urlOrForm;\n                            url = originalForm.action;\n                            for (var i = includeFields.length - 1; i >= 0; i--) {\n                                var fields = ko.utils.getFormFields(originalForm, includeFields[i]);\n                                for (var j = fields.length - 1; j >= 0; j--)\n                                    params[fields[j].name] = fields[j].value;\n                            }\n                        }\n\n                        data = ko.utils.unwrapObservable(data);\n                        var form = document.createElement(\"form\");\n                        form.style.display = \"none\";\n                        form.action = url;\n                        form.method = \"post\";\n                        for (var key in data) {\n                            // Since 'data' this is a model object, we include all properties including those inherited from its prototype\n                            var input = document.createElement(\"input\");\n                            input.type = \"hidden\";\n                            input.name = key;\n                            input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));\n                            form.appendChild(input);\n                        }\n                        objectForEach(params, function(key, value) {\n                            var input = document.createElement(\"input\");\n                            input.type = \"hidden\";\n                            input.name = key;\n                            input.value = value;\n                            form.appendChild(input);\n                        });\n                        document.body.appendChild(form);\n                        options['submitter'] ? options['submitter'](form) : form.submit();\n                        setTimeout(function () { form.parentNode.removeChild(form); }, 0);\n                    }\n                }\n            }());\n\n            ko.exportSymbol('utils', ko.utils);\n            ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);\n            ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);\n            ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);\n            ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);\n            ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);\n            ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);\n            ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);\n            ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);\n            ko.exportSymbol('utils.cloneNodes', ko.utils.cloneNodes);\n            ko.exportSymbol('utils.createSymbolOrString', ko.utils.createSymbolOrString);\n            ko.exportSymbol('utils.extend', ko.utils.extend);\n            ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);\n            ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);\n            ko.exportSymbol('utils.objectMap', ko.utils.objectMap);\n            ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);\n            ko.exportSymbol('utils.postJson', ko.utils.postJson);\n            ko.exportSymbol('utils.parseJson', ko.utils.parseJson);\n            ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);\n            ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);\n            ko.exportSymbol('utils.range', ko.utils.range);\n            ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);\n            ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);\n            ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);\n            ko.exportSymbol('utils.objectForEach', ko.utils.objectForEach);\n            ko.exportSymbol('utils.addOrRemoveItem', ko.utils.addOrRemoveItem);\n            ko.exportSymbol('utils.setTextContent', ko.utils.setTextContent);\n            ko.exportSymbol('unwrap', ko.utils.unwrapObservable); // Convenient shorthand, because this is used so commonly\n\n            if (!Function.prototype['bind']) {\n                // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)\n                // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js\n                Function.prototype['bind'] = function (object) {\n                    var originalFunction = this;\n                    if (arguments.length === 1) {\n                        return function () {\n                            return originalFunction.apply(object, arguments);\n                        };\n                    } else {\n                        var partialArgs = Array.prototype.slice.call(arguments, 1);\n                        return function () {\n                            var args = partialArgs.slice(0);\n                            args.push.apply(args, arguments);\n                            return originalFunction.apply(object, args);\n                        };\n                    }\n                };\n            }\n\n            ko.utils.domData = new (function () {\n                var uniqueId = 0;\n                var dataStoreKeyExpandoPropertyName = \"__ko__\" + (new Date).getTime();\n                var dataStore = {};\n\n                var getDataForNode, clear;\n                if (!ko.utils.ieVersion) {\n                    // We considered using WeakMap, but it has a problem in IE 11 and Edge that prevents using\n                    // it cross-window, so instead we just store the data directly on the node.\n                    // See https://github.com/knockout/knockout/issues/2141\n                    getDataForNode = function (node, createIfNotFound) {\n                        var dataForNode = node[dataStoreKeyExpandoPropertyName];\n                        if (!dataForNode && createIfNotFound) {\n                            dataForNode = node[dataStoreKeyExpandoPropertyName] = {};\n                        }\n                        return dataForNode;\n                    };\n                    clear = function (node) {\n                        if (node[dataStoreKeyExpandoPropertyName]) {\n                            delete node[dataStoreKeyExpandoPropertyName];\n                            return true; // Exposing \"did clean\" flag purely so specs can infer whether things have been cleaned up as intended\n                        }\n                        return false;\n                    };\n                } else {\n                    // Old IE versions have memory issues if you store objects on the node, so we use a\n                    // separate data storage and link to it from the node using a string key.\n                    getDataForNode = function (node, createIfNotFound) {\n                        var dataStoreKey = node[dataStoreKeyExpandoPropertyName];\n                        var hasExistingDataStore = dataStoreKey && (dataStoreKey !== \"null\") && dataStore[dataStoreKey];\n                        if (!hasExistingDataStore) {\n                            if (!createIfNotFound)\n                                return undefined;\n                            dataStoreKey = node[dataStoreKeyExpandoPropertyName] = \"ko\" + uniqueId++;\n                            dataStore[dataStoreKey] = {};\n                        }\n                        return dataStore[dataStoreKey];\n                    };\n                    clear = function (node) {\n                        var dataStoreKey = node[dataStoreKeyExpandoPropertyName];\n                        if (dataStoreKey) {\n                            delete dataStore[dataStoreKey];\n                            node[dataStoreKeyExpandoPropertyName] = null;\n                            return true; // Exposing \"did clean\" flag purely so specs can infer whether things have been cleaned up as intended\n                        }\n                        return false;\n                    };\n                }\n\n                return {\n                    get: function (node, key) {\n                        var dataForNode = getDataForNode(node, false);\n                        return dataForNode && dataForNode[key];\n                    },\n                    set: function (node, key, value) {\n                        // Make sure we don't actually create a new domData key if we are actually deleting a value\n                        var dataForNode = getDataForNode(node, value !== undefined /* createIfNotFound */);\n                        dataForNode && (dataForNode[key] = value);\n                    },\n                    getOrSet: function (node, key, value) {\n                        var dataForNode = getDataForNode(node, true /* createIfNotFound */);\n                        return dataForNode[key] || (dataForNode[key] = value);\n                    },\n                    clear: clear,\n\n                    nextKey: function () {\n                        return (uniqueId++) + dataStoreKeyExpandoPropertyName;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('utils.domData', ko.utils.domData);\n            ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully\n\n            ko.utils.domNodeDisposal = new (function () {\n                var domDataKey = ko.utils.domData.nextKey();\n                var cleanableNodeTypes = { 1: true, 8: true, 9: true };       // Element, Comment, Document\n                var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document\n\n                function getDisposeCallbacksCollection(node, createIfNotFound) {\n                    var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);\n                    if ((allDisposeCallbacks === undefined) && createIfNotFound) {\n                        allDisposeCallbacks = [];\n                        ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);\n                    }\n                    return allDisposeCallbacks;\n                }\n                function destroyCallbacksCollection(node) {\n                    ko.utils.domData.set(node, domDataKey, undefined);\n                }\n\n                function cleanSingleNode(node) {\n                    // Run all the dispose callbacks\n                    var callbacks = getDisposeCallbacksCollection(node, false);\n                    if (callbacks) {\n                        callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)\n                        for (var i = 0; i < callbacks.length; i++)\n                            callbacks[i](node);\n                    }\n\n                    // Erase the DOM data\n                    ko.utils.domData.clear(node);\n\n                    // Perform cleanup needed by external libraries (currently only jQuery, but can be extended)\n                    ko.utils.domNodeDisposal[\"cleanExternalData\"](node);\n\n                    // Clear any immediate-child comment nodes, as these wouldn't have been found by\n                    // node.getElementsByTagName(\"*\") in cleanNode() (comment nodes aren't elements)\n                    if (cleanableNodeTypesWithDescendants[node.nodeType]) {\n                        cleanNodesInList(node.childNodes, true/*onlyComments*/);\n                    }\n                }\n\n                function cleanNodesInList(nodeList, onlyComments) {\n                    var cleanedNodes = [], lastCleanedNode;\n                    for (var i = 0; i < nodeList.length; i++) {\n                        if (!onlyComments || nodeList[i].nodeType === 8) {\n                            cleanSingleNode(cleanedNodes[cleanedNodes.length] = lastCleanedNode = nodeList[i]);\n                            if (nodeList[i] !== lastCleanedNode) {\n                                while (i-- && ko.utils.arrayIndexOf(cleanedNodes, nodeList[i]) == -1) {}\n                            }\n                        }\n                    }\n                }\n\n                return {\n                    addDisposeCallback : function(node, callback) {\n                        if (typeof callback != \"function\")\n                            throw new Error(\"Callback must be a function\");\n                        getDisposeCallbacksCollection(node, true).push(callback);\n                    },\n\n                    removeDisposeCallback : function(node, callback) {\n                        var callbacksCollection = getDisposeCallbacksCollection(node, false);\n                        if (callbacksCollection) {\n                            ko.utils.arrayRemoveItem(callbacksCollection, callback);\n                            if (callbacksCollection.length == 0)\n                                destroyCallbacksCollection(node);\n                        }\n                    },\n\n                    cleanNode : function(node) {\n                        ko.dependencyDetection.ignore(function () {\n                            // First clean this node, where applicable\n                            if (cleanableNodeTypes[node.nodeType]) {\n                                cleanSingleNode(node);\n\n                                // ... then its descendants, where applicable\n                                if (cleanableNodeTypesWithDescendants[node.nodeType]) {\n                                    cleanNodesInList(node.getElementsByTagName(\"*\"));\n                                }\n                            }\n                        });\n\n                        return node;\n                    },\n\n                    removeNode : function(node) {\n                        ko.cleanNode(node);\n                        if (node.parentNode)\n                            node.parentNode.removeChild(node);\n                    },\n\n                    \"cleanExternalData\" : function (node) {\n                        // Special support for jQuery here because it's so commonly used.\n                        // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData\n                        // so notify it to tear down any resources associated with the node & descendants here.\n                        if (jQueryInstance && (typeof jQueryInstance['cleanData'] == \"function\"))\n                            jQueryInstance['cleanData']([node]);\n                    }\n                };\n            })();\n            ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience\n            ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience\n            ko.exportSymbol('cleanNode', ko.cleanNode);\n            ko.exportSymbol('removeNode', ko.removeNode);\n            ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);\n            ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);\n            ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);\n            (function () {\n                var none = [0, \"\", \"\"],\n                    table = [1, \"<table>\", \"</table>\"],\n                    tbody = [2, \"<table><tbody>\", \"</tbody></table>\"],\n                    tr = [3, \"<table><tbody><tr>\", \"</tr></tbody></table>\"],\n                    select = [1, \"<select multiple='multiple'>\", \"</select>\"],\n                    lookup = {\n                        'thead': table,\n                        'tbody': table,\n                        'tfoot': table,\n                        'tr': tbody,\n                        'td': tr,\n                        'th': tr,\n                        'option': select,\n                        'optgroup': select\n                    },\n\n                    // This is needed for old IE if you're *not* using either jQuery or innerShiv. Doesn't affect other cases.\n                    mayRequireCreateElementHack = ko.utils.ieVersion <= 8;\n\n                function getWrap(tags) {\n                    var m = tags.match(/^(?:<!--.*?-->\\s*?)*?<([a-z]+)[\\s>]/);\n                    return (m && lookup[m[1]]) || none;\n                }\n\n                function simpleHtmlParse(html, documentContext) {\n                    documentContext || (documentContext = document);\n                    var windowContext = documentContext['parentWindow'] || documentContext['defaultView'] || window;\n\n                    // Based on jQuery's \"clean\" function, but only accounting for table-related elements.\n                    // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's \"clean\" function directly\n\n                    // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of\n                    // a descendant node. For example: \"<div><!-- mycomment -->abc</div>\" will get parsed as \"<div>abc</div>\"\n                    // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node\n                    // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.\n\n                    // Trim whitespace, otherwise indexOf won't work as expected\n                    var tags = ko.utils.stringTrim(html).toLowerCase(), div = documentContext.createElement(\"div\"),\n                        wrap = getWrap(tags),\n                        depth = wrap[0];\n\n                    // Go to html and back, then peel off extra wrappers\n                    // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.\n                    var markup = \"ignored<div>\" + wrap[1] + html + wrap[2] + \"</div>\";\n                    if (typeof windowContext['innerShiv'] == \"function\") {\n                        // Note that innerShiv is deprecated in favour of html5shiv. We should consider adding\n                        // support for html5shiv (except if no explicit support is needed, e.g., if html5shiv\n                        // somehow shims the native APIs so it just works anyway)\n                        div.appendChild(windowContext['innerShiv'](markup));\n                    } else {\n                        if (mayRequireCreateElementHack) {\n                            // The document.createElement('my-element') trick to enable custom elements in IE6-8\n                            // only works if we assign innerHTML on an element associated with that document.\n                            documentContext.body.appendChild(div);\n                        }\n\n                        div.innerHTML = markup;\n\n                        if (mayRequireCreateElementHack) {\n                            div.parentNode.removeChild(div);\n                        }\n                    }\n\n                    // Move to the right depth\n                    while (depth--)\n                        div = div.lastChild;\n\n                    return ko.utils.makeArray(div.lastChild.childNodes);\n                }\n\n                function jQueryHtmlParse(html, documentContext) {\n                    // jQuery's \"parseHTML\" function was introduced in jQuery 1.8.0 and is a documented public API.\n                    if (jQueryInstance['parseHTML']) {\n                        return jQueryInstance['parseHTML'](html, documentContext) || []; // Ensure we always return an array and never null\n                    } else {\n                        // For jQuery < 1.8.0, we fall back on the undocumented internal \"clean\" function.\n                        var elems = jQueryInstance['clean']([html], documentContext);\n\n                        // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.\n                        // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.\n                        // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.\n                        if (elems && elems[0]) {\n                            // Find the top-most parent element that's a direct child of a document fragment\n                            var elem = elems[0];\n                            while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)\n                                elem = elem.parentNode;\n                            // ... then detach it\n                            if (elem.parentNode)\n                                elem.parentNode.removeChild(elem);\n                        }\n\n                        return elems;\n                    }\n                }\n\n                ko.utils.parseHtmlFragment = function(html, documentContext) {\n                    return jQueryInstance ?\n                        jQueryHtmlParse(html, documentContext) :   // As below, benefit from jQuery's optimisations where possible\n                        simpleHtmlParse(html, documentContext);  // ... otherwise, this simple logic will do in most common cases.\n                };\n\n                ko.utils.parseHtmlForTemplateNodes = function(html, documentContext) {\n                    var nodes = ko.utils.parseHtmlFragment(html, documentContext);\n                    return (nodes.length && nodes[0].parentElement) || ko.utils.moveCleanedNodesToContainerElement(nodes);\n                };\n\n                ko.utils.setHtml = function(node, html) {\n                    ko.utils.emptyDomNode(node);\n\n                    // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it\n                    html = ko.utils.unwrapObservable(html);\n\n                    if ((html !== null) && (html !== undefined)) {\n                        if (typeof html != 'string')\n                            html = html.toString();\n\n                        // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,\n                        // for example <tr> elements which are not normally allowed to exist on their own.\n                        // If you've referenced jQuery we'll use that rather than duplicating its code.\n                        if (jQueryInstance) {\n                            jQueryInstance(node)['html'](html);\n                        } else {\n                            // ... otherwise, use KO's own parsing logic.\n                            var parsedNodes = ko.utils.parseHtmlFragment(html, node.ownerDocument);\n                            for (var i = 0; i < parsedNodes.length; i++)\n                                node.appendChild(parsedNodes[i]);\n                        }\n                    }\n                };\n            })();\n\n            ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);\n            ko.exportSymbol('utils.setHtml', ko.utils.setHtml);\n\n            ko.memoization = (function () {\n                var memos = {};\n\n                function randomMax8HexChars() {\n                    return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);\n                }\n                function generateRandomId() {\n                    return randomMax8HexChars() + randomMax8HexChars();\n                }\n                function findMemoNodes(rootNode, appendToArray) {\n                    if (!rootNode)\n                        return;\n                    if (rootNode.nodeType == 8) {\n                        var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);\n                        if (memoId != null)\n                            appendToArray.push({ domNode: rootNode, memoId: memoId });\n                    } else if (rootNode.nodeType == 1) {\n                        for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)\n                            findMemoNodes(childNodes[i], appendToArray);\n                    }\n                }\n\n                return {\n                    memoize: function (callback) {\n                        if (typeof callback != \"function\")\n                            throw new Error(\"You can only pass a function to ko.memoization.memoize()\");\n                        var memoId = generateRandomId();\n                        memos[memoId] = callback;\n                        return \"<!--[ko_memo:\" + memoId + \"]-->\";\n                    },\n\n                    unmemoize: function (memoId, callbackParams) {\n                        var callback = memos[memoId];\n                        if (callback === undefined)\n                            throw new Error(\"Couldn't find any memo with ID \" + memoId + \". Perhaps it's already been unmemoized.\");\n                        try {\n                            callback.apply(null, callbackParams || []);\n                            return true;\n                        }\n                        finally { delete memos[memoId]; }\n                    },\n\n                    unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {\n                        var memos = [];\n                        findMemoNodes(domNode, memos);\n                        for (var i = 0, j = memos.length; i < j; i++) {\n                            var node = memos[i].domNode;\n                            var combinedParams = [node];\n                            if (extraCallbackParamsArray)\n                                ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);\n                            ko.memoization.unmemoize(memos[i].memoId, combinedParams);\n                            node.nodeValue = \"\"; // Neuter this node so we don't try to unmemoize it again\n                            if (node.parentNode)\n                                node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)\n                        }\n                    },\n\n                    parseMemoText: function (memoText) {\n                        var match = memoText.match(/^\\[ko_memo\\:(.*?)\\]$/);\n                        return match ? match[1] : null;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('memoization', ko.memoization);\n            ko.exportSymbol('memoization.memoize', ko.memoization.memoize);\n            ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);\n            ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);\n            ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);\n            ko.tasks = (function () {\n                var scheduler,\n                    taskQueue = [],\n                    taskQueueLength = 0,\n                    nextHandle = 1,\n                    nextIndexToProcess = 0;\n\n                if (window['MutationObserver']) {\n                    // Chrome 27+, Firefox 14+, IE 11+, Opera 15+, Safari 6.1+\n                    // From https://github.com/petkaantonov/bluebird * Copyright (c) 2014 Petka Antonov * License: MIT\n                    scheduler = (function (callback) {\n                        var div = document.createElement(\"div\");\n                        new MutationObserver(callback).observe(div, {attributes: true});\n                        return function () { div.classList.toggle(\"foo\"); };\n                    })(scheduledProcess);\n                } else if (document && \"onreadystatechange\" in document.createElement(\"script\")) {\n                    // IE 6-10\n                    // From https://github.com/YuzuJS/setImmediate * Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola * License: MIT\n                    scheduler = function (callback) {\n                        var script = document.createElement(\"script\");\n                        script.onreadystatechange = function () {\n                            script.onreadystatechange = null;\n                            document.documentElement.removeChild(script);\n                            script = null;\n                            callback();\n                        };\n                        document.documentElement.appendChild(script);\n                    };\n                } else {\n                    scheduler = function (callback) {\n                        setTimeout(callback, 0);\n                    };\n                }\n\n                function processTasks() {\n                    if (taskQueueLength) {\n                        // Each mark represents the end of a logical group of tasks and the number of these groups is\n                        // limited to prevent unchecked recursion.\n                        var mark = taskQueueLength, countMarks = 0;\n\n                        // nextIndexToProcess keeps track of where we are in the queue; processTasks can be called recursively without issue\n                        for (var task; nextIndexToProcess < taskQueueLength; ) {\n                            if (task = taskQueue[nextIndexToProcess++]) {\n                                if (nextIndexToProcess > mark) {\n                                    if (++countMarks >= 5000) {\n                                        nextIndexToProcess = taskQueueLength;   // skip all tasks remaining in the queue since any of them could be causing the recursion\n                                        ko.utils.deferError(Error(\"'Too much recursion' after processing \" + countMarks + \" task groups.\"));\n                                        break;\n                                    }\n                                    mark = taskQueueLength;\n                                }\n                                try {\n                                    task();\n                                } catch (ex) {\n                                    ko.utils.deferError(ex);\n                                }\n                            }\n                        }\n                    }\n                }\n\n                function scheduledProcess() {\n                    processTasks();\n\n                    // Reset the queue\n                    nextIndexToProcess = taskQueueLength = taskQueue.length = 0;\n                }\n\n                function scheduleTaskProcessing() {\n                    ko.tasks['scheduler'](scheduledProcess);\n                }\n\n                var tasks = {\n                    'scheduler': scheduler,     // Allow overriding the scheduler\n\n                    schedule: function (func) {\n                        if (!taskQueueLength) {\n                            scheduleTaskProcessing();\n                        }\n\n                        taskQueue[taskQueueLength++] = func;\n                        return nextHandle++;\n                    },\n\n                    cancel: function (handle) {\n                        var index = handle - (nextHandle - taskQueueLength);\n                        if (index >= nextIndexToProcess && index < taskQueueLength) {\n                            taskQueue[index] = null;\n                        }\n                    },\n\n                    // For testing only: reset the queue and return the previous queue length\n                    'resetForTesting': function () {\n                        var length = taskQueueLength - nextIndexToProcess;\n                        nextIndexToProcess = taskQueueLength = taskQueue.length = 0;\n                        return length;\n                    },\n\n                    runEarly: processTasks\n                };\n\n                return tasks;\n            })();\n\n            ko.exportSymbol('tasks', ko.tasks);\n            ko.exportSymbol('tasks.schedule', ko.tasks.schedule);\n//ko.exportSymbol('tasks.cancel', ko.tasks.cancel);  \"cancel\" isn't minified\n            ko.exportSymbol('tasks.runEarly', ko.tasks.runEarly);\n            ko.extenders = {\n                'throttle': function(target, timeout) {\n                    // Throttling means two things:\n\n                    // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies\n                    //     notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate\n                    target['throttleEvaluation'] = timeout;\n\n                    // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*\n                    //     so the target cannot change value synchronously or faster than a certain rate\n                    var writeTimeoutInstance = null;\n                    return ko.dependentObservable({\n                        'read': target,\n                        'write': function(value) {\n                            clearTimeout(writeTimeoutInstance);\n                            writeTimeoutInstance = ko.utils.setTimeout(function() {\n                                target(value);\n                            }, timeout);\n                        }\n                    });\n                },\n\n                'rateLimit': function(target, options) {\n                    var timeout, method, limitFunction;\n\n                    if (typeof options == 'number') {\n                        timeout = options;\n                    } else {\n                        timeout = options['timeout'];\n                        method = options['method'];\n                    }\n\n                    // rateLimit supersedes deferred updates\n                    target._deferUpdates = false;\n\n                    limitFunction = typeof method == 'function' ? method : method == 'notifyWhenChangesStop' ?  debounce : throttle;\n                    target.limit(function(callback) {\n                        return limitFunction(callback, timeout, options);\n                    });\n                },\n\n                'deferred': function(target, options) {\n                    if (options !== true) {\n                        throw new Error('The \\'deferred\\' extender only accepts the value \\'true\\', because it is not supported to turn deferral off once enabled.')\n                    }\n\n                    if (!target._deferUpdates) {\n                        target._deferUpdates = true;\n                        target.limit(function (callback) {\n                            var handle,\n                                ignoreUpdates = false;\n                            return function () {\n                                if (!ignoreUpdates) {\n                                    ko.tasks.cancel(handle);\n                                    handle = ko.tasks.schedule(callback);\n\n                                    try {\n                                        ignoreUpdates = true;\n                                        target['notifySubscribers'](undefined, 'dirty');\n                                    } finally {\n                                        ignoreUpdates = false;\n                                    }\n                                }\n                            };\n                        });\n                    }\n                },\n\n                'notify': function(target, notifyWhen) {\n                    target[\"equalityComparer\"] = notifyWhen == \"always\" ?\n                        null :  // null equalityComparer means to always notify\n                        valuesArePrimitiveAndEqual;\n                }\n            };\n\n            var primitiveTypes = { 'undefined':1, 'boolean':1, 'number':1, 'string':1 };\n            function valuesArePrimitiveAndEqual(a, b) {\n                var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);\n                return oldValueIsPrimitive ? (a === b) : false;\n            }\n\n            function throttle(callback, timeout) {\n                var timeoutInstance;\n                return function () {\n                    if (!timeoutInstance) {\n                        timeoutInstance = ko.utils.setTimeout(function () {\n                            timeoutInstance = undefined;\n                            callback();\n                        }, timeout);\n                    }\n                };\n            }\n\n            function debounce(callback, timeout) {\n                var timeoutInstance;\n                return function () {\n                    clearTimeout(timeoutInstance);\n                    timeoutInstance = ko.utils.setTimeout(callback, timeout);\n                };\n            }\n\n            function applyExtenders(requestedExtenders) {\n                var target = this;\n                if (requestedExtenders) {\n                    ko.utils.objectForEach(requestedExtenders, function(key, value) {\n                        var extenderHandler = ko.extenders[key];\n                        if (typeof extenderHandler == 'function') {\n                            target = extenderHandler(target, value) || target;\n                        }\n                    });\n                }\n                return target;\n            }\n\n            ko.exportSymbol('extenders', ko.extenders);\n\n            ko.subscription = function (target, callback, disposeCallback) {\n                this._target = target;\n                this._callback = callback;\n                this._disposeCallback = disposeCallback;\n                this._isDisposed = false;\n                this._node = null;\n                this._domNodeDisposalCallback = null;\n                ko.exportProperty(this, 'dispose', this.dispose);\n                ko.exportProperty(this, 'disposeWhenNodeIsRemoved', this.disposeWhenNodeIsRemoved);\n            };\n            ko.subscription.prototype.dispose = function () {\n                var self = this;\n                if (!self._isDisposed) {\n                    if (self._domNodeDisposalCallback) {\n                        ko.utils.domNodeDisposal.removeDisposeCallback(self._node, self._domNodeDisposalCallback);\n                    }\n                    self._isDisposed = true;\n                    self._disposeCallback();\n\n                    self._target = self._callback = self._disposeCallback = self._node = self._domNodeDisposalCallback = null;\n                }\n            };\n            ko.subscription.prototype.disposeWhenNodeIsRemoved = function (node) {\n                this._node = node;\n                ko.utils.domNodeDisposal.addDisposeCallback(node, this._domNodeDisposalCallback = this.dispose.bind(this));\n            };\n\n            ko.subscribable = function () {\n                ko.utils.setPrototypeOfOrExtend(this, ko_subscribable_fn);\n                ko_subscribable_fn.init(this);\n            }\n\n            var defaultEvent = \"change\";\n\n// Moved out of \"limit\" to avoid the extra closure\n            function limitNotifySubscribers(value, event) {\n                if (!event || event === defaultEvent) {\n                    this._limitChange(value);\n                } else if (event === 'beforeChange') {\n                    this._limitBeforeChange(value);\n                } else {\n                    this._origNotifySubscribers(value, event);\n                }\n            }\n\n            var ko_subscribable_fn = {\n                init: function(instance) {\n                    instance._subscriptions = { \"change\": [] };\n                    instance._versionNumber = 1;\n                },\n\n                subscribe: function (callback, callbackTarget, event) {\n                    var self = this;\n\n                    event = event || defaultEvent;\n                    var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;\n\n                    var subscription = new ko.subscription(self, boundCallback, function () {\n                        ko.utils.arrayRemoveItem(self._subscriptions[event], subscription);\n                        if (self.afterSubscriptionRemove)\n                            self.afterSubscriptionRemove(event);\n                    });\n\n                    if (self.beforeSubscriptionAdd)\n                        self.beforeSubscriptionAdd(event);\n\n                    if (!self._subscriptions[event])\n                        self._subscriptions[event] = [];\n                    self._subscriptions[event].push(subscription);\n\n                    return subscription;\n                },\n\n                \"notifySubscribers\": function (valueToNotify, event) {\n                    event = event || defaultEvent;\n                    if (event === defaultEvent) {\n                        this.updateVersion();\n                    }\n                    if (this.hasSubscriptionsForEvent(event)) {\n                        var subs = event === defaultEvent && this._changeSubscriptions || this._subscriptions[event].slice(0);\n                        try {\n                            ko.dependencyDetection.begin(); // Begin suppressing dependency detection (by setting the top frame to undefined)\n                            for (var i = 0, subscription; subscription = subs[i]; ++i) {\n                                // In case a subscription was disposed during the arrayForEach cycle, check\n                                // for isDisposed on each subscription before invoking its callback\n                                if (!subscription._isDisposed)\n                                    subscription._callback(valueToNotify);\n                            }\n                        } finally {\n                            ko.dependencyDetection.end(); // End suppressing dependency detection\n                        }\n                    }\n                },\n\n                getVersion: function () {\n                    return this._versionNumber;\n                },\n\n                hasChanged: function (versionToCheck) {\n                    return this.getVersion() !== versionToCheck;\n                },\n\n                updateVersion: function () {\n                    ++this._versionNumber;\n                },\n\n                limit: function(limitFunction) {\n                    var self = this, selfIsObservable = ko.isObservable(self),\n                        ignoreBeforeChange, notifyNextChange, previousValue, pendingValue, didUpdate,\n                        beforeChange = 'beforeChange';\n\n                    if (!self._origNotifySubscribers) {\n                        self._origNotifySubscribers = self[\"notifySubscribers\"];\n                        self[\"notifySubscribers\"] = limitNotifySubscribers;\n                    }\n\n                    var finish = limitFunction(function() {\n                        self._notificationIsPending = false;\n\n                        // If an observable provided a reference to itself, access it to get the latest value.\n                        // This allows computed observables to delay calculating their value until needed.\n                        if (selfIsObservable && pendingValue === self) {\n                            pendingValue = self._evalIfChanged ? self._evalIfChanged() : self();\n                        }\n                        var shouldNotify = notifyNextChange || (didUpdate && self.isDifferent(previousValue, pendingValue));\n\n                        didUpdate = notifyNextChange = ignoreBeforeChange = false;\n\n                        if (shouldNotify) {\n                            self._origNotifySubscribers(previousValue = pendingValue);\n                        }\n                    });\n\n                    self._limitChange = function(value, isDirty) {\n                        if (!isDirty || !self._notificationIsPending) {\n                            didUpdate = !isDirty;\n                        }\n                        self._changeSubscriptions = self._subscriptions[defaultEvent].slice(0);\n                        self._notificationIsPending = ignoreBeforeChange = true;\n                        pendingValue = value;\n                        finish();\n                    };\n                    self._limitBeforeChange = function(value) {\n                        if (!ignoreBeforeChange) {\n                            previousValue = value;\n                            self._origNotifySubscribers(value, beforeChange);\n                        }\n                    };\n                    self._recordUpdate = function() {\n                        didUpdate = true;\n                    };\n                    self._notifyNextChangeIfValueIsDifferent = function() {\n                        if (self.isDifferent(previousValue, self.peek(true /*evaluate*/))) {\n                            notifyNextChange = true;\n                        }\n                    };\n                },\n\n                hasSubscriptionsForEvent: function(event) {\n                    return this._subscriptions[event] && this._subscriptions[event].length;\n                },\n\n                getSubscriptionsCount: function (event) {\n                    if (event) {\n                        return this._subscriptions[event] && this._subscriptions[event].length || 0;\n                    } else {\n                        var total = 0;\n                        ko.utils.objectForEach(this._subscriptions, function(eventName, subscriptions) {\n                            if (eventName !== 'dirty')\n                                total += subscriptions.length;\n                        });\n                        return total;\n                    }\n                },\n\n                isDifferent: function(oldValue, newValue) {\n                    return !this['equalityComparer'] || !this['equalityComparer'](oldValue, newValue);\n                },\n\n                toString: function() {\n                    return '[object Object]'\n                },\n\n                extend: applyExtenders\n            };\n\n            ko.exportProperty(ko_subscribable_fn, 'init', ko_subscribable_fn.init);\n            ko.exportProperty(ko_subscribable_fn, 'subscribe', ko_subscribable_fn.subscribe);\n            ko.exportProperty(ko_subscribable_fn, 'extend', ko_subscribable_fn.extend);\n            ko.exportProperty(ko_subscribable_fn, 'getSubscriptionsCount', ko_subscribable_fn.getSubscriptionsCount);\n\n// For browsers that support proto assignment, we overwrite the prototype of each\n// observable instance. Since observables are functions, we need Function.prototype\n// to still be in the prototype chain.\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(ko_subscribable_fn, Function.prototype);\n            }\n\n            ko.subscribable['fn'] = ko_subscribable_fn;\n\n\n            ko.isSubscribable = function (instance) {\n                return instance != null && typeof instance.subscribe == \"function\" && typeof instance[\"notifySubscribers\"] == \"function\";\n            };\n\n            ko.exportSymbol('subscribable', ko.subscribable);\n            ko.exportSymbol('isSubscribable', ko.isSubscribable);\n\n            ko.computedContext = ko.dependencyDetection = (function () {\n                var outerFrames = [],\n                    currentFrame,\n                    lastId = 0;\n\n                // Return a unique ID that can be assigned to an observable for dependency tracking.\n                // Theoretically, you could eventually overflow the number storage size, resulting\n                // in duplicate IDs. But in JavaScript, the largest exact integral value is 2^53\n                // or 9,007,199,254,740,992. If you created 1,000,000 IDs per second, it would\n                // take over 285 years to reach that number.\n                // Reference http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html\n                function getId() {\n                    return ++lastId;\n                }\n\n                function begin(options) {\n                    outerFrames.push(currentFrame);\n                    currentFrame = options;\n                }\n\n                function end() {\n                    currentFrame = outerFrames.pop();\n                }\n\n                return {\n                    begin: begin,\n\n                    end: end,\n\n                    registerDependency: function (subscribable) {\n                        if (currentFrame) {\n                            if (!ko.isSubscribable(subscribable))\n                                throw new Error(\"Only subscribable things can act as dependencies\");\n                            currentFrame.callback.call(currentFrame.callbackTarget, subscribable, subscribable._id || (subscribable._id = getId()));\n                        }\n                    },\n\n                    ignore: function (callback, callbackTarget, callbackArgs) {\n                        try {\n                            begin();\n                            return callback.apply(callbackTarget, callbackArgs || []);\n                        } finally {\n                            end();\n                        }\n                    },\n\n                    getDependenciesCount: function () {\n                        if (currentFrame)\n                            return currentFrame.computed.getDependenciesCount();\n                    },\n\n                    getDependencies: function () {\n                        if (currentFrame)\n                            return currentFrame.computed.getDependencies();\n                    },\n\n                    isInitial: function() {\n                        if (currentFrame)\n                            return currentFrame.isInitial;\n                    },\n\n                    computed: function() {\n                        if (currentFrame)\n                            return currentFrame.computed;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('computedContext', ko.computedContext);\n            ko.exportSymbol('computedContext.getDependenciesCount', ko.computedContext.getDependenciesCount);\n            ko.exportSymbol('computedContext.getDependencies', ko.computedContext.getDependencies);\n            ko.exportSymbol('computedContext.isInitial', ko.computedContext.isInitial);\n            ko.exportSymbol('computedContext.registerDependency', ko.computedContext.registerDependency);\n\n            ko.exportSymbol('ignoreDependencies', ko.ignoreDependencies = ko.dependencyDetection.ignore);\n            var observableLatestValue = ko.utils.createSymbolOrString('_latestValue');\n\n            ko.observable = function (initialValue) {\n                function observable() {\n                    if (arguments.length > 0) {\n                        // Write\n\n                        // Ignore writes if the value hasn't changed\n                        if (observable.isDifferent(observable[observableLatestValue], arguments[0])) {\n                            observable.valueWillMutate();\n                            observable[observableLatestValue] = arguments[0];\n                            observable.valueHasMutated();\n                        }\n                        return this; // Permits chained assignments\n                    }\n                    else {\n                        // Read\n                        ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a \"read\" operation\n                        return observable[observableLatestValue];\n                    }\n                }\n\n                observable[observableLatestValue] = initialValue;\n\n                // Inherit from 'subscribable'\n                if (!ko.utils.canSetPrototype) {\n                    // 'subscribable' won't be on the prototype chain unless we put it there directly\n                    ko.utils.extend(observable, ko.subscribable['fn']);\n                }\n                ko.subscribable['fn'].init(observable);\n\n                // Inherit from 'observable'\n                ko.utils.setPrototypeOfOrExtend(observable, observableFn);\n\n                if (ko.options['deferUpdates']) {\n                    ko.extenders['deferred'](observable, true);\n                }\n\n                return observable;\n            }\n\n// Define prototype for observables\n            var observableFn = {\n                'equalityComparer': valuesArePrimitiveAndEqual,\n                peek: function() { return this[observableLatestValue]; },\n                valueHasMutated: function () {\n                    this['notifySubscribers'](this[observableLatestValue], 'spectate');\n                    this['notifySubscribers'](this[observableLatestValue]);\n                },\n                valueWillMutate: function () { this['notifySubscribers'](this[observableLatestValue], 'beforeChange'); }\n            };\n\n// Note that for browsers that don't support proto assignment, the\n// inheritance chain is created manually in the ko.observable constructor\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(observableFn, ko.subscribable['fn']);\n            }\n\n            var protoProperty = ko.observable.protoProperty = '__ko_proto__';\n            observableFn[protoProperty] = ko.observable;\n\n            ko.isObservable = function (instance) {\n                var proto = typeof instance == 'function' && instance[protoProperty];\n                if (proto && proto !== observableFn[protoProperty] && proto !== ko.computed['fn'][protoProperty]) {\n                    throw Error(\"Invalid object that looks like an observable; possibly from another Knockout instance\");\n                }\n                return !!proto;\n            };\n\n            ko.isWriteableObservable = function (instance) {\n                return (typeof instance == 'function' && (\n                    (instance[protoProperty] === observableFn[protoProperty]) ||  // Observable\n                    (instance[protoProperty] === ko.computed['fn'][protoProperty] && instance.hasWriteFunction)));   // Writable computed observable\n            };\n\n            ko.exportSymbol('observable', ko.observable);\n            ko.exportSymbol('isObservable', ko.isObservable);\n            ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);\n            ko.exportSymbol('isWritableObservable', ko.isWriteableObservable);\n            ko.exportSymbol('observable.fn', observableFn);\n            ko.exportProperty(observableFn, 'peek', observableFn.peek);\n            ko.exportProperty(observableFn, 'valueHasMutated', observableFn.valueHasMutated);\n            ko.exportProperty(observableFn, 'valueWillMutate', observableFn.valueWillMutate);\n            ko.observableArray = function (initialValues) {\n                initialValues = initialValues || [];\n\n                if (typeof initialValues != 'object' || !('length' in initialValues))\n                    throw new Error(\"The argument passed when initializing an observable array must be an array, or null, or undefined.\");\n\n                var result = ko.observable(initialValues);\n                ko.utils.setPrototypeOfOrExtend(result, ko.observableArray['fn']);\n                return result.extend({'trackArrayChanges':true});\n            };\n\n            ko.observableArray['fn'] = {\n                'remove': function (valueOrPredicate) {\n                    var underlyingArray = this.peek();\n                    var removedValues = [];\n                    var predicate = typeof valueOrPredicate == \"function\" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };\n                    for (var i = 0; i < underlyingArray.length; i++) {\n                        var value = underlyingArray[i];\n                        if (predicate(value)) {\n                            if (removedValues.length === 0) {\n                                this.valueWillMutate();\n                            }\n                            if (underlyingArray[i] !== value) {\n                                throw Error(\"Array modified during remove; cannot remove item\");\n                            }\n                            removedValues.push(value);\n                            underlyingArray.splice(i, 1);\n                            i--;\n                        }\n                    }\n                    if (removedValues.length) {\n                        this.valueHasMutated();\n                    }\n                    return removedValues;\n                },\n\n                'removeAll': function (arrayOfValues) {\n                    // If you passed zero args, we remove everything\n                    if (arrayOfValues === undefined) {\n                        var underlyingArray = this.peek();\n                        var allValues = underlyingArray.slice(0);\n                        this.valueWillMutate();\n                        underlyingArray.splice(0, underlyingArray.length);\n                        this.valueHasMutated();\n                        return allValues;\n                    }\n                    // If you passed an arg, we interpret it as an array of entries to remove\n                    if (!arrayOfValues)\n                        return [];\n                    return this['remove'](function (value) {\n                        return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;\n                    });\n                },\n\n                'destroy': function (valueOrPredicate) {\n                    var underlyingArray = this.peek();\n                    var predicate = typeof valueOrPredicate == \"function\" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };\n                    this.valueWillMutate();\n                    for (var i = underlyingArray.length - 1; i >= 0; i--) {\n                        var value = underlyingArray[i];\n                        if (predicate(value))\n                            value[\"_destroy\"] = true;\n                    }\n                    this.valueHasMutated();\n                },\n\n                'destroyAll': function (arrayOfValues) {\n                    // If you passed zero args, we destroy everything\n                    if (arrayOfValues === undefined)\n                        return this['destroy'](function() { return true });\n\n                    // If you passed an arg, we interpret it as an array of entries to destroy\n                    if (!arrayOfValues)\n                        return [];\n                    return this['destroy'](function (value) {\n                        return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;\n                    });\n                },\n\n                'indexOf': function (item) {\n                    var underlyingArray = this();\n                    return ko.utils.arrayIndexOf(underlyingArray, item);\n                },\n\n                'replace': function(oldItem, newItem) {\n                    var index = this['indexOf'](oldItem);\n                    if (index >= 0) {\n                        this.valueWillMutate();\n                        this.peek()[index] = newItem;\n                        this.valueHasMutated();\n                    }\n                },\n\n                'sorted': function (compareFunction) {\n                    var arrayCopy = this().slice(0);\n                    return compareFunction ? arrayCopy.sort(compareFunction) : arrayCopy.sort();\n                },\n\n                'reversed': function () {\n                    return this().slice(0).reverse();\n                }\n            };\n\n// Note that for browsers that don't support proto assignment, the\n// inheritance chain is created manually in the ko.observableArray constructor\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(ko.observableArray['fn'], ko.observable['fn']);\n            }\n\n// Populate ko.observableArray.fn with read/write functions from native arrays\n// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array\n// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale\n            ko.utils.arrayForEach([\"pop\", \"push\", \"reverse\", \"shift\", \"sort\", \"splice\", \"unshift\"], function (methodName) {\n                ko.observableArray['fn'][methodName] = function () {\n                    // Use \"peek\" to avoid creating a subscription in any computed that we're executing in the context of\n                    // (for consistency with mutating regular observables)\n                    var underlyingArray = this.peek();\n                    this.valueWillMutate();\n                    this.cacheDiffForKnownOperation(underlyingArray, methodName, arguments);\n                    var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);\n                    this.valueHasMutated();\n                    // The native sort and reverse methods return a reference to the array, but it makes more sense to return the observable array instead.\n                    return methodCallResult === underlyingArray ? this : methodCallResult;\n                };\n            });\n\n// Populate ko.observableArray.fn with read-only functions from native arrays\n            ko.utils.arrayForEach([\"slice\"], function (methodName) {\n                ko.observableArray['fn'][methodName] = function () {\n                    var underlyingArray = this();\n                    return underlyingArray[methodName].apply(underlyingArray, arguments);\n                };\n            });\n\n            ko.isObservableArray = function (instance) {\n                return ko.isObservable(instance)\n                    && typeof instance[\"remove\"] == \"function\"\n                    && typeof instance[\"push\"] == \"function\";\n            };\n\n            ko.exportSymbol('observableArray', ko.observableArray);\n            ko.exportSymbol('isObservableArray', ko.isObservableArray);\n            var arrayChangeEventName = 'arrayChange';\n            ko.extenders['trackArrayChanges'] = function(target, options) {\n                // Use the provided options--each call to trackArrayChanges overwrites the previously set options\n                target.compareArrayOptions = {};\n                if (options && typeof options == \"object\") {\n                    ko.utils.extend(target.compareArrayOptions, options);\n                }\n                target.compareArrayOptions['sparse'] = true;\n\n                // Only modify the target observable once\n                if (target.cacheDiffForKnownOperation) {\n                    return;\n                }\n                var trackingChanges = false,\n                    cachedDiff = null,\n                    changeSubscription,\n                    spectateSubscription,\n                    pendingChanges = 0,\n                    previousContents,\n                    underlyingBeforeSubscriptionAddFunction = target.beforeSubscriptionAdd,\n                    underlyingAfterSubscriptionRemoveFunction = target.afterSubscriptionRemove;\n\n                // Watch \"subscribe\" calls, and for array change events, ensure change tracking is enabled\n                target.beforeSubscriptionAdd = function (event) {\n                    if (underlyingBeforeSubscriptionAddFunction) {\n                        underlyingBeforeSubscriptionAddFunction.call(target, event);\n                    }\n                    if (event === arrayChangeEventName) {\n                        trackChanges();\n                    }\n                };\n                // Watch \"dispose\" calls, and for array change events, ensure change tracking is disabled when all are disposed\n                target.afterSubscriptionRemove = function (event) {\n                    if (underlyingAfterSubscriptionRemoveFunction) {\n                        underlyingAfterSubscriptionRemoveFunction.call(target, event);\n                    }\n                    if (event === arrayChangeEventName && !target.hasSubscriptionsForEvent(arrayChangeEventName)) {\n                        if (changeSubscription) {\n                            changeSubscription.dispose();\n                        }\n                        if (spectateSubscription) {\n                            spectateSubscription.dispose();\n                        }\n                        spectateSubscription = changeSubscription = null;\n                        trackingChanges = false;\n                        previousContents = undefined;\n                    }\n                };\n\n                function trackChanges() {\n                    if (trackingChanges) {\n                        // Whenever there's a new subscription and there are pending notifications, make sure all previous\n                        // subscriptions are notified of the change so that all subscriptions are in sync.\n                        notifyChanges();\n                        return;\n                    }\n\n                    trackingChanges = true;\n\n                    // Track how many times the array actually changed value\n                    spectateSubscription = target.subscribe(function () {\n                        ++pendingChanges;\n                    }, null, \"spectate\");\n\n                    // Each time the array changes value, capture a clone so that on the next\n                    // change it's possible to produce a diff\n                    previousContents = [].concat(target.peek() || []);\n                    cachedDiff = null;\n                    changeSubscription = target.subscribe(notifyChanges);\n\n                    function notifyChanges() {\n                        if (pendingChanges) {\n                            // Make a copy of the current contents and ensure it's an array\n                            var currentContents = [].concat(target.peek() || []), changes;\n\n                            // Compute the diff and issue notifications, but only if someone is listening\n                            if (target.hasSubscriptionsForEvent(arrayChangeEventName)) {\n                                changes = getChanges(previousContents, currentContents);\n                            }\n\n                            // Eliminate references to the old, removed items, so they can be GCed\n                            previousContents = currentContents;\n                            cachedDiff = null;\n                            pendingChanges = 0;\n\n                            if (changes && changes.length) {\n                                target['notifySubscribers'](changes, arrayChangeEventName);\n                            }\n                        }\n                    }\n                }\n\n                function getChanges(previousContents, currentContents) {\n                    // We try to re-use cached diffs.\n                    // The scenarios where pendingChanges > 1 are when using rate limiting or deferred updates,\n                    // which without this check would not be compatible with arrayChange notifications. Normally,\n                    // notifications are issued immediately so we wouldn't be queueing up more than one.\n                    if (!cachedDiff || pendingChanges > 1) {\n                        cachedDiff = ko.utils.compareArrays(previousContents, currentContents, target.compareArrayOptions);\n                    }\n\n                    return cachedDiff;\n                }\n\n                target.cacheDiffForKnownOperation = function(rawArray, operationName, args) {\n                    // Only run if we're currently tracking changes for this observable array\n                    // and there aren't any pending deferred notifications.\n                    if (!trackingChanges || pendingChanges) {\n                        return;\n                    }\n                    var diff = [],\n                        arrayLength = rawArray.length,\n                        argsLength = args.length,\n                        offset = 0;\n\n                    function pushDiff(status, value, index) {\n                        return diff[diff.length] = { 'status': status, 'value': value, 'index': index };\n                    }\n                    switch (operationName) {\n                        case 'push':\n                            offset = arrayLength;\n                        case 'unshift':\n                            for (var index = 0; index < argsLength; index++) {\n                                pushDiff('added', args[index], offset + index);\n                            }\n                            break;\n\n                        case 'pop':\n                            offset = arrayLength - 1;\n                        case 'shift':\n                            if (arrayLength) {\n                                pushDiff('deleted', rawArray[offset], offset);\n                            }\n                            break;\n\n                        case 'splice':\n                            // Negative start index means 'from end of array'. After that we clamp to [0...arrayLength].\n                            // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice\n                            var startIndex = Math.min(Math.max(0, args[0] < 0 ? arrayLength + args[0] : args[0]), arrayLength),\n                                endDeleteIndex = argsLength === 1 ? arrayLength : Math.min(startIndex + (args[1] || 0), arrayLength),\n                                endAddIndex = startIndex + argsLength - 2,\n                                endIndex = Math.max(endDeleteIndex, endAddIndex),\n                                additions = [], deletions = [];\n                            for (var index = startIndex, argsIndex = 2; index < endIndex; ++index, ++argsIndex) {\n                                if (index < endDeleteIndex)\n                                    deletions.push(pushDiff('deleted', rawArray[index], index));\n                                if (index < endAddIndex)\n                                    additions.push(pushDiff('added', args[argsIndex], index));\n                            }\n                            ko.utils.findMovesInArrayComparison(deletions, additions);\n                            break;\n\n                        default:\n                            return;\n                    }\n                    cachedDiff = diff;\n                };\n            };\n            var computedState = ko.utils.createSymbolOrString('_state');\n\n            ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {\n                if (typeof evaluatorFunctionOrOptions === \"object\") {\n                    // Single-parameter syntax - everything is on this \"options\" param\n                    options = evaluatorFunctionOrOptions;\n                } else {\n                    // Multi-parameter syntax - construct the options according to the params passed\n                    options = options || {};\n                    if (evaluatorFunctionOrOptions) {\n                        options[\"read\"] = evaluatorFunctionOrOptions;\n                    }\n                }\n                if (typeof options[\"read\"] != \"function\")\n                    throw Error(\"Pass a function that returns the value of the ko.computed\");\n\n                var writeFunction = options[\"write\"];\n                var state = {\n                    latestValue: undefined,\n                    isStale: true,\n                    isDirty: true,\n                    isBeingEvaluated: false,\n                    suppressDisposalUntilDisposeWhenReturnsFalse: false,\n                    isDisposed: false,\n                    pure: false,\n                    isSleeping: false,\n                    readFunction: options[\"read\"],\n                    evaluatorFunctionTarget: evaluatorFunctionTarget || options[\"owner\"],\n                    disposeWhenNodeIsRemoved: options[\"disposeWhenNodeIsRemoved\"] || options.disposeWhenNodeIsRemoved || null,\n                    disposeWhen: options[\"disposeWhen\"] || options.disposeWhen,\n                    domNodeDisposalCallback: null,\n                    dependencyTracking: {},\n                    dependenciesCount: 0,\n                    evaluationTimeoutInstance: null\n                };\n\n                function computedObservable() {\n                    if (arguments.length > 0) {\n                        if (typeof writeFunction === \"function\") {\n                            // Writing a value\n                            writeFunction.apply(state.evaluatorFunctionTarget, arguments);\n                        } else {\n                            throw new Error(\"Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.\");\n                        }\n                        return this; // Permits chained assignments\n                    } else {\n                        // Reading the value\n                        if (!state.isDisposed) {\n                            ko.dependencyDetection.registerDependency(computedObservable);\n                        }\n                        if (state.isDirty || (state.isSleeping && computedObservable.haveDependenciesChanged())) {\n                            computedObservable.evaluateImmediate();\n                        }\n                        return state.latestValue;\n                    }\n                }\n\n                computedObservable[computedState] = state;\n                computedObservable.hasWriteFunction = typeof writeFunction === \"function\";\n\n                // Inherit from 'subscribable'\n                if (!ko.utils.canSetPrototype) {\n                    // 'subscribable' won't be on the prototype chain unless we put it there directly\n                    ko.utils.extend(computedObservable, ko.subscribable['fn']);\n                }\n                ko.subscribable['fn'].init(computedObservable);\n\n                // Inherit from 'computed'\n                ko.utils.setPrototypeOfOrExtend(computedObservable, computedFn);\n\n                if (options['pure']) {\n                    state.pure = true;\n                    state.isSleeping = true;     // Starts off sleeping; will awake on the first subscription\n                    ko.utils.extend(computedObservable, pureComputedOverrides);\n                } else if (options['deferEvaluation']) {\n                    ko.utils.extend(computedObservable, deferEvaluationOverrides);\n                }\n\n                if (ko.options['deferUpdates']) {\n                    ko.extenders['deferred'](computedObservable, true);\n                }\n\n                if (DEBUG) {\n                    // #1731 - Aid debugging by exposing the computed's options\n                    computedObservable[\"_options\"] = options;\n                }\n\n                if (state.disposeWhenNodeIsRemoved) {\n                    // Since this computed is associated with a DOM node, and we don't want to dispose the computed\n                    // until the DOM node is *removed* from the document (as opposed to never having been in the document),\n                    // we'll prevent disposal until \"disposeWhen\" first returns false.\n                    state.suppressDisposalUntilDisposeWhenReturnsFalse = true;\n\n                    // disposeWhenNodeIsRemoved: true can be used to opt into the \"only dispose after first false result\"\n                    // behaviour even if there's no specific node to watch. In that case, clear the option so we don't try\n                    // to watch for a non-node's disposal. This technique is intended for KO's internal use only and shouldn't\n                    // be documented or used by application code, as it's likely to change in a future version of KO.\n                    if (!state.disposeWhenNodeIsRemoved.nodeType) {\n                        state.disposeWhenNodeIsRemoved = null;\n                    }\n                }\n\n                // Evaluate, unless sleeping or deferEvaluation is true\n                if (!state.isSleeping && !options['deferEvaluation']) {\n                    computedObservable.evaluateImmediate();\n                }\n\n                // Attach a DOM node disposal callback so that the computed will be proactively disposed as soon as the node is\n                // removed using ko.removeNode. But skip if isActive is false (there will never be any dependencies to dispose).\n                if (state.disposeWhenNodeIsRemoved && computedObservable.isActive()) {\n                    ko.utils.domNodeDisposal.addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = function () {\n                        computedObservable.dispose();\n                    });\n                }\n\n                return computedObservable;\n            };\n\n// Utility function that disposes a given dependencyTracking entry\n            function computedDisposeDependencyCallback(id, entryToDispose) {\n                if (entryToDispose !== null && entryToDispose.dispose) {\n                    entryToDispose.dispose();\n                }\n            }\n\n// This function gets called each time a dependency is detected while evaluating a computed.\n// It's factored out as a shared function to avoid creating unnecessary function instances during evaluation.\n            function computedBeginDependencyDetectionCallback(subscribable, id) {\n                var computedObservable = this.computedObservable,\n                    state = computedObservable[computedState];\n                if (!state.isDisposed) {\n                    if (this.disposalCount && this.disposalCandidates[id]) {\n                        // Don't want to dispose this subscription, as it's still being used\n                        computedObservable.addDependencyTracking(id, subscribable, this.disposalCandidates[id]);\n                        this.disposalCandidates[id] = null; // No need to actually delete the property - disposalCandidates is a transient object anyway\n                        --this.disposalCount;\n                    } else if (!state.dependencyTracking[id]) {\n                        // Brand new subscription - add it\n                        computedObservable.addDependencyTracking(id, subscribable, state.isSleeping ? { _target: subscribable } : computedObservable.subscribeToDependency(subscribable));\n                    }\n                    // If the observable we've accessed has a pending notification, ensure we get notified of the actual final value (bypass equality checks)\n                    if (subscribable._notificationIsPending) {\n                        subscribable._notifyNextChangeIfValueIsDifferent();\n                    }\n                }\n            }\n\n            var computedFn = {\n                \"equalityComparer\": valuesArePrimitiveAndEqual,\n                getDependenciesCount: function () {\n                    return this[computedState].dependenciesCount;\n                },\n                getDependencies: function () {\n                    var dependencyTracking = this[computedState].dependencyTracking, dependentObservables = [];\n\n                    ko.utils.objectForEach(dependencyTracking, function (id, dependency) {\n                        dependentObservables[dependency._order] = dependency._target;\n                    });\n\n                    return dependentObservables;\n                },\n                hasAncestorDependency: function (obs) {\n                    if (!this[computedState].dependenciesCount) {\n                        return false;\n                    }\n                    var dependencies = this.getDependencies();\n                    if (ko.utils.arrayIndexOf(dependencies, obs) !== -1) {\n                        return true;\n                    }\n                    return !!ko.utils.arrayFirst(dependencies, function (dep) {\n                        return dep.hasAncestorDependency && dep.hasAncestorDependency(obs);\n                    });\n                },\n                addDependencyTracking: function (id, target, trackingObj) {\n                    if (this[computedState].pure && target === this) {\n                        throw Error(\"A 'pure' computed must not be called recursively\");\n                    }\n\n                    this[computedState].dependencyTracking[id] = trackingObj;\n                    trackingObj._order = this[computedState].dependenciesCount++;\n                    trackingObj._version = target.getVersion();\n                },\n                haveDependenciesChanged: function () {\n                    var id, dependency, dependencyTracking = this[computedState].dependencyTracking;\n                    for (id in dependencyTracking) {\n                        if (Object.prototype.hasOwnProperty.call(dependencyTracking, id)) {\n                            dependency = dependencyTracking[id];\n                            if ((this._evalDelayed && dependency._target._notificationIsPending) || dependency._target.hasChanged(dependency._version)) {\n                                return true;\n                            }\n                        }\n                    }\n                },\n                markDirty: function () {\n                    // Process \"dirty\" events if we can handle delayed notifications\n                    if (this._evalDelayed && !this[computedState].isBeingEvaluated) {\n                        this._evalDelayed(false /*isChange*/);\n                    }\n                },\n                isActive: function () {\n                    var state = this[computedState];\n                    return state.isDirty || state.dependenciesCount > 0;\n                },\n                respondToChange: function () {\n                    // Ignore \"change\" events if we've already scheduled a delayed notification\n                    if (!this._notificationIsPending) {\n                        this.evaluatePossiblyAsync();\n                    } else if (this[computedState].isDirty) {\n                        this[computedState].isStale = true;\n                    }\n                },\n                subscribeToDependency: function (target) {\n                    if (target._deferUpdates) {\n                        var dirtySub = target.subscribe(this.markDirty, this, 'dirty'),\n                            changeSub = target.subscribe(this.respondToChange, this);\n                        return {\n                            _target: target,\n                            dispose: function () {\n                                dirtySub.dispose();\n                                changeSub.dispose();\n                            }\n                        };\n                    } else {\n                        return target.subscribe(this.evaluatePossiblyAsync, this);\n                    }\n                },\n                evaluatePossiblyAsync: function () {\n                    var computedObservable = this,\n                        throttleEvaluationTimeout = computedObservable['throttleEvaluation'];\n                    if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {\n                        clearTimeout(this[computedState].evaluationTimeoutInstance);\n                        this[computedState].evaluationTimeoutInstance = ko.utils.setTimeout(function () {\n                            computedObservable.evaluateImmediate(true /*notifyChange*/);\n                        }, throttleEvaluationTimeout);\n                    } else if (computedObservable._evalDelayed) {\n                        computedObservable._evalDelayed(true /*isChange*/);\n                    } else {\n                        computedObservable.evaluateImmediate(true /*notifyChange*/);\n                    }\n                },\n                evaluateImmediate: function (notifyChange) {\n                    var computedObservable = this,\n                        state = computedObservable[computedState],\n                        disposeWhen = state.disposeWhen,\n                        changed = false;\n\n                    if (state.isBeingEvaluated) {\n                        // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.\n                        // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost\n                        // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing\n                        // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387\n                        return;\n                    }\n\n                    // Do not evaluate (and possibly capture new dependencies) if disposed\n                    if (state.isDisposed) {\n                        return;\n                    }\n\n                    if (state.disposeWhenNodeIsRemoved && !ko.utils.domNodeIsAttachedToDocument(state.disposeWhenNodeIsRemoved) || disposeWhen && disposeWhen()) {\n                        // See comment above about suppressDisposalUntilDisposeWhenReturnsFalse\n                        if (!state.suppressDisposalUntilDisposeWhenReturnsFalse) {\n                            computedObservable.dispose();\n                            return;\n                        }\n                    } else {\n                        // It just did return false, so we can stop suppressing now\n                        state.suppressDisposalUntilDisposeWhenReturnsFalse = false;\n                    }\n\n                    state.isBeingEvaluated = true;\n                    try {\n                        changed = this.evaluateImmediate_CallReadWithDependencyDetection(notifyChange);\n                    } finally {\n                        state.isBeingEvaluated = false;\n                    }\n\n                    return changed;\n                },\n                evaluateImmediate_CallReadWithDependencyDetection: function (notifyChange) {\n                    // This function is really just part of the evaluateImmediate logic. You would never call it from anywhere else.\n                    // Factoring it out into a separate function means it can be independent of the try/catch block in evaluateImmediate,\n                    // which contributes to saving about 40% off the CPU overhead of computed evaluation (on V8 at least).\n\n                    var computedObservable = this,\n                        state = computedObservable[computedState],\n                        changed = false;\n\n                    // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).\n                    // Then, during evaluation, we cross off any that are in fact still being used.\n                    var isInitial = state.pure ? undefined : !state.dependenciesCount,   // If we're evaluating when there are no previous dependencies, it must be the first time\n                        dependencyDetectionContext = {\n                            computedObservable: computedObservable,\n                            disposalCandidates: state.dependencyTracking,\n                            disposalCount: state.dependenciesCount\n                        };\n\n                    ko.dependencyDetection.begin({\n                        callbackTarget: dependencyDetectionContext,\n                        callback: computedBeginDependencyDetectionCallback,\n                        computed: computedObservable,\n                        isInitial: isInitial\n                    });\n\n                    state.dependencyTracking = {};\n                    state.dependenciesCount = 0;\n\n                    var newValue = this.evaluateImmediate_CallReadThenEndDependencyDetection(state, dependencyDetectionContext);\n\n                    if (!state.dependenciesCount) {\n                        computedObservable.dispose();\n                        changed = true; // When evaluation causes a disposal, make sure all dependent computeds get notified so they'll see the new state\n                    } else {\n                        changed = computedObservable.isDifferent(state.latestValue, newValue);\n                    }\n\n                    if (changed) {\n                        if (!state.isSleeping) {\n                            computedObservable[\"notifySubscribers\"](state.latestValue, \"beforeChange\");\n                        } else {\n                            computedObservable.updateVersion();\n                        }\n\n                        state.latestValue = newValue;\n                        if (DEBUG) computedObservable._latestValue = newValue;\n\n                        computedObservable[\"notifySubscribers\"](state.latestValue, \"spectate\");\n\n                        if (!state.isSleeping && notifyChange) {\n                            computedObservable[\"notifySubscribers\"](state.latestValue);\n                        }\n                        if (computedObservable._recordUpdate) {\n                            computedObservable._recordUpdate();\n                        }\n                    }\n\n                    if (isInitial) {\n                        computedObservable[\"notifySubscribers\"](state.latestValue, \"awake\");\n                    }\n\n                    return changed;\n                },\n                evaluateImmediate_CallReadThenEndDependencyDetection: function (state, dependencyDetectionContext) {\n                    // This function is really part of the evaluateImmediate_CallReadWithDependencyDetection logic.\n                    // You'd never call it from anywhere else. Factoring it out means that evaluateImmediate_CallReadWithDependencyDetection\n                    // can be independent of try/finally blocks, which contributes to saving about 40% off the CPU\n                    // overhead of computed evaluation (on V8 at least).\n\n                    try {\n                        var readFunction = state.readFunction;\n                        return state.evaluatorFunctionTarget ? readFunction.call(state.evaluatorFunctionTarget) : readFunction();\n                    } finally {\n                        ko.dependencyDetection.end();\n\n                        // For each subscription no longer being used, remove it from the active subscriptions list and dispose it\n                        if (dependencyDetectionContext.disposalCount && !state.isSleeping) {\n                            ko.utils.objectForEach(dependencyDetectionContext.disposalCandidates, computedDisposeDependencyCallback);\n                        }\n\n                        state.isStale = state.isDirty = false;\n                    }\n                },\n                peek: function (evaluate) {\n                    // By default, peek won't re-evaluate, except while the computed is sleeping or to get the initial value when \"deferEvaluation\" is set.\n                    // Pass in true to evaluate if needed.\n                    var state = this[computedState];\n                    if ((state.isDirty && (evaluate || !state.dependenciesCount)) || (state.isSleeping && this.haveDependenciesChanged())) {\n                        this.evaluateImmediate();\n                    }\n                    return state.latestValue;\n                },\n                limit: function (limitFunction) {\n                    // Override the limit function with one that delays evaluation as well\n                    ko.subscribable['fn'].limit.call(this, limitFunction);\n                    this._evalIfChanged = function () {\n                        if (!this[computedState].isSleeping) {\n                            if (this[computedState].isStale) {\n                                this.evaluateImmediate();\n                            } else {\n                                this[computedState].isDirty = false;\n                            }\n                        }\n                        return this[computedState].latestValue;\n                    };\n                    this._evalDelayed = function (isChange) {\n                        this._limitBeforeChange(this[computedState].latestValue);\n\n                        // Mark as dirty\n                        this[computedState].isDirty = true;\n                        if (isChange) {\n                            this[computedState].isStale = true;\n                        }\n\n                        // Pass the observable to the \"limit\" code, which will evaluate it when\n                        // it's time to do the notification.\n                        this._limitChange(this, !isChange /* isDirty */);\n                    };\n                },\n                dispose: function () {\n                    var state = this[computedState];\n                    if (!state.isSleeping && state.dependencyTracking) {\n                        ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {\n                            if (dependency.dispose)\n                                dependency.dispose();\n                        });\n                    }\n                    if (state.disposeWhenNodeIsRemoved && state.domNodeDisposalCallback) {\n                        ko.utils.domNodeDisposal.removeDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback);\n                    }\n                    state.dependencyTracking = undefined;\n                    state.dependenciesCount = 0;\n                    state.isDisposed = true;\n                    state.isStale = false;\n                    state.isDirty = false;\n                    state.isSleeping = false;\n                    state.disposeWhenNodeIsRemoved = undefined;\n                    state.disposeWhen = undefined;\n                    state.readFunction = undefined;\n                    if (!this.hasWriteFunction) {\n                        state.evaluatorFunctionTarget = undefined;\n                    }\n                }\n            };\n\n            var pureComputedOverrides = {\n                beforeSubscriptionAdd: function (event) {\n                    // If asleep, wake up the computed by subscribing to any dependencies.\n                    var computedObservable = this,\n                        state = computedObservable[computedState];\n                    if (!state.isDisposed && state.isSleeping && event == 'change') {\n                        state.isSleeping = false;\n                        if (state.isStale || computedObservable.haveDependenciesChanged()) {\n                            state.dependencyTracking = null;\n                            state.dependenciesCount = 0;\n                            if (computedObservable.evaluateImmediate()) {\n                                computedObservable.updateVersion();\n                            }\n                        } else {\n                            // First put the dependencies in order\n                            var dependenciesOrder = [];\n                            ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {\n                                dependenciesOrder[dependency._order] = id;\n                            });\n                            // Next, subscribe to each one\n                            ko.utils.arrayForEach(dependenciesOrder, function (id, order) {\n                                var dependency = state.dependencyTracking[id],\n                                    subscription = computedObservable.subscribeToDependency(dependency._target);\n                                subscription._order = order;\n                                subscription._version = dependency._version;\n                                state.dependencyTracking[id] = subscription;\n                            });\n                            // Waking dependencies may have triggered effects\n                            if (computedObservable.haveDependenciesChanged()) {\n                                if (computedObservable.evaluateImmediate()) {\n                                    computedObservable.updateVersion();\n                                }\n                            }\n                        }\n\n                        if (!state.isDisposed) {     // test since evaluating could trigger disposal\n                            computedObservable[\"notifySubscribers\"](state.latestValue, \"awake\");\n                        }\n                    }\n                },\n                afterSubscriptionRemove: function (event) {\n                    var state = this[computedState];\n                    if (!state.isDisposed && event == 'change' && !this.hasSubscriptionsForEvent('change')) {\n                        ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {\n                            if (dependency.dispose) {\n                                state.dependencyTracking[id] = {\n                                    _target: dependency._target,\n                                    _order: dependency._order,\n                                    _version: dependency._version\n                                };\n                                dependency.dispose();\n                            }\n                        });\n                        state.isSleeping = true;\n                        this[\"notifySubscribers\"](undefined, \"asleep\");\n                    }\n                },\n                getVersion: function () {\n                    // Because a pure computed is not automatically updated while it is sleeping, we can't\n                    // simply return the version number. Instead, we check if any of the dependencies have\n                    // changed and conditionally re-evaluate the computed observable.\n                    var state = this[computedState];\n                    if (state.isSleeping && (state.isStale || this.haveDependenciesChanged())) {\n                        this.evaluateImmediate();\n                    }\n                    return ko.subscribable['fn'].getVersion.call(this);\n                }\n            };\n\n            var deferEvaluationOverrides = {\n                beforeSubscriptionAdd: function (event) {\n                    // This will force a computed with deferEvaluation to evaluate when the first subscription is registered.\n                    if (event == 'change' || event == 'beforeChange') {\n                        this.peek();\n                    }\n                }\n            };\n\n// Note that for browsers that don't support proto assignment, the\n// inheritance chain is created manually in the ko.computed constructor\n            if (ko.utils.canSetPrototype) {\n                ko.utils.setPrototypeOf(computedFn, ko.subscribable['fn']);\n            }\n\n// Set the proto values for ko.computed\n            var protoProp = ko.observable.protoProperty; // == \"__ko_proto__\"\n            computedFn[protoProp] = ko.computed;\n\n            ko.isComputed = function (instance) {\n                return (typeof instance == 'function' && instance[protoProp] === computedFn[protoProp]);\n            };\n\n            ko.isPureComputed = function (instance) {\n                return ko.isComputed(instance) && instance[computedState] && instance[computedState].pure;\n            };\n\n            ko.exportSymbol('computed', ko.computed);\n            ko.exportSymbol('dependentObservable', ko.computed);    // export ko.dependentObservable for backwards compatibility (1.x)\n            ko.exportSymbol('isComputed', ko.isComputed);\n            ko.exportSymbol('isPureComputed', ko.isPureComputed);\n            ko.exportSymbol('computed.fn', computedFn);\n            ko.exportProperty(computedFn, 'peek', computedFn.peek);\n            ko.exportProperty(computedFn, 'dispose', computedFn.dispose);\n            ko.exportProperty(computedFn, 'isActive', computedFn.isActive);\n            ko.exportProperty(computedFn, 'getDependenciesCount', computedFn.getDependenciesCount);\n            ko.exportProperty(computedFn, 'getDependencies', computedFn.getDependencies);\n\n            ko.pureComputed = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget) {\n                if (typeof evaluatorFunctionOrOptions === 'function') {\n                    return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, {'pure':true});\n                } else {\n                    evaluatorFunctionOrOptions = ko.utils.extend({}, evaluatorFunctionOrOptions);   // make a copy of the parameter object\n                    evaluatorFunctionOrOptions['pure'] = true;\n                    return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);\n                }\n            }\n            ko.exportSymbol('pureComputed', ko.pureComputed);\n\n            (function() {\n                var maxNestedObservableDepth = 10; // Escape the (unlikely) pathological case where an observable's current value is itself (or similar reference cycle)\n\n                ko.toJS = function(rootObject) {\n                    if (arguments.length == 0)\n                        throw new Error(\"When calling ko.toJS, pass the object you want to convert.\");\n\n                    // We just unwrap everything at every level in the object graph\n                    return mapJsObjectGraph(rootObject, function(valueToMap) {\n                        // Loop because an observable's value might in turn be another observable wrapper\n                        for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)\n                            valueToMap = valueToMap();\n                        return valueToMap;\n                    });\n                };\n\n                ko.toJSON = function(rootObject, replacer, space) {     // replacer and space are optional\n                    var plainJavaScriptObject = ko.toJS(rootObject);\n                    return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);\n                };\n\n                function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {\n                    visitedObjects = visitedObjects || new objectLookup();\n\n                    rootObject = mapInputCallback(rootObject);\n                    var canHaveProperties = (typeof rootObject == \"object\") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof RegExp)) && (!(rootObject instanceof Date)) && (!(rootObject instanceof String)) && (!(rootObject instanceof Number)) && (!(rootObject instanceof Boolean));\n                    if (!canHaveProperties)\n                        return rootObject;\n\n                    var outputProperties = rootObject instanceof Array ? [] : {};\n                    visitedObjects.save(rootObject, outputProperties);\n\n                    visitPropertiesOrArrayEntries(rootObject, function(indexer) {\n                        var propertyValue = mapInputCallback(rootObject[indexer]);\n\n                        switch (typeof propertyValue) {\n                            case \"boolean\":\n                            case \"number\":\n                            case \"string\":\n                            case \"function\":\n                                outputProperties[indexer] = propertyValue;\n                                break;\n                            case \"object\":\n                            case \"undefined\":\n                                var previouslyMappedValue = visitedObjects.get(propertyValue);\n                                outputProperties[indexer] = (previouslyMappedValue !== undefined)\n                                    ? previouslyMappedValue\n                                    : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);\n                                break;\n                        }\n                    });\n\n                    return outputProperties;\n                }\n\n                function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {\n                    if (rootObject instanceof Array) {\n                        for (var i = 0; i < rootObject.length; i++)\n                            visitorCallback(i);\n\n                        // For arrays, also respect toJSON property for custom mappings (fixes #278)\n                        if (typeof rootObject['toJSON'] == 'function')\n                            visitorCallback('toJSON');\n                    } else {\n                        for (var propertyName in rootObject) {\n                            visitorCallback(propertyName);\n                        }\n                    }\n                };\n\n                function objectLookup() {\n                    this.keys = [];\n                    this.values = [];\n                };\n\n                objectLookup.prototype = {\n                    constructor: objectLookup,\n                    save: function(key, value) {\n                        var existingIndex = ko.utils.arrayIndexOf(this.keys, key);\n                        if (existingIndex >= 0)\n                            this.values[existingIndex] = value;\n                        else {\n                            this.keys.push(key);\n                            this.values.push(value);\n                        }\n                    },\n                    get: function(key) {\n                        var existingIndex = ko.utils.arrayIndexOf(this.keys, key);\n                        return (existingIndex >= 0) ? this.values[existingIndex] : undefined;\n                    }\n                };\n            })();\n\n            ko.exportSymbol('toJS', ko.toJS);\n            ko.exportSymbol('toJSON', ko.toJSON);\n            ko.when = function(predicate, callback, context) {\n                function kowhen (resolve) {\n                    var observable = ko.pureComputed(predicate, context).extend({notify:'always'});\n                    var subscription = observable.subscribe(function(value) {\n                        if (value) {\n                            subscription.dispose();\n                            resolve(value);\n                        }\n                    });\n                    // In case the initial value is true, process it right away\n                    observable['notifySubscribers'](observable.peek());\n\n                    return subscription;\n                }\n                if (typeof Promise === \"function\" && !callback) {\n                    return new Promise(kowhen);\n                } else {\n                    return kowhen(callback.bind(context));\n                }\n            };\n\n            ko.exportSymbol('when', ko.when);\n            (function () {\n                var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';\n\n                // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values\n                // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values\n                // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.\n                ko.selectExtensions = {\n                    readValue : function(element) {\n                        switch (ko.utils.tagNameLower(element)) {\n                            case 'option':\n                                if (element[hasDomDataExpandoProperty] === true)\n                                    return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);\n                                return ko.utils.ieVersion <= 7\n                                    ? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)\n                                    : element.value;\n                            case 'select':\n                                return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;\n                            default:\n                                return element.value;\n                        }\n                    },\n\n                    writeValue: function(element, value, allowUnset) {\n                        switch (ko.utils.tagNameLower(element)) {\n                            case 'option':\n                                if (typeof value === \"string\") {\n                                    ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);\n                                    if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node\n                                        delete element[hasDomDataExpandoProperty];\n                                    }\n                                    element.value = value;\n                                }\n                                else {\n                                    // Store arbitrary object using DomData\n                                    ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);\n                                    element[hasDomDataExpandoProperty] = true;\n\n                                    // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.\n                                    element.value = typeof value === \"number\" ? value : \"\";\n                                }\n                                break;\n                            case 'select':\n                                if (value === \"\" || value === null)       // A blank string or null value will select the caption\n                                    value = undefined;\n                                var selection = -1;\n                                for (var i = 0, n = element.options.length, optionValue; i < n; ++i) {\n                                    optionValue = ko.selectExtensions.readValue(element.options[i]);\n                                    // Include special check to handle selecting a caption with a blank string value\n                                    if (optionValue == value || (optionValue === \"\" && value === undefined)) {\n                                        selection = i;\n                                        break;\n                                    }\n                                }\n                                if (allowUnset || selection >= 0 || (value === undefined && element.size > 1)) {\n                                    element.selectedIndex = selection;\n                                    if (ko.utils.ieVersion === 6) {\n                                        // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread\n                                        // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread\n                                        // to apply the value as well.\n                                        ko.utils.setTimeout(function () {\n                                            element.selectedIndex = selection;\n                                        }, 0);\n                                    }\n                                }\n                                break;\n                            default:\n                                if ((value === null) || (value === undefined))\n                                    value = \"\";\n                                element.value = value;\n                                break;\n                        }\n                    }\n                };\n            })();\n\n            ko.exportSymbol('selectExtensions', ko.selectExtensions);\n            ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);\n            ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);\n            ko.expressionRewriting = (function () {\n                var javaScriptReservedWords = [\"true\", \"false\", \"null\", \"undefined\"];\n\n                // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor\n                // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).\n                // This also will not properly handle nested brackets (e.g., obj1[obj2['prop']]; see #911).\n                var javaScriptAssignmentTarget = /^(?:[$_a-z][$\\w]*|(.+)(\\.\\s*[$_a-z][$\\w]*|\\[.+\\]))$/i;\n\n                function getWriteableValue(expression) {\n                    if (ko.utils.arrayIndexOf(javaScriptReservedWords, expression) >= 0)\n                        return false;\n                    var match = expression.match(javaScriptAssignmentTarget);\n                    return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;\n                }\n\n                // The following regular expressions will be used to split an object-literal string into tokens\n\n                var specials = ',\"\\'`{}()/:[\\\\]',    // These characters have special meaning to the parser and must not appear in the middle of a token, except as part of a string.\n                    // Create the actual regular expression by or-ing the following regex strings. The order is important.\n                    bindingToken = RegExp([\n                        // These match strings, either with double quotes, single quotes, or backticks\n                        '\"(?:\\\\\\\\.|[^\"])*\"',\n                        \"'(?:\\\\\\\\.|[^'])*'\",\n                        \"`(?:\\\\\\\\.|[^`])*`\",\n                        // Match C style comments\n                        \"/\\\\*(?:[^*]|\\\\*+[^*/])*\\\\*+/\",\n                        // Match C++ style comments\n                        \"//.*\\n\",\n                        // Match a regular expression (text enclosed by slashes), but will also match sets of divisions\n                        // as a regular expression (this is handled by the parsing loop below).\n                        '/(?:\\\\\\\\.|[^/])+/\\w*',\n                        // Match text (at least two characters) that does not contain any of the above special characters,\n                        // although some of the special characters are allowed to start it (all but the colon and comma).\n                        // The text can contain spaces, but leading or trailing spaces are skipped.\n                        '[^\\\\s:,/][^' + specials + ']*[^\\\\s' + specials + ']',\n                        // Match any non-space character not matched already. This will match colons and commas, since they're\n                        // not matched by \"everyThingElse\", but will also match any other single character that wasn't already\n                        // matched (for example: in \"a: 1, b: 2\", each of the non-space characters will be matched by oneNotSpace).\n                        '[^\\\\s]'\n                    ].join('|'), 'g'),\n\n                    // Match end of previous token to determine whether a slash is a division or regex.\n                    divisionLookBehind = /[\\])\"'A-Za-z0-9_$]+$/,\n                    keywordRegexLookBehind = {'in':1,'return':1,'typeof':1};\n\n                function parseObjectLiteral(objectLiteralString) {\n                    // Trim leading and trailing spaces from the string\n                    var str = ko.utils.stringTrim(objectLiteralString);\n\n                    // Trim braces '{' surrounding the whole object literal\n                    if (str.charCodeAt(0) === 123) str = str.slice(1, -1);\n\n                    // Add a newline to correctly match a C++ style comment at the end of the string and\n                    // add a comma so that we don't need a separate code block to deal with the last item\n                    str += \"\\n,\";\n\n                    // Split into tokens\n                    var result = [], toks = str.match(bindingToken), key, values = [], depth = 0;\n\n                    if (toks.length > 1) {\n                        for (var i = 0, tok; tok = toks[i]; ++i) {\n                            var c = tok.charCodeAt(0);\n                            // A comma signals the end of a key/value pair if depth is zero\n                            if (c === 44) { // \",\"\n                                if (depth <= 0) {\n                                    result.push((key && values.length) ? {key: key, value: values.join('')} : {'unknown': key || values.join('')});\n                                    key = depth = 0;\n                                    values = [];\n                                    continue;\n                                }\n                                // Simply skip the colon that separates the name and value\n                            } else if (c === 58) { // \":\"\n                                if (!depth && !key && values.length === 1) {\n                                    key = values.pop();\n                                    continue;\n                                }\n                                // Comments: skip them\n                            } else if (c === 47 && tok.length > 1 && (tok.charCodeAt(1) === 47 || tok.charCodeAt(1) === 42)) {  // \"//\" or \"/*\"\n                                continue;\n                                // A set of slashes is initially matched as a regular expression, but could be division\n                            } else if (c === 47 && i && tok.length > 1) {  // \"/\"\n                                // Look at the end of the previous token to determine if the slash is actually division\n                                var match = toks[i-1].match(divisionLookBehind);\n                                if (match && !keywordRegexLookBehind[match[0]]) {\n                                    // The slash is actually a division punctuator; re-parse the remainder of the string (not including the slash)\n                                    str = str.substr(str.indexOf(tok) + 1);\n                                    toks = str.match(bindingToken);\n                                    i = -1;\n                                    // Continue with just the slash\n                                    tok = '/';\n                                }\n                                // Increment depth for parentheses, braces, and brackets so that interior commas are ignored\n                            } else if (c === 40 || c === 123 || c === 91) { // '(', '{', '['\n                                ++depth;\n                            } else if (c === 41 || c === 125 || c === 93) { // ')', '}', ']'\n                                --depth;\n                                // The key will be the first token; if it's a string, trim the quotes\n                            } else if (!key && !values.length && (c === 34 || c === 39)) { // '\"', \"'\"\n                                tok = tok.slice(1, -1);\n                            }\n                            values.push(tok);\n                        }\n                        if (depth > 0) {\n                            throw Error(\"Unbalanced parentheses, braces, or brackets\");\n                        }\n                    }\n                    return result;\n                }\n\n                // Two-way bindings include a write function that allow the handler to update the value even if it's not an observable.\n                var twoWayBindings = {};\n\n                function preProcessBindings(bindingsStringOrKeyValueArray, bindingOptions) {\n                    bindingOptions = bindingOptions || {};\n\n                    function processKeyValue(key, val) {\n                        var writableVal;\n                        function callPreprocessHook(obj) {\n                            return (obj && obj['preprocess']) ? (val = obj['preprocess'](val, key, processKeyValue)) : true;\n                        }\n                        if (!bindingParams) {\n                            if (!callPreprocessHook(ko['getBindingHandler'](key)))\n                                return;\n\n                            if (twoWayBindings[key] && (writableVal = getWriteableValue(val))) {\n                                // For two-way bindings, provide a write method in case the value\n                                // isn't a writable observable.\n                                var writeKey = typeof twoWayBindings[key] == 'string' ? twoWayBindings[key] : key;\n                                propertyAccessorResultStrings.push(\"'\" + writeKey + \"':function(_z){\" + writableVal + \"=_z}\");\n                            }\n                        }\n                        // Values are wrapped in a function so that each value can be accessed independently\n                        if (makeValueAccessors) {\n                            val = 'function(){return ' + val + ' }';\n                        }\n                        resultStrings.push(\"'\" + key + \"':\" + val);\n                    }\n\n                    var resultStrings = [],\n                        propertyAccessorResultStrings = [],\n                        makeValueAccessors = bindingOptions['valueAccessors'],\n                        bindingParams = bindingOptions['bindingParams'],\n                        keyValueArray = typeof bindingsStringOrKeyValueArray === \"string\" ?\n                            parseObjectLiteral(bindingsStringOrKeyValueArray) : bindingsStringOrKeyValueArray;\n\n                    ko.utils.arrayForEach(keyValueArray, function(keyValue) {\n                        processKeyValue(keyValue.key || keyValue['unknown'], keyValue.value);\n                    });\n\n                    if (propertyAccessorResultStrings.length)\n                        processKeyValue('_ko_property_writers', \"{\" + propertyAccessorResultStrings.join(\",\") + \" }\");\n\n                    return resultStrings.join(\",\");\n                }\n\n                return {\n                    bindingRewriteValidators: [],\n\n                    twoWayBindings: twoWayBindings,\n\n                    parseObjectLiteral: parseObjectLiteral,\n\n                    preProcessBindings: preProcessBindings,\n\n                    keyValueArrayContainsKey: function(keyValueArray, key) {\n                        for (var i = 0; i < keyValueArray.length; i++)\n                            if (keyValueArray[i]['key'] == key)\n                                return true;\n                        return false;\n                    },\n\n                    // Internal, private KO utility for updating model properties from within bindings\n                    // property:            If the property being updated is (or might be) an observable, pass it here\n                    //                      If it turns out to be a writable observable, it will be written to directly\n                    // allBindings:         An object with a get method to retrieve bindings in the current execution context.\n                    //                      This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable\n                    // key:                 The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'\n                    // value:               The value to be written\n                    // checkIfDifferent:    If true, and if the property being written is a writable observable, the value will only be written if\n                    //                      it is !== existing value on that writable observable\n                    writeValueToProperty: function(property, allBindings, key, value, checkIfDifferent) {\n                        if (!property || !ko.isObservable(property)) {\n                            var propWriters = allBindings.get('_ko_property_writers');\n                            if (propWriters && propWriters[key])\n                                propWriters[key](value);\n                        } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {\n                            property(value);\n                        }\n                    }\n                };\n            })();\n\n            ko.exportSymbol('expressionRewriting', ko.expressionRewriting);\n            ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);\n            ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);\n            ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);\n\n// Making bindings explicitly declare themselves as \"two way\" isn't ideal in the long term (it would be better if\n// all bindings could use an official 'property writer' API without needing to declare that they might). However,\n// since this is not, and has never been, a public API (_ko_property_writers was never documented), it's acceptable\n// as an internal implementation detail in the short term.\n// For those developers who rely on _ko_property_writers in their custom bindings, we expose _twoWayBindings as an\n// undocumented feature that makes it relatively easy to upgrade to KO 3.0. However, this is still not an official\n// public API, and we reserve the right to remove it at any time if we create a real public property writers API.\n            ko.exportSymbol('expressionRewriting._twoWayBindings', ko.expressionRewriting.twoWayBindings);\n\n// For backward compatibility, define the following aliases. (Previously, these function names were misleading because\n// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)\n            ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);\n            ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);\n            (function() {\n                // \"Virtual elements\" is an abstraction on top of the usual DOM API which understands the notion that comment nodes\n                // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).\n                // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state\n                // of that virtual hierarchy\n                //\n                // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)\n                // without having to scatter special cases all over the binding and templating code.\n\n                // IE 9 cannot reliably read the \"nodeValue\" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)\n                // but it does give them a nonstandard alternative property called \"text\" that it can read reliably. Other browsers don't have that property.\n                // So, use node.text where available, and node.nodeValue elsewhere\n                var commentNodesHaveTextProperty = document && document.createComment(\"test\").text === \"<!--test-->\";\n\n                var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\\s*ko(?:\\s+([\\s\\S]+))?\\s*-->$/ : /^\\s*ko(?:\\s+([\\s\\S]+))?\\s*$/;\n                var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\\s*\\/ko\\s*-->$/ : /^\\s*\\/ko\\s*$/;\n                var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };\n\n                function isStartComment(node) {\n                    return (node.nodeType == 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);\n                }\n\n                function isEndComment(node) {\n                    return (node.nodeType == 8) && endCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);\n                }\n\n                function isUnmatchedEndComment(node) {\n                    return isEndComment(node) && !(ko.utils.domData.get(node, matchedEndCommentDataKey));\n                }\n\n                var matchedEndCommentDataKey = \"__ko_matchedEndComment__\"\n\n                function getVirtualChildren(startComment, allowUnbalanced) {\n                    var currentNode = startComment;\n                    var depth = 1;\n                    var children = [];\n                    while (currentNode = currentNode.nextSibling) {\n                        if (isEndComment(currentNode)) {\n                            ko.utils.domData.set(currentNode, matchedEndCommentDataKey, true);\n                            depth--;\n                            if (depth === 0)\n                                return children;\n                        }\n\n                        children.push(currentNode);\n\n                        if (isStartComment(currentNode))\n                            depth++;\n                    }\n                    if (!allowUnbalanced)\n                        throw new Error(\"Cannot find closing comment tag to match: \" + startComment.nodeValue);\n                    return null;\n                }\n\n                function getMatchingEndComment(startComment, allowUnbalanced) {\n                    var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);\n                    if (allVirtualChildren) {\n                        if (allVirtualChildren.length > 0)\n                            return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;\n                        return startComment.nextSibling;\n                    } else\n                        return null; // Must have no matching end comment, and allowUnbalanced is true\n                }\n\n                function getUnbalancedChildTags(node) {\n                    // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>\n                    //       from <div>OK</div><!-- /ko --><!-- /ko -->,             returns: <!-- /ko --><!-- /ko -->\n                    var childNode = node.firstChild, captureRemaining = null;\n                    if (childNode) {\n                        do {\n                            if (captureRemaining)                   // We already hit an unbalanced node and are now just scooping up all subsequent nodes\n                                captureRemaining.push(childNode);\n                            else if (isStartComment(childNode)) {\n                                var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);\n                                if (matchingEndComment)             // It's a balanced tag, so skip immediately to the end of this virtual set\n                                    childNode = matchingEndComment;\n                                else\n                                    captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point\n                            } else if (isEndComment(childNode)) {\n                                captureRemaining = [childNode];     // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing\n                            }\n                        } while (childNode = childNode.nextSibling);\n                    }\n                    return captureRemaining;\n                }\n\n                ko.virtualElements = {\n                    allowedBindings: {},\n\n                    childNodes: function(node) {\n                        return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;\n                    },\n\n                    emptyNode: function(node) {\n                        if (!isStartComment(node))\n                            ko.utils.emptyDomNode(node);\n                        else {\n                            var virtualChildren = ko.virtualElements.childNodes(node);\n                            for (var i = 0, j = virtualChildren.length; i < j; i++)\n                                ko.removeNode(virtualChildren[i]);\n                        }\n                    },\n\n                    setDomNodeChildren: function(node, childNodes) {\n                        if (!isStartComment(node))\n                            ko.utils.setDomNodeChildren(node, childNodes);\n                        else {\n                            ko.virtualElements.emptyNode(node);\n                            var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children\n                            for (var i = 0, j = childNodes.length; i < j; i++)\n                                endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);\n                        }\n                    },\n\n                    prepend: function(containerNode, nodeToPrepend) {\n                        var insertBeforeNode;\n\n                        if (isStartComment(containerNode)) {\n                            // Start comments must always have a parent and at least one following sibling (the end comment)\n                            insertBeforeNode = containerNode.nextSibling;\n                            containerNode = containerNode.parentNode;\n                        } else {\n                            insertBeforeNode = containerNode.firstChild;\n                        }\n\n                        if (!insertBeforeNode) {\n                            containerNode.appendChild(nodeToPrepend);\n                        } else if (nodeToPrepend !== insertBeforeNode) {       // IE will sometimes crash if you try to insert a node before itself\n                            containerNode.insertBefore(nodeToPrepend, insertBeforeNode);\n                        }\n                    },\n\n                    insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {\n                        if (!insertAfterNode) {\n                            ko.virtualElements.prepend(containerNode, nodeToInsert);\n                        } else {\n                            // Children of start comments must always have a parent and at least one following sibling (the end comment)\n                            var insertBeforeNode = insertAfterNode.nextSibling;\n\n                            if (isStartComment(containerNode)) {\n                                containerNode = containerNode.parentNode;\n                            }\n\n                            if (!insertBeforeNode) {\n                                containerNode.appendChild(nodeToInsert);\n                            } else if (nodeToInsert !== insertBeforeNode) {       // IE will sometimes crash if you try to insert a node before itself\n                                containerNode.insertBefore(nodeToInsert, insertBeforeNode);\n                            }\n                        }\n                    },\n\n                    firstChild: function(node) {\n                        if (!isStartComment(node)) {\n                            if (node.firstChild && isEndComment(node.firstChild)) {\n                                throw new Error(\"Found invalid end comment, as the first child of \" + node);\n                            }\n                            return node.firstChild;\n                        } else if (!node.nextSibling || isEndComment(node.nextSibling)) {\n                            return null;\n                        } else {\n                            return node.nextSibling;\n                        }\n                    },\n\n                    nextSibling: function(node) {\n                        if (isStartComment(node)) {\n                            node = getMatchingEndComment(node);\n                        }\n\n                        if (node.nextSibling && isEndComment(node.nextSibling)) {\n                            if (isUnmatchedEndComment(node.nextSibling)) {\n                                throw Error(\"Found end comment without a matching opening comment, as child of \" + node);\n                            } else {\n                                return null;\n                            }\n                        } else {\n                            return node.nextSibling;\n                        }\n                    },\n\n                    hasBindingValue: isStartComment,\n\n                    virtualNodeBindingValue: function(node) {\n                        var regexMatch = (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);\n                        return regexMatch ? regexMatch[1] : null;\n                    },\n\n                    normaliseVirtualElementDomStructure: function(elementVerified) {\n                        // Workaround for https://github.com/SteveSanderson/knockout/issues/155\n                        // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes\n                        // that are direct descendants of <ul> into the preceding <li>)\n                        if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])\n                            return;\n\n                        // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags\n                        // must be intended to appear *after* that child, so move them there.\n                        var childNode = elementVerified.firstChild;\n                        if (childNode) {\n                            do {\n                                if (childNode.nodeType === 1) {\n                                    var unbalancedTags = getUnbalancedChildTags(childNode);\n                                    if (unbalancedTags) {\n                                        // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child\n                                        var nodeToInsertBefore = childNode.nextSibling;\n                                        for (var i = 0; i < unbalancedTags.length; i++) {\n                                            if (nodeToInsertBefore)\n                                                elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);\n                                            else\n                                                elementVerified.appendChild(unbalancedTags[i]);\n                                        }\n                                    }\n                                }\n                            } while (childNode = childNode.nextSibling);\n                        }\n                    }\n                };\n            })();\n            ko.exportSymbol('virtualElements', ko.virtualElements);\n            ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);\n            ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);\n//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild);     // firstChild is not minified\n            ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);\n//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling);   // nextSibling is not minified\n            ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);\n            ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);\n            (function() {\n                var defaultBindingAttributeName = \"data-bind\";\n\n                ko.bindingProvider = function() {\n                    this.bindingCache = {};\n                };\n\n                ko.utils.extend(ko.bindingProvider.prototype, {\n                    'nodeHasBindings': function(node) {\n                        switch (node.nodeType) {\n                            case 1: // Element\n                                return node.getAttribute(defaultBindingAttributeName) != null\n                                    || ko.components['getComponentNameForNode'](node);\n                            case 8: // Comment node\n                                return ko.virtualElements.hasBindingValue(node);\n                            default: return false;\n                        }\n                    },\n\n                    'getBindings': function(node, bindingContext) {\n                        var bindingsString = this['getBindingsString'](node, bindingContext),\n                            parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;\n                        return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ false);\n                    },\n\n                    'getBindingAccessors': function(node, bindingContext) {\n                        var bindingsString = this['getBindingsString'](node, bindingContext),\n                            parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node, { 'valueAccessors': true }) : null;\n                        return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ true);\n                    },\n\n                    // The following function is only used internally by this default provider.\n                    // It's not part of the interface definition for a general binding provider.\n                    'getBindingsString': function(node, bindingContext) {\n                        switch (node.nodeType) {\n                            case 1: return node.getAttribute(defaultBindingAttributeName);   // Element\n                            case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node\n                            default: return null;\n                        }\n                    },\n\n                    // The following function is only used internally by this default provider.\n                    // It's not part of the interface definition for a general binding provider.\n                    'parseBindingsString': function(bindingsString, bindingContext, node, options) {\n                        try {\n                            var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache, options);\n                            return bindingFunction(bindingContext, node);\n                        } catch (ex) {\n                            ex.message = \"Unable to parse bindings.\\nBindings value: \" + bindingsString + \"\\nMessage: \" + ex.message;\n                            throw ex;\n                        }\n                    }\n                });\n\n                ko.bindingProvider['instance'] = new ko.bindingProvider();\n\n                function createBindingsStringEvaluatorViaCache(bindingsString, cache, options) {\n                    var cacheKey = bindingsString + (options && options['valueAccessors'] || '');\n                    return cache[cacheKey]\n                        || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString, options));\n                }\n\n                function createBindingsStringEvaluator(bindingsString, options) {\n                    // Build the source for a function that evaluates \"expression\"\n                    // For each scope variable, add an extra level of \"with\" nesting\n                    // Example result: with(sc1) { with(sc0) { return (expression) } }\n                    var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString, options),\n                        functionBody = \"with($context){with($data||{}){return{\" + rewrittenBindings + \"}}}\";\n                    return new Function(\"$context\", \"$element\", functionBody);\n                }\n            })();\n\n            ko.exportSymbol('bindingProvider', ko.bindingProvider);\n            (function () {\n                // Hide or don't minify context properties, see https://github.com/knockout/knockout/issues/2294\n                var contextSubscribable = ko.utils.createSymbolOrString('_subscribable');\n                var contextAncestorBindingInfo = ko.utils.createSymbolOrString('_ancestorBindingInfo');\n                var contextDataDependency = ko.utils.createSymbolOrString('_dataDependency');\n\n                ko.bindingHandlers = {};\n\n                // The following element types will not be recursed into during binding.\n                var bindingDoesNotRecurseIntoElementTypes = {\n                    // Don't want bindings that operate on text nodes to mutate <script> and <textarea> contents,\n                    // because it's unexpected and a potential XSS issue.\n                    // Also bindings should not operate on <template> elements since this breaks in Internet Explorer\n                    // and because such elements' contents are always intended to be bound in a different context\n                    // from where they appear in the document.\n                    'script': true,\n                    'textarea': true,\n                    'template': true\n                };\n\n                // Use an overridable method for retrieving binding handlers so that plugins may support dynamically created handlers\n                ko['getBindingHandler'] = function(bindingKey) {\n                    return ko.bindingHandlers[bindingKey];\n                };\n\n                var inheritParentVm = {};\n\n                // The ko.bindingContext constructor is only called directly to create the root context. For child\n                // contexts, use bindingContext.createChildContext or bindingContext.extend.\n                ko.bindingContext = function(dataItemOrAccessor, parentContext, dataItemAlias, extendCallback, options) {\n\n                    // The binding context object includes static properties for the current, parent, and root view models.\n                    // If a view model is actually stored in an observable, the corresponding binding context object, and\n                    // any child contexts, must be updated when the view model is changed.\n                    function updateContext() {\n                        // Most of the time, the context will directly get a view model object, but if a function is given,\n                        // we call the function to retrieve the view model. If the function accesses any observables or returns\n                        // an observable, the dependency is tracked, and those observables can later cause the binding\n                        // context to be updated.\n                        var dataItemOrObservable = isFunc ? realDataItemOrAccessor() : realDataItemOrAccessor,\n                            dataItem = ko.utils.unwrapObservable(dataItemOrObservable);\n\n                        if (parentContext) {\n                            // Copy $root and any custom properties from the parent context\n                            ko.utils.extend(self, parentContext);\n\n                            // Copy Symbol properties\n                            if (contextAncestorBindingInfo in parentContext) {\n                                self[contextAncestorBindingInfo] = parentContext[contextAncestorBindingInfo];\n                            }\n                        } else {\n                            self['$parents'] = [];\n                            self['$root'] = dataItem;\n\n                            // Export 'ko' in the binding context so it will be available in bindings and templates\n                            // even if 'ko' isn't exported as a global, such as when using an AMD loader.\n                            // See https://github.com/SteveSanderson/knockout/issues/490\n                            self['ko'] = ko;\n                        }\n\n                        self[contextSubscribable] = subscribable;\n\n                        if (shouldInheritData) {\n                            dataItem = self['$data'];\n                        } else {\n                            self['$rawData'] = dataItemOrObservable;\n                            self['$data'] = dataItem;\n                        }\n\n                        if (dataItemAlias)\n                            self[dataItemAlias] = dataItem;\n\n                        // The extendCallback function is provided when creating a child context or extending a context.\n                        // It handles the specific actions needed to finish setting up the binding context. Actions in this\n                        // function could also add dependencies to this binding context.\n                        if (extendCallback)\n                            extendCallback(self, parentContext, dataItem);\n\n                        // When a \"parent\" context is given and we don't already have a dependency on its context, register a dependency on it.\n                        // Thus whenever the parent context is updated, this context will also be updated.\n                        if (parentContext && parentContext[contextSubscribable] && !ko.computedContext.computed().hasAncestorDependency(parentContext[contextSubscribable])) {\n                            parentContext[contextSubscribable]();\n                        }\n\n                        if (dataDependency) {\n                            self[contextDataDependency] = dataDependency;\n                        }\n\n                        return self['$data'];\n                    }\n\n                    var self = this,\n                        shouldInheritData = dataItemOrAccessor === inheritParentVm,\n                        realDataItemOrAccessor = shouldInheritData ? undefined : dataItemOrAccessor,\n                        isFunc = typeof(realDataItemOrAccessor) == \"function\" && !ko.isObservable(realDataItemOrAccessor),\n                        nodes,\n                        subscribable,\n                        dataDependency = options && options['dataDependency'];\n\n                    if (options && options['exportDependencies']) {\n                        // The \"exportDependencies\" option means that the calling code will track any dependencies and re-create\n                        // the binding context when they change.\n                        updateContext();\n                    } else {\n                        subscribable = ko.pureComputed(updateContext);\n                        subscribable.peek();\n\n                        // At this point, the binding context has been initialized, and the \"subscribable\" computed observable is\n                        // subscribed to any observables that were accessed in the process. If there is nothing to track, the\n                        // computed will be inactive, and we can safely throw it away. If it's active, the computed is stored in\n                        // the context object.\n                        if (subscribable.isActive()) {\n                            // Always notify because even if the model ($data) hasn't changed, other context properties might have changed\n                            subscribable['equalityComparer'] = null;\n                        } else {\n                            self[contextSubscribable] = undefined;\n                        }\n                    }\n                }\n\n                // Extend the binding context hierarchy with a new view model object. If the parent context is watching\n                // any observables, the new child context will automatically get a dependency on the parent context.\n                // But this does not mean that the $data value of the child context will also get updated. If the child\n                // view model also depends on the parent view model, you must provide a function that returns the correct\n                // view model on each update.\n                ko.bindingContext.prototype['createChildContext'] = function (dataItemOrAccessor, dataItemAlias, extendCallback, options) {\n                    if (!options && dataItemAlias && typeof dataItemAlias == \"object\") {\n                        options = dataItemAlias;\n                        dataItemAlias = options['as'];\n                        extendCallback = options['extend'];\n                    }\n\n                    if (dataItemAlias && options && options['noChildContext']) {\n                        var isFunc = typeof(dataItemOrAccessor) == \"function\" && !ko.isObservable(dataItemOrAccessor);\n                        return new ko.bindingContext(inheritParentVm, this, null, function (self) {\n                            if (extendCallback)\n                                extendCallback(self);\n                            self[dataItemAlias] = isFunc ? dataItemOrAccessor() : dataItemOrAccessor;\n                        }, options);\n                    }\n\n                    return new ko.bindingContext(dataItemOrAccessor, this, dataItemAlias, function (self, parentContext) {\n                        // Extend the context hierarchy by setting the appropriate pointers\n                        self['$parentContext'] = parentContext;\n                        self['$parent'] = parentContext['$data'];\n                        self['$parents'] = (parentContext['$parents'] || []).slice(0);\n                        self['$parents'].unshift(self['$parent']);\n                        if (extendCallback)\n                            extendCallback(self);\n                    }, options);\n                };\n\n                // Extend the binding context with new custom properties. This doesn't change the context hierarchy.\n                // Similarly to \"child\" contexts, provide a function here to make sure that the correct values are set\n                // when an observable view model is updated.\n                ko.bindingContext.prototype['extend'] = function(properties, options) {\n                    return new ko.bindingContext(inheritParentVm, this, null, function(self, parentContext) {\n                        ko.utils.extend(self, typeof(properties) == \"function\" ? properties(self) : properties);\n                    }, options);\n                };\n\n                var boundElementDomDataKey = ko.utils.domData.nextKey();\n\n                function asyncContextDispose(node) {\n                    var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey),\n                        asyncContext = bindingInfo && bindingInfo.asyncContext;\n                    if (asyncContext) {\n                        bindingInfo.asyncContext = null;\n                        asyncContext.notifyAncestor();\n                    }\n                }\n                function AsyncCompleteContext(node, bindingInfo, ancestorBindingInfo) {\n                    this.node = node;\n                    this.bindingInfo = bindingInfo;\n                    this.asyncDescendants = [];\n                    this.childrenComplete = false;\n\n                    if (!bindingInfo.asyncContext) {\n                        ko.utils.domNodeDisposal.addDisposeCallback(node, asyncContextDispose);\n                    }\n\n                    if (ancestorBindingInfo && ancestorBindingInfo.asyncContext) {\n                        ancestorBindingInfo.asyncContext.asyncDescendants.push(node);\n                        this.ancestorBindingInfo = ancestorBindingInfo;\n                    }\n                }\n                AsyncCompleteContext.prototype.notifyAncestor = function () {\n                    if (this.ancestorBindingInfo && this.ancestorBindingInfo.asyncContext) {\n                        this.ancestorBindingInfo.asyncContext.descendantComplete(this.node);\n                    }\n                };\n                AsyncCompleteContext.prototype.descendantComplete = function (node) {\n                    ko.utils.arrayRemoveItem(this.asyncDescendants, node);\n                    if (!this.asyncDescendants.length && this.childrenComplete) {\n                        this.completeChildren();\n                    }\n                };\n                AsyncCompleteContext.prototype.completeChildren = function () {\n                    this.childrenComplete = true;\n                    if (this.bindingInfo.asyncContext && !this.asyncDescendants.length) {\n                        this.bindingInfo.asyncContext = null;\n                        ko.utils.domNodeDisposal.removeDisposeCallback(this.node, asyncContextDispose);\n                        ko.bindingEvent.notify(this.node, ko.bindingEvent.descendantsComplete);\n                        this.notifyAncestor();\n                    }\n                };\n\n                ko.bindingEvent = {\n                    childrenComplete: \"childrenComplete\",\n                    descendantsComplete : \"descendantsComplete\",\n\n                    subscribe: function (node, event, callback, context, options) {\n                        var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});\n                        if (!bindingInfo.eventSubscribable) {\n                            bindingInfo.eventSubscribable = new ko.subscribable;\n                        }\n                        if (options && options['notifyImmediately'] && bindingInfo.notifiedEvents[event]) {\n                            ko.dependencyDetection.ignore(callback, context, [node]);\n                        }\n                        return bindingInfo.eventSubscribable.subscribe(callback, context, event);\n                    },\n\n                    notify: function (node, event) {\n                        var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey);\n                        if (bindingInfo) {\n                            bindingInfo.notifiedEvents[event] = true;\n                            if (bindingInfo.eventSubscribable) {\n                                bindingInfo.eventSubscribable['notifySubscribers'](node, event);\n                            }\n                            if (event == ko.bindingEvent.childrenComplete) {\n                                if (bindingInfo.asyncContext) {\n                                    bindingInfo.asyncContext.completeChildren();\n                                } else if (bindingInfo.asyncContext === undefined && bindingInfo.eventSubscribable && bindingInfo.eventSubscribable.hasSubscriptionsForEvent(ko.bindingEvent.descendantsComplete)) {\n                                    // It's currently an error to register a descendantsComplete handler for a node that was never registered as completing asynchronously.\n                                    // That's because without the asyncContext, we don't have a way to know that all descendants have completed.\n                                    throw new Error(\"descendantsComplete event not supported for bindings on this node\");\n                                }\n                            }\n                        }\n                    },\n\n                    startPossiblyAsyncContentBinding: function (node, bindingContext) {\n                        var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});\n\n                        if (!bindingInfo.asyncContext) {\n                            bindingInfo.asyncContext = new AsyncCompleteContext(node, bindingInfo, bindingContext[contextAncestorBindingInfo]);\n                        }\n\n                        // If the provided context was already extended with this node's binding info, just return the extended context\n                        if (bindingContext[contextAncestorBindingInfo] == bindingInfo) {\n                            return bindingContext;\n                        }\n\n                        return bindingContext['extend'](function (ctx) {\n                            ctx[contextAncestorBindingInfo] = bindingInfo;\n                        });\n                    }\n                };\n\n                // Returns the valueAccessor function for a binding value\n                function makeValueAccessor(value) {\n                    return function() {\n                        return value;\n                    };\n                }\n\n                // Returns the value of a valueAccessor function\n                function evaluateValueAccessor(valueAccessor) {\n                    return valueAccessor();\n                }\n\n                // Given a function that returns bindings, create and return a new object that contains\n                // binding value-accessors functions. Each accessor function calls the original function\n                // so that it always gets the latest value and all dependencies are captured. This is used\n                // by ko.applyBindingsToNode and getBindingsAndMakeAccessors.\n                function makeAccessorsFromFunction(callback) {\n                    return ko.utils.objectMap(ko.dependencyDetection.ignore(callback), function(value, key) {\n                        return function() {\n                            return callback()[key];\n                        };\n                    });\n                }\n\n                // Given a bindings function or object, create and return a new object that contains\n                // binding value-accessors functions. This is used by ko.applyBindingsToNode.\n                function makeBindingAccessors(bindings, context, node) {\n                    if (typeof bindings === 'function') {\n                        return makeAccessorsFromFunction(bindings.bind(null, context, node));\n                    } else {\n                        return ko.utils.objectMap(bindings, makeValueAccessor);\n                    }\n                }\n\n                // This function is used if the binding provider doesn't include a getBindingAccessors function.\n                // It must be called with 'this' set to the provider instance.\n                function getBindingsAndMakeAccessors(node, context) {\n                    return makeAccessorsFromFunction(this['getBindings'].bind(this, node, context));\n                }\n\n                function validateThatBindingIsAllowedForVirtualElements(bindingName) {\n                    var validator = ko.virtualElements.allowedBindings[bindingName];\n                    if (!validator)\n                        throw new Error(\"The binding '\" + bindingName + \"' cannot be used with virtual elements\")\n                }\n\n                function applyBindingsToDescendantsInternal(bindingContext, elementOrVirtualElement) {\n                    var nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);\n\n                    if (nextInQueue) {\n                        var currentChild,\n                            provider = ko.bindingProvider['instance'],\n                            preprocessNode = provider['preprocessNode'];\n\n                        // Preprocessing allows a binding provider to mutate a node before bindings are applied to it. For example it's\n                        // possible to insert new siblings after it, and/or replace the node with a different one. This can be used to\n                        // implement custom binding syntaxes, such as {{ value }} for string interpolation, or custom element types that\n                        // trigger insertion of <template> contents at that point in the document.\n                        if (preprocessNode) {\n                            while (currentChild = nextInQueue) {\n                                nextInQueue = ko.virtualElements.nextSibling(currentChild);\n                                preprocessNode.call(provider, currentChild);\n                            }\n                            // Reset nextInQueue for the next loop\n                            nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);\n                        }\n\n                        while (currentChild = nextInQueue) {\n                            // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position\n                            nextInQueue = ko.virtualElements.nextSibling(currentChild);\n                            applyBindingsToNodeAndDescendantsInternal(bindingContext, currentChild);\n                        }\n                    }\n                    ko.bindingEvent.notify(elementOrVirtualElement, ko.bindingEvent.childrenComplete);\n                }\n\n                function applyBindingsToNodeAndDescendantsInternal(bindingContext, nodeVerified) {\n                    var bindingContextForDescendants = bindingContext;\n\n                    var isElement = (nodeVerified.nodeType === 1);\n                    if (isElement) // Workaround IE <= 8 HTML parsing weirdness\n                        ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);\n\n                    // Perf optimisation: Apply bindings only if...\n                    // (1) We need to store the binding info for the node (all element nodes)\n                    // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)\n                    var shouldApplyBindings = isElement || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);\n                    if (shouldApplyBindings)\n                        bindingContextForDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext)['bindingContextForDescendants'];\n\n                    if (bindingContextForDescendants && !bindingDoesNotRecurseIntoElementTypes[ko.utils.tagNameLower(nodeVerified)]) {\n                        applyBindingsToDescendantsInternal(bindingContextForDescendants, nodeVerified);\n                    }\n                }\n\n                function topologicalSortBindings(bindings) {\n                    // Depth-first sort\n                    var result = [],                // The list of key/handler pairs that we will return\n                        bindingsConsidered = {},    // A temporary record of which bindings are already in 'result'\n                        cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it\n                    ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {\n                        if (!bindingsConsidered[bindingKey]) {\n                            var binding = ko['getBindingHandler'](bindingKey);\n                            if (binding) {\n                                // First add dependencies (if any) of the current binding\n                                if (binding['after']) {\n                                    cyclicDependencyStack.push(bindingKey);\n                                    ko.utils.arrayForEach(binding['after'], function(bindingDependencyKey) {\n                                        if (bindings[bindingDependencyKey]) {\n                                            if (ko.utils.arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {\n                                                throw Error(\"Cannot combine the following bindings, because they have a cyclic dependency: \" + cyclicDependencyStack.join(\", \"));\n                                            } else {\n                                                pushBinding(bindingDependencyKey);\n                                            }\n                                        }\n                                    });\n                                    cyclicDependencyStack.length--;\n                                }\n                                // Next add the current binding\n                                result.push({ key: bindingKey, handler: binding });\n                            }\n                            bindingsConsidered[bindingKey] = true;\n                        }\n                    });\n\n                    return result;\n                }\n\n                function applyBindingsToNodeInternal(node, sourceBindings, bindingContext) {\n                    var bindingInfo = ko.utils.domData.getOrSet(node, boundElementDomDataKey, {});\n\n                    // Prevent multiple applyBindings calls for the same node, except when a binding value is specified\n                    var alreadyBound = bindingInfo.alreadyBound;\n                    if (!sourceBindings) {\n                        if (alreadyBound) {\n                            throw Error(\"You cannot apply bindings multiple times to the same element.\");\n                        }\n                        bindingInfo.alreadyBound = true;\n                    }\n                    if (!alreadyBound) {\n                        bindingInfo.context = bindingContext;\n                    }\n                    if (!bindingInfo.notifiedEvents) {\n                        bindingInfo.notifiedEvents = {};\n                    }\n\n                    // Use bindings if given, otherwise fall back on asking the bindings provider to give us some bindings\n                    var bindings;\n                    if (sourceBindings && typeof sourceBindings !== 'function') {\n                        bindings = sourceBindings;\n                    } else {\n                        var provider = ko.bindingProvider['instance'],\n                            getBindings = provider['getBindingAccessors'] || getBindingsAndMakeAccessors;\n\n                        // Get the binding from the provider within a computed observable so that we can update the bindings whenever\n                        // the binding context is updated or if the binding provider accesses observables.\n                        var bindingsUpdater = ko.dependentObservable(\n                            function() {\n                                bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext);\n                                // Register a dependency on the binding context to support observable view models.\n                                if (bindings) {\n                                    if (bindingContext[contextSubscribable]) {\n                                        bindingContext[contextSubscribable]();\n                                    }\n                                    if (bindingContext[contextDataDependency]) {\n                                        bindingContext[contextDataDependency]();\n                                    }\n                                }\n                                return bindings;\n                            },\n                            null, { disposeWhenNodeIsRemoved: node }\n                        );\n\n                        if (!bindings || !bindingsUpdater.isActive())\n                            bindingsUpdater = null;\n                    }\n\n                    var contextToExtend = bindingContext;\n                    var bindingHandlerThatControlsDescendantBindings;\n                    if (bindings) {\n                        // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding\n                        // context update), just return the value accessor from the binding. Otherwise, return a function that always gets\n                        // the latest binding value and registers a dependency on the binding updater.\n                        var getValueAccessor = bindingsUpdater\n                            ? function(bindingKey) {\n                                return function() {\n                                    return evaluateValueAccessor(bindingsUpdater()[bindingKey]);\n                                };\n                            } : function(bindingKey) {\n                                return bindings[bindingKey];\n                            };\n\n                        // Use of allBindings as a function is maintained for backwards compatibility, but its use is deprecated\n                        function allBindings() {\n                            return ko.utils.objectMap(bindingsUpdater ? bindingsUpdater() : bindings, evaluateValueAccessor);\n                        }\n                        // The following is the 3.x allBindings API\n                        allBindings['get'] = function(key) {\n                            return bindings[key] && evaluateValueAccessor(getValueAccessor(key));\n                        };\n                        allBindings['has'] = function(key) {\n                            return key in bindings;\n                        };\n\n                        if (ko.bindingEvent.childrenComplete in bindings) {\n                            ko.bindingEvent.subscribe(node, ko.bindingEvent.childrenComplete, function () {\n                                var callback = evaluateValueAccessor(bindings[ko.bindingEvent.childrenComplete]);\n                                if (callback) {\n                                    var nodes = ko.virtualElements.childNodes(node);\n                                    if (nodes.length) {\n                                        callback(nodes, ko.dataFor(nodes[0]));\n                                    }\n                                }\n                            });\n                        }\n\n                        if (ko.bindingEvent.descendantsComplete in bindings) {\n                            contextToExtend = ko.bindingEvent.startPossiblyAsyncContentBinding(node, bindingContext);\n                            ko.bindingEvent.subscribe(node, ko.bindingEvent.descendantsComplete, function () {\n                                var callback = evaluateValueAccessor(bindings[ko.bindingEvent.descendantsComplete]);\n                                if (callback && ko.virtualElements.firstChild(node)) {\n                                    callback(node);\n                                }\n                            });\n                        }\n\n                        // First put the bindings into the right order\n                        var orderedBindings = topologicalSortBindings(bindings);\n\n                        // Go through the sorted bindings, calling init and update for each\n                        ko.utils.arrayForEach(orderedBindings, function(bindingKeyAndHandler) {\n                            // Note that topologicalSortBindings has already filtered out any nonexistent binding handlers,\n                            // so bindingKeyAndHandler.handler will always be nonnull.\n                            var handlerInitFn = bindingKeyAndHandler.handler[\"init\"],\n                                handlerUpdateFn = bindingKeyAndHandler.handler[\"update\"],\n                                bindingKey = bindingKeyAndHandler.key;\n\n                            if (node.nodeType === 8) {\n                                validateThatBindingIsAllowedForVirtualElements(bindingKey);\n                            }\n\n                            try {\n                                // Run init, ignoring any dependencies\n                                if (typeof handlerInitFn == \"function\") {\n                                    ko.dependencyDetection.ignore(function() {\n                                        var initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend);\n\n                                        // If this binding handler claims to control descendant bindings, make a note of this\n                                        if (initResult && initResult['controlsDescendantBindings']) {\n                                            if (bindingHandlerThatControlsDescendantBindings !== undefined)\n                                                throw new Error(\"Multiple bindings (\" + bindingHandlerThatControlsDescendantBindings + \" and \" + bindingKey + \") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.\");\n                                            bindingHandlerThatControlsDescendantBindings = bindingKey;\n                                        }\n                                    });\n                                }\n\n                                // Run update in its own computed wrapper\n                                if (typeof handlerUpdateFn == \"function\") {\n                                    ko.dependentObservable(\n                                        function() {\n                                            handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend['$data'], contextToExtend);\n                                        },\n                                        null,\n                                        { disposeWhenNodeIsRemoved: node }\n                                    );\n                                }\n                            } catch (ex) {\n                                ex.message = \"Unable to process binding \\\"\" + bindingKey + \": \" + bindings[bindingKey] + \"\\\"\\nMessage: \" + ex.message;\n                                throw ex;\n                            }\n                        });\n                    }\n\n                    var shouldBindDescendants = bindingHandlerThatControlsDescendantBindings === undefined;\n                    return {\n                        'shouldBindDescendants': shouldBindDescendants,\n                        'bindingContextForDescendants': shouldBindDescendants && contextToExtend\n                    };\n                };\n\n                ko.storedBindingContextForNode = function (node) {\n                    var bindingInfo = ko.utils.domData.get(node, boundElementDomDataKey);\n                    return bindingInfo && bindingInfo.context;\n                }\n\n                function getBindingContext(viewModelOrBindingContext, extendContextCallback) {\n                    return viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)\n                        ? viewModelOrBindingContext\n                        : new ko.bindingContext(viewModelOrBindingContext, undefined, undefined, extendContextCallback);\n                }\n\n                ko.applyBindingAccessorsToNode = function (node, bindings, viewModelOrBindingContext) {\n                    if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness\n                        ko.virtualElements.normaliseVirtualElementDomStructure(node);\n                    return applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext));\n                };\n\n                ko.applyBindingsToNode = function (node, bindings, viewModelOrBindingContext) {\n                    var context = getBindingContext(viewModelOrBindingContext);\n                    return ko.applyBindingAccessorsToNode(node, makeBindingAccessors(bindings, context, node), context);\n                };\n\n                ko.applyBindingsToDescendants = function(viewModelOrBindingContext, rootNode) {\n                    if (rootNode.nodeType === 1 || rootNode.nodeType === 8)\n                        applyBindingsToDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode);\n                };\n\n                ko.applyBindings = function (viewModelOrBindingContext, rootNode, extendContextCallback) {\n                    // If jQuery is loaded after Knockout, we won't initially have access to it. So save it here.\n                    if (!jQueryInstance && window['jQuery']) {\n                        jQueryInstance = window['jQuery'];\n                    }\n\n                    if (arguments.length < 2) {\n                        rootNode = document.body;\n                        if (!rootNode) {\n                            throw Error(\"ko.applyBindings: could not find document.body; has the document been loaded?\");\n                        }\n                    } else if (!rootNode || (rootNode.nodeType !== 1 && rootNode.nodeType !== 8)) {\n                        throw Error(\"ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node\");\n                    }\n\n                    applyBindingsToNodeAndDescendantsInternal(getBindingContext(viewModelOrBindingContext, extendContextCallback), rootNode);\n                };\n\n                // Retrieving binding context from arbitrary nodes\n                ko.contextFor = function(node) {\n                    // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)\n                    if (node && (node.nodeType === 1 || node.nodeType === 8)) {\n                        return ko.storedBindingContextForNode(node);\n                    }\n                    return undefined;\n                };\n                ko.dataFor = function(node) {\n                    var context = ko.contextFor(node);\n                    return context ? context['$data'] : undefined;\n                };\n\n                ko.exportSymbol('bindingHandlers', ko.bindingHandlers);\n                ko.exportSymbol('bindingEvent', ko.bindingEvent);\n                ko.exportSymbol('bindingEvent.subscribe', ko.bindingEvent.subscribe);\n                ko.exportSymbol('bindingEvent.startPossiblyAsyncContentBinding', ko.bindingEvent.startPossiblyAsyncContentBinding);\n                ko.exportSymbol('applyBindings', ko.applyBindings);\n                ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);\n                ko.exportSymbol('applyBindingAccessorsToNode', ko.applyBindingAccessorsToNode);\n                ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);\n                ko.exportSymbol('contextFor', ko.contextFor);\n                ko.exportSymbol('dataFor', ko.dataFor);\n            })();\n            (function(undefined) {\n                var loadingSubscribablesCache = {}, // Tracks component loads that are currently in flight\n                    loadedDefinitionsCache = {};    // Tracks component loads that have already completed\n\n                ko.components = {\n                    get: function(componentName, callback) {\n                        var cachedDefinition = getObjectOwnProperty(loadedDefinitionsCache, componentName);\n                        if (cachedDefinition) {\n                            // It's already loaded and cached. Reuse the same definition object.\n                            // Note that for API consistency, even cache hits complete asynchronously by default.\n                            // You can bypass this by putting synchronous:true on your component config.\n                            if (cachedDefinition.isSynchronousComponent) {\n                                ko.dependencyDetection.ignore(function() { // See comment in loaderRegistryBehaviors.js for reasoning\n                                    callback(cachedDefinition.definition);\n                                });\n                            } else {\n                                ko.tasks.schedule(function() { callback(cachedDefinition.definition); });\n                            }\n                        } else {\n                            // Join the loading process that is already underway, or start a new one.\n                            loadComponentAndNotify(componentName, callback);\n                        }\n                    },\n\n                    clearCachedDefinition: function(componentName) {\n                        delete loadedDefinitionsCache[componentName];\n                    },\n\n                    _getFirstResultFromLoaders: getFirstResultFromLoaders\n                };\n\n                function getObjectOwnProperty(obj, propName) {\n                    return Object.prototype.hasOwnProperty.call(obj, propName) ? obj[propName] : undefined;\n                }\n\n                function loadComponentAndNotify(componentName, callback) {\n                    var subscribable = getObjectOwnProperty(loadingSubscribablesCache, componentName),\n                        completedAsync;\n                    if (!subscribable) {\n                        // It's not started loading yet. Start loading, and when it's done, move it to loadedDefinitionsCache.\n                        subscribable = loadingSubscribablesCache[componentName] = new ko.subscribable();\n                        subscribable.subscribe(callback);\n\n                        beginLoadingComponent(componentName, function(definition, config) {\n                            var isSynchronousComponent = !!(config && config['synchronous']);\n                            loadedDefinitionsCache[componentName] = { definition: definition, isSynchronousComponent: isSynchronousComponent };\n                            delete loadingSubscribablesCache[componentName];\n\n                            // For API consistency, all loads complete asynchronously. However we want to avoid\n                            // adding an extra task schedule if it's unnecessary (i.e., the completion is already\n                            // async).\n                            //\n                            // You can bypass the 'always asynchronous' feature by putting the synchronous:true\n                            // flag on your component configuration when you register it.\n                            if (completedAsync || isSynchronousComponent) {\n                                // Note that notifySubscribers ignores any dependencies read within the callback.\n                                // See comment in loaderRegistryBehaviors.js for reasoning\n                                subscribable['notifySubscribers'](definition);\n                            } else {\n                                ko.tasks.schedule(function() {\n                                    subscribable['notifySubscribers'](definition);\n                                });\n                            }\n                        });\n                        completedAsync = true;\n                    } else {\n                        subscribable.subscribe(callback);\n                    }\n                }\n\n                function beginLoadingComponent(componentName, callback) {\n                    getFirstResultFromLoaders('getConfig', [componentName], function(config) {\n                        if (config) {\n                            // We have a config, so now load its definition\n                            getFirstResultFromLoaders('loadComponent', [componentName, config], function(definition) {\n                                callback(definition, config);\n                            });\n                        } else {\n                            // The component has no config - it's unknown to all the loaders.\n                            // Note that this is not an error (e.g., a module loading error) - that would abort the\n                            // process and this callback would not run. For this callback to run, all loaders must\n                            // have confirmed they don't know about this component.\n                            callback(null, null);\n                        }\n                    });\n                }\n\n                function getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders) {\n                    // On the first call in the stack, start with the full set of loaders\n                    if (!candidateLoaders) {\n                        candidateLoaders = ko.components['loaders'].slice(0); // Use a copy, because we'll be mutating this array\n                    }\n\n                    // Try the next candidate\n                    var currentCandidateLoader = candidateLoaders.shift();\n                    if (currentCandidateLoader) {\n                        var methodInstance = currentCandidateLoader[methodName];\n                        if (methodInstance) {\n                            var wasAborted = false,\n                                synchronousReturnValue = methodInstance.apply(currentCandidateLoader, argsExceptCallback.concat(function(result) {\n                                    if (wasAborted) {\n                                        callback(null);\n                                    } else if (result !== null) {\n                                        // This candidate returned a value. Use it.\n                                        callback(result);\n                                    } else {\n                                        // Try the next candidate\n                                        getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);\n                                    }\n                                }));\n\n                            // Currently, loaders may not return anything synchronously. This leaves open the possibility\n                            // that we'll extend the API to support synchronous return values in the future. It won't be\n                            // a breaking change, because currently no loader is allowed to return anything except undefined.\n                            if (synchronousReturnValue !== undefined) {\n                                wasAborted = true;\n\n                                // Method to suppress exceptions will remain undocumented. This is only to keep\n                                // KO's specs running tidily, since we can observe the loading got aborted without\n                                // having exceptions cluttering up the console too.\n                                if (!currentCandidateLoader['suppressLoaderExceptions']) {\n                                    throw new Error('Component loaders must supply values by invoking the callback, not by returning values synchronously.');\n                                }\n                            }\n                        } else {\n                            // This candidate doesn't have the relevant handler. Synchronously move on to the next one.\n                            getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);\n                        }\n                    } else {\n                        // No candidates returned a value\n                        callback(null);\n                    }\n                }\n\n                // Reference the loaders via string name so it's possible for developers\n                // to replace the whole array by assigning to ko.components.loaders\n                ko.components['loaders'] = [];\n\n                ko.exportSymbol('components', ko.components);\n                ko.exportSymbol('components.get', ko.components.get);\n                ko.exportSymbol('components.clearCachedDefinition', ko.components.clearCachedDefinition);\n            })();\n            (function(undefined) {\n\n                // The default loader is responsible for two things:\n                // 1. Maintaining the default in-memory registry of component configuration objects\n                //    (i.e., the thing you're writing to when you call ko.components.register(someName, ...))\n                // 2. Answering requests for components by fetching configuration objects\n                //    from that default in-memory registry and resolving them into standard\n                //    component definition objects (of the form { createViewModel: ..., template: ... })\n                // Custom loaders may override either of these facilities, i.e.,\n                // 1. To supply configuration objects from some other source (e.g., conventions)\n                // 2. Or, to resolve configuration objects by loading viewmodels/templates via arbitrary logic.\n\n                var defaultConfigRegistry = {};\n\n                ko.components.register = function(componentName, config) {\n                    if (!config) {\n                        throw new Error('Invalid configuration for ' + componentName);\n                    }\n\n                    if (ko.components.isRegistered(componentName)) {\n                        throw new Error('Component ' + componentName + ' is already registered');\n                    }\n\n                    defaultConfigRegistry[componentName] = config;\n                };\n\n                ko.components.isRegistered = function(componentName) {\n                    return Object.prototype.hasOwnProperty.call(defaultConfigRegistry, componentName);\n                };\n\n                ko.components.unregister = function(componentName) {\n                    delete defaultConfigRegistry[componentName];\n                    ko.components.clearCachedDefinition(componentName);\n                };\n\n                ko.components.defaultLoader = {\n                    'getConfig': function(componentName, callback) {\n                        var result = ko.components.isRegistered(componentName)\n                            ? defaultConfigRegistry[componentName]\n                            : null;\n                        callback(result);\n                    },\n\n                    'loadComponent': function(componentName, config, callback) {\n                        var errorCallback = makeErrorCallback(componentName);\n                        possiblyGetConfigFromAmd(errorCallback, config, function(loadedConfig) {\n                            resolveConfig(componentName, errorCallback, loadedConfig, callback);\n                        });\n                    },\n\n                    'loadTemplate': function(componentName, templateConfig, callback) {\n                        resolveTemplate(makeErrorCallback(componentName), templateConfig, callback);\n                    },\n\n                    'loadViewModel': function(componentName, viewModelConfig, callback) {\n                        resolveViewModel(makeErrorCallback(componentName), viewModelConfig, callback);\n                    }\n                };\n\n                var createViewModelKey = 'createViewModel';\n\n                // Takes a config object of the form { template: ..., viewModel: ... }, and asynchronously convert it\n                // into the standard component definition format:\n                //    { template: <ArrayOfDomNodes>, createViewModel: function(params, componentInfo) { ... } }.\n                // Since both template and viewModel may need to be resolved asynchronously, both tasks are performed\n                // in parallel, and the results joined when both are ready. We don't depend on any promises infrastructure,\n                // so this is implemented manually below.\n                function resolveConfig(componentName, errorCallback, config, callback) {\n                    var result = {},\n                        makeCallBackWhenZero = 2,\n                        tryIssueCallback = function() {\n                            if (--makeCallBackWhenZero === 0) {\n                                callback(result);\n                            }\n                        },\n                        templateConfig = config['template'],\n                        viewModelConfig = config['viewModel'];\n\n                    if (templateConfig) {\n                        possiblyGetConfigFromAmd(errorCallback, templateConfig, function(loadedConfig) {\n                            ko.components._getFirstResultFromLoaders('loadTemplate', [componentName, loadedConfig], function(resolvedTemplate) {\n                                result['template'] = resolvedTemplate;\n                                tryIssueCallback();\n                            });\n                        });\n                    } else {\n                        tryIssueCallback();\n                    }\n\n                    if (viewModelConfig) {\n                        possiblyGetConfigFromAmd(errorCallback, viewModelConfig, function(loadedConfig) {\n                            ko.components._getFirstResultFromLoaders('loadViewModel', [componentName, loadedConfig], function(resolvedViewModel) {\n                                result[createViewModelKey] = resolvedViewModel;\n                                tryIssueCallback();\n                            });\n                        });\n                    } else {\n                        tryIssueCallback();\n                    }\n                }\n\n                function resolveTemplate(errorCallback, templateConfig, callback) {\n                    if (typeof templateConfig === 'string') {\n                        // Markup - parse it\n                        callback(ko.utils.parseHtmlFragment(templateConfig));\n                    } else if (templateConfig instanceof Array) {\n                        // Assume already an array of DOM nodes - pass through unchanged\n                        callback(templateConfig);\n                    } else if (isDocumentFragment(templateConfig)) {\n                        // Document fragment - use its child nodes\n                        callback(ko.utils.makeArray(templateConfig.childNodes));\n                    } else if (templateConfig['element']) {\n                        var element = templateConfig['element'];\n                        if (isDomElement(element)) {\n                            // Element instance - copy its child nodes\n                            callback(cloneNodesFromTemplateSourceElement(element));\n                        } else if (typeof element === 'string') {\n                            // Element ID - find it, then copy its child nodes\n                            var elemInstance = document.getElementById(element);\n                            if (elemInstance) {\n                                callback(cloneNodesFromTemplateSourceElement(elemInstance));\n                            } else {\n                                errorCallback('Cannot find element with ID ' + element);\n                            }\n                        } else {\n                            errorCallback('Unknown element type: ' + element);\n                        }\n                    } else {\n                        errorCallback('Unknown template value: ' + templateConfig);\n                    }\n                }\n\n                function resolveViewModel(errorCallback, viewModelConfig, callback) {\n                    if (typeof viewModelConfig === 'function') {\n                        // Constructor - convert to standard factory function format\n                        // By design, this does *not* supply componentInfo to the constructor, as the intent is that\n                        // componentInfo contains non-viewmodel data (e.g., the component's element) that should only\n                        // be used in factory functions, not viewmodel constructors.\n                        callback(function (params /*, componentInfo */) {\n                            return new viewModelConfig(params);\n                        });\n                    } else if (typeof viewModelConfig[createViewModelKey] === 'function') {\n                        // Already a factory function - use it as-is\n                        callback(viewModelConfig[createViewModelKey]);\n                    } else if ('instance' in viewModelConfig) {\n                        // Fixed object instance - promote to createViewModel format for API consistency\n                        var fixedInstance = viewModelConfig['instance'];\n                        callback(function (params, componentInfo) {\n                            return fixedInstance;\n                        });\n                    } else if ('viewModel' in viewModelConfig) {\n                        // Resolved AMD module whose value is of the form { viewModel: ... }\n                        resolveViewModel(errorCallback, viewModelConfig['viewModel'], callback);\n                    } else {\n                        errorCallback('Unknown viewModel value: ' + viewModelConfig);\n                    }\n                }\n\n                function cloneNodesFromTemplateSourceElement(elemInstance) {\n                    switch (ko.utils.tagNameLower(elemInstance)) {\n                        case 'script':\n                            return ko.utils.parseHtmlFragment(elemInstance.text);\n                        case 'textarea':\n                            return ko.utils.parseHtmlFragment(elemInstance.value);\n                        case 'template':\n                            // For browsers with proper <template> element support (i.e., where the .content property\n                            // gives a document fragment), use that document fragment.\n                            if (isDocumentFragment(elemInstance.content)) {\n                                return ko.utils.cloneNodes(elemInstance.content.childNodes);\n                            }\n                    }\n\n                    // Regular elements such as <div>, and <template> elements on old browsers that don't really\n                    // understand <template> and just treat it as a regular container\n                    return ko.utils.cloneNodes(elemInstance.childNodes);\n                }\n\n                function isDomElement(obj) {\n                    if (window['HTMLElement']) {\n                        return obj instanceof HTMLElement;\n                    } else {\n                        return obj && obj.tagName && obj.nodeType === 1;\n                    }\n                }\n\n                function isDocumentFragment(obj) {\n                    if (window['DocumentFragment']) {\n                        return obj instanceof DocumentFragment;\n                    } else {\n                        return obj && obj.nodeType === 11;\n                    }\n                }\n\n                function possiblyGetConfigFromAmd(errorCallback, config, callback) {\n                    if (typeof config['require'] === 'string') {\n                        // The config is the value of an AMD module\n                        if (amdRequire || window['require']) {\n                            (amdRequire || window['require'])([config['require']], function (module) {\n                                if (module && typeof module === 'object' && module.__esModule && module.default) {\n                                    module = module.default;\n                                }\n                                callback(module);\n                            });\n                        } else {\n                            errorCallback('Uses require, but no AMD loader is present');\n                        }\n                    } else {\n                        callback(config);\n                    }\n                }\n\n                function makeErrorCallback(componentName) {\n                    return function (message) {\n                        throw new Error('Component \\'' + componentName + '\\': ' + message);\n                    };\n                }\n\n                ko.exportSymbol('components.register', ko.components.register);\n                ko.exportSymbol('components.isRegistered', ko.components.isRegistered);\n                ko.exportSymbol('components.unregister', ko.components.unregister);\n\n                // Expose the default loader so that developers can directly ask it for configuration\n                // or to resolve configuration\n                ko.exportSymbol('components.defaultLoader', ko.components.defaultLoader);\n\n                // By default, the default loader is the only registered component loader\n                ko.components['loaders'].push(ko.components.defaultLoader);\n\n                // Privately expose the underlying config registry for use in old-IE shim\n                ko.components._allRegisteredComponents = defaultConfigRegistry;\n            })();\n            (function (undefined) {\n                // Overridable API for determining which component name applies to a given node. By overriding this,\n                // you can for example map specific tagNames to components that are not preregistered.\n                ko.components['getComponentNameForNode'] = function(node) {\n                    var tagNameLower = ko.utils.tagNameLower(node);\n                    if (ko.components.isRegistered(tagNameLower)) {\n                        // Try to determine that this node can be considered a *custom* element; see https://github.com/knockout/knockout/issues/1603\n                        if (tagNameLower.indexOf('-') != -1 || ('' + node) == \"[object HTMLUnknownElement]\" || (ko.utils.ieVersion <= 8 && node.tagName === tagNameLower)) {\n                            return tagNameLower;\n                        }\n                    }\n                };\n\n                ko.components.addBindingsForCustomElement = function(allBindings, node, bindingContext, valueAccessors) {\n                    // Determine if it's really a custom element matching a component\n                    if (node.nodeType === 1) {\n                        var componentName = ko.components['getComponentNameForNode'](node);\n                        if (componentName) {\n                            // It does represent a component, so add a component binding for it\n                            allBindings = allBindings || {};\n\n                            if (allBindings['component']) {\n                                // Avoid silently overwriting some other 'component' binding that may already be on the element\n                                throw new Error('Cannot use the \"component\" binding on a custom element matching a component');\n                            }\n\n                            var componentBindingValue = { 'name': componentName, 'params': getComponentParamsFromCustomElement(node, bindingContext) };\n\n                            allBindings['component'] = valueAccessors\n                                ? function() { return componentBindingValue; }\n                                : componentBindingValue;\n                        }\n                    }\n\n                    return allBindings;\n                }\n\n                var nativeBindingProviderInstance = new ko.bindingProvider();\n\n                function getComponentParamsFromCustomElement(elem, bindingContext) {\n                    var paramsAttribute = elem.getAttribute('params');\n\n                    if (paramsAttribute) {\n                        var params = nativeBindingProviderInstance['parseBindingsString'](paramsAttribute, bindingContext, elem, { 'valueAccessors': true, 'bindingParams': true }),\n                            rawParamComputedValues = ko.utils.objectMap(params, function(paramValue, paramName) {\n                                return ko.computed(paramValue, null, { disposeWhenNodeIsRemoved: elem });\n                            }),\n                            result = ko.utils.objectMap(rawParamComputedValues, function(paramValueComputed, paramName) {\n                                var paramValue = paramValueComputed.peek();\n                                // Does the evaluation of the parameter value unwrap any observables?\n                                if (!paramValueComputed.isActive()) {\n                                    // No it doesn't, so there's no need for any computed wrapper. Just pass through the supplied value directly.\n                                    // Example: \"someVal: firstName, age: 123\" (whether or not firstName is an observable/computed)\n                                    return paramValue;\n                                } else {\n                                    // Yes it does. Supply a computed property that unwraps both the outer (binding expression)\n                                    // level of observability, and any inner (resulting model value) level of observability.\n                                    // This means the component doesn't have to worry about multiple unwrapping. If the value is a\n                                    // writable observable, the computed will also be writable and pass the value on to the observable.\n                                    return ko.computed({\n                                        'read': function() {\n                                            return ko.utils.unwrapObservable(paramValueComputed());\n                                        },\n                                        'write': ko.isWriteableObservable(paramValue) && function(value) {\n                                            paramValueComputed()(value);\n                                        },\n                                        disposeWhenNodeIsRemoved: elem\n                                    });\n                                }\n                            });\n\n                        // Give access to the raw computeds, as long as that wouldn't overwrite any custom param also called '$raw'\n                        // This is in case the developer wants to react to outer (binding) observability separately from inner\n                        // (model value) observability, or in case the model value observable has subobservables.\n                        if (!Object.prototype.hasOwnProperty.call(result, '$raw')) {\n                            result['$raw'] = rawParamComputedValues;\n                        }\n\n                        return result;\n                    } else {\n                        // For consistency, absence of a \"params\" attribute is treated the same as the presence of\n                        // any empty one. Otherwise component viewmodels need special code to check whether or not\n                        // 'params' or 'params.$raw' is null/undefined before reading subproperties, which is annoying.\n                        return { '$raw': {} };\n                    }\n                }\n\n                // --------------------------------------------------------------------------------\n                // Compatibility code for older (pre-HTML5) IE browsers\n\n                if (ko.utils.ieVersion < 9) {\n                    // Whenever you preregister a component, enable it as a custom element in the current document\n                    ko.components['register'] = (function(originalFunction) {\n                        return function(componentName) {\n                            document.createElement(componentName); // Allows IE<9 to parse markup containing the custom element\n                            return originalFunction.apply(this, arguments);\n                        }\n                    })(ko.components['register']);\n\n                    // Whenever you create a document fragment, enable all preregistered component names as custom elements\n                    // This is needed to make innerShiv/jQuery HTML parsing correctly handle the custom elements\n                    document.createDocumentFragment = (function(originalFunction) {\n                        return function() {\n                            var newDocFrag = originalFunction(),\n                                allComponents = ko.components._allRegisteredComponents;\n                            for (var componentName in allComponents) {\n                                if (Object.prototype.hasOwnProperty.call(allComponents, componentName)) {\n                                    newDocFrag.createElement(componentName);\n                                }\n                            }\n                            return newDocFrag;\n                        };\n                    })(document.createDocumentFragment);\n                }\n            })();(function(undefined) {\n                var componentLoadingOperationUniqueId = 0;\n\n                ko.bindingHandlers['component'] = {\n                    'init': function(element, valueAccessor, ignored1, ignored2, bindingContext) {\n                        var currentViewModel,\n                            currentLoadingOperationId,\n                            afterRenderSub,\n                            disposeAssociatedComponentViewModel = function () {\n                                var currentViewModelDispose = currentViewModel && currentViewModel['dispose'];\n                                if (typeof currentViewModelDispose === 'function') {\n                                    currentViewModelDispose.call(currentViewModel);\n                                }\n                                if (afterRenderSub) {\n                                    afterRenderSub.dispose();\n                                }\n                                afterRenderSub = null;\n                                currentViewModel = null;\n                                // Any in-flight loading operation is no longer relevant, so make sure we ignore its completion\n                                currentLoadingOperationId = null;\n                            },\n                            originalChildNodes = ko.utils.makeArray(ko.virtualElements.childNodes(element));\n\n                        ko.virtualElements.emptyNode(element);\n                        ko.utils.domNodeDisposal.addDisposeCallback(element, disposeAssociatedComponentViewModel);\n\n                        ko.computed(function () {\n                            var value = ko.utils.unwrapObservable(valueAccessor()),\n                                componentName, componentParams;\n\n                            if (typeof value === 'string') {\n                                componentName = value;\n                            } else {\n                                componentName = ko.utils.unwrapObservable(value['name']);\n                                componentParams = ko.utils.unwrapObservable(value['params']);\n                            }\n\n                            if (!componentName) {\n                                throw new Error('No component name specified');\n                            }\n\n                            var asyncContext = ko.bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);\n\n                            var loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;\n                            ko.components.get(componentName, function(componentDefinition) {\n                                // If this is not the current load operation for this element, ignore it.\n                                if (currentLoadingOperationId !== loadingOperationId) {\n                                    return;\n                                }\n\n                                // Clean up previous state\n                                disposeAssociatedComponentViewModel();\n\n                                // Instantiate and bind new component. Implicitly this cleans any old DOM nodes.\n                                if (!componentDefinition) {\n                                    throw new Error('Unknown component \\'' + componentName + '\\'');\n                                }\n                                cloneTemplateIntoElement(componentName, componentDefinition, element);\n\n                                var componentInfo = {\n                                    'element': element,\n                                    'templateNodes': originalChildNodes\n                                };\n\n                                var componentViewModel = createViewModel(componentDefinition, componentParams, componentInfo),\n                                    childBindingContext = asyncContext['createChildContext'](componentViewModel, {\n                                        'extend': function(ctx) {\n                                            ctx['$component'] = componentViewModel;\n                                            ctx['$componentTemplateNodes'] = originalChildNodes;\n                                        }\n                                    });\n\n                                if (componentViewModel && componentViewModel['koDescendantsComplete']) {\n                                    afterRenderSub = ko.bindingEvent.subscribe(element, ko.bindingEvent.descendantsComplete, componentViewModel['koDescendantsComplete'], componentViewModel);\n                                }\n\n                                currentViewModel = componentViewModel;\n                                ko.applyBindingsToDescendants(childBindingContext, element);\n                            });\n                        }, null, { disposeWhenNodeIsRemoved: element });\n\n                        return { 'controlsDescendantBindings': true };\n                    }\n                };\n\n                ko.virtualElements.allowedBindings['component'] = true;\n\n                function cloneTemplateIntoElement(componentName, componentDefinition, element) {\n                    var template = componentDefinition['template'];\n                    if (!template) {\n                        throw new Error('Component \\'' + componentName + '\\' has no template');\n                    }\n\n                    var clonedNodesArray = ko.utils.cloneNodes(template);\n                    ko.virtualElements.setDomNodeChildren(element, clonedNodesArray);\n                }\n\n                function createViewModel(componentDefinition, componentParams, componentInfo) {\n                    var componentViewModelFactory = componentDefinition['createViewModel'];\n                    return componentViewModelFactory\n                        ? componentViewModelFactory.call(componentDefinition, componentParams, componentInfo)\n                        : componentParams; // Template-only component\n                }\n\n            })();\n            var attrHtmlToJavaScriptMap = { 'class': 'className', 'for': 'htmlFor' };\n            ko.bindingHandlers['attr'] = {\n                'update': function(element, valueAccessor, allBindings) {\n                    var value = ko.utils.unwrapObservable(valueAccessor()) || {};\n                    ko.utils.objectForEach(value, function(attrName, attrValue) {\n                        attrValue = ko.utils.unwrapObservable(attrValue);\n\n                        // Find the namespace of this attribute, if any.\n                        var prefixLen = attrName.indexOf(':');\n                        var namespace = \"lookupNamespaceURI\" in element && prefixLen > 0 && element.lookupNamespaceURI(attrName.substr(0, prefixLen));\n\n                        // To cover cases like \"attr: { checked:someProp }\", we want to remove the attribute entirely\n                        // when someProp is a \"no value\"-like value (strictly null, false, or undefined)\n                        // (because the absence of the \"checked\" attr is how to mark an element as not checked, etc.)\n                        var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);\n                        if (toRemove) {\n                            namespace ? element.removeAttributeNS(namespace, attrName) : element.removeAttribute(attrName);\n                        } else {\n                            attrValue = attrValue.toString();\n                        }\n\n                        // In IE <= 7 and IE8 Quirks Mode, you have to use the JavaScript property name instead of the\n                        // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,\n                        // but instead of figuring out the mode, we'll just set the attribute through the JavaScript\n                        // property for IE <= 8.\n                        if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavaScriptMap) {\n                            attrName = attrHtmlToJavaScriptMap[attrName];\n                            if (toRemove)\n                                element.removeAttribute(attrName);\n                            else\n                                element[attrName] = attrValue;\n                        } else if (!toRemove) {\n                            namespace ? element.setAttributeNS(namespace, attrName, attrValue) : element.setAttribute(attrName, attrValue);\n                        }\n\n                        // Treat \"name\" specially - although you can think of it as an attribute, it also needs\n                        // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)\n                        // Deliberately being case-sensitive here because XHTML would regard \"Name\" as a different thing\n                        // entirely, and there's no strong reason to allow for such casing in HTML.\n                        if (attrName === \"name\") {\n                            ko.utils.setElementName(element, toRemove ? \"\" : attrValue);\n                        }\n                    });\n                }\n            };\n            (function() {\n\n                ko.bindingHandlers['checked'] = {\n                    'after': ['value', 'attr'],\n                    'init': function (element, valueAccessor, allBindings) {\n                        var checkedValue = ko.pureComputed(function() {\n                            // Treat \"value\" like \"checkedValue\" when it is included with \"checked\" binding\n                            if (allBindings['has']('checkedValue')) {\n                                return ko.utils.unwrapObservable(allBindings.get('checkedValue'));\n                            } else if (useElementValue) {\n                                if (allBindings['has']('value')) {\n                                    return ko.utils.unwrapObservable(allBindings.get('value'));\n                                } else {\n                                    return element.value;\n                                }\n                            }\n                        });\n\n                        function updateModel() {\n                            // This updates the model value from the view value.\n                            // It runs in response to DOM events (click) and changes in checkedValue.\n                            var isChecked = element.checked,\n                                elemValue = checkedValue();\n\n                            // When we're first setting up this computed, don't change any model state.\n                            if (ko.computedContext.isInitial()) {\n                                return;\n                            }\n\n                            // We can ignore unchecked radio buttons, because some other radio\n                            // button will be checked, and that one can take care of updating state.\n                            // Also ignore value changes to an already unchecked checkbox.\n                            if (!isChecked && (isRadio || ko.computedContext.getDependenciesCount())) {\n                                return;\n                            }\n\n                            var modelValue = ko.dependencyDetection.ignore(valueAccessor);\n                            if (valueIsArray) {\n                                var writableValue = rawValueIsNonArrayObservable ? modelValue.peek() : modelValue,\n                                    saveOldValue = oldElemValue;\n                                oldElemValue = elemValue;\n\n                                if (saveOldValue !== elemValue) {\n                                    // When we're responding to the checkedValue changing, and the element is\n                                    // currently checked, replace the old elem value with the new elem value\n                                    // in the model array.\n                                    if (isChecked) {\n                                        ko.utils.addOrRemoveItem(writableValue, elemValue, true);\n                                        ko.utils.addOrRemoveItem(writableValue, saveOldValue, false);\n                                    }\n                                } else {\n                                    // When we're responding to the user having checked/unchecked a checkbox,\n                                    // add/remove the element value to the model array.\n                                    ko.utils.addOrRemoveItem(writableValue, elemValue, isChecked);\n                                }\n\n                                if (rawValueIsNonArrayObservable && ko.isWriteableObservable(modelValue)) {\n                                    modelValue(writableValue);\n                                }\n                            } else {\n                                if (isCheckbox) {\n                                    if (elemValue === undefined) {\n                                        elemValue = isChecked;\n                                    } else if (!isChecked) {\n                                        elemValue = undefined;\n                                    }\n                                }\n                                ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);\n                            }\n                        };\n\n                        function updateView() {\n                            // This updates the view value from the model value.\n                            // It runs in response to changes in the bound (checked) value.\n                            var modelValue = ko.utils.unwrapObservable(valueAccessor()),\n                                elemValue = checkedValue();\n\n                            if (valueIsArray) {\n                                // When a checkbox is bound to an array, being checked represents its value being present in that array\n                                element.checked = ko.utils.arrayIndexOf(modelValue, elemValue) >= 0;\n                                oldElemValue = elemValue;\n                            } else if (isCheckbox && elemValue === undefined) {\n                                // When a checkbox is bound to any other value (not an array) and \"checkedValue\" is not defined,\n                                // being checked represents the value being trueish\n                                element.checked = !!modelValue;\n                            } else {\n                                // Otherwise, being checked means that the checkbox or radio button's value corresponds to the model value\n                                element.checked = (checkedValue() === modelValue);\n                            }\n                        };\n\n                        var isCheckbox = element.type == \"checkbox\",\n                            isRadio = element.type == \"radio\";\n\n                        // Only bind to check boxes and radio buttons\n                        if (!isCheckbox && !isRadio) {\n                            return;\n                        }\n\n                        var rawValue = valueAccessor(),\n                            valueIsArray = isCheckbox && (ko.utils.unwrapObservable(rawValue) instanceof Array),\n                            rawValueIsNonArrayObservable = !(valueIsArray && rawValue.push && rawValue.splice),\n                            useElementValue = isRadio || valueIsArray,\n                            oldElemValue = valueIsArray ? checkedValue() : undefined;\n\n                        // IE 6 won't allow radio buttons to be selected unless they have a name\n                        if (isRadio && !element.name)\n                            ko.bindingHandlers['uniqueName']['init'](element, function() { return true });\n\n                        // Set up two computeds to update the binding:\n\n                        // The first responds to changes in the checkedValue value and to element clicks\n                        ko.computed(updateModel, null, { disposeWhenNodeIsRemoved: element });\n                        ko.utils.registerEventHandler(element, \"click\", updateModel);\n\n                        // The second responds to changes in the model value (the one associated with the checked binding)\n                        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });\n\n                        rawValue = undefined;\n                    }\n                };\n                ko.expressionRewriting.twoWayBindings['checked'] = true;\n\n                ko.bindingHandlers['checkedValue'] = {\n                    'update': function (element, valueAccessor) {\n                        element.value = ko.utils.unwrapObservable(valueAccessor());\n                    }\n                };\n\n            })();var classesWrittenByBindingKey = '__ko__cssValue';\n            ko.bindingHandlers['class'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.stringTrim(ko.utils.unwrapObservable(valueAccessor()));\n                    ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);\n                    element[classesWrittenByBindingKey] = value;\n                    ko.utils.toggleDomNodeCssClass(element, value, true);\n                }\n            };\n\n            ko.bindingHandlers['css'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor());\n                    if (value !== null && typeof value == \"object\") {\n                        ko.utils.objectForEach(value, function(className, shouldHaveClass) {\n                            shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);\n                            ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);\n                        });\n                    } else {\n                        ko.bindingHandlers['class']['update'](element, valueAccessor);\n                    }\n                }\n            };\n            ko.bindingHandlers['enable'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor());\n                    if (value && element.disabled)\n                        element.removeAttribute(\"disabled\");\n                    else if ((!value) && (!element.disabled))\n                        element.disabled = true;\n                }\n            };\n\n            ko.bindingHandlers['disable'] = {\n                'update': function (element, valueAccessor) {\n                    ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });\n                }\n            };\n// For certain common events (currently just 'click'), allow a simplified data-binding syntax\n// e.g. click:handler instead of the usual full-length event:{click:handler}\n            function makeEventHandlerShortcut(eventName) {\n                ko.bindingHandlers[eventName] = {\n                    'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                        var newValueAccessor = function () {\n                            var result = {};\n                            result[eventName] = valueAccessor();\n                            return result;\n                        };\n                        return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);\n                    }\n                }\n            }\n\n            ko.bindingHandlers['event'] = {\n                'init' : function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    var eventsToHandle = valueAccessor() || {};\n                    ko.utils.objectForEach(eventsToHandle, function(eventName) {\n                        if (typeof eventName == \"string\") {\n                            ko.utils.registerEventHandler(element, eventName, function (event) {\n                                var handlerReturnValue;\n                                var handlerFunction = valueAccessor()[eventName];\n                                if (!handlerFunction)\n                                    return;\n\n                                try {\n                                    // Take all the event args, and prefix with the viewmodel\n                                    var argsForHandler = ko.utils.makeArray(arguments);\n                                    viewModel = bindingContext['$data'];\n                                    argsForHandler.unshift(viewModel);\n                                    handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);\n                                } finally {\n                                    if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.\n                                        if (event.preventDefault)\n                                            event.preventDefault();\n                                        else\n                                            event.returnValue = false;\n                                    }\n                                }\n\n                                var bubble = allBindings.get(eventName + 'Bubble') !== false;\n                                if (!bubble) {\n                                    event.cancelBubble = true;\n                                    if (event.stopPropagation)\n                                        event.stopPropagation();\n                                }\n                            });\n                        }\n                    });\n                }\n            };\n// \"foreach: someExpression\" is equivalent to \"template: { foreach: someExpression }\"\n// \"foreach: { data: someExpression, afterAdd: myfn }\" is equivalent to \"template: { foreach: someExpression, afterAdd: myfn }\"\n            ko.bindingHandlers['foreach'] = {\n                makeTemplateValueAccessor: function(valueAccessor) {\n                    return function() {\n                        var modelValue = valueAccessor(),\n                            unwrappedValue = ko.utils.peekObservable(modelValue);    // Unwrap without setting a dependency here\n\n                        // If unwrappedValue is the array, pass in the wrapped value on its own\n                        // The value will be unwrapped and tracked within the template binding\n                        // (See https://github.com/SteveSanderson/knockout/issues/523)\n                        if ((!unwrappedValue) || typeof unwrappedValue.length == \"number\")\n                            return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };\n\n                        // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates\n                        ko.utils.unwrapObservable(modelValue);\n                        return {\n                            'foreach': unwrappedValue['data'],\n                            'as': unwrappedValue['as'],\n                            'noChildContext': unwrappedValue['noChildContext'],\n                            'includeDestroyed': unwrappedValue['includeDestroyed'],\n                            'afterAdd': unwrappedValue['afterAdd'],\n                            'beforeRemove': unwrappedValue['beforeRemove'],\n                            'afterRender': unwrappedValue['afterRender'],\n                            'beforeMove': unwrappedValue['beforeMove'],\n                            'afterMove': unwrappedValue['afterMove'],\n                            'templateEngine': ko.nativeTemplateEngine.instance\n                        };\n                    };\n                },\n                'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));\n                },\n                'update': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindings, viewModel, bindingContext);\n                }\n            };\n            ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings\n            ko.virtualElements.allowedBindings['foreach'] = true;\n            var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';\n            var hasfocusLastValue = '__ko_hasfocusLastValue';\n            ko.bindingHandlers['hasfocus'] = {\n                'init': function(element, valueAccessor, allBindings) {\n                    var handleElementFocusChange = function(isFocused) {\n                        // Where possible, ignore which event was raised and determine focus state using activeElement,\n                        // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.\n                        // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,\n                        // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus\n                        // from calling 'blur()' on the element when it loses focus.\n                        // Discussion at https://github.com/SteveSanderson/knockout/pull/352\n                        element[hasfocusUpdatingProperty] = true;\n                        var ownerDoc = element.ownerDocument;\n                        if (\"activeElement\" in ownerDoc) {\n                            var active;\n                            try {\n                                active = ownerDoc.activeElement;\n                            } catch(e) {\n                                // IE9 throws if you access activeElement during page load (see issue #703)\n                                active = ownerDoc.body;\n                            }\n                            isFocused = (active === element);\n                        }\n                        var modelValue = valueAccessor();\n                        ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'hasfocus', isFocused, true);\n\n                        //cache the latest value, so we can avoid unnecessarily calling focus/blur in the update function\n                        element[hasfocusLastValue] = isFocused;\n                        element[hasfocusUpdatingProperty] = false;\n                    };\n                    var handleElementFocusIn = handleElementFocusChange.bind(null, true);\n                    var handleElementFocusOut = handleElementFocusChange.bind(null, false);\n\n                    ko.utils.registerEventHandler(element, \"focus\", handleElementFocusIn);\n                    ko.utils.registerEventHandler(element, \"focusin\", handleElementFocusIn); // For IE\n                    ko.utils.registerEventHandler(element, \"blur\",  handleElementFocusOut);\n                    ko.utils.registerEventHandler(element, \"focusout\",  handleElementFocusOut); // For IE\n\n                    // Assume element is not focused (prevents \"blur\" being called initially)\n                    element[hasfocusLastValue] = false;\n                },\n                'update': function(element, valueAccessor) {\n                    var value = !!ko.utils.unwrapObservable(valueAccessor());\n\n                    if (!element[hasfocusUpdatingProperty] && element[hasfocusLastValue] !== value) {\n                        value ? element.focus() : element.blur();\n\n                        // In IE, the blur method doesn't always cause the element to lose focus (for example, if the window is not in focus).\n                        // Setting focus to the body element does seem to be reliable in IE, but should only be used if we know that the current\n                        // element was focused already.\n                        if (!value && element[hasfocusLastValue]) {\n                            element.ownerDocument.body.focus();\n                        }\n\n                        // For IE, which doesn't reliably fire \"focus\" or \"blur\" events synchronously\n                        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? \"focusin\" : \"focusout\"]);\n                    }\n                }\n            };\n            ko.expressionRewriting.twoWayBindings['hasfocus'] = true;\n\n            ko.bindingHandlers['hasFocus'] = ko.bindingHandlers['hasfocus']; // Make \"hasFocus\" an alias\n            ko.expressionRewriting.twoWayBindings['hasFocus'] = 'hasfocus';\n            ko.bindingHandlers['html'] = {\n                'init': function() {\n                    // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)\n                    return { 'controlsDescendantBindings': true };\n                },\n                'update': function (element, valueAccessor) {\n                    // setHtml will unwrap the value if needed\n                    ko.utils.setHtml(element, valueAccessor());\n                }\n            };\n            (function () {\n\n// Makes a binding like with or if\n                function makeWithIfBinding(bindingKey, isWith, isNot) {\n                    ko.bindingHandlers[bindingKey] = {\n                        'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                            var didDisplayOnLastUpdate, savedNodes, contextOptions = {}, completeOnRender, needAsyncContext, renderOnEveryChange;\n\n                            if (isWith) {\n                                var as = allBindings.get('as'), noChildContext = allBindings.get('noChildContext');\n                                renderOnEveryChange = !(as && noChildContext);\n                                contextOptions = { 'as': as, 'noChildContext': noChildContext, 'exportDependencies': renderOnEveryChange };\n                            }\n\n                            completeOnRender = allBindings.get(\"completeOn\") == \"render\";\n                            needAsyncContext = completeOnRender || allBindings['has'](ko.bindingEvent.descendantsComplete);\n\n                            ko.computed(function() {\n                                var value = ko.utils.unwrapObservable(valueAccessor()),\n                                    shouldDisplay = !isNot !== !value, // equivalent to isNot ? !value : !!value,\n                                    isInitial = !savedNodes,\n                                    childContext;\n\n                                if (!renderOnEveryChange && shouldDisplay === didDisplayOnLastUpdate) {\n                                    return;\n                                }\n\n                                if (needAsyncContext) {\n                                    bindingContext = ko.bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);\n                                }\n\n                                if (shouldDisplay) {\n                                    if (!isWith || renderOnEveryChange) {\n                                        contextOptions['dataDependency'] = ko.computedContext.computed();\n                                    }\n\n                                    if (isWith) {\n                                        childContext = bindingContext['createChildContext'](typeof value == \"function\" ? value : valueAccessor, contextOptions);\n                                    } else if (ko.computedContext.getDependenciesCount()) {\n                                        childContext = bindingContext['extend'](null, contextOptions);\n                                    } else {\n                                        childContext = bindingContext;\n                                    }\n                                }\n\n                                // Save a copy of the inner nodes on the initial update, but only if we have dependencies.\n                                if (isInitial && ko.computedContext.getDependenciesCount()) {\n                                    savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);\n                                }\n\n                                if (shouldDisplay) {\n                                    if (!isInitial) {\n                                        ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(savedNodes));\n                                    }\n\n                                    ko.applyBindingsToDescendants(childContext, element);\n                                } else {\n                                    ko.virtualElements.emptyNode(element);\n\n                                    if (!completeOnRender) {\n                                        ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);\n                                    }\n                                }\n\n                                didDisplayOnLastUpdate = shouldDisplay;\n\n                            }, null, { disposeWhenNodeIsRemoved: element });\n\n                            return { 'controlsDescendantBindings': true };\n                        }\n                    };\n                    ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings\n                    ko.virtualElements.allowedBindings[bindingKey] = true;\n                }\n\n// Construct the actual binding handlers\n                makeWithIfBinding('if');\n                makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);\n                makeWithIfBinding('with', true /* isWith */);\n\n            })();ko.bindingHandlers['let'] = {\n                'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    // Make a modified binding context, with extra properties, and apply it to descendant elements\n                    var innerContext = bindingContext['extend'](valueAccessor);\n                    ko.applyBindingsToDescendants(innerContext, element);\n\n                    return { 'controlsDescendantBindings': true };\n                }\n            };\n            ko.virtualElements.allowedBindings['let'] = true;\n            var captionPlaceholder = {};\n            ko.bindingHandlers['options'] = {\n                'init': function(element) {\n                    if (ko.utils.tagNameLower(element) !== \"select\")\n                        throw new Error(\"options binding applies only to SELECT elements\");\n\n                    // Remove all existing <option>s.\n                    while (element.length > 0) {\n                        element.remove(0);\n                    }\n\n                    // Ensures that the binding processor doesn't try to bind the options\n                    return { 'controlsDescendantBindings': true };\n                },\n                'update': function (element, valueAccessor, allBindings) {\n                    function selectedOptions() {\n                        return ko.utils.arrayFilter(element.options, function (node) { return node.selected; });\n                    }\n\n                    var selectWasPreviouslyEmpty = element.length == 0,\n                        multiple = element.multiple,\n                        previousScrollTop = (!selectWasPreviouslyEmpty && multiple) ? element.scrollTop : null,\n                        unwrappedArray = ko.utils.unwrapObservable(valueAccessor()),\n                        valueAllowUnset = allBindings.get('valueAllowUnset') && allBindings['has']('value'),\n                        includeDestroyed = allBindings.get('optionsIncludeDestroyed'),\n                        arrayToDomNodeChildrenOptions = {},\n                        captionValue,\n                        filteredArray,\n                        previousSelectedValues = [];\n\n                    if (!valueAllowUnset) {\n                        if (multiple) {\n                            previousSelectedValues = ko.utils.arrayMap(selectedOptions(), ko.selectExtensions.readValue);\n                        } else if (element.selectedIndex >= 0) {\n                            previousSelectedValues.push(ko.selectExtensions.readValue(element.options[element.selectedIndex]));\n                        }\n                    }\n\n                    if (unwrappedArray) {\n                        if (typeof unwrappedArray.length == \"undefined\") // Coerce single value into array\n                            unwrappedArray = [unwrappedArray];\n\n                        // Filter out any entries marked as destroyed\n                        filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {\n                            return includeDestroyed || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);\n                        });\n\n                        // If caption is included, add it to the array\n                        if (allBindings['has']('optionsCaption')) {\n                            captionValue = ko.utils.unwrapObservable(allBindings.get('optionsCaption'));\n                            // If caption value is null or undefined, don't show a caption\n                            if (captionValue !== null && captionValue !== undefined) {\n                                filteredArray.unshift(captionPlaceholder);\n                            }\n                        }\n                    } else {\n                        // If a falsy value is provided (e.g. null), we'll simply empty the select element\n                    }\n\n                    function applyToObject(object, predicate, defaultValue) {\n                        var predicateType = typeof predicate;\n                        if (predicateType == \"function\")    // Given a function; run it against the data value\n                            return predicate(object);\n                        else if (predicateType == \"string\") // Given a string; treat it as a property name on the data value\n                            return object[predicate];\n                        else                                // Given no optionsText arg; use the data value itself\n                            return defaultValue;\n                    }\n\n                    // The following functions can run at two different times:\n                    // The first is when the whole array is being updated directly from this binding handler.\n                    // The second is when an observable value for a specific array entry is updated.\n                    // oldOptions will be empty in the first case, but will be filled with the previously generated option in the second.\n                    var itemUpdate = false;\n                    function optionForArrayItem(arrayEntry, index, oldOptions) {\n                        if (oldOptions.length) {\n                            previousSelectedValues = !valueAllowUnset && oldOptions[0].selected ? [ ko.selectExtensions.readValue(oldOptions[0]) ] : [];\n                            itemUpdate = true;\n                        }\n                        var option = element.ownerDocument.createElement(\"option\");\n                        if (arrayEntry === captionPlaceholder) {\n                            ko.utils.setTextContent(option, allBindings.get('optionsCaption'));\n                            ko.selectExtensions.writeValue(option, undefined);\n                        } else {\n                            // Apply a value to the option element\n                            var optionValue = applyToObject(arrayEntry, allBindings.get('optionsValue'), arrayEntry);\n                            ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));\n\n                            // Apply some text to the option element\n                            var optionText = applyToObject(arrayEntry, allBindings.get('optionsText'), optionValue);\n                            ko.utils.setTextContent(option, optionText);\n                        }\n                        return [option];\n                    }\n\n                    // By using a beforeRemove callback, we delay the removal until after new items are added. This fixes a selection\n                    // problem in IE<=8 and Firefox. See https://github.com/knockout/knockout/issues/1208\n                    arrayToDomNodeChildrenOptions['beforeRemove'] =\n                        function (option) {\n                            element.removeChild(option);\n                        };\n\n                    function setSelectionCallback(arrayEntry, newOptions) {\n                        if (itemUpdate && valueAllowUnset) {\n                            // The model value is authoritative, so make sure its value is the one selected\n                            ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);\n                        } else if (previousSelectedValues.length) {\n                            // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.\n                            // That's why we first added them without selection. Now it's time to set the selection.\n                            var isSelected = ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[0])) >= 0;\n                            ko.utils.setOptionNodeSelectionState(newOptions[0], isSelected);\n\n                            // If this option was changed from being selected during a single-item update, notify the change\n                            if (itemUpdate && !isSelected) {\n                                ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, \"change\"]);\n                            }\n                        }\n                    }\n\n                    var callback = setSelectionCallback;\n                    if (allBindings['has']('optionsAfterRender') && typeof allBindings.get('optionsAfterRender') == \"function\") {\n                        callback = function(arrayEntry, newOptions) {\n                            setSelectionCallback(arrayEntry, newOptions);\n                            ko.dependencyDetection.ignore(allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined]);\n                        }\n                    }\n\n                    ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, arrayToDomNodeChildrenOptions, callback);\n\n                    if (!valueAllowUnset) {\n                        // Determine if the selection has changed as a result of updating the options list\n                        var selectionChanged;\n                        if (multiple) {\n                            // For a multiple-select box, compare the new selection count to the previous one\n                            // But if nothing was selected before, the selection can't have changed\n                            selectionChanged = previousSelectedValues.length && selectedOptions().length < previousSelectedValues.length;\n                        } else {\n                            // For a single-select box, compare the current value to the previous value\n                            // But if nothing was selected before or nothing is selected now, just look for a change in selection\n                            selectionChanged = (previousSelectedValues.length && element.selectedIndex >= 0)\n                                ? (ko.selectExtensions.readValue(element.options[element.selectedIndex]) !== previousSelectedValues[0])\n                                : (previousSelectedValues.length || element.selectedIndex >= 0);\n                        }\n\n                        // Ensure consistency between model value and selected option.\n                        // If the dropdown was changed so that selection is no longer the same,\n                        // notify the value or selectedOptions binding.\n                        if (selectionChanged) {\n                            ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, \"change\"]);\n                        }\n                    }\n\n                    if (valueAllowUnset || ko.computedContext.isInitial()) {\n                        ko.bindingEvent.notify(element, ko.bindingEvent.childrenComplete);\n                    }\n\n                    // Workaround for IE bug\n                    ko.utils.ensureSelectElementIsRenderedCorrectly(element);\n\n                    if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20)\n                        element.scrollTop = previousScrollTop;\n                }\n            };\n            ko.bindingHandlers['options'].optionValueDomDataKey = ko.utils.domData.nextKey();\n            ko.bindingHandlers['selectedOptions'] = {\n                'init': function (element, valueAccessor, allBindings) {\n                    function updateFromView() {\n                        var value = valueAccessor(), valueToWrite = [];\n                        ko.utils.arrayForEach(element.getElementsByTagName(\"option\"), function(node) {\n                            if (node.selected)\n                                valueToWrite.push(ko.selectExtensions.readValue(node));\n                        });\n                        ko.expressionRewriting.writeValueToProperty(value, allBindings, 'selectedOptions', valueToWrite);\n                    }\n\n                    function updateFromModel() {\n                        var newValue = ko.utils.unwrapObservable(valueAccessor()),\n                            previousScrollTop = element.scrollTop;\n\n                        if (newValue && typeof newValue.length == \"number\") {\n                            ko.utils.arrayForEach(element.getElementsByTagName(\"option\"), function(node) {\n                                var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;\n                                if (node.selected != isSelected) {      // This check prevents flashing of the select element in IE\n                                    ko.utils.setOptionNodeSelectionState(node, isSelected);\n                                }\n                            });\n                        }\n\n                        element.scrollTop = previousScrollTop;\n                    }\n\n                    if (ko.utils.tagNameLower(element) != \"select\") {\n                        throw new Error(\"selectedOptions binding applies only to SELECT elements\");\n                    }\n\n                    var updateFromModelComputed;\n                    ko.bindingEvent.subscribe(element, ko.bindingEvent.childrenComplete, function () {\n                        if (!updateFromModelComputed) {\n                            ko.utils.registerEventHandler(element, \"change\", updateFromView);\n                            updateFromModelComputed = ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });\n                        } else {\n                            updateFromView();\n                        }\n                    }, null, { 'notifyImmediately': true });\n                },\n                'update': function() {} // Keep for backwards compatibility with code that may have wrapped binding\n            };\n            ko.expressionRewriting.twoWayBindings['selectedOptions'] = true;\n            ko.bindingHandlers['style'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor() || {});\n                    ko.utils.objectForEach(value, function(styleName, styleValue) {\n                        styleValue = ko.utils.unwrapObservable(styleValue);\n\n                        if (styleValue === null || styleValue === undefined || styleValue === false) {\n                            // Empty string removes the value, whereas null/undefined have no effect\n                            styleValue = \"\";\n                        }\n\n                        if (jQueryInstance) {\n                            jQueryInstance(element)['css'](styleName, styleValue);\n                        } else if (/^--/.test(styleName)) {\n                            // Is styleName a custom CSS property?\n                            element.style.setProperty(styleName, styleValue);\n                        } else {\n                            styleName = styleName.replace(/-(\\w)/g, function (all, letter) {\n                                return letter.toUpperCase();\n                            });\n\n                            var previousStyle = element.style[styleName];\n                            element.style[styleName] = styleValue;\n\n                            if (styleValue !== previousStyle && element.style[styleName] == previousStyle && !isNaN(styleValue)) {\n                                element.style[styleName] = styleValue + \"px\";\n                            }\n                        }\n                    });\n                }\n            };\n            ko.bindingHandlers['submit'] = {\n                'init': function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    if (typeof valueAccessor() != \"function\")\n                        throw new Error(\"The value for a submit binding must be a function\");\n                    ko.utils.registerEventHandler(element, \"submit\", function (event) {\n                        var handlerReturnValue;\n                        var value = valueAccessor();\n                        try { handlerReturnValue = value.call(bindingContext['$data'], element); }\n                        finally {\n                            if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.\n                                if (event.preventDefault)\n                                    event.preventDefault();\n                                else\n                                    event.returnValue = false;\n                            }\n                        }\n                    });\n                }\n            };\n            ko.bindingHandlers['text'] = {\n                'init': function() {\n                    // Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications).\n                    // It should also make things faster, as we no longer have to consider whether the text node might be bindable.\n                    return { 'controlsDescendantBindings': true };\n                },\n                'update': function (element, valueAccessor) {\n                    ko.utils.setTextContent(element, valueAccessor());\n                }\n            };\n            ko.virtualElements.allowedBindings['text'] = true;\n            (function () {\n\n                if (window && window.navigator) {\n                    var parseVersion = function (matches) {\n                        if (matches) {\n                            return parseFloat(matches[1]);\n                        }\n                    };\n\n                    // Detect various browser versions because some old versions don't fully support the 'input' event\n                    var userAgent = window.navigator.userAgent,\n                        operaVersion, chromeVersion, safariVersion, firefoxVersion, ieVersion, edgeVersion;\n\n                    (operaVersion = window.opera && window.opera.version && parseInt(window.opera.version()))\n                    || (edgeVersion = parseVersion(userAgent.match(/Edge\\/([^ ]+)$/)))\n                    || (chromeVersion = parseVersion(userAgent.match(/Chrome\\/([^ ]+)/)))\n                    || (safariVersion = parseVersion(userAgent.match(/Version\\/([^ ]+) Safari/)))\n                    || (firefoxVersion = parseVersion(userAgent.match(/Firefox\\/([^ ]+)/)))\n                    || (ieVersion = ko.utils.ieVersion || parseVersion(userAgent.match(/MSIE ([^ ]+)/)))      // Detects up to IE 10\n                    || (ieVersion = parseVersion(userAgent.match(/rv:([^ )]+)/)));      // Detects IE 11\n                }\n\n// IE 8 and 9 have bugs that prevent the normal events from firing when the value changes.\n// But it does fire the 'selectionchange' event on many of those, presumably because the\n// cursor is moving and that counts as the selection changing. The 'selectionchange' event is\n// fired at the document level only and doesn't directly indicate which element changed. We\n// set up just one event handler for the document and use 'activeElement' to determine which\n// element was changed.\n                if (ieVersion >= 8 && ieVersion < 10) {\n                    var selectionChangeRegisteredName = ko.utils.domData.nextKey(),\n                        selectionChangeHandlerName = ko.utils.domData.nextKey();\n                    var selectionChangeHandler = function(event) {\n                        var target = this.activeElement,\n                            handler = target && ko.utils.domData.get(target, selectionChangeHandlerName);\n                        if (handler) {\n                            handler(event);\n                        }\n                    };\n                    var registerForSelectionChangeEvent = function (element, handler) {\n                        var ownerDoc = element.ownerDocument;\n                        if (!ko.utils.domData.get(ownerDoc, selectionChangeRegisteredName)) {\n                            ko.utils.domData.set(ownerDoc, selectionChangeRegisteredName, true);\n                            ko.utils.registerEventHandler(ownerDoc, 'selectionchange', selectionChangeHandler);\n                        }\n                        ko.utils.domData.set(element, selectionChangeHandlerName, handler);\n                    };\n                }\n\n                ko.bindingHandlers['textInput'] = {\n                    'init': function (element, valueAccessor, allBindings) {\n\n                        var previousElementValue = element.value,\n                            timeoutHandle,\n                            elementValueBeforeEvent;\n\n                        var updateModel = function (event) {\n                            clearTimeout(timeoutHandle);\n                            elementValueBeforeEvent = timeoutHandle = undefined;\n\n                            var elementValue = element.value;\n                            if (previousElementValue !== elementValue) {\n                                // Provide a way for tests to know exactly which event was processed\n                                if (DEBUG && event) element['_ko_textInputProcessedEvent'] = event.type;\n                                previousElementValue = elementValue;\n                                ko.expressionRewriting.writeValueToProperty(valueAccessor(), allBindings, 'textInput', elementValue);\n                            }\n                        };\n\n                        var deferUpdateModel = function (event) {\n                            if (!timeoutHandle) {\n                                // The elementValueBeforeEvent variable is set *only* during the brief gap between an\n                                // event firing and the updateModel function running. This allows us to ignore model\n                                // updates that are from the previous state of the element, usually due to techniques\n                                // such as rateLimit. Such updates, if not ignored, can cause keystrokes to be lost.\n                                elementValueBeforeEvent = element.value;\n                                var handler = DEBUG ? updateModel.bind(element, {type: event.type}) : updateModel;\n                                timeoutHandle = ko.utils.setTimeout(handler, 4);\n                            }\n                        };\n\n                        // IE9 will mess up the DOM if you handle events synchronously which results in DOM changes (such as other bindings);\n                        // so we'll make sure all updates are asynchronous\n                        var ieUpdateModel = ko.utils.ieVersion == 9 ? deferUpdateModel : updateModel,\n                            ourUpdate = false;\n\n                        var updateView = function () {\n                            var modelValue = ko.utils.unwrapObservable(valueAccessor());\n\n                            if (modelValue === null || modelValue === undefined) {\n                                modelValue = '';\n                            }\n\n                            if (elementValueBeforeEvent !== undefined && modelValue === elementValueBeforeEvent) {\n                                ko.utils.setTimeout(updateView, 4);\n                                return;\n                            }\n\n                            // Update the element only if the element and model are different. On some browsers, updating the value\n                            // will move the cursor to the end of the input, which would be bad while the user is typing.\n                            if (element.value !== modelValue) {\n                                ourUpdate = true;  // Make sure we ignore events (propertychange) that result from updating the value\n                                element.value = modelValue;\n                                ourUpdate = false;\n                                previousElementValue = element.value; // In case the browser changes the value (see #2281)\n                            }\n                        };\n\n                        var onEvent = function (event, handler) {\n                            ko.utils.registerEventHandler(element, event, handler);\n                        };\n\n                        if (DEBUG && ko.bindingHandlers['textInput']['_forceUpdateOn']) {\n                            // Provide a way for tests to specify exactly which events are bound\n                            ko.utils.arrayForEach(ko.bindingHandlers['textInput']['_forceUpdateOn'], function(eventName) {\n                                if (eventName.slice(0,5) == 'after') {\n                                    onEvent(eventName.slice(5), deferUpdateModel);\n                                } else {\n                                    onEvent(eventName, updateModel);\n                                }\n                            });\n                        } else {\n                            if (ieVersion) {\n                                // All versions (including 11) of Internet Explorer have a bug that they don't generate an input or propertychange event when ESC is pressed\n                                onEvent('keypress', updateModel);\n                            }\n                            if (ieVersion < 11) {\n                                // Internet Explorer <= 8 doesn't support the 'input' event, but does include 'propertychange' that fires whenever\n                                // any property of an element changes. Unlike 'input', it also fires if a property is changed from JavaScript code,\n                                // but that's an acceptable compromise for this binding. IE 9 and 10 support 'input', but since they don't always\n                                // fire it when using autocomplete, we'll use 'propertychange' for them also.\n                                onEvent('propertychange', function(event) {\n                                    if (!ourUpdate && event.propertyName === 'value') {\n                                        ieUpdateModel(event);\n                                    }\n                                });\n                            }\n                            if (ieVersion == 8) {\n                                // IE 8 has a bug where it fails to fire 'propertychange' on the first update following a value change from\n                                // JavaScript code. It also doesn't fire if you clear the entire value. To fix this, we bind to the following\n                                // events too.\n                                onEvent('keyup', updateModel);      // A single keystoke\n                                onEvent('keydown', updateModel);    // The first character when a key is held down\n                            }\n                            if (registerForSelectionChangeEvent) {\n                                // Internet Explorer 9 doesn't fire the 'input' event when deleting text, including using\n                                // the backspace, delete, or ctrl-x keys, clicking the 'x' to clear the input, dragging text\n                                // out of the field, and cutting or deleting text using the context menu. 'selectionchange'\n                                // can detect all of those except dragging text out of the field, for which we use 'dragend'.\n                                // These are also needed in IE8 because of the bug described above.\n                                registerForSelectionChangeEvent(element, ieUpdateModel);  // 'selectionchange' covers cut, paste, drop, delete, etc.\n                                onEvent('dragend', deferUpdateModel);\n                            }\n\n                            if (!ieVersion || ieVersion >= 9) {\n                                // All other supported browsers support the 'input' event, which fires whenever the content of the element is changed\n                                // through the user interface.\n                                onEvent('input', ieUpdateModel);\n                            }\n\n                            if (safariVersion < 5 && ko.utils.tagNameLower(element) === \"textarea\") {\n                                // Safari <5 doesn't fire the 'input' event for <textarea> elements (it does fire 'textInput'\n                                // but only when typing). So we'll just catch as much as we can with keydown, cut, and paste.\n                                onEvent('keydown', deferUpdateModel);\n                                onEvent('paste', deferUpdateModel);\n                                onEvent('cut', deferUpdateModel);\n                            } else if (operaVersion < 11) {\n                                // Opera 10 doesn't always fire the 'input' event for cut, paste, undo & drop operations.\n                                // We can try to catch some of those using 'keydown'.\n                                onEvent('keydown', deferUpdateModel);\n                            } else if (firefoxVersion < 4.0) {\n                                // Firefox <= 3.6 doesn't fire the 'input' event when text is filled in through autocomplete\n                                onEvent('DOMAutoComplete', updateModel);\n\n                                // Firefox <=3.5 doesn't fire the 'input' event when text is dropped into the input.\n                                onEvent('dragdrop', updateModel);       // <3.5\n                                onEvent('drop', updateModel);           // 3.5\n                            } else if (edgeVersion && element.type === \"number\") {\n                                // Microsoft Edge doesn't fire 'input' or 'change' events for number inputs when\n                                // the value is changed via the up / down arrow keys\n                                onEvent('keydown', deferUpdateModel);\n                            }\n                        }\n\n                        // Bind to the change event so that we can catch programmatic updates of the value that fire this event.\n                        onEvent('change', updateModel);\n\n                        // To deal with browsers that don't notify any kind of event for some changes (IE, Safari, etc.)\n                        onEvent('blur', updateModel);\n\n                        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });\n                    }\n                };\n                ko.expressionRewriting.twoWayBindings['textInput'] = true;\n\n// textinput is an alias for textInput\n                ko.bindingHandlers['textinput'] = {\n                    // preprocess is the only way to set up a full alias\n                    'preprocess': function (value, name, addBinding) {\n                        addBinding('textInput', value);\n                    }\n                };\n\n            })();ko.bindingHandlers['uniqueName'] = {\n                'init': function (element, valueAccessor) {\n                    if (valueAccessor()) {\n                        var name = \"ko_unique_\" + (++ko.bindingHandlers['uniqueName'].currentIndex);\n                        ko.utils.setElementName(element, name);\n                    }\n                }\n            };\n            ko.bindingHandlers['uniqueName'].currentIndex = 0;\n            ko.bindingHandlers['using'] = {\n                'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {\n                    var options;\n\n                    if (allBindings['has']('as')) {\n                        options = { 'as': allBindings.get('as'), 'noChildContext': allBindings.get('noChildContext') };\n                    }\n\n                    var innerContext = bindingContext['createChildContext'](valueAccessor, options);\n                    ko.applyBindingsToDescendants(innerContext, element);\n\n                    return { 'controlsDescendantBindings': true };\n                }\n            };\n            ko.virtualElements.allowedBindings['using'] = true;\n            ko.bindingHandlers['value'] = {\n                'init': function (element, valueAccessor, allBindings) {\n                    var tagName = ko.utils.tagNameLower(element),\n                        isInputElement = tagName == \"input\";\n\n                    // If the value binding is placed on a radio/checkbox, then just pass through to checkedValue and quit\n                    if (isInputElement && (element.type == \"checkbox\" || element.type == \"radio\")) {\n                        ko.applyBindingAccessorsToNode(element, { 'checkedValue': valueAccessor });\n                        return;\n                    }\n\n                    var eventsToCatch = [];\n                    var requestedEventsToCatch = allBindings.get(\"valueUpdate\");\n                    var propertyChangedFired = false;\n                    var elementValueBeforeEvent = null;\n\n                    if (requestedEventsToCatch) {\n                        // Allow both individual event names, and arrays of event names\n                        if (typeof requestedEventsToCatch == \"string\") {\n                            eventsToCatch = [requestedEventsToCatch];\n                        } else {\n                            eventsToCatch = ko.utils.arrayGetDistinctValues(requestedEventsToCatch);\n                        }\n                        ko.utils.arrayRemoveItem(eventsToCatch, \"change\");  // We'll subscribe to \"change\" events later\n                    }\n\n                    var valueUpdateHandler = function() {\n                        elementValueBeforeEvent = null;\n                        propertyChangedFired = false;\n                        var modelValue = valueAccessor();\n                        var elementValue = ko.selectExtensions.readValue(element);\n                        ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'value', elementValue);\n                    }\n\n                    // Workaround for https://github.com/SteveSanderson/knockout/issues/122\n                    // IE doesn't fire \"change\" events on textboxes if the user selects a value from its autocomplete list\n                    var ieAutoCompleteHackNeeded = ko.utils.ieVersion && isInputElement && element.type == \"text\"\n                        && element.autocomplete != \"off\" && (!element.form || element.form.autocomplete != \"off\");\n                    if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, \"propertychange\") == -1) {\n                        ko.utils.registerEventHandler(element, \"propertychange\", function () { propertyChangedFired = true });\n                        ko.utils.registerEventHandler(element, \"focus\", function () { propertyChangedFired = false });\n                        ko.utils.registerEventHandler(element, \"blur\", function() {\n                            if (propertyChangedFired) {\n                                valueUpdateHandler();\n                            }\n                        });\n                    }\n\n                    ko.utils.arrayForEach(eventsToCatch, function(eventName) {\n                        // The syntax \"after<eventname>\" means \"run the handler asynchronously after the event\"\n                        // This is useful, for example, to catch \"keydown\" events after the browser has updated the control\n                        // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)\n                        var handler = valueUpdateHandler;\n                        if (ko.utils.stringStartsWith(eventName, \"after\")) {\n                            handler = function() {\n                                // The elementValueBeforeEvent variable is non-null *only* during the brief gap between\n                                // a keyX event firing and the valueUpdateHandler running, which is scheduled to happen\n                                // at the earliest asynchronous opportunity. We store this temporary information so that\n                                // if, between keyX and valueUpdateHandler, the underlying model value changes separately,\n                                // we can overwrite that model value change with the value the user just typed. Otherwise,\n                                // techniques like rateLimit can trigger model changes at critical moments that will\n                                // override the user's inputs, causing keystrokes to be lost.\n                                elementValueBeforeEvent = ko.selectExtensions.readValue(element);\n                                ko.utils.setTimeout(valueUpdateHandler, 0);\n                            };\n                            eventName = eventName.substring(\"after\".length);\n                        }\n                        ko.utils.registerEventHandler(element, eventName, handler);\n                    });\n\n                    var updateFromModel;\n\n                    if (isInputElement && element.type == \"file\") {\n                        // For file input elements, can only write the empty string\n                        updateFromModel = function () {\n                            var newValue = ko.utils.unwrapObservable(valueAccessor());\n                            if (newValue === null || newValue === undefined || newValue === \"\") {\n                                element.value = \"\";\n                            } else {\n                                ko.dependencyDetection.ignore(valueUpdateHandler);  // reset the model to match the element\n                            }\n                        }\n                    } else {\n                        updateFromModel = function () {\n                            var newValue = ko.utils.unwrapObservable(valueAccessor());\n                            var elementValue = ko.selectExtensions.readValue(element);\n\n                            if (elementValueBeforeEvent !== null && newValue === elementValueBeforeEvent) {\n                                ko.utils.setTimeout(updateFromModel, 0);\n                                return;\n                            }\n\n                            var valueHasChanged = newValue !== elementValue;\n\n                            if (valueHasChanged || elementValue === undefined) {\n                                if (tagName === \"select\") {\n                                    var allowUnset = allBindings.get('valueAllowUnset');\n                                    ko.selectExtensions.writeValue(element, newValue, allowUnset);\n                                    if (!allowUnset && newValue !== ko.selectExtensions.readValue(element)) {\n                                        // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,\n                                        // because you're not allowed to have a model value that disagrees with a visible UI selection.\n                                        ko.dependencyDetection.ignore(valueUpdateHandler);\n                                    }\n                                } else {\n                                    ko.selectExtensions.writeValue(element, newValue);\n                                }\n                            }\n                        };\n                    }\n\n                    if (tagName === \"select\") {\n                        var updateFromModelComputed;\n                        ko.bindingEvent.subscribe(element, ko.bindingEvent.childrenComplete, function () {\n                            if (!updateFromModelComputed) {\n                                ko.utils.registerEventHandler(element, \"change\", valueUpdateHandler);\n                                updateFromModelComputed = ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });\n                            } else if (allBindings.get('valueAllowUnset')) {\n                                updateFromModel();\n                            } else {\n                                valueUpdateHandler();\n                            }\n                        }, null, { 'notifyImmediately': true });\n                    } else {\n                        ko.utils.registerEventHandler(element, \"change\", valueUpdateHandler);\n                        ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });\n                    }\n                },\n                'update': function() {} // Keep for backwards compatibility with code that may have wrapped value binding\n            };\n            ko.expressionRewriting.twoWayBindings['value'] = true;\n            ko.bindingHandlers['visible'] = {\n                'update': function (element, valueAccessor) {\n                    var value = ko.utils.unwrapObservable(valueAccessor());\n                    var isCurrentlyVisible = !(element.style.display == \"none\");\n                    if (value && !isCurrentlyVisible)\n                        element.style.display = \"\";\n                    else if ((!value) && isCurrentlyVisible)\n                        element.style.display = \"none\";\n                }\n            };\n\n            ko.bindingHandlers['hidden'] = {\n                'update': function (element, valueAccessor) {\n                    ko.bindingHandlers['visible']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });\n                }\n            };\n// 'click' is just a shorthand for the usual full-length event:{click:handler}\n            makeEventHandlerShortcut('click');\n// If you want to make a custom template engine,\n//\n// [1] Inherit from this class (like ko.nativeTemplateEngine does)\n// [2] Override 'renderTemplateSource', supplying a function with this signature:\n//\n//        function (templateSource, bindingContext, options) {\n//            // - templateSource.text() is the text of the template you should render\n//            // - bindingContext.$data is the data you should pass into the template\n//            //   - you might also want to make bindingContext.$parent, bindingContext.$parents,\n//            //     and bindingContext.$root available in the template too\n//            // - options gives you access to any other properties set on \"data-bind: { template: options }\"\n//            // - templateDocument is the document object of the template\n//            //\n//            // Return value: an array of DOM nodes\n//        }\n//\n// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:\n//\n//        function (script) {\n//            // Return value: Whatever syntax means \"Evaluate the JavaScript statement 'script' and output the result\"\n//            //               For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'\n//        }\n//\n//     This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.\n//     If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)\n//     and then you don't need to override 'createJavaScriptEvaluatorBlock'.\n\n            ko.templateEngine = function () { };\n\n            ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {\n                throw new Error(\"Override renderTemplateSource\");\n            };\n\n            ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {\n                throw new Error(\"Override createJavaScriptEvaluatorBlock\");\n            };\n\n            ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {\n                // Named template\n                if (typeof template == \"string\") {\n                    templateDocument = templateDocument || document;\n                    var elem = templateDocument.getElementById(template);\n                    if (!elem)\n                        throw new Error(\"Cannot find template with ID \" + template);\n                    return new ko.templateSources.domElement(elem);\n                } else if ((template.nodeType == 1) || (template.nodeType == 8)) {\n                    // Anonymous template\n                    return new ko.templateSources.anonymousTemplate(template);\n                } else\n                    throw new Error(\"Unknown template type: \" + template);\n            };\n\n            ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {\n                var templateSource = this['makeTemplateSource'](template, templateDocument);\n                return this['renderTemplateSource'](templateSource, bindingContext, options, templateDocument);\n            };\n\n            ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {\n                // Skip rewriting if requested\n                if (this['allowTemplateRewriting'] === false)\n                    return true;\n                return this['makeTemplateSource'](template, templateDocument)['data'](\"isRewritten\");\n            };\n\n            ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {\n                var templateSource = this['makeTemplateSource'](template, templateDocument);\n                var rewritten = rewriterCallback(templateSource['text']());\n                templateSource['text'](rewritten);\n                templateSource['data'](\"isRewritten\", true);\n            };\n\n            ko.exportSymbol('templateEngine', ko.templateEngine);\n\n            ko.templateRewriting = (function () {\n                var memoizeDataBindingAttributeSyntaxRegex = /(<([a-z]+\\d*)(?:\\s+(?!data-bind\\s*=\\s*)[a-z0-9\\-]+(?:=(?:\\\"[^\\\"]*\\\"|\\'[^\\']*\\'|[^>]*))?)*\\s+)data-bind\\s*=\\s*([\"'])([\\s\\S]*?)\\3/gi;\n                var memoizeVirtualContainerBindingSyntaxRegex = /<!--\\s*ko\\b\\s*([\\s\\S]*?)\\s*-->/g;\n\n                function validateDataBindValuesForRewriting(keyValueArray) {\n                    var allValidators = ko.expressionRewriting.bindingRewriteValidators;\n                    for (var i = 0; i < keyValueArray.length; i++) {\n                        var key = keyValueArray[i]['key'];\n                        if (Object.prototype.hasOwnProperty.call(allValidators, key)) {\n                            var validator = allValidators[key];\n\n                            if (typeof validator === \"function\") {\n                                var possibleErrorMessage = validator(keyValueArray[i]['value']);\n                                if (possibleErrorMessage)\n                                    throw new Error(possibleErrorMessage);\n                            } else if (!validator) {\n                                throw new Error(\"This template engine does not support the '\" + key + \"' binding within its templates\");\n                            }\n                        }\n                    }\n                }\n\n                function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, nodeName, templateEngine) {\n                    var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);\n                    validateDataBindValuesForRewriting(dataBindKeyValueArray);\n                    var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray, {'valueAccessors':true});\n\n                    // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional\n                    // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this\n                    // extra indirection.\n                    var applyBindingsToNextSiblingScript =\n                        \"ko.__tr_ambtns(function($context,$element){return(function(){return{ \" + rewrittenDataBindAttributeValue + \" } })()},'\" + nodeName.toLowerCase() + \"')\";\n                    return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;\n                }\n\n                return {\n                    ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {\n                        if (!templateEngine['isTemplateRewritten'](template, templateDocument))\n                            templateEngine['rewriteTemplate'](template, function (htmlString) {\n                                return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);\n                            }, templateDocument);\n                    },\n\n                    memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {\n                        return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {\n                            return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[4], /* tagToRetain: */ arguments[1], /* nodeName: */ arguments[2], templateEngine);\n                        }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {\n                            return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ \"<!-- ko -->\", /* nodeName: */ \"#comment\", templateEngine);\n                        });\n                    },\n\n                    applyMemoizedBindingsToNextSibling: function (bindings, nodeName) {\n                        return ko.memoization.memoize(function (domNode, bindingContext) {\n                            var nodeToBind = domNode.nextSibling;\n                            if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {\n                                ko.applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);\n                            }\n                        });\n                    }\n                }\n            })();\n\n\n// Exported only because it has to be referenced by string lookup from within rewritten template\n            ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);\n            (function() {\n                // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving\n                // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)\n                //\n                // Two are provided by default:\n                //  1. ko.templateSources.domElement       - reads/writes the text content of an arbitrary DOM element\n                //  2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but\n                //                                           without reading/writing the actual element text content, since it will be overwritten\n                //                                           with the rendered template output.\n                // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.\n                // Template sources need to have the following functions:\n                //   text() \t\t\t- returns the template text from your storage location\n                //   text(value)\t\t- writes the supplied template text to your storage location\n                //   data(key)\t\t\t- reads values stored using data(key, value) - see below\n                //   data(key, value)\t- associates \"value\" with this template and the key \"key\". Is used to store information like \"isRewritten\".\n                //\n                // Optionally, template sources can also have the following functions:\n                //   nodes()            - returns a DOM element containing the nodes of this template, where available\n                //   nodes(value)       - writes the given DOM element to your storage location\n                // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()\n                // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().\n                //\n                // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were\n                // using and overriding \"makeTemplateSource\" to return an instance of your custom template source.\n\n                ko.templateSources = {};\n\n                // ---- ko.templateSources.domElement -----\n\n                // template types\n                var templateScript = 1,\n                    templateTextArea = 2,\n                    templateTemplate = 3,\n                    templateElement = 4;\n\n                ko.templateSources.domElement = function(element) {\n                    this.domElement = element;\n\n                    if (element) {\n                        var tagNameLower = ko.utils.tagNameLower(element);\n                        this.templateType =\n                            tagNameLower === \"script\" ? templateScript :\n                                tagNameLower === \"textarea\" ? templateTextArea :\n                                    // For browsers with proper <template> element support, where the .content property gives a document fragment\n                                    tagNameLower == \"template\" && element.content && element.content.nodeType === 11 ? templateTemplate :\n                                        templateElement;\n                    }\n                }\n\n                ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {\n                    var elemContentsProperty = this.templateType === templateScript ? \"text\"\n                        : this.templateType === templateTextArea ? \"value\"\n                            : \"innerHTML\";\n\n                    if (arguments.length == 0) {\n                        return this.domElement[elemContentsProperty];\n                    } else {\n                        var valueToWrite = arguments[0];\n                        if (elemContentsProperty === \"innerHTML\")\n                            ko.utils.setHtml(this.domElement, valueToWrite);\n                        else\n                            this.domElement[elemContentsProperty] = valueToWrite;\n                    }\n                };\n\n                var dataDomDataPrefix = ko.utils.domData.nextKey() + \"_\";\n                ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {\n                    if (arguments.length === 1) {\n                        return ko.utils.domData.get(this.domElement, dataDomDataPrefix + key);\n                    } else {\n                        ko.utils.domData.set(this.domElement, dataDomDataPrefix + key, arguments[1]);\n                    }\n                };\n\n                var templatesDomDataKey = ko.utils.domData.nextKey();\n                function getTemplateDomData(element) {\n                    return ko.utils.domData.get(element, templatesDomDataKey) || {};\n                }\n                function setTemplateDomData(element, data) {\n                    ko.utils.domData.set(element, templatesDomDataKey, data);\n                }\n\n                ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {\n                    var element = this.domElement;\n                    if (arguments.length == 0) {\n                        var templateData = getTemplateDomData(element),\n                            nodes = templateData.containerData || (\n                                this.templateType === templateTemplate ? element.content :\n                                    this.templateType === templateElement ? element :\n                                        undefined);\n                        if (!nodes || templateData.alwaysCheckText) {\n                            // If the template is associated with an element that stores the template as text,\n                            // parse and cache the nodes whenever there's new text content available. This allows\n                            // the user to update the template content by updating the text of template node.\n                            var text = this['text']();\n                            if (text && text !== templateData.textData) {\n                                nodes = ko.utils.parseHtmlForTemplateNodes(text, element.ownerDocument);\n                                setTemplateDomData(element, {containerData: nodes, textData: text, alwaysCheckText: true});\n                            }\n                        }\n                        return nodes;\n                    } else {\n                        var valueToWrite = arguments[0];\n                        if (this.templateType !== undefined) {\n                            this['text'](\"\");   // clear the text from the node\n                        }\n                        setTemplateDomData(element, {containerData: valueToWrite});\n                    }\n                };\n\n                // ---- ko.templateSources.anonymousTemplate -----\n                // Anonymous templates are normally saved/retrieved as DOM nodes through \"nodes\".\n                // For compatibility, you can also read \"text\"; it will be serialized from the nodes on demand.\n                // Writing to \"text\" is still supported, but then the template data will not be available as DOM nodes.\n\n                ko.templateSources.anonymousTemplate = function(element) {\n                    this.domElement = element;\n                }\n                ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();\n                ko.templateSources.anonymousTemplate.prototype.constructor = ko.templateSources.anonymousTemplate;\n                ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {\n                    if (arguments.length == 0) {\n                        var templateData = getTemplateDomData(this.domElement);\n                        if (templateData.textData === undefined && templateData.containerData)\n                            templateData.textData = templateData.containerData.innerHTML;\n                        return templateData.textData;\n                    } else {\n                        var valueToWrite = arguments[0];\n                        setTemplateDomData(this.domElement, {textData: valueToWrite});\n                    }\n                };\n\n                ko.exportSymbol('templateSources', ko.templateSources);\n                ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);\n                ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);\n            })();\n            (function () {\n                var _templateEngine;\n                ko.setTemplateEngine = function (templateEngine) {\n                    if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))\n                        throw new Error(\"templateEngine must inherit from ko.templateEngine\");\n                    _templateEngine = templateEngine;\n                }\n\n                function invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {\n                    var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);\n                    while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {\n                        nextInQueue = ko.virtualElements.nextSibling(node);\n                        action(node, nextInQueue);\n                    }\n                }\n\n                function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {\n                    // To be used on any nodes that have been rendered by a template and have been inserted into some parent element\n                    // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because\n                    // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,\n                    // (1) Does a regular \"applyBindings\" to associate bindingContext with this node and to activate any non-memoized bindings\n                    // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)\n\n                    if (continuousNodeArray.length) {\n                        var firstNode = continuousNodeArray[0],\n                            lastNode = continuousNodeArray[continuousNodeArray.length - 1],\n                            parentNode = firstNode.parentNode,\n                            provider = ko.bindingProvider['instance'],\n                            preprocessNode = provider['preprocessNode'];\n\n                        if (preprocessNode) {\n                            invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node, nextNodeInRange) {\n                                var nodePreviousSibling = node.previousSibling;\n                                var newNodes = preprocessNode.call(provider, node);\n                                if (newNodes) {\n                                    if (node === firstNode)\n                                        firstNode = newNodes[0] || nextNodeInRange;\n                                    if (node === lastNode)\n                                        lastNode = newNodes[newNodes.length - 1] || nodePreviousSibling;\n                                }\n                            });\n\n                            // Because preprocessNode can change the nodes, including the first and last nodes, update continuousNodeArray to match.\n                            // We need the full set, including inner nodes, because the unmemoize step might remove the first node (and so the real\n                            // first node needs to be in the array).\n                            continuousNodeArray.length = 0;\n                            if (!firstNode) { // preprocessNode might have removed all the nodes, in which case there's nothing left to do\n                                return;\n                            }\n                            if (firstNode === lastNode) {\n                                continuousNodeArray.push(firstNode);\n                            } else {\n                                continuousNodeArray.push(firstNode, lastNode);\n                                ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);\n                            }\n                        }\n\n                        // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)\n                        // whereas a regular applyBindings won't introduce new memoized nodes\n                        invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {\n                            if (node.nodeType === 1 || node.nodeType === 8)\n                                ko.applyBindings(bindingContext, node);\n                        });\n                        invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {\n                            if (node.nodeType === 1 || node.nodeType === 8)\n                                ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);\n                        });\n\n                        // Make sure any changes done by applyBindings or unmemoize are reflected in the array\n                        ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);\n                    }\n                }\n\n                function getFirstNodeFromPossibleArray(nodeOrNodeArray) {\n                    return nodeOrNodeArray.nodeType ? nodeOrNodeArray\n                        : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]\n                            : null;\n                }\n\n                function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {\n                    options = options || {};\n                    var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);\n                    var templateDocument = (firstTargetNode || template || {}).ownerDocument;\n                    var templateEngineToUse = (options['templateEngine'] || _templateEngine);\n                    ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);\n                    var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);\n\n                    // Loosely check result is an array of DOM nodes\n                    if ((typeof renderedNodesArray.length != \"number\") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != \"number\"))\n                        throw new Error(\"Template engine must return an array of DOM nodes\");\n\n                    var haveAddedNodesToParent = false;\n                    switch (renderMode) {\n                        case \"replaceChildren\":\n                            ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);\n                            haveAddedNodesToParent = true;\n                            break;\n                        case \"replaceNode\":\n                            ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);\n                            haveAddedNodesToParent = true;\n                            break;\n                        case \"ignoreTargetNode\": break;\n                        default:\n                            throw new Error(\"Unknown renderMode: \" + renderMode);\n                    }\n\n                    if (haveAddedNodesToParent) {\n                        activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);\n                        if (options['afterRender']) {\n                            ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext[options['as'] || '$data']]);\n                        }\n                        if (renderMode == \"replaceChildren\") {\n                            ko.bindingEvent.notify(targetNodeOrNodeArray, ko.bindingEvent.childrenComplete);\n                        }\n                    }\n\n                    return renderedNodesArray;\n                }\n\n                function resolveTemplateName(template, data, context) {\n                    // The template can be specified as:\n                    if (ko.isObservable(template)) {\n                        // 1. An observable, with string value\n                        return template();\n                    } else if (typeof template === 'function') {\n                        // 2. A function of (data, context) returning a string\n                        return template(data, context);\n                    } else {\n                        // 3. A string\n                        return template;\n                    }\n                }\n\n                ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {\n                    options = options || {};\n                    if ((options['templateEngine'] || _templateEngine) == undefined)\n                        throw new Error(\"Set a template engine before calling renderTemplate\");\n                    renderMode = renderMode || \"replaceChildren\";\n\n                    if (targetNodeOrNodeArray) {\n                        var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);\n\n                        var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)\n                        var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == \"replaceNode\") ? firstTargetNode.parentNode : firstTargetNode;\n\n                        return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes\n                            function () {\n                                // Ensure we've got a proper binding context to work with\n                                var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))\n                                    ? dataOrBindingContext\n                                    : new ko.bindingContext(dataOrBindingContext, null, null, null, { \"exportDependencies\": true });\n\n                                var templateName = resolveTemplateName(template, bindingContext['$data'], bindingContext),\n                                    renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);\n\n                                if (renderMode == \"replaceNode\") {\n                                    targetNodeOrNodeArray = renderedNodesArray;\n                                    firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);\n                                }\n                            },\n                            null,\n                            { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }\n                        );\n                    } else {\n                        // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node\n                        return ko.memoization.memoize(function (domNode) {\n                            ko.renderTemplate(template, dataOrBindingContext, options, domNode, \"replaceNode\");\n                        });\n                    }\n                };\n\n                ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {\n                    // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then\n                    // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.\n                    var arrayItemContext, asName = options['as'];\n\n                    // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode\n                    var executeTemplateForArrayItem = function (arrayValue, index) {\n                        // Support selecting template as a function of the data being rendered\n                        arrayItemContext = parentBindingContext['createChildContext'](arrayValue, {\n                            'as': asName,\n                            'noChildContext': options['noChildContext'],\n                            'extend': function(context) {\n                                context['$index'] = index;\n                                if (asName) {\n                                    context[asName + \"Index\"] = index;\n                                }\n                            }\n                        });\n\n                        var templateName = resolveTemplateName(template, arrayValue, arrayItemContext);\n                        return executeTemplate(targetNode, \"ignoreTargetNode\", templateName, arrayItemContext, options);\n                    };\n\n                    // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode\n                    var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {\n                        activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);\n                        if (options['afterRender'])\n                            options['afterRender'](addedNodesArray, arrayValue);\n\n                        // release the \"cache\" variable, so that it can be collected by\n                        // the GC when its value isn't used from within the bindings anymore.\n                        arrayItemContext = null;\n                    };\n\n                    var setDomNodeChildrenFromArrayMapping = function (newArray, changeList) {\n                        // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).\n                        // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.\n                        ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, newArray, executeTemplateForArrayItem, options, activateBindingsCallback, changeList]);\n                        ko.bindingEvent.notify(targetNode, ko.bindingEvent.childrenComplete);\n                    };\n\n                    var shouldHideDestroyed = (options['includeDestroyed'] === false) || (ko.options['foreachHidesDestroyed'] && !options['includeDestroyed']);\n\n                    if (!shouldHideDestroyed && !options['beforeRemove'] && ko.isObservableArray(arrayOrObservableArray)) {\n                        setDomNodeChildrenFromArrayMapping(arrayOrObservableArray.peek());\n\n                        var subscription = arrayOrObservableArray.subscribe(function (changeList) {\n                            setDomNodeChildrenFromArrayMapping(arrayOrObservableArray(), changeList);\n                        }, null, \"arrayChange\");\n                        subscription.disposeWhenNodeIsRemoved(targetNode);\n\n                        return subscription;\n                    } else {\n                        return ko.dependentObservable(function () {\n                            var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];\n                            if (typeof unwrappedArray.length == \"undefined\") // Coerce single value into array\n                                unwrappedArray = [unwrappedArray];\n\n                            if (shouldHideDestroyed) {\n                                // Filter out any entries marked as destroyed\n                                unwrappedArray = ko.utils.arrayFilter(unwrappedArray, function(item) {\n                                    return item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);\n                                });\n                            }\n                            setDomNodeChildrenFromArrayMapping(unwrappedArray);\n\n                        }, null, { disposeWhenNodeIsRemoved: targetNode });\n                    }\n                };\n\n                var templateComputedDomDataKey = ko.utils.domData.nextKey();\n                function disposeOldComputedAndStoreNewOne(element, newComputed) {\n                    var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);\n                    if (oldComputed && (typeof(oldComputed.dispose) == 'function'))\n                        oldComputed.dispose();\n                    ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && (!newComputed.isActive || newComputed.isActive())) ? newComputed : undefined);\n                }\n\n                var cleanContainerDomDataKey = ko.utils.domData.nextKey();\n                ko.bindingHandlers['template'] = {\n                    'init': function(element, valueAccessor) {\n                        // Support anonymous templates\n                        var bindingValue = ko.utils.unwrapObservable(valueAccessor());\n                        if (typeof bindingValue == \"string\" || 'name' in bindingValue) {\n                            // It's a named template - clear the element\n                            ko.virtualElements.emptyNode(element);\n                        } else if ('nodes' in bindingValue) {\n                            // We've been given an array of DOM nodes. Save them as the template source.\n                            // There is no known use case for the node array being an observable array (if the output\n                            // varies, put that behavior *into* your template - that's what templates are for), and\n                            // the implementation would be a mess, so assert that it's not observable.\n                            var nodes = bindingValue['nodes'] || [];\n                            if (ko.isObservable(nodes)) {\n                                throw new Error('The \"nodes\" option must be a plain, non-observable array.');\n                            }\n\n                            // If the nodes are already attached to a KO-generated container, we reuse that container without moving the\n                            // elements to a new one (we check only the first node, as the nodes are always moved together)\n                            var container = nodes[0] && nodes[0].parentNode;\n                            if (!container || !ko.utils.domData.get(container, cleanContainerDomDataKey)) {\n                                container = ko.utils.moveCleanedNodesToContainerElement(nodes);\n                                ko.utils.domData.set(container, cleanContainerDomDataKey, true);\n                            }\n\n                            new ko.templateSources.anonymousTemplate(element)['nodes'](container);\n                        } else {\n                            // It's an anonymous template - store the element contents, then clear the element\n                            var templateNodes = ko.virtualElements.childNodes(element);\n                            if (templateNodes.length > 0) {\n                                var container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent\n                                new ko.templateSources.anonymousTemplate(element)['nodes'](container);\n                            } else {\n                                throw new Error(\"Anonymous template defined, but no template content was provided\");\n                            }\n                        }\n                        return { 'controlsDescendantBindings': true };\n                    },\n                    'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {\n                        var value = valueAccessor(),\n                            options = ko.utils.unwrapObservable(value),\n                            shouldDisplay = true,\n                            templateComputed = null,\n                            template;\n\n                        if (typeof options == \"string\") {\n                            template = value;\n                            options = {};\n                        } else {\n                            template = 'name' in options ? options['name'] : element;\n\n                            // Support \"if\"/\"ifnot\" conditions\n                            if ('if' in options)\n                                shouldDisplay = ko.utils.unwrapObservable(options['if']);\n                            if (shouldDisplay && 'ifnot' in options)\n                                shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);\n\n                            // Don't show anything if an empty name is given (see #2446)\n                            if (shouldDisplay && !template) {\n                                shouldDisplay = false;\n                            }\n                        }\n\n                        if ('foreach' in options) {\n                            // Render once for each data point (treating data set as empty if shouldDisplay==false)\n                            var dataArray = (shouldDisplay && options['foreach']) || [];\n                            templateComputed = ko.renderTemplateForEach(template, dataArray, options, element, bindingContext);\n                        } else if (!shouldDisplay) {\n                            ko.virtualElements.emptyNode(element);\n                        } else {\n                            // Render once for this single data point (or use the viewModel if no data was provided)\n                            var innerBindingContext = bindingContext;\n                            if ('data' in options) {\n                                innerBindingContext = bindingContext['createChildContext'](options['data'], {\n                                    'as': options['as'],\n                                    'noChildContext': options['noChildContext'],\n                                    'exportDependencies': true\n                                });\n                            }\n                            templateComputed = ko.renderTemplate(template, innerBindingContext, options, element);\n                        }\n\n                        // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)\n                        disposeOldComputedAndStoreNewOne(element, templateComputed);\n                    }\n                };\n\n                // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.\n                ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {\n                    var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);\n\n                    if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])\n                        return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)\n\n                    if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, \"name\"))\n                        return null; // Named templates can be rewritten, so return \"no error\"\n                    return \"This template engine does not support anonymous templates nested within its templates\";\n                };\n\n                ko.virtualElements.allowedBindings['template'] = true;\n            })();\n\n            ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);\n            ko.exportSymbol('renderTemplate', ko.renderTemplate);\n// Go through the items that have been added and deleted and try to find matches between them.\n            ko.utils.findMovesInArrayComparison = function (left, right, limitFailedCompares) {\n                if (left.length && right.length) {\n                    var failedCompares, l, r, leftItem, rightItem;\n                    for (failedCompares = l = 0; (!limitFailedCompares || failedCompares < limitFailedCompares) && (leftItem = left[l]); ++l) {\n                        for (r = 0; rightItem = right[r]; ++r) {\n                            if (leftItem['value'] === rightItem['value']) {\n                                leftItem['moved'] = rightItem['index'];\n                                rightItem['moved'] = leftItem['index'];\n                                right.splice(r, 1);         // This item is marked as moved; so remove it from right list\n                                failedCompares = r = 0;     // Reset failed compares count because we're checking for consecutive failures\n                                break;\n                            }\n                        }\n                        failedCompares += r;\n                    }\n                }\n            };\n\n            ko.utils.compareArrays = (function () {\n                var statusNotInOld = 'added', statusNotInNew = 'deleted';\n\n                // Simple calculation based on Levenshtein distance.\n                function compareArrays(oldArray, newArray, options) {\n                    // For backward compatibility, if the third arg is actually a bool, interpret\n                    // it as the old parameter 'dontLimitMoves'. Newer code should use { dontLimitMoves: true }.\n                    options = (typeof options === 'boolean') ? { 'dontLimitMoves': options } : (options || {});\n                    oldArray = oldArray || [];\n                    newArray = newArray || [];\n\n                    if (oldArray.length < newArray.length)\n                        return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, options);\n                    else\n                        return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, options);\n                }\n\n                function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, options) {\n                    var myMin = Math.min,\n                        myMax = Math.max,\n                        editDistanceMatrix = [],\n                        smlIndex, smlIndexMax = smlArray.length,\n                        bigIndex, bigIndexMax = bigArray.length,\n                        compareRange = (bigIndexMax - smlIndexMax) || 1,\n                        maxDistance = smlIndexMax + bigIndexMax + 1,\n                        thisRow, lastRow,\n                        bigIndexMaxForRow, bigIndexMinForRow;\n\n                    for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {\n                        lastRow = thisRow;\n                        editDistanceMatrix.push(thisRow = []);\n                        bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);\n                        bigIndexMinForRow = myMax(0, smlIndex - 1);\n                        for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {\n                            if (!bigIndex)\n                                thisRow[bigIndex] = smlIndex + 1;\n                            else if (!smlIndex)  // Top row - transform empty array into new array via additions\n                                thisRow[bigIndex] = bigIndex + 1;\n                            else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])\n                                thisRow[bigIndex] = lastRow[bigIndex - 1];                  // copy value (no edit)\n                            else {\n                                var northDistance = lastRow[bigIndex] || maxDistance;       // not in big (deletion)\n                                var westDistance = thisRow[bigIndex - 1] || maxDistance;    // not in small (addition)\n                                thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;\n                            }\n                        }\n                    }\n\n                    var editScript = [], meMinusOne, notInSml = [], notInBig = [];\n                    for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {\n                        meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;\n                        if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {\n                            notInSml.push(editScript[editScript.length] = {     // added\n                                'status': statusNotInSml,\n                                'value': bigArray[--bigIndex],\n                                'index': bigIndex });\n                        } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {\n                            notInBig.push(editScript[editScript.length] = {     // deleted\n                                'status': statusNotInBig,\n                                'value': smlArray[--smlIndex],\n                                'index': smlIndex });\n                        } else {\n                            --bigIndex;\n                            --smlIndex;\n                            if (!options['sparse']) {\n                                editScript.push({\n                                    'status': \"retained\",\n                                    'value': bigArray[bigIndex] });\n                            }\n                        }\n                    }\n\n                    // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of\n                    // smlIndexMax keeps the time complexity of this algorithm linear.\n                    ko.utils.findMovesInArrayComparison(notInBig, notInSml, !options['dontLimitMoves'] && smlIndexMax * 10);\n\n                    return editScript.reverse();\n                }\n\n                return compareArrays;\n            })();\n\n            ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);\n            (function () {\n                // Objective:\n                // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,\n                //   map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node\n                // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node\n                //   so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we\n                //   previously mapped - retain those nodes, and just insert/delete other ones\n\n                // \"callbackAfterAddingNodes\" will be invoked after any \"mapping\"-generated nodes are inserted into the container node\n                // You can use this, for example, to activate bindings on those nodes.\n\n                function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {\n                    // Map this array value inside a dependentObservable so we re-map when any dependency changes\n                    var mappedNodes = [];\n                    var dependentObservable = ko.dependentObservable(function() {\n                        var newMappedNodes = mapping(valueToMap, index, ko.utils.fixUpContinuousNodeArray(mappedNodes, containerNode)) || [];\n\n                        // On subsequent evaluations, just replace the previously-inserted DOM nodes\n                        if (mappedNodes.length > 0) {\n                            ko.utils.replaceDomNodes(mappedNodes, newMappedNodes);\n                            if (callbackAfterAddingNodes)\n                                ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);\n                        }\n\n                        // Replace the contents of the mappedNodes array, thereby updating the record\n                        // of which nodes would be deleted if valueToMap was itself later removed\n                        mappedNodes.length = 0;\n                        ko.utils.arrayPushAll(mappedNodes, newMappedNodes);\n                    }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return !ko.utils.anyDomNodeIsAttachedToDocument(mappedNodes); } });\n                    return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };\n                }\n\n                var lastMappingResultDomDataKey = ko.utils.domData.nextKey(),\n                    deletedItemDummyValue = ko.utils.domData.nextKey();\n\n                ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes, editScript) {\n                    array = array || [];\n                    if (typeof array.length == \"undefined\") // Coerce single value into array\n                        array = [array];\n\n                    options = options || {};\n                    var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey);\n                    var isFirstExecution = !lastMappingResult;\n\n                    // Build the new mapping result\n                    var newMappingResult = [];\n                    var lastMappingResultIndex = 0;\n                    var currentArrayIndex = 0;\n\n                    var nodesToDelete = [];\n                    var itemsToMoveFirstIndexes = [];\n                    var itemsForBeforeRemoveCallbacks = [];\n                    var itemsForMoveCallbacks = [];\n                    var itemsForAfterAddCallbacks = [];\n                    var mapData;\n                    var countWaitingForRemove = 0;\n\n                    function itemAdded(value) {\n                        mapData = { arrayEntry: value, indexObservable: ko.observable(currentArrayIndex++) };\n                        newMappingResult.push(mapData);\n                        if (!isFirstExecution) {\n                            itemsForAfterAddCallbacks.push(mapData);\n                        }\n                    }\n\n                    function itemMovedOrRetained(oldPosition) {\n                        mapData = lastMappingResult[oldPosition];\n                        if (currentArrayIndex !== mapData.indexObservable.peek())\n                            itemsForMoveCallbacks.push(mapData);\n                        // Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray\n                        mapData.indexObservable(currentArrayIndex++);\n                        ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode);\n                        newMappingResult.push(mapData);\n                    }\n\n                    function callCallback(callback, items) {\n                        if (callback) {\n                            for (var i = 0, n = items.length; i < n; i++) {\n                                ko.utils.arrayForEach(items[i].mappedNodes, function(node) {\n                                    callback(node, i, items[i].arrayEntry);\n                                });\n                            }\n                        }\n                    }\n\n                    if (isFirstExecution) {\n                        ko.utils.arrayForEach(array, itemAdded);\n                    } else {\n                        if (!editScript || (lastMappingResult && lastMappingResult['_countWaitingForRemove'])) {\n                            // Compare the provided array against the previous one\n                            var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; }),\n                                compareOptions = {\n                                    'dontLimitMoves': options['dontLimitMoves'],\n                                    'sparse': true\n                                };\n                            editScript = ko.utils.compareArrays(lastArray, array, compareOptions);\n                        }\n\n                        for (var i = 0, editScriptItem, movedIndex, itemIndex; editScriptItem = editScript[i]; i++) {\n                            movedIndex = editScriptItem['moved'];\n                            itemIndex = editScriptItem['index'];\n                            switch (editScriptItem['status']) {\n                                case \"deleted\":\n                                    while (lastMappingResultIndex < itemIndex) {\n                                        itemMovedOrRetained(lastMappingResultIndex++);\n                                    }\n                                    if (movedIndex === undefined) {\n                                        mapData = lastMappingResult[lastMappingResultIndex];\n\n                                        // Stop tracking changes to the mapping for these nodes\n                                        if (mapData.dependentObservable) {\n                                            mapData.dependentObservable.dispose();\n                                            mapData.dependentObservable = undefined;\n                                        }\n\n                                        // Queue these nodes for later removal\n                                        if (ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode).length) {\n                                            if (options['beforeRemove']) {\n                                                newMappingResult.push(mapData);\n                                                countWaitingForRemove++;\n                                                if (mapData.arrayEntry === deletedItemDummyValue) {\n                                                    mapData = null;\n                                                } else {\n                                                    itemsForBeforeRemoveCallbacks.push(mapData);\n                                                }\n                                            }\n                                            if (mapData) {\n                                                nodesToDelete.push.apply(nodesToDelete, mapData.mappedNodes);\n                                            }\n                                        }\n                                    }\n                                    lastMappingResultIndex++;\n                                    break;\n\n                                case \"added\":\n                                    while (currentArrayIndex < itemIndex) {\n                                        itemMovedOrRetained(lastMappingResultIndex++);\n                                    }\n                                    if (movedIndex !== undefined) {\n                                        itemsToMoveFirstIndexes.push(newMappingResult.length);\n                                        itemMovedOrRetained(movedIndex);\n                                    } else {\n                                        itemAdded(editScriptItem['value']);\n                                    }\n                                    break;\n                            }\n                        }\n\n                        while (currentArrayIndex < array.length) {\n                            itemMovedOrRetained(lastMappingResultIndex++);\n                        }\n\n                        // Record that the current view may still contain deleted items\n                        // because it means we won't be able to use a provided editScript.\n                        newMappingResult['_countWaitingForRemove'] = countWaitingForRemove;\n                    }\n\n                    // Store a copy of the array items we just considered so we can difference it next time\n                    ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);\n\n                    // Call beforeMove first before any changes have been made to the DOM\n                    callCallback(options['beforeMove'], itemsForMoveCallbacks);\n\n                    // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)\n                    ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);\n\n                    var i, j, lastNode, nodeToInsert, mappedNodes, activeElement;\n\n                    // Since most browsers remove the focus from an element when it's moved to another location,\n                    // save the focused element and try to restore it later.\n                    try {\n                        activeElement = domNode.ownerDocument.activeElement;\n                    } catch(e) {\n                        // IE9 throws if you access activeElement during page load (see issue #703)\n                    }\n\n                    // Try to reduce overall moved nodes by first moving the ones that were marked as moved by the edit script\n                    if (itemsToMoveFirstIndexes.length) {\n                        while ((i = itemsToMoveFirstIndexes.shift()) != undefined) {\n                            mapData = newMappingResult[i];\n                            for (lastNode = undefined; i; ) {\n                                if ((mappedNodes = newMappingResult[--i].mappedNodes) && mappedNodes.length) {\n                                    lastNode = mappedNodes[mappedNodes.length-1];\n                                    break;\n                                }\n                            }\n                            for (j = 0; nodeToInsert = mapData.mappedNodes[j]; lastNode = nodeToInsert, j++) {\n                                ko.virtualElements.insertAfter(domNode, nodeToInsert, lastNode);\n                            }\n                        }\n                    }\n\n                    // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)\n                    for (i = 0; mapData = newMappingResult[i]; i++) {\n                        // Get nodes for newly added items\n                        if (!mapData.mappedNodes)\n                            ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));\n\n                        // Put nodes in the right place if they aren't there already\n                        for (j = 0; nodeToInsert = mapData.mappedNodes[j]; lastNode = nodeToInsert, j++) {\n                            ko.virtualElements.insertAfter(domNode, nodeToInsert, lastNode);\n                        }\n\n                        // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)\n                        if (!mapData.initialized && callbackAfterAddingNodes) {\n                            callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);\n                            mapData.initialized = true;\n                            lastNode = mapData.mappedNodes[mapData.mappedNodes.length - 1];     // get the last node again since it may have been changed by a preprocessor\n                        }\n                    }\n\n                    // Restore the focused element if it had lost focus\n                    if (activeElement && domNode.ownerDocument.activeElement != activeElement) {\n                        activeElement.focus();\n                    }\n\n                    // If there's a beforeRemove callback, call it after reordering.\n                    // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using\n                    // some sort of animation, which is why we first reorder the nodes that will be removed. If the\n                    // callback instead removes the nodes right away, it would be more efficient to skip reordering them.\n                    // Perhaps we'll make that change in the future if this scenario becomes more common.\n                    callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);\n\n                    // Replace the stored values of deleted items with a dummy value. This provides two benefits: it marks this item\n                    // as already \"removed\" so we won't call beforeRemove for it again, and it ensures that the item won't match up\n                    // with an actual item in the array and appear as \"retained\" or \"moved\".\n                    for (i = 0; i < itemsForBeforeRemoveCallbacks.length; ++i) {\n                        itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue;\n                    }\n\n                    // Finally call afterMove and afterAdd callbacks\n                    callCallback(options['afterMove'], itemsForMoveCallbacks);\n                    callCallback(options['afterAdd'], itemsForAfterAddCallbacks);\n                }\n            })();\n\n            ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);\n            ko.nativeTemplateEngine = function () {\n                this['allowTemplateRewriting'] = false;\n            }\n\n            ko.nativeTemplateEngine.prototype = new ko.templateEngine();\n            ko.nativeTemplateEngine.prototype.constructor = ko.nativeTemplateEngine;\n            ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {\n                var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly\n                    templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,\n                    templateNodes = templateNodesFunc ? templateSource['nodes']() : null;\n\n                if (templateNodes) {\n                    return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);\n                } else {\n                    var templateText = templateSource['text']();\n                    return ko.utils.parseHtmlFragment(templateText, templateDocument);\n                }\n            };\n\n            ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();\n            ko.setTemplateEngine(ko.nativeTemplateEngine.instance);\n\n            ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);\n            (function() {\n                ko.jqueryTmplTemplateEngine = function () {\n                    // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl\n                    // doesn't expose a version number, so we have to infer it.\n                    // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,\n                    // which KO internally refers to as version \"2\", so older versions are no longer detected.\n                    var jQueryTmplVersion = this.jQueryTmplVersion = (function() {\n                        if (!jQueryInstance || !(jQueryInstance['tmpl']))\n                            return 0;\n                        // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.\n                        try {\n                            if (jQueryInstance['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {\n                                // Since 1.0.0pre, custom tags should append markup to an array called \"__\"\n                                return 2; // Final version of jquery.tmpl\n                            }\n                        } catch(ex) { /* Apparently not the version we were looking for */ }\n\n                        return 1; // Any older version that we don't support\n                    })();\n\n                    function ensureHasReferencedJQueryTemplates() {\n                        if (jQueryTmplVersion < 2)\n                            throw new Error(\"Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.\");\n                    }\n\n                    function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {\n                        return jQueryInstance['tmpl'](compiledTemplate, data, jQueryTemplateOptions);\n                    }\n\n                    this['renderTemplateSource'] = function(templateSource, bindingContext, options, templateDocument) {\n                        templateDocument = templateDocument || document;\n                        options = options || {};\n                        ensureHasReferencedJQueryTemplates();\n\n                        // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)\n                        var precompiled = templateSource['data']('precompiled');\n                        if (!precompiled) {\n                            var templateText = templateSource['text']() || \"\";\n                            // Wrap in \"with($whatever.koBindingContext) { ... }\"\n                            templateText = \"{{ko_with $item.koBindingContext}}\" + templateText + \"{{/ko_with}}\";\n\n                            precompiled = jQueryInstance['template'](null, templateText);\n                            templateSource['data']('precompiled', precompiled);\n                        }\n\n                        var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays\n                        var jQueryTemplateOptions = jQueryInstance['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);\n\n                        var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);\n                        resultNodes['appendTo'](templateDocument.createElement(\"div\")); // Using \"appendTo\" forces jQuery/jQuery.tmpl to perform necessary cleanup work\n\n                        jQueryInstance['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders\n                        return resultNodes;\n                    };\n\n                    this['createJavaScriptEvaluatorBlock'] = function(script) {\n                        return \"{{ko_code ((function() { return \" + script + \" })()) }}\";\n                    };\n\n                    this['addTemplate'] = function(templateName, templateMarkup) {\n                        document.write(\"<script type='text/html' id='\" + templateName + \"'>\" + templateMarkup + \"<\" + \"/script>\");\n                    };\n\n                    if (jQueryTmplVersion > 0) {\n                        jQueryInstance['tmpl']['tag']['ko_code'] = {\n                            open: \"__.push($1 || '');\"\n                        };\n                        jQueryInstance['tmpl']['tag']['ko_with'] = {\n                            open: \"with($1) {\",\n                            close: \"} \"\n                        };\n                    }\n                };\n\n                ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();\n                ko.jqueryTmplTemplateEngine.prototype.constructor = ko.jqueryTmplTemplateEngine;\n\n                // Use this one by default *only if jquery.tmpl is referenced*\n                var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();\n                if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)\n                    ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);\n\n                ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);\n            })();\n        }));\n    }());\n})();\n","WebShopApps_MatrixRate/js/view/shipping-rates-validation.js":"/**\n * Copyright \u00a9 2015 Magento. 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/shipping-rates-validator',\n        'Magento_Checkout/js/model/shipping-rates-validation-rules',\n        '../model/shipping-rates-validator',\n        '../model/shipping-rates-validation-rules'\n    ],\n    function (\n        Component,\n        defaultShippingRatesValidator,\n        defaultShippingRatesValidationRules,\n        matrixrateShippingRatesValidator,\n        matrixrateShippingRatesValidationRules\n    ) {\n        \"use strict\";\n        defaultShippingRatesValidator.registerValidator('matrixrate', matrixrateShippingRatesValidator);\n        defaultShippingRatesValidationRules.registerRules('matrixrate', matrixrateShippingRatesValidationRules);\n        return Component;\n    }\n);\n","WebShopApps_MatrixRate/js/model/shipping-rates-validator.js":"define(\n    [\n        'jquery',\n        'mageUtils',\n        './shipping-rates-validation-rules',\n        'mage/translate'\n    ],\n    function ($, utils, validationRules, $t) {\n        \"use strict\";\n        return {\n            validationErrors: [],\n            validate: function (address) {\n                var self = this;\n                this.validationErrors = [];\n                $.each(validationRules.getRules(), function (field, rule) {\n                    if (rule.required && utils.isEmpty(address[field])) {\n                        var message = $t('Field ') + field + $t(' is required.');\n                        self.validationErrors.push(message);\n                    }\n                });\n                return !Boolean(this.validationErrors.length);\n            }\n        };\n    }\n);","WebShopApps_MatrixRate/js/model/shipping-rates-validation-rules.js":"/**\n * Copyright \u00a9 2015 Magento. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*global define*/\ndefine(\n    [],\n    function () {\n        \"use strict\";\n        return {\n            getRules: function () {\n                return {\n                    'postcode': {\n                        'required': true\n                    },\n                    'country_id': {\n                        'required': true\n                    },\n                    'region_id' : {\n                        'required': false\n                    },\n                    'city' : {\n                        'required': false\n                    }\n                };\n            }\n        };\n    }\n);\n","Magento_Paypal/js/paypal-checkout.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Ui/js/modal/confirm',\n    'Magento_Customer/js/customer-data',\n    'jquery-ui-modules/widget',\n    'mage/mage'\n], function ($, confirm, customerData) {\n    'use strict';\n\n    $.widget('mage.paypalCheckout', {\n        options: {\n            originalForm:\n                'form:not(#product_addtocart_form_from_popup):has(input[name=\"product\"][value=%1])',\n            productId: 'input[type=\"hidden\"][name=\"product\"]',\n            ppCheckoutSelector: '[data-role=pp-checkout-url]',\n            ppCheckoutInput: '<input type=\"hidden\" data-role=\"pp-checkout-url\" name=\"return_url\" value=\"\"/>'\n        },\n\n        /**\n         * Initialize store credit events\n         * @private\n         */\n        _create: function () {\n            this.element.on('click', '[data-action=\"checkout-form-submit\"]', $.proxy(function (e) {\n                var $target = $(e.target),\n                    returnUrl = $target.data('checkout-url'),\n                    productId = $target.closest('form').find(this.options.productId).val(),\n                    originalForm = this.options.originalForm.replace('%1', productId),\n                    self = this,\n                    billingAgreement = customerData.get('paypal-billing-agreement');\n\n                e.preventDefault();\n\n                if (billingAgreement().askToCreate) {\n                    confirm({\n                        content: billingAgreement().confirmMessage,\n                        actions: {\n\n                            /**\n                             * Confirmation handler\n                             *\n                             */\n                            confirm: function () {\n                                returnUrl = billingAgreement().confirmUrl;\n                                self._redirect(returnUrl, originalForm);\n                            },\n\n                            /**\n                             * Cancel confirmation handler\n                             *\n                             */\n                            cancel: function (event) {\n                                if (event && !$(event.target).hasClass('action-close')) {\n                                    self._redirect(returnUrl);\n                                }\n                            }\n                        }\n                    });\n                } else {\n                    this._redirect(returnUrl, originalForm);\n                }\n            }, this));\n        },\n\n        /**\n         * Redirect to certain url, with optional form\n         * @param {String} returnUrl\n         * @param {HTMLElement} originalForm\n         *\n         */\n        _redirect: function (returnUrl, originalForm) {\n            var $form,\n                ppCheckoutInput;\n\n            if (this.options.isCatalogProduct) {\n                // find the form from which the button was clicked\n                $form = originalForm ? $(originalForm) : $($(this.options.shortcutContainerClass).closest('form'));\n\n                ppCheckoutInput = $form.find(this.options.ppCheckoutSelector)[0];\n\n                if (!ppCheckoutInput) {\n                    ppCheckoutInput = $(this.options.ppCheckoutInput);\n                    ppCheckoutInput.appendTo($form);\n                }\n                $(ppCheckoutInput).val(returnUrl);\n\n                $form.trigger('submit');\n            } else {\n                $.mage.redirect(returnUrl);\n            }\n        }\n    });\n\n    return $.mage.paypalCheckout;\n});\n","Magento_Paypal/js/order-review.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/alert',\n    'jquery-ui-modules/widget',\n    'mage/translate',\n    'mage/mage',\n    'mage/validation'\n], function ($, alert) {\n    'use strict';\n\n    $.widget('mage.orderReview', {\n        options: {\n            orderReviewSubmitSelector: '#review-button',\n            shippingSelector: '#shipping_method',\n            shippingSubmitFormSelector: null,\n            updateOrderSelector: '#update-order',\n            billingAsShippingSelector: '#billing\\\\:as_shipping',\n            updateContainerSelector: '#details-reload',\n            waitLoadingContainer: '#review-please-wait',\n            shippingMethodContainer: '#shipping-method-container',\n            agreementSelector: 'div.checkout-agreements input',\n            isAjax: false,\n            shippingMethodUpdateUrl: null,\n            updateOrderSubmitUrl: null,\n            canEditShippingMethod: false\n        },\n\n        /**\n         * Widget instance properties\n         */\n        triggerPropertyChange: true,\n        isShippingSubmitForm: false,\n\n        /** @inheritdoc */\n        _create: function () {\n            var isDisable;\n\n            //change handler for ajaxEnabled\n            if (this.options.isAjax) {\n                this._submitOrder = this._ajaxSubmitOrder;\n            }\n\n            this.element.on('click', this.options.orderReviewSubmitSelector, $.proxy(this._submitOrder, this))\n                .on('click', this.options.billingAsShippingSelector, $.proxy(this._shippingTobilling, this))\n                .on('change',\n                    this.options.shippingSelector,\n                    $.proxy(this._submitUpdateOrder,\n                        this,\n                        this.options.updateOrderSubmitUrl,\n                        this.options.updateContainerSelector\n                    )\n                ).find(this.options.updateOrderSelector).on('click', $.proxy(this._updateOrderHandler, this)).end();\n            this._shippingTobilling();\n\n            if ($(this.options.shippingSubmitFormSelector).length && this.options.canEditShippingMethod) {\n                this.isShippingSubmitForm = true;\n                $(this.options.shippingSubmitFormSelector)\n                    .on('change',\n                        this.options.shippingSelector,\n                        $.proxy(\n                            this._submitUpdateOrder,\n                            this,\n                            $(this.options.shippingSubmitFormSelector).prop('action'),\n                            this.options.updateContainerSelector\n                        )\n                    );\n                this._updateOrderSubmit(!$(this.options.shippingSubmitFormSelector)\n                    .find(this.options.shippingSelector).val());\n            } else {\n                isDisable = this.isShippingSubmitForm && this.element.find(this.options.shippingSelector).val();\n                this.element\n                    .on('input propertychange', ':input[name]',\n                        $.proxy(this._updateOrderSubmit, this, isDisable, this._onShippingChange)\n                    ).find('select').not(this.options.shippingSelector).on('change', this._propertyChange);\n                this._updateOrderSubmit(isDisable);\n            }\n        },\n\n        /**\n         * show ajax loader\n         */\n        _ajaxBeforeSend: function () {\n            this.element.find(this.options.waitLoadingContainer).show();\n        },\n\n        /**\n         * hide ajax loader\n         */\n        _ajaxComplete: function () {\n            this.element.find(this.options.waitLoadingContainer).hide();\n        },\n\n        /**\n         * trigger propertychange for input type select\n         */\n        _propertyChange: function () {\n            $(this).trigger('propertychange');\n        },\n\n        /**\n         * trigger change for the update of shipping methods from server\n         */\n        _updateOrderHandler: function () {\n            $(this.options.shippingSelector).trigger('change');\n        },\n\n        /**\n         * Attempt to submit order\n         */\n        _submitOrder: function () {\n            if (this._validateForm()) {\n                this.element.find(this.options.updateOrderSelector).fadeTo(0, 0.5)\n                    .end().find(this.options.waitLoadingContainer).show()\n                    .end().trigger('submit');\n                this._updateOrderSubmit(true);\n            }\n        },\n\n        /**\n         * Attempt to ajax submit order\n         */\n        _ajaxSubmitOrder: function () {\n            if (this.element.find(this.options.waitLoadingContainer).is(':visible')) {\n                return false;\n            }\n            $.ajax({\n                url: this.element.prop('action'),\n                type: 'post',\n                context: this,\n                data: {\n                    isAjax: 1\n                },\n                dataType: 'json',\n                beforeSend: this._ajaxBeforeSend,\n                complete: this._ajaxComplete,\n\n                /** @inheritdoc */\n                success: function (response) {\n                    var msg;\n\n                    if (typeof response === 'object' && !$.isEmptyObject(response)) {\n                        if (response['error_messages']) {\n                            this._ajaxComplete();\n                            msg = response['error_messages'];\n\n                            /* eslint-disable max-depth */\n                            if (msg) {\n                                if (Array.isArray(msg)) {\n                                    msg = msg.join('\\n');\n                                }\n                            }\n\n                            /* eslint-enablemax-depth */\n                            alert({\n                                content: msg\n                            });\n\n                            return false;\n                        }\n\n                        if (response.redirect) {\n                            $.mage.redirect(response.redirect);\n\n                            return false;\n                        } else if (response.success) {\n                            $.mage.redirect(this.options.successUrl);\n\n                            return false;\n                        }\n                        this._ajaxComplete();\n                        alert({\n                            content: $.mage.__('Sorry, something went wrong.')\n                        });\n                    }\n                },\n\n                /** @inheritdoc */\n                error: function () {\n                    alert({\n                        content: $.mage.__('Sorry, something went wrong. Please try again later.')\n                    });\n                    this._ajaxComplete();\n                }\n            });\n        },\n\n        /**\n         * Validate Order form\n         */\n        _validateForm: function () {\n            this.element.find(this.options.agreementSelector).off('change').on('change', $.proxy(function () {\n                var isValid = this._validateForm();\n\n                this._updateOrderSubmit(!isValid);\n            }, this));\n\n            if (this.element.data('mageValidation')) {\n                return this.element.validation().valid();\n            }\n\n            return true;\n        },\n\n        /**\n         * Check/Set whether order can be submitted\n         * Also disables form submission element, if any\n         * @param {*} shouldDisable - whether should prevent order submission explicitly\n         * @param {Function} [fn] - function for shipping change handler\n         * @param {*} [*] - if true the property change will be set to true\n         */\n        _updateOrderSubmit: function (shouldDisable, fn) {\n            this._toggleButton(this.options.orderReviewSubmitSelector, shouldDisable);\n\n            if (typeof fn === 'function') {\n                fn.call(this);\n            }\n        },\n\n        /**\n         * Enable/Disable button\n         * @param {jQuery} button - button selector to be toggled\n         * @param {*} disable - boolean for toggling\n         */\n        _toggleButton: function (button, disable) {\n            $(button).prop({\n                'disabled': disable\n            }).toggleClass('no-checkout', disable).fadeTo(0, disable ? 0.5 : 1);\n        },\n\n        /**\n         * Copy element value from shipping to billing address\n         * @param {jQuery.Event} e - optional\n         */\n        _shippingTobilling: function (e) {\n            var isChecked, opacity;\n\n            if (this.options.shippingSubmitFormSelector) {\n                return false;\n            }\n            isChecked = $(this.options.billingAsShippingSelector).is(':checked');\n            opacity = isChecked ? 0.5 : 1;\n\n            if (isChecked) {\n                this.element.validation('clearError', ':input[name^=\"billing\"]');\n            }\n            $(':input[name^=\"shipping\"]', this.element).each($.proxy(function (key, value) {\n                var fieldObj = $(value.id.replace('shipping:', '#billing\\\\:'));\n\n                if (isChecked) {\n                    fieldObj = fieldObj.val($(value).val());\n                }\n                fieldObj.prop({\n                    'readonly': isChecked,\n                    'disabled': isChecked\n                }).fadeTo(0, opacity);\n\n                if (fieldObj.is('select')) {\n                    this.triggerPropertyChange = false;\n                    fieldObj.trigger('change');\n                }\n            }, this));\n\n            if (isChecked || e) {\n                this._updateOrderSubmit(true);\n            }\n            this.triggerPropertyChange = true;\n        },\n\n        /**\n         * Dispatch an ajax request of Update Order submission\n         * @param {*} url - url where to submit shipping method\n         * @param {*} resultId - id of element to be updated\n         */\n        _submitUpdateOrder: function (url, resultId) {\n            var isChecked, formData, callBackResponseHandler, shippingMethod;\n\n            if (this.element.find(this.options.waitLoadingContainer).is(':visible')) {\n                return false;\n            }\n            isChecked = $(this.options.billingAsShippingSelector).is(':checked');\n            formData = null;\n            callBackResponseHandler = null;\n            let val = $(this.options.shippingSelector).val();\n\n            shippingMethod = val.trim();\n            this._shippingTobilling();\n\n            if (url && resultId && shippingMethod) {\n                this._updateOrderSubmit(true);\n                this._toggleButton(this.options.updateOrderSelector, true);\n\n                // form data and callBack updated based on the shipping Form element\n                if (this.isShippingSubmitForm) {\n                    formData = $(this.options.shippingSubmitFormSelector).serialize() + '&isAjax=true';\n\n                    /**\n                     * @param {Object} response\n                     */\n                    callBackResponseHandler = function (response) {\n                        $(resultId).html(response);\n                        this._updateOrderSubmit(false);\n                        this._ajaxComplete();\n                    };\n                } else {\n                    formData = this.element.serialize() + '&isAjax=true';\n\n                    /**\n                     * @param {Object} response\n                     */\n                    callBackResponseHandler = function (response) {\n                        $(resultId).html(response);\n                        this._ajaxShippingUpdate(shippingMethod);\n                    };\n                }\n\n                if (isChecked) {\n                    $(this.options.shippingSelect).prop('disabled', true);\n                }\n                $.ajax({\n                    url: url,\n                    type: 'post',\n                    context: this,\n                    beforeSend: this._ajaxBeforeSend,\n                    data: formData,\n                    success: callBackResponseHandler\n                });\n            }\n        },\n\n        /**\n         * Update Shipping Methods Element from server\n         * @param {*} shippingMethod\n         */\n        _ajaxShippingUpdate: function (shippingMethod) {\n            $.ajax({\n                url: this.options.shippingMethodUpdateUrl,\n                data: {\n                    isAjax: true,\n                    'shipping_method': shippingMethod\n                },\n                type: 'post',\n                context: this,\n\n                /** @inheritdoc */\n                success: function (response) {\n                    $(this.options.shippingMethodContainer).parent().html(response);\n                    this._toggleButton(this.options.updateOrderSelector, false);\n                    this._updateOrderSubmit(false);\n                },\n                complete: this._ajaxComplete\n            });\n        },\n\n        /**\n         * Actions on change Shipping Address data\n         */\n        _onShippingChange: function () {\n            let val = $(this.options.shippingSelector).val();\n\n            if (this.triggerPropertyChange && val.trim()) {\n                this.element.find(this.options.shippingSelector).hide().end()\n                    .find(this.options.shippingSelector + '_update').show();\n            }\n        }\n    });\n\n    return $.mage.orderReview;\n});\n","Magento_Paypal/js/action/set-payment-method.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/action/set-payment-information'\n], function (quote, setPaymentInformation) {\n    'use strict';\n\n    return function (messageContainer) {\n        return setPaymentInformation(messageContainer, quote.paymentMethod());\n    };\n});\n","Magento_Paypal/js/in-context/button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'uiComponent',\n    'jquery',\n    'Magento_Paypal/js/in-context/express-checkout-wrapper',\n    'Magento_Customer/js/customer-data'\n], function (Component, $, Wrapper, customerData) {\n    'use strict';\n\n    return Component.extend(Wrapper).extend({\n        defaults: {\n            declinePayment: false\n        },\n\n        /** @inheritdoc */\n        initialize: function (config, element) {\n            var cart = customerData.get('cart'),\n                customer = customerData.get('customer');\n\n            this._super();\n            this.renderPayPalButtons(element);\n\n            if (cart().isGuestCheckoutAllowed === undefined) {\n                cart.subscribe(function (updatedCart) {\n                    this.declinePayment = !customer().firstname && !cart().isGuestCheckoutAllowed;\n\n                    return updatedCart;\n                }.bind(this));\n            }\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        beforePayment: function (resolve, reject) {\n            var promise = $.Deferred();\n\n            if (this.declinePayment) {\n                this.addError(this.signInMessage, 'warning');\n\n                reject();\n            } else {\n                promise.resolve();\n            }\n\n            return promise;\n        },\n\n        /** @inheritdoc */\n        prepareClientConfig: function () {\n            this._super();\n\n            return this.clientConfig;\n        }\n    });\n});\n","Magento_Paypal/js/in-context/express-checkout-wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'mage/translate',\n    'Magento_Customer/js/customer-data',\n    'Magento_Paypal/js/in-context/express-checkout-smart-buttons',\n    'Magento_Ui/js/modal/alert',\n    'mage/cookies'\n], function ($, $t, customerData, checkoutSmartButtons, alert) {\n    'use strict';\n\n    return {\n        defaults: {\n            paymentActionError: $t('Something went wrong with your request. Please try again later.'),\n            signInMessage: $t('To check out, please sign in with your email address.')\n        },\n\n        /**\n         * Render PayPal buttons using checkout.js\n         */\n        renderPayPalButtons: function (element) {\n            checkoutSmartButtons(this.prepareClientConfig(), element);\n        },\n\n        /**\n         * Validate payment method\n         *\n         * @param {Object} actions\n         */\n        validate: function (actions) {\n            this.actions = actions || this.actions;\n        },\n\n        /**\n         * Execute logic on Paypal button click\n         */\n        onClick: function () {},\n\n        /**\n         * Before payment execute\n         *\n         * @param {Function} resolve\n         * @param {Function} reject\n         * @return {*}\n         */\n        beforePayment: function (resolve, reject) { //eslint-disable-line no-unused-vars\n            return $.Deferred().resolve();\n        },\n\n        /**\n         * After payment execute\n         *\n         * @param {Object} res\n         * @param {Function} resolve\n         * @param {Function} reject\n         *\n         * @return {*}\n         */\n        afterPayment: function (res, resolve, reject) {\n\n            if (res.success) {\n                return resolve(res.token);\n            }\n\n            return reject(new Error(res['error_message']));\n        },\n\n        /**\n         * Catch payment\n         *\n         * @param {Error} err\n         * @param {Function} resolve\n         * @param {Function} reject\n         */\n        catchPayment: function (err, resolve, reject) {\n            this.addAlert(this.paymentActionError);\n            reject(err);\n        },\n\n        /**\n         * Before onAuthorize execute\n         *\n         * @param {Function} resolve\n         * @param {Function} reject\n         * @param {Object} actions\n         *\n         * @return {jQuery.Deferred}\n         */\n        beforeOnAuthorize: function (resolve, reject, actions) { //eslint-disable-line no-unused-vars\n            //display loading widget.\n            $('body').trigger('processStart');\n\n            return $.Deferred().resolve();\n        },\n\n        /**\n         * After onAuthorize execute\n         *\n         * @param {Object} res\n         * @param {Function} resolve\n         * @param {Function} reject\n         * @param {Object} actions\n         *\n         * @return {*}\n         */\n        afterOnAuthorize: function (res, resolve, reject, actions) {\n            $('body').trigger('processStop');\n\n            if (res.success) {\n                resolve();\n\n                return actions.redirect(res.redirectUrl);\n            }\n\n            return reject(new Error(res['error_message']));\n        },\n\n        /**\n         * Catch payment\n         *\n         * @param {Error} err\n         * @param {Function} resolve\n         * @param {Function} reject\n         */\n        catchOnAuthorize: function (err, resolve, reject) {\n            $('body').trigger('processStop');\n            this.addAlert(this.paymentActionError);\n            reject(err);\n        },\n\n        /**\n         * Process cancel action\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         */\n        onCancel: function (data, actions) {\n            $('body').trigger('processStop');\n            actions.redirect(this.clientConfig.onCancelUrl);\n        },\n\n        /**\n         * Process errors\n         *\n         * @param {Error} err\n         */\n        onError: function (err) { //eslint-disable-line no-unused-vars\n            // Uncaught error isn't displayed in the console\n        },\n\n        /**\n         * Adds error message\n         *\n         * @param {String} message\n         * @param {String} [type]\n         */\n        addError: function (message, type) {\n            type = type || 'error';\n            customerData.set('messages', {\n                messages: [{\n                    type: type,\n                    text: message\n                }],\n                'data_id': Math.floor(Date.now() / 1000)\n            });\n        },\n\n        /**\n         * Add alert message\n         *\n         * @param {String} message\n         */\n        addAlert: function (message) {\n            alert({\n                content: message\n            });\n        },\n\n        /**\n         * @returns {String}\n         */\n        getButtonId: function () {\n            return this.inContextId;\n        },\n\n        /**\n         * Populate client config with all required data\n         *\n         * @return {Object}\n         */\n        prepareClientConfig: function () {\n            this.clientConfig.rendererComponent = this;\n            this.clientConfig.formKey = $.mage.cookies.get('form_key');\n\n            return this.clientConfig;\n        }\n    };\n});\n","Magento_Paypal/js/in-context/express-checkout-smart-buttons.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* eslint-disable max-nested-callbacks */\ndefine([\n    'underscore',\n    'jquery',\n    'Magento_Paypal/js/in-context/paypal-sdk',\n    'Magento_Customer/js/customer-data',\n    'domReady!'\n], function (_, $, paypalSdk, customerData) {\n    'use strict';\n\n    /**\n     * Triggers beforePayment action on PayPal buttons\n     *\n     * @param {Object} clientConfig\n     * @returns {Object} jQuery promise\n     */\n    function performCreateOrder(clientConfig) {\n        var params = {\n            'quote_id': clientConfig.quoteId,\n            'customer_id': clientConfig.customerId || '',\n            'form_key': clientConfig.formKey,\n            button: clientConfig.button\n        };\n\n        return $.Deferred(function (deferred) {\n            clientConfig.rendererComponent.beforePayment(deferred.resolve, deferred.reject).then(function () {\n                $.post(clientConfig.getTokenUrl, params).done(function (res) {\n                    clientConfig.rendererComponent.afterPayment(res, deferred.resolve, deferred.reject);\n                }).fail(function (jqXHR, textStatus, err) {\n                    clientConfig.rendererComponent.catchPayment(err, deferred.resolve, deferred.reject);\n                });\n            });\n        }).promise();\n    }\n\n    /**\n     * Triggers beforeOnAuthorize action on PayPal buttons\n     * @param {Object} clientConfig\n     * @param {Object} data\n     * @param {Object} actions\n     * @returns {Object} jQuery promise\n     */\n    function performOnApprove(clientConfig, data, actions) {\n        var params = {\n            paymentToken: data.orderID,\n            payerId: data.payerID,\n            paypalFundingSource: customerData.get('paypal-funding-source'),\n            'form_key': clientConfig.formKey\n        };\n\n        return $.Deferred(function (deferred) {\n            clientConfig.rendererComponent.beforeOnAuthorize(deferred.resolve, deferred.reject, actions)\n                .then(function () {\n                    $.post(clientConfig.onAuthorizeUrl, params).done(function (res) {\n                        if (res.success === false) {\n                            clientConfig.rendererComponent.catchOnAuthorize(res, deferred.resolve, deferred.reject);\n                            return;\n                        }\n                        clientConfig.rendererComponent\n                            .afterOnAuthorize(res, deferred.resolve, deferred.reject, actions);\n                        customerData.set('paypal-funding-source', '');\n                    }).fail(function (jqXHR, textStatus, err) {\n                        clientConfig.rendererComponent.catchOnAuthorize(err, deferred.resolve, deferred.reject);\n                        customerData.set('paypal-funding-source', '');\n                    });\n                });\n        }).promise();\n    }\n\n    return function (clientConfig, element) {\n        paypalSdk(clientConfig.sdkUrl, clientConfig.dataAttributes).done(function (paypal) {\n            paypal.Buttons({\n                style: clientConfig.styles,\n\n                /**\n                 * onInit is called when the button first renders\n                 * @param {Object} data\n                 * @param {Object} actions\n                 */\n                onInit: function (data, actions) {\n                    clientConfig.rendererComponent.validate(actions);\n                },\n\n                /**\n                 * Triggers beforePayment action on PayPal buttons\n                 * @returns {Object} jQuery promise\n                 */\n                createOrder: function () {\n                    return performCreateOrder(clientConfig);\n                },\n\n                /**\n                 * Triggers beforeOnAuthorize action on PayPal buttons\n                 * @param {Object} data\n                 * @param {Object} actions\n                 */\n                onApprove: function (data, actions) {\n                    performOnApprove(clientConfig, data, actions);\n                },\n\n                /**\n                 * Execute logic on Paypal button click\n                 */\n                onClick: function (data) {\n                    customerData.set('paypal-funding-source', data.fundingSource);\n                    clientConfig.rendererComponent.validate();\n                    clientConfig.rendererComponent.onClick();\n                },\n\n                /**\n                 * Process cancel action\n                 * @param {Object} data\n                 * @param {Object} actions\n                 */\n                onCancel: function (data, actions) {\n                    clientConfig.rendererComponent.onCancel(data, actions);\n                },\n\n                /**\n                 * Process errors\n                 *\n                 * @param {Error} err\n                 */\n                onError: function (err) {\n                    clientConfig.rendererComponent.onError(err);\n                }\n            }).render(element);\n        });\n    };\n});\n","Magento_Paypal/js/in-context/paypal-sdk.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    var dfd = $.Deferred();\n\n    /**\n     * Loads the PayPal SDK object\n     * @param {String} paypalUrl - the url of the PayPal SDK\n     * @param {Array} dataAttributes - Array of the Attributes for PayPal SDK Script tag\n     */\n    return function loadPaypalScript(paypalUrl, dataAttributes) {\n        //configuration for loaded PayPal script\n        require.config({\n            paths: {\n                paypalSdk: paypalUrl\n            },\n            shim: {\n                paypalSdk: {\n                    exports: 'paypal'\n                }\n            },\n            attributes: {\n                'paypalSdk': dataAttributes\n            },\n\n            /**\n             * Add attributes under Paypal SDK Script tag\n             */\n            onNodeCreated: function (node, config, name) {\n                if (config.attributes && config.attributes[name]) {\n                    $.each(dataAttributes, function (index, elem) {\n                        node.setAttribute(index, elem);\n                    });\n                }\n            }\n        });\n\n        if (dfd.state() !== 'resolved') {\n            require(['paypalSdk'], function (paypalObject) {\n                dfd.resolve(paypalObject);\n            });\n        }\n\n        return dfd.promise();\n    };\n});\n","Magento_Paypal/js/in-context/product-express-checkout.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'jquery',\n    'uiComponent',\n    'Magento_Paypal/js/in-context/express-checkout-wrapper',\n    'Magento_Customer/js/customer-data'\n], function (_, $, Component, Wrapper, customerData) {\n    'use strict';\n\n    return Component.extend(Wrapper).extend({\n        defaults: {\n            productFormSelector: '#product_addtocart_form',\n            declinePayment: false,\n            formInvalid: false,\n            productAddedToCart: false\n        },\n\n        /** @inheritdoc */\n        initialize: function (config, element) {\n            var cart = customerData.get('cart'),\n                customer = customerData.get('customer'),\n                isGuestCheckoutAllowed;\n\n            this._super();\n\n            isGuestCheckoutAllowed = cart().isGuestCheckoutAllowed;\n\n            if (typeof isGuestCheckoutAllowed === 'undefined') {\n                isGuestCheckoutAllowed = config.clientConfig.isGuestCheckoutAllowed;\n            }\n\n            if (config.clientConfig.isVisibleOnProductPage) {\n                this.renderPayPalButtons(element);\n            }\n\n            this.declinePayment = !customer().firstname && !isGuestCheckoutAllowed;\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        onClick: function () {\n            var $form = $(this.productFormSelector);\n\n            if (!this.declinePayment && !this.productAddedToCart) {\n                $form.trigger('submit');\n                this.formInvalid = !$form.validation('isValid');\n                this.productAddedToCart = true;\n            }\n        },\n\n        /** @inheritdoc */\n        beforePayment: function (resolve, reject) {\n            var promise = $.Deferred();\n\n            if (this.declinePayment) {\n                this.addError(this.signInMessage, 'warning');\n                reject();\n            } else if (this.formInvalid) {\n                reject();\n            } else {\n                $(document).on('ajax:addToCart', function (e, data) {\n                    if (_.isEmpty(data.response)) {\n                        return promise.resolve();\n                    }\n\n                    return reject();\n                });\n                $(document).on('ajax:addToCart:error', reject);\n            }\n\n            return promise;\n        },\n\n        /**\n         * After payment execute\n         *\n         * @param {Object} res\n         * @param {Function} resolve\n         * @param {Function} reject\n         *\n         * @return {*}\n         */\n        afterPayment: function (res, resolve, reject) {\n            if (res.success) {\n                return resolve(res.token);\n            }\n\n            this.addAlert(res['error_message']);\n\n            return reject(new Error(res['error_message']));\n        },\n\n        /** @inheritdoc */\n        prepareClientConfig: function () {\n            this._super();\n            this.clientConfig.quoteId = '';\n            this.clientConfig.customerId = '';\n\n            return this.clientConfig;\n        },\n\n        /** @inheritdoc */\n        onError: function (err) {\n            this.productAddedToCart = false;\n            this._super(err);\n        },\n\n        /** @inheritdoc */\n        onCancel: function (data, actions) {\n            this.productAddedToCart = false;\n            this._super(data, actions);\n        },\n\n        /** @inheritdoc */\n        afterOnAuthorize: function (res, resolve, reject, actions) {\n            this.productAddedToCart = false;\n\n            return this._super(res, resolve, reject, actions);\n        }\n    });\n});\n","Magento_Paypal/js/in-context/billing-agreement.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'Magento_Ui/js/modal/confirm',\n    'Magento_Customer/js/customer-data'\n], function ($, confirm, customerData) {\n    'use strict';\n\n    $.widget('mage.billingAgreement', {\n        options: {\n            invalidateOnLoad: false,\n            cancelButtonSelector: '.block-billing-agreements-view button.cancel',\n            cancelMessage: '',\n            cancelUrl: ''\n        },\n\n        /**\n         * Initialize billing agreements events\n         * @private\n         */\n        _create: function () {\n            var self = this;\n\n            if (this.options.invalidateOnLoad) {\n                this.invalidate();\n            }\n            $(this.options.cancelButtonSelector).on('click', function () {\n                confirm({\n                    content: self.options.cancelMessage,\n                    actions: {\n                        /**\n                         * 'Confirm' action handler.\n                         */\n                        confirm: function () {\n                            self.invalidate();\n                            window.location.href = self.options.cancelUrl;\n                        }\n                    }\n                });\n\n                return false;\n            });\n        },\n\n        /**\n         * clear paypal billing agreement customer data\n         * @returns void\n         */\n        invalidate: function () {\n            customerData.invalidate(['paypal-billing-agreement']);\n        }\n    });\n\n    return $.mage.billingAgreement;\n});\n","Magento_Paypal/js/view/paylater.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'ko',\n    'uiElement',\n    'uiLayout',\n    'Magento_Paypal/js/in-context/paypal-sdk',\n    'domReady!'\n], function (\n    $,\n    ko,\n    Component,\n    layout,\n    paypalSdk\n) {\n    'use strict';\n\n    return Component.extend({\n\n        defaults: {\n            template: 'Magento_Paypal/paylater',\n            sdkUrl: '',\n            attributes: {\n                class: 'pay-later-message'\n            },\n            dataAttributes: {},\n            refreshSelector: '',\n            displayAmount: false,\n            amountComponentConfig: {\n                name: '${ $.name }.amountProvider',\n                component: ''\n            }\n        },\n        paypal: null,\n        amount: null,\n\n        /**\n         * Initialize\n         *\n         * @returns {*}\n         */\n        initialize: function () {\n            this._super()\n                .observe(['amount']);\n\n            if (this.displayAmount) {\n                layout([this.amountComponentConfig]);\n            }\n\n            if (this.sdkUrl !== '') {\n                this.loadPayPalSdk(this.sdkUrl, this.dataAttributes)\n                    .then(this._setPayPalObject.bind(this));\n            }\n\n            if (this.refreshSelector) {\n                $(this.refreshSelector).on('click', this._refreshMessages.bind(this));\n            }\n\n            return this;\n        },\n\n        /**\n         * Get attribute value from configuration\n         *\n         * @param {String} attributeName\n         * @returns {*|null}\n         */\n        getAttribute: function (attributeName) {\n            return typeof this.attributes[attributeName] !== 'undefined' ?\n                this.attributes[attributeName] : null;\n        },\n\n        /**\n         * Load PP SDK with preconfigured options\n         *\n         * @param {String} sdkUrl - the url of the PayPal SDK\n         * @param {Array} dataAttributes - Array of the Attributes for PayPal SDK Script tag\n         */\n        loadPayPalSdk: function (sdkUrl, dataAttributes) {\n            return paypalSdk(sdkUrl, dataAttributes);\n        },\n\n        /**\n         * Set reference to paypal Sdk object\n         *\n         * @param {Object} paypal\n         * @private\n         */\n        _setPayPalObject: function (paypal) {\n            this.paypal = paypal;\n        },\n\n        /**\n         * Render messages\n         *\n         * @private\n         */\n        _refreshMessages: function () {\n            if (this.paypal) {\n                this.paypal.Messages.render();\n            }\n        }\n    });\n});\n","Magento_Paypal/js/view/payment/paypal-payments.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], function (Component, rendererList) {\n    'use strict';\n\n    var isContextCheckout = window.checkoutConfig.payment.paypalExpress.isContextCheckout,\n        paypalExpress = 'Magento_Paypal/js/view/payment/method-renderer' +\n            (isContextCheckout ? '/in-context/checkout-express' : '/paypal-express');\n\n    rendererList.push(\n        {\n            type: 'paypal_express',\n            component: paypalExpress,\n            config: window.checkoutConfig.payment.paypalExpress.inContextConfig\n        },\n        {\n            type: 'payflow_express',\n            component: 'Magento_Paypal/js/view/payment/method-renderer/payflow-express'\n        },\n        {\n            type: 'payflow_express_bml',\n            component: 'Magento_Paypal/js/view/payment/method-renderer/payflow-express-bml'\n        },\n        {\n            type: 'payflowpro',\n            component: 'Magento_Paypal/js/view/payment/method-renderer/payflowpro-method'\n        },\n        {\n            type: 'payflow_link',\n            component: 'Magento_Paypal/js/view/payment/method-renderer/iframe-methods'\n        },\n        {\n            type: 'payflow_advanced',\n            component: 'Magento_Paypal/js/view/payment/method-renderer/iframe-methods'\n        },\n        {\n            type: 'hosted_pro',\n            component: 'Magento_Paypal/js/view/payment/method-renderer/iframe-methods'\n        },\n        {\n            type: 'paypal_billing_agreement',\n            component: 'Magento_Paypal/js/view/payment/method-renderer/paypal-billing-agreement'\n        }\n    );\n\n    /**\n     * Add view logic here if needed\n     **/\n    return Component.extend({});\n});\n","Magento_Paypal/js/view/payment/method-renderer/payflowpro-method.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/iframe',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Checkout/js/action/set-payment-information',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'Magento_Vault/js/view/payment/vault-enabler'\n], function ($, Component, additionalValidators, setPaymentInformationAction, fullScreenLoader, VaultEnabler) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Paypal/payment/payflowpro-form'\n        },\n        placeOrderHandler: null,\n        validateHandler: null,\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         * @param {Function} handler\n         */\n        setPlaceOrderHandler: function (handler) {\n            this.placeOrderHandler = handler;\n        },\n\n        /**\n         * @param {Function} handler\n         */\n        setValidateHandler: function (handler) {\n            this.validateHandler = handler;\n        },\n\n        /**\n         * @returns {Object}\n         */\n        context: function () {\n            return this;\n        },\n\n        /**\n         * @returns {Boolean}\n         */\n        isShowLegend: function () {\n            return true;\n        },\n\n        /**\n         * @returns {String}\n         */\n        getCode: function () {\n            return 'payflowpro';\n        },\n\n        /**\n         * @returns {Boolean}\n         */\n        isActive: function () {\n            return true;\n        },\n\n        /**\n         * @override\n         */\n        placeOrder: function () {\n            var self = this;\n\n            if (this.validateHandler() &&\n                additionalValidators.validate() &&\n                this.isPlaceOrderActionAllowed() === true\n            ) {\n                this.isPlaceOrderActionAllowed(false);\n                fullScreenLoader.startLoader();\n                $.when(\n                    setPaymentInformationAction(this.messageContainer, self.getData())\n                ).done(\n                    function () {\n                        self.placeOrderHandler().fail(\n                            function () {\n                                fullScreenLoader.stopLoader();\n                            }\n                        );\n                    }\n                ).always(\n                    function () {\n                        self.isPlaceOrderActionAllowed(true);\n                        fullScreenLoader.stopLoader();\n                    }\n                );\n            }\n        },\n\n        /**\n         * @returns {Object}\n         */\n        getData: function () {\n            var data = {\n                'method': this.getCode(),\n                'additional_data': {\n                    'cc_type': this.creditCardType(),\n                    'cc_exp_year': this.creditCardExpYear(),\n                    'cc_exp_month': this.creditCardExpMonth(),\n                    'cc_last_4': this.creditCardNumber().substr(-4)\n                }\n            };\n\n            this.vaultEnabler.visitAdditionalData(data);\n\n            return data;\n        },\n\n        /**\n         * @returns {Bool}\n         */\n        isVaultEnabled: function () {\n            return this.vaultEnabler.isVaultEnabled();\n        },\n\n        /**\n         * @returns {String}\n         */\n        getVaultCode: function () {\n            return 'payflowpro_cc_vault';\n        }\n    });\n});\n","Magento_Paypal/js/view/payment/method-renderer/paypal-express.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Paypal/js/view/payment/method-renderer/paypal-express-abstract'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Paypal/payment/paypal-express'\n        }\n    });\n});\n","Magento_Paypal/js/view/payment/method-renderer/payflow-express.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Paypal/js/view/payment/method-renderer/paypal-express-abstract'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Paypal/payment/payflow-express'\n        }\n    });\n});\n","Magento_Paypal/js/view/payment/method-renderer/payflow-express-bml.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Paypal/js/view/payment/method-renderer/paypal-express-abstract'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Paypal/payment/payflow-express-bml'\n        }\n    });\n});\n","Magento_Paypal/js/view/payment/method-renderer/iframe-methods.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Checkout/js/view/payment/default',\n    'Magento_Paypal/js/model/iframe',\n    'Magento_Checkout/js/model/full-screen-loader'\n], function (Component, iframe, fullScreenLoader) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Paypal/payment/iframe-methods',\n            paymentReady: false\n        },\n        redirectAfterPlaceOrder: false,\n        isInAction: iframe.isInAction,\n\n        /**\n         * @return {exports}\n         */\n        initObservable: function () {\n            this._super()\n                .observe('paymentReady');\n\n            return this;\n        },\n\n        /**\n         * @return {*}\n         */\n        isPaymentReady: function () {\n            return this.paymentReady();\n        },\n\n        /**\n         * Get action url for payment method iframe.\n         * @returns {String}\n         */\n        getActionUrl: function () {\n            return this.isInAction() ? window.checkoutConfig.payment.paypalIframe.actionUrl[this.getCode()] : '';\n        },\n\n        /**\n         * Places order in pending payment status.\n         */\n        placePendingPaymentOrder: function () {\n            if (this.placeOrder()) {\n                fullScreenLoader.startLoader();\n                this.isInAction(true);\n                // capture all click events\n                document.addEventListener('click', iframe.stopEventPropagation, true);\n            }\n        },\n\n        /**\n         * @return {*}\n         */\n        getPlaceOrderDeferredObject: function () {\n            var self = this;\n\n            return this._super().fail(function () {\n                fullScreenLoader.stopLoader();\n                self.isInAction(false);\n                document.removeEventListener('click', iframe.stopEventPropagation, true);\n            });\n        },\n\n        /**\n         * After place order callback\n         */\n        afterPlaceOrder: function () {\n            if (this.iframeIsLoaded) {\n                document.getElementById(this.getCode() + '-iframe')\n                    .contentWindow.location.reload();\n                this.paymentReady(false);\n            }\n\n            this.paymentReady(true);\n            this.iframeIsLoaded = true;\n            this.isPlaceOrderActionAllowed(true);\n            fullScreenLoader.stopLoader();\n        },\n\n        /**\n         * Hide loader when iframe is fully loaded.\n         */\n        iframeLoaded: function () {\n            fullScreenLoader.stopLoader();\n        }\n    });\n});\n","Magento_Paypal/js/view/payment/method-renderer/paypal-billing-agreement.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Checkout/js/view/payment/default',\n    'mage/validation'\n], function ($, Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Paypal/payment/paypal_billing_agreement-form',\n            selectedBillingAgreement: ''\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super()\n                .observe('selectedBillingAgreement');\n\n            return this;\n        },\n\n        /**\n         * @return {*}\n         */\n        getTransportName: function () {\n            return window.checkoutConfig.payment.paypalBillingAgreement.transportName;\n        },\n\n        /**\n         * @return {*}\n         */\n        getBillingAgreements: function () {\n            return window.checkoutConfig.payment.paypalBillingAgreement.agreements;\n        },\n\n        /**\n         * @return {Object}\n         */\n        getData: function () {\n            var additionalData = null;\n\n            if (this.getTransportName()) {\n                additionalData = {};\n                additionalData[this.getTransportName()] = this.selectedBillingAgreement();\n            }\n\n            return {\n                'method': this.item.method,\n                'additional_data': additionalData\n            };\n        },\n\n        /**\n         * @return {jQuery}\n         */\n        validate: function () {\n            var form = '#billing-agreement-form';\n\n            return $(form).validation() && $(form).validation('isValid');\n        }\n    });\n});\n","Magento_Paypal/js/view/payment/method-renderer/paypal-express-abstract.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Checkout/js/view/payment/default',\n    'Magento_Paypal/js/action/set-payment-method',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Customer/js/customer-data'\n], function ($, Component, setPaymentMethodAction, additionalValidators, quote, customerData) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Paypal/payment/payflow-express-bml',\n            billingAgreement: ''\n        },\n\n        /** Init observable variables */\n        initObservable: function () {\n            this._super()\n                .observe('billingAgreement');\n\n            return this;\n        },\n\n        /** Open window with  */\n        showAcceptanceWindow: function (data, event) {\n            window.open(\n                $(event.currentTarget).attr('href'),\n                'olcwhatispaypal',\n                'toolbar=no, location=no,' +\n                ' directories=no, status=no,' +\n                ' menubar=no, scrollbars=yes,' +\n                ' resizable=yes, ,left=0,' +\n                ' top=0, width=400, height=350'\n            );\n\n            return false;\n        },\n\n        /** Returns payment acceptance mark link path */\n        getPaymentAcceptanceMarkHref: function () {\n            return window.checkoutConfig.payment.paypalExpress.paymentAcceptanceMarkHref;\n        },\n\n        /** Returns payment acceptance mark image path */\n        getPaymentAcceptanceMarkSrc: function () {\n            return window.checkoutConfig.payment.paypalExpress.paymentAcceptanceMarkSrc;\n        },\n\n        /** Returns billing agreement data */\n        getBillingAgreementCode: function () {\n            return window.checkoutConfig.payment.paypalExpress.billingAgreementCode[this.item.method];\n        },\n\n        /** Returns payment information data */\n        getData: function () {\n            var parent = this._super(),\n                additionalData = null;\n\n            if (this.getBillingAgreementCode()) {\n                additionalData = {};\n                additionalData[this.getBillingAgreementCode()] = this.billingAgreement();\n            }\n\n            return $.extend(true, parent, {\n                'additional_data': additionalData\n            });\n        },\n\n        /** Redirect to paypal */\n        continueToPayPal: function () {\n            if (additionalValidators.validate()) {\n                //update payment method information if additional data was changed\n                setPaymentMethodAction(this.messageContainer).done(\n                    function () {\n                        customerData.invalidate(['cart']);\n                        $.mage.redirect(\n                            window.checkoutConfig.payment.paypalExpress.redirectUrl[quote.paymentMethod().method]\n                        );\n                    }\n                );\n\n                return false;\n            }\n        }\n    });\n});\n","Magento_Paypal/js/view/payment/method-renderer/payflowpro/vault.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Vault/js/view/payment/method-renderer/vault'\n], function (VaultComponent) {\n    'use strict';\n\n    return VaultComponent.extend({\n        defaults: {\n            template: 'Magento_Vault/payment/form'\n        },\n\n        /**\n         * @returns {String}\n         */\n        getToken: function () {\n            return this.publicHash;\n        },\n\n        /**\n         * Get last 4 digits of card\n         * @returns {String}\n         */\n        getMaskedCard: function () {\n            return this.details['cc_last_4'];\n        },\n\n        /**\n         * Get expiration date\n         * @returns {String}\n         */\n        getExpirationDate: function () {\n            return this.details['cc_exp_month'] + '/' + this.details['cc_exp_year'];\n        },\n\n        /**\n         * Get card type\n         * @returns {String}\n         */\n        getCardType: function () {\n            return this.details['cc_type'];\n        }\n    });\n});\n","Magento_Paypal/js/view/payment/method-renderer/in-context/checkout-express.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'Magento_Paypal/js/view/payment/method-renderer/paypal-express-abstract',\n    'Magento_Paypal/js/in-context/express-checkout-wrapper',\n    'Magento_Paypal/js/action/set-payment-method',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Ui/js/model/messageList',\n    'Magento_Ui/js/lib/view/utils/async'\n], function ($, Component, Wrapper, setPaymentMethod, additionalValidators, messageList) {\n    'use strict';\n\n    return Component.extend(Wrapper).extend({\n        defaults: {\n            template: 'Magento_Paypal/payment/paypal-express-in-context',\n            validationElements: 'input'\n        },\n\n        /**\n         * Listens element on change and validate it.\n         *\n         * @param {HTMLElement} context\n         */\n        initListeners: function (context) {\n            $.async(this.validationElements, context, function (element) {\n                $(element).on('change', function () {\n                    this.validate();\n                }.bind(this));\n            }.bind(this));\n        },\n\n        /**\n         *  Validates Smart Buttons\n         */\n        validate: function () {\n            this._super();\n\n            if (this.actions) {\n                additionalValidators.validate(true) ? this.actions.enable() : this.actions.disable();\n            }\n        },\n\n        /** @inheritdoc */\n        beforePayment: function (resolve, reject) {\n            var promise = $.Deferred();\n\n            setPaymentMethod(this.messageContainer).done(function () {\n                return promise.resolve();\n            }).fail(function (response) {\n                var error;\n\n                try {\n                    error = JSON.parse(response.responseText);\n                } catch (exception) {\n                    error = this.paymentActionError;\n                }\n\n                this.addError(error);\n\n                return reject(new Error(error));\n            }.bind(this));\n\n            return promise;\n        },\n\n        /**\n         * Populate client config with all required data\n         *\n         * @return {Object}\n         */\n        prepareClientConfig: function () {\n            this._super();\n            this.clientConfig.quoteId = window.checkoutConfig.quoteData['entity_id'];\n            this.clientConfig.customerId = window.customerData.id;\n            this.clientConfig.button = 0;\n\n            return this.clientConfig;\n        },\n\n        /**\n         * Adding logic to be triggered onClick action for smart buttons component\n         */\n        onClick: function () {\n            additionalValidators.validate();\n        },\n\n        /**\n         * Adds error message\n         *\n         * @param {String} message\n         */\n        addError: function (message) {\n            messageList.addErrorMessage({\n                message: message\n            });\n        },\n\n        /**\n         * After payment execute\n         *\n         * @param {Object} res\n         * @param {Function} resolve\n         * @param {Function} reject\n         *\n         * @return {*}\n         */\n        afterPayment: function (res, resolve, reject) {\n            if (res.success) {\n                return resolve(res.token);\n            }\n\n            this.addError(res['error_message']);\n\n            return reject(new Error(res['error_message']));\n        },\n\n        /**\n         * After onAuthorize execute\n         *\n         * @param {Object} res\n         * @param {Function} resolve\n         * @param {Function} reject\n         * @param {Object} actions\n         *\n         * @return {*}\n         */\n        afterOnAuthorize: function (res, resolve, reject, actions) {\n            if (res.success) {\n                resolve();\n\n                return actions.redirect(res.redirectUrl);\n            }\n\n            this.addError(res['error_message']);\n\n            return reject(new Error(res['error_message']));\n        }\n    });\n});\n","Magento_Paypal/js/view/amountProviders/checkout.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'ko',\n    'uiElement',\n    'uiRegistry',\n    'Magento_Checkout/js/model/quote',\n    'domReady!'\n], function (\n    $,\n    ko,\n    Component,\n    registry,\n    quote\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            amount: null\n        },\n\n        /**\n         * Initialize\n         *\n         * @returns {*}\n         */\n        initialize: function () {\n            this._super();\n\n            this.updateAmount();\n\n            return this;\n        },\n\n        /**\n         * Update amount\n         */\n        updateAmount: function () {\n            var payLater = registry.get(this.parentName);\n\n            quote.totals.subscribe(function (newValue) {\n                payLater.amount(newValue['base_grand_total']);\n            });\n        }\n    });\n});\n","Magento_Paypal/js/view/amountProviders/product-grouped.js":"/**\n* Copyright \u00a9 Magento, Inc. All rights reserved.\n* See COPYING.txt for license details.\n*/\n\ndefine([\n    'jquery',\n    'uiElement',\n    'uiRegistry',\n    'domReady!'\n], function (\n    $,\n    Component,\n    registry\n) {\n    'use strict';\n\n    return Component.extend({\n\n        defaults: {\n            tableWrapperSelector: '.table-wrapper.grouped',\n            priceBoxSelector: '[data-role=\"priceBox\"]',\n            qtyFieldSelector: '.input-text.qty',\n            amount: null\n        },\n        priceInfo: {},\n\n        /**\n         * Initialize\n         *\n         * @returns {*}\n         */\n        initialize: function () {\n            var self = this;\n\n            this._super();\n\n            $('tbody tr', this.tableWrapperSelector).each(function (index, element) {\n                var priceBox = $(self.priceBoxSelector, element),\n                    qtyElement = $(self.qtyFieldSelector, element),\n                    productId = priceBox.data('productId'),\n                    priceElement = $('#product-price-' + productId);\n\n                self.priceInfo[productId] = {\n                    qty: self._getQty(qtyElement),\n                    price: priceElement.data('priceAmount')\n                };\n            });\n\n            $(this.qtyFieldSelector).on('change', this._onQtyChange.bind(this));\n\n            this._updateAmount();\n\n            return this;\n        },\n\n        /**\n         * Get product quantity\n         *\n         * @param {jQuery.Element} element\n         * @private\n         */\n        _getQty: function (element) {\n            var qty = parseFloat(element.val());\n\n            return !isNaN(qty) && qty ? qty : 0;\n        },\n\n        /**\n         * Handle changed product quantity\n         *\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _onQtyChange: function (event) {\n            var qtyElement = $(event.target),\n                parent = qtyElement.parents('tr'),\n                priceBox = $(this.priceBoxSelector, parent),\n                productId = priceBox.data('productId');\n\n            if (this.priceInfo[productId]) {\n                this.priceInfo[productId].qty = this._getQty(qtyElement);\n            }\n\n            this._updateAmount();\n        },\n\n        /**\n         * Calculate and update amount\n         *\n         * @private\n         */\n        _updateAmount: function () {\n            var productId,\n                amount = 0,\n                payLater = registry.get(this.parentName);\n\n            for (productId in this.priceInfo) {\n                if (this.priceInfo.hasOwnProperty(productId)) {\n                    amount += this.priceInfo[productId].price * this.priceInfo[productId].qty;\n                }\n            }\n\n            payLater.amount(amount);\n        }\n    });\n});\n","Magento_Paypal/js/view/amountProviders/product.js":"/**\n* Copyright \u00a9 Magento, Inc. All rights reserved.\n* See COPYING.txt for license details.\n*/\n\ndefine([\n    'jquery',\n    'uiElement',\n    'uiRegistry',\n    'priceBox',\n    'domReady!'\n], function (\n    $,\n    Component,\n    registry\n) {\n    'use strict';\n\n    return Component.extend({\n\n        defaults: {\n            priceBoxSelector: '.price-box',\n            qtyFieldSelector: '#product_addtocart_form [name=\"qty\"]',\n            amount: null\n        },\n        qty: 1,\n        price: 0,\n        priceType: '',\n\n        /**\n         * Initialize\n         *\n         * @returns {*}\n         */\n        initialize: function () {\n            var priceBox;\n\n            this._super();\n\n            priceBox = $(this.priceBoxSelector);\n            priceBox.on('priceUpdated', this._onPriceChange.bind(this));\n\n            if (priceBox.priceBox('option') &&\n                priceBox.priceBox('option').prices &&\n                (priceBox.priceBox('option').prices.finalPrice || priceBox.priceBox('option').prices.basePrice)\n            ) {\n                this.priceType = priceBox.priceBox('option').prices.finalPrice ? 'finalPrice' : 'basePrice';\n                this.price = priceBox.priceBox('option').prices[this.priceType].amount;\n            }\n\n            $(this.qtyFieldSelector).on('change', this._onQtyChange.bind(this));\n\n            priceBox.trigger('updatePrice');\n\n            return this;\n        },\n\n        /**\n         * Handle changed product qty\n         *\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _onQtyChange: function (event) {\n            var qty = parseFloat($(event.target).val());\n\n            this.qty = !isNaN(qty) && qty ? qty : 1;\n            this._updateAmount();\n        },\n\n        /**\n         * Handle product price change\n         *\n         * @param {jQuery.Event} event\n         * @param {Object} data\n         * @private\n         */\n        _onPriceChange: function (event, data) {\n            this.price = data[this.priceType].amount;\n            this._updateAmount();\n        },\n\n        /**\n         * Calculate and update amount\n         *\n         * @private\n         */\n        _updateAmount: function () {\n            var amount = this.price * this.qty,\n                payLater = registry.get(this.parentName);\n\n            if (amount !== 0) {\n                payLater.amount(amount);\n            }\n        }\n    });\n});\n","Magento_Paypal/js/model/iframe-redirect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'Magento_Paypal/js/model/iframe',\n    'Magento_Ui/js/model/messageList'\n],\nfunction (ko, iframe, messageList) {\n    'use strict';\n\n    return function (cartUrl, errorMessage, goToSuccessPage, successUrl) {\n        if (this === window.self) {\n            window.location = cartUrl;\n        }\n\n        if (!!errorMessage.message) { //eslint-disable-line no-extra-boolean-cast\n            document.removeEventListener('click', iframe.stopEventPropagation, true);\n            iframe.isInAction(false);\n            messageList.addErrorMessage(errorMessage);\n        } else if (!!goToSuccessPage) { //eslint-disable-line no-extra-boolean-cast\n            window.location = successUrl;\n        } else {\n            window.location = cartUrl;\n        }\n    };\n});\n","Magento_Paypal/js/model/iframe.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['ko'], function (ko) {\n    'use strict';\n\n    var isInAction = ko.observable(false);\n\n    return {\n        isInAction: isInAction,\n\n        /**\n         * @param {jQuery.Event} event\n         */\n        stopEventPropagation: function (event) {\n            event.stopImmediatePropagation();\n            event.preventDefault();\n        }\n    };\n});\n","Magento_Reports/js/recently-viewed.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.recentlyViewedProducts', {\n        options: {\n            localStorageKey: 'recently-viewed-products',\n            productBlock: '#widget_viewed_item',\n            viewedContainer: 'ol'\n        },\n\n        /**\n         * Bind events to the appropriate handlers.\n         * @private\n         */\n        _create: function () {\n            var productHtml = $(this.options.productBlock).html(),\n                productSku = $(this.options.productBlock).data('sku'),\n                products = JSON.parse(window.localStorage.getItem(this.options.localStorageKey)),\n                productsLength, maximum, showed, index;\n\n            if (products) {\n                productsLength = products.sku.length;\n                maximum = $(this.element).data('count');\n                showed = 0;\n\n                for (index = 0; index <= productsLength; index++) {\n                    if (products.sku[index] == productSku || showed >= maximum) { //eslint-disable-line\n                        products.sku.splice(index, 1);\n                        products.html.splice(index, 1);\n                    } else {\n                        $(this.element).find(this.options.viewedContainer).append(products.html[index]);\n                        $(this.element).show();\n                        showed++;\n                    }\n                }\n                $(this.element).find(this.options.productBlock).show();\n            } else {\n                products = {};\n                products.sku = [];\n                products.html = [];\n            }\n            products.sku.unshift(productSku);\n            products.html.unshift(productHtml);\n            window.localStorage.setItem(this.options.localStorageKey, JSON.stringify(products));\n        }\n    });\n\n    return $.mage.recentlyViewedProducts;\n});\n","Magento_GoogleGtag/js/google-adwords.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* jscs:disable */\n/* eslint-disable */\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * @param {Object} config\n     */\n    return function (config) {\n        if (!window.gtag) {\n            // Inject Global Site Tag\n            var gtagScript = document.createElement('script');\n            gtagScript.type = 'text/javascript';\n            gtagScript.async = true;\n            gtagScript.src = config.gtagSiteSrc;\n            document.head.appendChild(gtagScript);\n\n            window.dataLayer = window.dataLayer || [];\n\n            function gtag(){dataLayer.push(arguments);}\n            gtag('js', new Date());\n            gtag('set', 'developer_id.dYjhlMD', true);\n            if (config.conversionLabel) {\n                gtag(\n                    'event',\n                    'conversion',\n                    {'send_to': config.conversionId + '/'\n                            + config.conversionLabel}\n                );\n            }\n        } else {\n            gtag('config', config.conversionId);\n        }\n    }\n});\n","Magento_GoogleGtag/js/google-analytics.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* jscs:disable */\n/* eslint-disable */\ndefine([\n    'jquery',\n    'mage/cookies'\n], function ($) {\n    'use strict';\n\n    /**\n     * @param {Object} config\n     */\n    return function (config) {\n        var allowServices = false,\n            allowedCookies,\n            allowedWebsites,\n            measurementId;\n\n        if (config.isCookieRestrictionModeEnabled) {\n            allowedCookies = $.mage.cookies.get(config.cookieName);\n\n            if (allowedCookies !== null) {\n                allowedWebsites = JSON.parse(allowedCookies);\n\n                if (allowedWebsites[config.currentWebsite] === 1) {\n                    allowServices = true;\n                }\n            }\n        } else {\n            allowServices = true;\n        }\n\n        if (allowServices) {\n            /* Global site tag (gtag.js) - Google Analytics */\n            measurementId = config.pageTrackingData.measurementId;\n            if (window.gtag) {\n                gtag('config', measurementId, { 'anonymize_ip': true });\n                // Purchase Event\n                if (config.ordersTrackingData.hasOwnProperty('currency')) {\n                    var purchaseObject = config.ordersTrackingData.orders[0];\n                    purchaseObject['items'] = config.ordersTrackingData.products;\n                    gtag('event', 'purchase', purchaseObject);\n                }\n            } else {\n                (function(d,s,u){\n                    var gtagScript = d.createElement(s);\n                    gtagScript.type = 'text/javascript';\n                    gtagScript.async = true;\n                    gtagScript.src = u;\n                    d.head.insertBefore(gtagScript, d.head.children[0]);\n                })(document, 'script', 'https://www.googletagmanager.com/gtag/js?id=' + measurementId);\n                window.dataLayer = window.dataLayer || [];\n                function gtag(){dataLayer.push(arguments);}\n                gtag('js', new Date());\n                gtag('set', 'developer_id.dYjhlMD', true);\n                gtag('config', measurementId, { 'anonymize_ip': true });\n                // Purchase Event\n                if (config.ordersTrackingData.hasOwnProperty('currency')) {\n                    var purchaseObject = config.ordersTrackingData.orders[0];\n                    purchaseObject['items'] = config.ordersTrackingData.products;\n                    gtag('event', 'purchase', purchaseObject);\n                }\n            }\n        }\n    }\n});\n","Magento_Shipping/js/view/checkout/shipping/shipping-policy.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Shipping/js/model/config'\n\n], function (Component, config) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Shipping/checkout/shipping/shipping-policy'\n        },\n        config: config()\n    });\n});\n","Magento_Shipping/js/model/config.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    return function () {\n        return window.checkoutConfig.shippingPolicy;\n    };\n});\n","Magento_PaymentServicesPaypal/js/order-review.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'uiComponent',\n    'Magento_Customer/js/customer-data'\n], function ($, Component, customerData) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            element: null,\n            placeOrderButtonSelector: '#review-button',\n            shippingMethodFormSelector: '#shipping-method-form',\n            shippingMethodInputSelector: '#shipping-method',\n            updateContainerSelector: '#details-reload',\n            waitLoadingContainer: '#review-please-wait',\n            orderFormSelector: '#order-review-form',\n            editShoppingCartSelector: '.magento-payments-review-items .edit',\n            updateShippingMethodUrl: null,\n            placeOrderUrl: null,\n            canEditShippingMethod: false,\n            isVirtual: false\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config, element) {\n            this._super();\n            this.element = element;\n\n            $(this.placeOrderButtonSelector).on('click', this.submitOrder.bind(this));\n            $(this.editShoppingCartSelector).on('click', this.invalidateCustomerData.bind(this));\n\n            if (!this.isVirtual && this.canEditShippingMethod) {\n                $(this.shippingMethodInputSelector).on('change', this.selectShippingMethod.bind(this));\n                this.setPlaceOrderButtonActive(!!$(this.shippingMethodInputSelector).val());\n            }\n        },\n\n        invalidateCustomerData: function () {\n            customerData.invalidate(['cart']);\n        },\n\n        /**\n         * Before request start\n         */\n        beforeRequestStart: function () {\n            $(this.waitLoadingContainer).show();\n        },\n\n        /**\n         * On request complete\n         */\n        onRequestComplete: function () {\n            $(this.waitLoadingContainer).hide();\n        },\n\n        /**\n         * Submit order\n         */\n        submitOrder: function () {\n            if (this.validateForm()) {\n                this.beforeRequestStart();\n                $(this.orderFormSelector).trigger('submit');\n                this.setPlaceOrderButtonActive(false);\n            }\n        },\n\n        /**\n         * Validate form\n         */\n        validateForm: function () {\n            return $(this.element).validation().valid();\n        },\n\n        /**\n         * Enable/disable order button\n         *\n         * @param {Boolean} isActive\n         */\n        setPlaceOrderButtonActive: function (isActive) {\n            $(this.placeOrderButtonSelector).prop('disabled', !isActive).toggleClass('no-checkout', !isActive);\n        },\n\n        /**\n         * Select shipping method\n         */\n        selectShippingMethod: function () {\n            var shippingMethod,\n                formData,\n                responseCallback;\n\n            if ($(this.waitLoadingContainer).is(':visible')) {\n                return false;\n            }\n            shippingMethod = $(this.shippingMethodInputSelector).val();\n            shippingMethod = shippingMethod.trim();\n            this.setPlaceOrderButtonActive(false);\n\n            if (shippingMethod) {\n                formData = $(this.shippingMethodFormSelector).serialize() + '&isAjax=true';\n\n                /**\n                 * @param {Object} response\n                 */\n                responseCallback = function (response) {\n                    if (typeof response.redirectUrl == 'undefined') {\n                        $(this.updateContainerSelector).html(response.html);\n                    } else {\n                        window.location = response.redirectUrl;\n                    }\n                    this.setPlaceOrderButtonActive(true);\n                    this.onRequestComplete();\n                };\n                $.ajax({\n                    url: this.updateShippingMethodUrl,\n                    type: 'post',\n                    context: this,\n                    beforeSend: this.beforeRequestStart,\n                    data: formData,\n                    success: responseCallback\n                });\n            }\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/product/bundle-product-data-provider.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'Magento_PaymentServicesPaypal/js/view/product/product-data-provider'\n], function ($, _, Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            priceBoxContextSelector: '#bundleSummary',\n            slideSelector: '#bundle-slide'\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n\n            // Need to track bundle product slide to trigger amount update to make message visible.\n            $(this.slideSelector).on('click', function () {\n                setTimeout(function () {\n                    this.updateAmount(this.getAmount());\n                }.bind(this), 300);\n            }.bind(this));\n            this.updateAmount(this.getAmount());\n\n            return this;\n        },\n\n        /**\n         * Checks if product is grouped type.\n         *\n         * @return {Boolean}\n         */\n        isBundleProduct: function () {\n            return !!$(this.constructor.defaults.priceBoxContextSelector).length;\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/product/gift-card-product-data-provider.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'Magento_PaymentServicesPaypal/js/view/product/product-data-provider'\n], function ($, _, Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            priceBoxContextSelector: '.giftcard-amount',\n            priceBoxSelector: '#giftcard-amount, #giftcard-amount-input'\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n            this.price = $(this.priceBoxSelector, this.priceBoxContextSelector).val();\n\n            return this;\n        },\n\n        /**\n         * Subscribe for price change.\n         */\n        priceSubscribe: function () {\n            $(this.priceBoxSelector, this.priceBoxContextSelector).on('change', function (event) {\n                this.price = event.target.value;\n                this.updateAmount(this.getAmount());\n            }.bind(this));\n        },\n\n        /**\n         * Checks if product is grouped type.\n         *\n         * @return {Boolean}\n         */\n        isProductGiftCard: function () {\n            return !!$(this.constructor.defaults.priceBoxContextSelector).length;\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/product/grouped-product-data-provider.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery', 'underscore', 'uiClass'], function ($, _, Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            tableWrapperSelector: '.table-wrapper.grouped',\n            qtyFieldSelector: '.input-text.qty',\n            priceBoxSelector: '[data-role=\"priceBox\"]',\n            priceInfo: {}\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function () {\n            this._super();\n            $('tbody tr', this.tableWrapperSelector).each(function (index, element) {\n                var priceBox = $(this.priceBoxSelector, element),\n                    qtyElement = $(this.qtyFieldSelector, element),\n                    productId = priceBox.data('productId'),\n                    priceElement = $('#product-price-' + productId);\n\n                this.priceInfo[productId] = {\n                    qty: this.getQuantity(qtyElement),\n                    price: priceElement.data('priceAmount')\n                };\n            }.bind(this));\n            this.quantitySubscribe();\n\n            return this;\n        },\n\n        /**\n         * Subscribe for quantity changes.\n         */\n        quantitySubscribe: function () {\n            $(this.qtyFieldSelector).on('change', function (event) {\n                var qtyElement = $(event.target),\n                    parent = qtyElement.parents('tr'),\n                    priceBox = $(this.priceBoxSelector, parent),\n                    productId = priceBox.data('productId');\n\n                if (this.priceInfo[productId]) {\n                    this.priceInfo[productId].qty = this.getQuantity(qtyElement);\n                }\n\n                this.updateAmount(this.getAmount());\n            }.bind(this));\n        },\n\n        /**\n         * Get product amount.\n         *\n         * @return {Number}\n         */\n        getAmount: function () {\n            var amount = 0;\n\n            _.each(this.priceInfo, function (info) {\n                amount += info.price * info.qty;\n            });\n\n            return amount;\n        },\n\n        /**\n         * Get product quantity.\n         *\n         * @param {HTMLElement} element\n         * @return {Number}\n         */\n        getQuantity: function (element) {\n            var qty = parseFloat(element.val());\n\n            return !isNaN(qty) && qty ? qty : 0;\n        },\n\n        /**\n         * Checks if product is grouped type.\n         *\n         * @return {Boolean}\n         */\n        isProductGrouped: function () {\n            return !!$(this.constructor.defaults.tableWrapperSelector).length;\n        },\n\n        /**\n         * Subscribe for price change.\n         */\n        priceSubscribe: function () {\n        },\n\n        /**\n         * Trigger price update.\n         */\n        updatePrice: function () {\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/product/product-data-provider.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery', 'uiClass', 'priceBox'], function ($, Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            qtyFieldSelector: '#qty',\n            priceBoxSelector: '.price-box',\n            priceBoxContextSelector: '.product-info-main',\n            finalPriceSelector: '[data-price-type=\"finalPrice\"]',\n            price: 0,\n            qty: 0\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n            this.price = $(this.finalPriceSelector, this.priceBoxContextSelector).attr('data-price-amount');\n            this.qty = $(this.qtyFieldSelector).val();\n            this.quantitySubscribe();\n            this.priceSubscribe();\n\n            return this;\n        },\n\n        /**\n         * Subscribe for quantity changes.\n         */\n        quantitySubscribe: function () {\n            $(this.qtyFieldSelector).on('change', function () {\n                this.qty = $(this.qtyFieldSelector).val();\n                this.updateAmount(this.getAmount());\n            }.bind(this));\n        },\n\n        /**\n         * Subscribe for price change.\n         */\n        priceSubscribe: function () {\n            $(this.priceBoxSelector, this.priceBoxContextSelector).on('updatePrice', function (event) {\n                var prices = $(event.target).data('magePriceBox').cache.displayPrices;\n\n                this.price = prices.finalPrice.amount;\n                this.updateAmount(this.getAmount());\n            }.bind(this));\n        },\n\n        /**\n         * Trigger price update.\n         */\n        updatePrice: function () {\n            $(this.priceBoxSelector).trigger('updatePrice');\n        },\n\n        /**\n         * Get product amount.\n         *\n         * @return {Number}\n         */\n        getAmount: function () {\n            return this.qty * this.price;\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/errors/response-error.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    /**\n     * Error type to handle response errors.\n     *\n     * @param {String} message\n     * @constructor\n     */\n    function ResponseError(message) {\n        this.name = 'ResponseError';\n        this.message = message;\n        this.stack = new Error().stack;\n    }\n\n    ResponseError.prototype = new Error;\n\n    /**\n     * Return a string representation\n     *\n     * @returns {String}\n     */\n    ResponseError.prototype.toString = function () {\n        return this.message;\n    };\n\n    return ResponseError;\n});\n","Magento_PaymentServicesPaypal/js/view/payment/method-renderer.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], function (Component, rendererList) {\n    'use strict';\n\n    rendererList.push({\n        type: 'payment_services_paypal_hosted_fields',\n        component: 'Magento_PaymentServicesPaypal/js/view/payment/method-renderer/hosted-fields'\n    }, {\n        type: 'payment_services_paypal_smart_buttons',\n        component: 'Magento_PaymentServicesPaypal/js/view/payment/method-renderer/smart-buttons'\n    }, {\n        type: 'payment_services_paypal_apple_pay',\n        component: 'Magento_PaymentServicesPaypal/js/view/payment/method-renderer/apple-pay'\n    }, {\n        type: 'payment_services_paypal_google_pay',\n        component: 'Magento_PaymentServicesPaypal/js/view/payment/method-renderer/google-pay'\n    });\n\n    return Component.extend({});\n});\n","Magento_PaymentServicesPaypal/js/view/payment/vault.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/*browser:true*/\n\n/* @api */\ndefine([\n    'underscore',\n    'uiComponent',\n    'mage/translate',\n    'Magento_Checkout/js/model/payment/renderer-list',\n    'uiLayout',\n    'uiRegistry'\n], function (_, Component, $t, rendererList, layout, registry) {\n    'use strict';\n\n    var vaultGroupName = 'vaultGroup';\n\n    layout([{\n        name: vaultGroupName,\n        component: 'Magento_Checkout/js/model/payment/method-group',\n        alias: 'vault',\n        sortOrder: 10,\n        title: $t('Stored Cards')\n    }]);\n\n    registry.get(vaultGroupName, function (vaultGroup) {\n        _.each(window.checkoutConfig.payment.vault, function (config, index) {\n            rendererList.push(\n                {\n                    type: index,\n                    config: config.config,\n                    component: config.component,\n                    group: vaultGroup,\n\n                    /**\n                     * Custom payment method types comparator\n                     * @param {String} typeA\n                     * @param {String} typeB\n                     * @return {Boolean}\n                     */\n                    typeComparatorCallback: function (typeA, typeB) {\n                        // vault token items have the same name as vault payment without index\n                        return typeA.substring(0, typeA.lastIndexOf('_')) === typeB;\n                    }\n                }\n            );\n        });\n    });\n\n    /**\n     * Add view logic here if needed\n     */\n    return Component.extend({});\n});\n","Magento_PaymentServicesPaypal/js/view/payment/smart-buttons-product.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'underscore',\n    'jquery',\n    'mageUtils',\n    'Magento_PaymentServicesPaypal/js/view/payment/paypal-abstract',\n    'scriptLoader',\n    'Magento_PaymentServicesPaypal/js/view/payment/methods/smart-buttons',\n    'mage/translate',\n    'Magento_Customer/js/customer-data',\n    'Magento_PaymentServicesPaypal/js/view/errors/response-error',\n    'jquery/jquery-storageapi'\n], function (_, $, utils, Component, loadSdkScript, SmartButtons, $t, customerData, ResponseError) {\n    'use strict';\n\n    var refreshCustomerData = function (url) {\n        // Trigger ajaxComplete event to update customer data\n        customerData.onAjaxComplete(\n            {},\n            {\n                type: 'POST',\n                url: url,\n            }\n        );\n    }\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypalProduct',\n            buttonsContainerId: 'smart-buttons-${ $.uid }',\n            element: null,\n            productFormSelector: '#product_addtocart_form',\n            formInvalid: false,\n            paymentActionError: $t('Something went wrong with your request. Please try again later.'),\n            addToCartUrl: null,\n            isErrorDisplayed: false\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config, element) {\n            _.bindAll(this, 'renderButtons', 'initSmartButtons', 'onClick', 'catchError', 'beforeCreateOrder',\n                'afterCreateOrder', 'beforeOnAuthorize', 'afterOnAuthorize', 'onCancel');\n            config.uid = utils.uniqueid();\n            this._super();\n            this.element = element;\n            this.element.id = this.buttonsContainerId;\n            this.getSdkParams()\n                .then(this.initSmartButtons)\n                .then(this.renderButtons)\n                .catch(function (e) {\n                    console.log(e);\n                });\n\n            return this;\n        },\n\n        /**\n         * Create instance of smart buttons.\n         */\n        initSmartButtons: function () {\n            this.buttons = new SmartButtons({\n                sdkNamespace: this.sdkNamespace,\n                scriptParams: this.sdkParams,\n                styles: this.styles,\n                createOrderUrl: this.createOrderUrl,\n                authorizeOrderUrl: this.authorizeOrderUrl,\n                onClick: this.onClick,\n                beforeCreateOrder: this.beforeCreateOrder,\n                afterCreateOrder: this.afterCreateOrder,\n                catchCreateOrder: this.catchError,\n                finallyCreateOrder: this.showLoader.bind(this, false),\n                beforeOnAuthorize: this.beforeOnAuthorize,\n                afterOnAuthorize: this.afterOnAuthorize,\n                catchOnAuthorize: this.catchError,\n                finallyOnAuthorize: this.showLoader.bind(this, false),\n                onError: this.catchError,\n                onCancel: this.onCancel\n            });\n        },\n\n        /**\n         * Render buttons\n         */\n        renderButtons: function () {\n            this.buttons.sdkLoaded.then(function () {\n                try {\n                    this.buttons && this.buttons.render('#' + this.buttonsContainerId);\n                } catch (e) {\n                    console.log(e);\n                }\n            }.bind(this)).catch(function () {\n                console.log('Error: Failed to load PayPal SDK script!');\n            });\n        },\n\n        /**\n         * Show/hide loader.\n         *\n         * @param {Boolean} show\n         */\n        showLoader: function (show) {\n            var event = show ? 'processStart' : 'processStop';\n\n            $('body').trigger(event);\n        },\n\n        /**\n         * Catch errors.\n         *\n         * @param {*} error\n         */\n        catchError: function (error) {\n            var message = error instanceof ResponseError ? error.message : this.paymentActionError;\n\n            this.showLoader(false);\n\n            if (this.isErrorDisplayed) {\n                return;\n            }\n            this.addMessage(message);\n            this.isErrorDisplayed = true;\n        },\n\n        /**\n         * Add message to customer data.\n         *\n         * @param {String} message\n         * @param {String} [type]\n         */\n        addMessage: function (message, type) {\n            type = type || 'error';\n            customerData.set('messages', {\n                messages: [{\n                    type: type,\n                    text: message\n                }],\n                'data_id': Math.floor(Date.now() / 1000)\n            });\n        },\n\n        /**\n         * Calls when user click paypal button\n         *\n         * @param {Object} data\n         * @param {Promise} actions\n         * @return {Promise}\n         */\n        onClick: function (data, actions) {\n            var $form = $(this.productFormSelector);\n\n            if ($form.data('mageValidation')) {\n                this.formInvalid = !$form.validation('isValid');\n            }\n\n            if (this.formInvalid) {\n                return actions.reject();\n            }\n\n            return actions.resolve();\n        },\n\n        /**\n         * Before create order.\n         *\n         * @return {Promise}\n         */\n        beforeCreateOrder: function () {\n            this.isErrorDisplayed = false;\n            this.showLoader(true);\n\n            return new Promise(function (resolve, reject) {\n                if (this.formInvalid) {\n                    return reject();\n                }\n\n                fetch(this.addToCartUrl, {\n                    method: 'POST',\n                    headers: {},\n                    body: new FormData($(this.productFormSelector)[0]),\n                    credentials: 'same-origin'\n                }).then(function (response) {\n                    return response.json();\n                }).then(function (data) {\n                    if (typeof data.success !== 'undefined') {\n                        refreshCustomerData(this.addToCartUrl);\n\n                        return resolve();\n                    }\n\n                    return reject(new ResponseError(data.error));\n                }.bind(this)).catch(function () {\n                    return reject();\n                });\n            }.bind(this));\n        },\n\n        /**\n         * After order id created.\n         *\n         * @param {Object} res\n         * @return {*}\n         */\n        afterCreateOrder: function (res) {\n            if (res.response['is_successful']) {\n                refreshCustomerData(this.createOrderUrl);\n\n                return res.response['paypal-order'].id;\n            }\n\n            throw new ResponseError(res.response.error);\n        },\n\n        /**\n         * Before onAuthorize execute\n         *\n         * @param {Object} data\n         * @return {Promise}\n         */\n        beforeOnAuthorize: function (data) {\n            this.showLoader(true);\n\n            return Promise.resolve(data);\n        },\n\n        /**\n         * After onAuthorize execute\n         *\n         * @param {Object} res\n         * @param {Object} actions\n         * @return {*}\n         */\n        afterOnAuthorize: function (res, actions) {\n            if (res.success) {\n                return actions.redirect(res.redirectUrl);\n            }\n\n            throw new ResponseError(res.error);\n        },\n\n        /**\n         * Redirect to cart on cancel.\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         */\n        onCancel: function (data, actions) {\n            customerData.invalidate(['cart']);\n            actions.redirect(this.cancelUrl);\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/message-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_PaymentServicesPaypal/js/view/payment/paypal-abstract',\n    'Magento_PaymentServicesPaypal/js/view/payment/message',\n    'Magento_Customer/js/customer-data'\n], function (Component, Message, customerData) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypalCart',\n            element: null,\n            message: null\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config, element) {\n            var cartData = customerData.get('cart');\n\n            this.element = element;\n            this._super();\n            this.getSdkParams()\n                .then(this.initMessage.bind(this))\n                .then(function () {\n                    cartData.subscribe(function (updatedCart) {\n                        this.message.updateAmount(updatedCart.subtotalAmount);\n                    }, this);\n                }.bind(this))\n                .then(this.render.bind(this));\n\n        },\n\n        /**\n         * Create instance of messages.\n         */\n        initMessage: function () {\n            var cartData = customerData.get('cart');\n\n            this.message = new Message({\n                sdkNamespace: this.sdkNamespace,\n                scriptParams: this.sdkParams,\n                element: this.element,\n                renderContainer: this.renderContainer,\n                styles: this.styles,\n                placement: this.placement,\n                amount: cartData().subtotalAmount\n            });\n        },\n\n        /**\n         * Render message\n         */\n        render: function () {\n            this.message.render();\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/google-pay-product.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'underscore',\n    'jquery',\n    'mageUtils',\n    'Magento_PaymentServicesPaypal/js/view/payment/paypal-abstract',\n    'mage/translate',\n    'Magento_Customer/js/customer-data',\n    'Magento_PaymentServicesPaypal/js/view/errors/response-error',\n    'Magento_PaymentServicesPaypal/js/view/payment/methods/google-pay'\n], function (_, $, utils, Component, $t, customerData, ResponseError, GooglePayButton) {\n    'use strict';\n\n    const HTTP_STATUS_OK = 200;\n\n    var refreshCustomerData = function (url) {\n        // Trigger ajaxComplete event to update customer data\n        customerData.onAjaxComplete(\n            {},\n            {\n                type: 'POST',\n                url: url,\n            }\n        );\n    }\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypalGooglePay',\n            scriptParams: {},\n            buttonContainerId: 'google-pay-${ $.uid }',\n            template: 'Magento_PaymentServicesPaypal/payment/google-pay',\n            paymentsOrderId: null,\n            paypalOrderId: null,\n            sdkLoaded: null,\n            sdkParamsKey: 'googlepay',\n            paymentTypeIconTitle: $t('Pay with Google Pay'),\n            requestProcessingError: $t('Something went wrong with your request. Please try again later.'),\n            notEligibleErrorMessage: $t('This payment option is currently unavailable.'),\n            productFormSelector: '#product_addtocart_form'\n        },\n\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config, element) {\n            _.bindAll(this, 'initGooglePayButton', 'onClick', 'afterUpdateQuote',\n                'catchError', 'beforeCreateOrder', 'afterOnAuthorize', 'onCancel');\n            config.uid = utils.uniqueid();\n            this._super();\n            this.element = element;\n            this.element.id = this.buttonContainerId;\n            this.getSdkParams()\n                .then(this.initGooglePayButton)\n                .catch(console.log);\n\n            return this;\n        },\n\n        initGooglePayButton: function () {\n            this.googlePayButton = new GooglePayButton({\n                scriptParams: this.sdkParams,\n                createOrderUrl: this.createOrderUrl,\n                updateQuoteUrl: this.authorizeOrderUrl,\n                onClick: this.onClick,\n                beforeCreateOrder: this.beforeCreateOrder,\n                catchCreateOrder: this.catchError,\n                onError: this.catchError,\n                buttonContainerId: this.buttonContainerId,\n                afterUpdateQuote: this.afterUpdateQuote,\n                shippingAddressRequired: !this.isVirtual,\n                styles: this.styles,\n                afterOnAuthorize: this.afterOnAuthorize,\n                onCancel: this.onCancel,\n                mode: this.googlePayMode\n            });\n\n            this.googlePayButton.sdkLoaded\n                .then(this.googlePayButton.initGoogleSDK);\n        },\n\n        afterUpdateQuote: function (data) {\n            window.location = data.redirectUrl;\n            this.googlePayButton.showLoader(false);\n        },\n\n        onClick: function () {\n            var $form = $(this.productFormSelector);\n\n            if ($form.data('mageValidation')) {\n                this.formValid = $form.validation('isValid');\n            }\n\n            if (this.formValid) {\n                this.isErrorDisplayed = false;\n\n                this.googlePayButton.showLoaderAsync(true)\n                    .then(() => {\n                        return this.googlePayButton.createOrder();\n                    })\n                    .then(() => {\n                        refreshCustomerData(this.createOrderUrl);\n                    })\n                    .catch(error => {\n                        this.catchError(error);\n                    });\n            }\n        },\n\n        /**\n         * Catch errors.\n         *\n         * @param {*} error\n         */\n        catchError: function (error) {\n            console.log(error);\n            this.googlePayButton.showLoader(false);\n\n            if (this.isErrorDisplayed) {\n                return;\n            }\n\n            if (error.hidden === undefined || !error.hidden) {\n                this.addMessage(this.requestProcessingError);\n            }\n\n            this.isErrorDisplayed = true;\n        },\n\n        /**\n         * Add message to customer data.\n         *\n         * @param {String} message\n         * @param {String} [type]\n         */\n        addMessage: function (message, type) {\n            type = type || 'error';\n            customerData.set('messages', {\n                messages: [{\n                    type: type,\n                    text: message\n                }],\n                'data_id': Math.floor(Date.now() / 1000)\n            });\n        },\n\n        /**\n         * Before create order.\n         *\n         * @return {String}\n         */\n        beforeCreateOrder: function () {\n            this.isErrorDisplayed = false;\n\n            if (this.formInvalid) {\n                throw new Error('Form is Invalid');\n            }\n\n            let xhr = new XMLHttpRequest();\n            xhr.open('POST', this.addToCartUrl, false);\n            xhr.send(new FormData($(this.productFormSelector)[0]));\n\n            if (xhr.status !== HTTP_STATUS_OK) {\n                throw new Error('Request failed');\n            } else {\n                try {\n                    let result = JSON.parse(xhr.responseText);\n\n                    if (typeof result.success !== 'undefined') {\n                        refreshCustomerData(this.addToCartUrl);\n                        return result.success;\n                    }\n                } catch (parseError) {\n                    throw new Error('Failed to parse response JSON: ' + parseError.message);\n                }\n            }\n        },\n\n        afterOnAuthorize: function (data) {\n            window.location = data.redirectUrl;\n            this.googlePayButton.showLoader(false);\n        },\n\n        /**\n         * Redirect to cart on cancel.\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         */\n        onCancel: function () {\n            customerData.invalidate(['cart']);\n            window.location = this.cancelUrl;\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/message.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'uiComponent',\n    'scriptLoader'\n], function ($, Component, loadSdkScript) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypal',\n            renderContainer: null,\n            amountAttribute: 'data-pp-amount',\n            amount: null\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function () {\n            this._super();\n            this.sdkLoaded = loadSdkScript(this.scriptParams, this.sdkNamespace);\n\n            return this;\n        },\n\n        /**\n         * Update amount\n         *\n         * @param {*} amount\n         */\n        updateAmount: function (amount) {\n            this.amount = amount;\n            $(this.renderContainer).attr(this.amountAttribute, this.amount);\n        },\n\n        /**\n         * Render message\n         *\n         * @return {Promise}\n         */\n        render: function () {\n            return this.sdkLoaded.then(function (sdkScript) {\n                sdkScript.Messages({\n                    amount: parseFloat(this.amount).toFixed(2),\n                    placement: this.placement,\n                    style: this.styles\n                })\n                .render(this.renderContainer);\n            }.bind(this)).catch(function (exception) {\n                console.log('Error: Failed to load PayPal SDK script!');\n                console.log(exception.message);\n            });\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/google-pay-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'underscore',\n    'jquery',\n    'mageUtils',\n    'Magento_PaymentServicesPaypal/js/view/payment/paypal-abstract',\n    'mage/translate',\n    'Magento_Customer/js/customer-data',\n    'Magento_PaymentServicesPaypal/js/view/errors/response-error',\n    'Magento_PaymentServicesPaypal/js/view/payment/methods/google-pay'\n], function (_, $, utils, Component, $t, customerData, ResponseError, GooglePayButton) {\n    'use strict';\n\n    var refreshCustomerData = function (url) {\n        // Trigger ajaxComplete event to update customer data\n        customerData.onAjaxComplete(\n            {},\n            {\n                type: 'POST',\n                url: url,\n            }\n        );\n    }\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypalGooglePay',\n            sdkParamsKey: 'googlepay',\n            buttonContainerId: 'google-pay-${ $.uid }',\n            paymentActionError: $t('Something went wrong with your request. Please try again later.'),\n            isErrorDisplayed: false\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config, element) {\n            _.bindAll(this, 'initGooglePayButton', 'onClick',\n                'afterOnAuthorize', 'catchError', 'onCancel');\n            config.uid = utils.uniqueid();\n            this._super();\n            this.element = element;\n            this.element.id = this.buttonContainerId;\n            this.getSdkParams()\n                .then(this.initGooglePayButton)\n                .catch(console.log);\n\n            return this;\n        },\n\n        initGooglePayButton: function () {\n            this.googlePayButton = new GooglePayButton({\n                scriptParams: this.sdkParams,\n                createOrderUrl: this.createOrderUrl,\n                updateQuoteUrl: this.authorizeOrderUrl,\n                onClick: this.onClick,\n                catchCreateOrder: this.catchError,\n                onError: this.catchError,\n                buttonContainerId: this.buttonContainerId,\n                afterOnAuthorize: this.afterOnAuthorize,\n                shippingAddressRequired: !this.isVirtual,\n                styles: this.styles,\n                onCancel: this.onCancel,\n                mode: this.googlePayMode\n            });\n\n            this.googlePayButton.sdkLoaded\n                .then(this.googlePayButton.initGoogleSDK);\n        },\n\n        afterOnAuthorize: function (data) {\n            window.location = data.redirectUrl;\n            this.googlePayButton.showLoader(false);\n        },\n\n        onClick: function () {\n            this.isErrorDisplayed = false;\n\n            this.googlePayButton.showLoaderAsync(true)\n                .then(() => {\n                    return this.googlePayButton.createOrder();\n                })\n                .then(() => {\n                    refreshCustomerData(this.createOrderUrl);\n                })\n                .catch(error => {\n                    this.catchError(error);\n                });\n        },\n\n        /**\n         * Catch errors.\n         *\n         * @param {*} error\n         */\n        catchError: function (error) {\n            var message = error instanceof ResponseError ? error.message : this.paymentActionError;\n\n            console.log(error);\n\n            this.googlePayButton.showLoader(false);\n\n            if (this.isErrorDisplayed) {\n                return;\n            }\n\n            if (error.hidden === undefined || !error.hidden) {\n                this.addMessage(message);\n            }\n\n            this.isErrorDisplayed = true;\n        },\n\n        /**\n         * Add message to customer data.\n         *\n         * @param {String} message\n         * @param {String} [type]\n         */\n        addMessage: function (message, type) {\n            type = type || 'error';\n            customerData.set('messages', {\n                messages: [{\n                    type: type,\n                    text: message\n                }],\n                'data_id': Math.floor(Date.now() / 1000)\n            });\n        },\n\n        /**\n         * Redirect to cart on cancel.\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         */\n        onCancel: function () {\n            customerData.invalidate(['cart']);\n            window.location = this.cancelUrl;\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/apple-pay-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'underscore',\n    'jquery',\n    'mageUtils',\n    'Magento_PaymentServicesPaypal/js/view/payment/paypal-abstract',\n    'mage/translate',\n    'Magento_Customer/js/customer-data',\n    'Magento_PaymentServicesPaypal/js/view/errors/response-error',\n    'Magento_PaymentServicesPaypal/js/view/payment/methods/apple-pay',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/cart/totals-processor/default',\n], function (_, $, utils, Component, $t, customerData, ResponseError, ApplePayButton, quote, totalsProcessor) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypalApplePay',\n            sdkParamsKey: 'applepay',\n            buttonContainerId: 'apple-pay-${ $.uid }',\n            paymentActionError: $t('Something went wrong with your request. Please try again later.'),\n            isErrorDisplayed: false\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config, element) {\n            _.bindAll(this, 'initApplePayButton', 'onClick', 'afterOnAuthorize',  'afterCreateOrder', 'showPopup', 'cancelApplePay');\n            config.uid = utils.uniqueid();\n            this._super();\n            this.element = element;\n            this.element.id = this.buttonContainerId;\n\n            this.getSdkParams()\n                .then(this.initApplePayButton)\n                .catch(console.log);\n\n            // Reload quote totals in minicart to have the correct grand_total for the Apple Popup\n            if (this.pageType === 'minicart') {\n                totalsProcessor.estimateTotals().done(function (result) {\n                    quote.setTotals(result);\n                });\n            }\n            return this;\n        },\n\n        initApplePayButton: function () {\n            this.applePayButton = new ApplePayButton({\n                scriptParams: this.sdkParams,\n                createOrderUrl: this.createOrderUrl,\n                estimateShippingMethodsWhenLoggedInUrl: this.estimateShippingMethodsWhenLoggedInUrl,\n                estimateShippingMethodsWhenGuestUrl: this.estimateShippingMethodsWhenGuestUrl,\n                shippingInformationWhenLoggedInUrl: this.shippingInformationWhenLoggedInUrl,\n                shippingInformationWhenGuestUrl: this.shippingInformationWhenGuestUrl,\n                updatePaypalOrderUrl: this.updatePaypalOrderUrl,\n                countriesUrl: this.countriesUrl,\n                placeOrderUrl: this.placeOrderUrl,\n                showPopup: this.showPopup,\n                updateQuoteUrl: this.authorizeOrderUrl,\n                onClick: this.onClick,\n                afterCreateOrder: this.afterCreateOrder,\n                catchCreateOrder: this.catchError,\n                onError: this.catchError,\n                buttonContainerId: this.buttonContainerId,\n                afterOnAuthorize: this.afterOnAuthorize,\n                shippingAddressRequired: !this.isVirtual,\n                styles: this.styles,\n                pageType: this.pageType,\n            });\n\n            $('#' + this.buttonContainerId).on('click', this.onClick);\n\n            this.applePayButton.sdkLoaded\n                .then(this.applePayButton.initAppleSDK);\n        },\n\n        afterOnAuthorize: function (data) {\n\n            this.applePayButton.showLoaderAsync(true)\n            .then(() => {\n                $.ajax({\n                    type: 'POST',\n                    url: this.placeOrderUrl,\n                }).then(result => {\n                    customerData.invalidate(['cart']);\n                    document.open();\n                    document.write(result);\n                    document.close();\n                });\n            })\n            .catch(error => {\n                this.catchError(error);\n            });\n        },\n\n        onClick: function () {\n            this.isErrorDisplayed = false;\n\n            this.applePayButton.showLoaderAsync(true).then(() => {\n                const data = {\n                    response: {\n                        'paypal-order': {\n                            currency_code: String(quote.totals().quote_currency_code),\n                            amount: Number(quote.totals().grand_total).toString(),\n                        }\n                    }\n                }\n                this.applePayButton.showPopup(data);\n            })\n        },\n\n        /**\n         * After order created.\n         *\n         * @param {Object} data\n         * @return {String}\n         */\n        afterCreateOrder: function (data) {\n            if (data.response['paypal-order'] && data.response['paypal-order']['mp_order_id']) {\n                this.paymentsOrderId = data.response['paypal-order']['mp_order_id'];\n                this.paypalOrderId = data.response['paypal-order'].id;\n                return this.paypalOrderId;\n            }\n\n            throw new Error();\n        },\n\n        cancelApplePay: function (){\n            customerData.invalidate(['cart']);\n            window.location.reload();\n        },\n\n        showPopup: function (paymentData) {\n            const paymentRequest = {\n                countryCode: this.applePayButton.applePayConfig.countryCode,\n                merchantCapabilities: this.applePayButton.applePayConfig.merchantCapabilities,\n                supportedNetworks: this.applePayButton.applePayConfig.supportedNetworks,\n                currencyCode: paymentData.response['paypal-order']['currency_code'],\n                requiredShippingContactFields: [\"name\", \"phone\", \"email\", \"postalAddress\"],\n                requiredBillingContactFields: [\"postalAddress\"],\n                total: {\n                    label: $t(\"Summary\"),\n                    type: \"final\",\n                    amount: Number(paymentData.response['paypal-order']['amount']).toString(),\n                }\n            };\n\n            // See https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession\n            this.applePaySession = new ApplePaySession(this.applePayButton.applePayVersionNumber, paymentRequest);\n\n            this.applePayButton.onApplePayValidateMerchant(this.applePaySession);\n            this.applePayButton.onApplePayPaymentMethodSelected(this.applePaySession, paymentRequest.total);\n            this.applePayButton.onApplePayCancel(this.applePaySession, this.cancelApplePay);\n            this.applePayButton.onApplePayShippingContactSelected(this.applePaySession, quote.getQuoteId() , paymentRequest.total, quote.isVirtual());\n            this.applePayButton.onApplePayShippingMethodSelectedInCartPage(this.applePaySession, quote.getQuoteId());\n            this.applePayButton.onApplePayPaymentAuthorized(this.applePaySession);\n\n            this.applePaySession.begin();\n        },\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/apple-pay-product.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'jquery',\n    'underscore',\n    'mageUtils',\n    'Magento_PaymentServicesPaypal/js/view/payment/paypal-abstract',\n    'mage/translate',\n    'Magento_Customer/js/customer-data',\n    'Magento_PaymentServicesPaypal/js/view/errors/response-error',\n    'Magento_PaymentServicesPaypal/js/view/payment/methods/apple-pay',\n], function ($, _, utils, Component, $t, customerData, ResponseError, ApplePayButton) {\n    'use strict';\n\n    const HTTP_STATUS_OK = 200;\n\n    var refreshCustomerData = function (url) {\n        // Trigger ajaxComplete event to update customer data\n        customerData.onAjaxComplete(\n            {},\n            {\n                type: 'POST',\n                url: url,\n            }\n        );\n    }\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypalApplePay',\n            scriptParams: {},\n            buttonContainerId: 'apple-pay-${ $.uid }',\n            template: 'Magento_PaymentServicesPaypal/payment/apple-pay',\n            paymentsOrderId: null,\n            paypalOrderId: null,\n            sdkLoaded: null,\n            quoteIdForRest: null,\n            quoteId: null,\n            sdkParamsKey: 'applepay',\n            paymentTypeIconTitle: $t('Pay with Apple Pay'),\n            notEligibleErrorMessage: $t('This payment option is currently unavailable.'),\n            productFormSelector: '#product_addtocart_form'\n        },\n\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config, element) {\n            _.bindAll(this, 'initApplePayButton', 'onClick', 'afterUpdateQuote', 'beforeCreateOrder',\n                'afterCreateOrder', 'afterOnAuthorize', 'onCancel');\n            config.uid = utils.uniqueid();\n            this._super();\n            this.element = element;\n            this.element.id = this.buttonContainerId;\n            this.getSdkParams()\n                .then(this.initApplePayButton)\n                .catch(console.log);\n\n            return this;\n        },\n\n        initApplePayButton: function () {\n            this.applePayButton = new ApplePayButton({\n                scriptParams: this.sdkParams,\n                createOrderUrl: this.createOrderUrl,\n                updateQuoteUrl: this.authorizeOrderUrl,\n                shippingInformationWhenGuestUrl: this.shippingInformationWhenGuestUrl,\n                shippingInformationWhenLoggedInUrl: this.shippingInformationWhenLoggedInUrl,\n                estimateShippingMethodsWhenGuestUrl: this.estimateShippingMethodsWhenGuestUrl,\n                estimateShippingMethodsWhenLoggedInUrl: this.estimateShippingMethodsWhenLoggedInUrl,\n                updatePayPalOrderUrl: this.updatePayPalOrderUrl,\n                setQuoteAsInactiveUrl: this.setQuoteAsInactiveUrl,\n                countriesUrl: this.countriesUrl,\n                placeOrderUrl: this.placeOrderUrl,\n                onClick: this.onClick,\n                beforeCreateOrder: this.beforeCreateOrder,\n                afterCreateOrder: this.afterCreateOrder,\n                catchCreateOrder: this.catchError,\n                onError: this.catchError,\n                buttonContainerId: this.buttonContainerId,\n                afterUpdateQuote: this.afterUpdateQuote,\n                shippingAddressRequired: !this.isVirtual,\n                styles: this.styles,\n                afterOnAuthorize: this.afterOnAuthorize,\n                onCancel: this.onCancel,\n                pageType: this.pageType,\n            });\n\n            $('#' + this.buttonContainerId).on('click', this.onClick);\n\n            this.applePayButton.sdkLoaded\n                .then(this.applePayButton.initAppleSDK);\n        },\n\n        afterUpdateQuote: function (data) {\n            window.location = data.redirectUrl;\n            this.applePayButton.showLoader(false);\n        },\n\n        onClick: function () {\n\n            var $form = $(this.productFormSelector);\n\n            if ($form.data('mageValidation')) {\n                this.formValid = $form.validation('isValid');\n            }\n\n            if (this.formValid) {\n                this.applePayButton.showLoaderAsync(true)\n                    .then(() => {\n                        return this.applePayButton.createOrder();\n                    })\n                    .then(() => {\n                        refreshCustomerData(this.createOrderUrl);\n                    })\n                    .catch(error => {\n                        this.applePayButton.catchError(error);\n                    });\n            }\n        },\n\n        setQuoteInactive: function () {\n            // Set Quote as inactive to avoid having multiple active quotes for the customer\n            $.ajax({\n                type: 'POST',\n                url: this.setQuoteAsInactiveUrl,\n            });\n        },\n\n        showPopup: function (paymentData) {\n\n            const paymentRequest = {\n                countryCode: this.applePayButton.applePayConfig.countryCode,\n                merchantCapabilities: this.applePayButton.applePayConfig.merchantCapabilities,\n                supportedNetworks: this.applePayButton.applePayConfig.supportedNetworks,\n                currencyCode: String(paymentData['currencyCode']),\n                requiredShippingContactFields: [\"name\", \"phone\", \"email\", \"postalAddress\"],\n                requiredBillingContactFields: [\"postalAddress\"],\n                total: {\n                    label: $t(\"Summary\"),\n                    type: \"final\",\n                    amount: Number(paymentData['totalPrice']).toString(),\n                }\n            };\n\n            // See https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession\n            this.applePaySession = new ApplePaySession(this.applePayButton.applePayVersionNumber, paymentRequest);\n            this.applePayButton.onApplePayValidateMerchant(this.applePaySession);\n            this.applePayButton.onApplePayPaymentMethodSelected(this.applePaySession, paymentRequest.total);\n            this.applePayButton.onApplePayCancel(this.applePaySession, this.setQuoteInactive.bind(this));\n            this.applePayButton.onApplePayShippingContactSelected(this.applePaySession, this.quoteIdForRest, paymentRequest.total, null);\n            this.applePayButton.onApplePayShippingMethodSelected(this.applePaySession, this.quoteId, this.quoteIdForRest, this.paypalOrderId);\n            this.applePayButton.onApplePayPaymentAuthorized(this.applePaySession);\n\n            this.applePaySession.begin();\n        },\n\n        /**\n         * Before create order.\n         *\n         * @return {String}\n         */\n        beforeCreateOrder: function () {\n            if (this.formInvalid) {\n                throw new Error('Form is Invalid');\n            }\n\n            let xhr = new XMLHttpRequest();\n            xhr.open('POST', this.addToCartUrl, false);\n            xhr.send(new FormData($(this.productFormSelector)[0]));\n\n            if (xhr.status !== HTTP_STATUS_OK) {\n                throw new Error('Request failed');\n            } else {\n                try {\n                    let result = JSON.parse(xhr.responseText);\n\n                    if (typeof result.success !== 'undefined') {\n                        refreshCustomerData(this.addToCartUrl);\n                        this.quoteIdForRest = result.success.quoteIdMask;\n                        this.quoteId = result.success.quoteId;\n                        return result.success;\n                    }\n                } catch (parseError) {\n                    throw new Error('Failed to parse response JSON: ' + parseError.message);\n                }\n            }\n        },\n\n        /**\n         * After order created.\n         *\n         * @param {Object} data\n         * @return {String}\n         */\n        afterCreateOrder: function (data) {\n            if (data.response['paypal-order'] && data.response['paypal-order']['mp_order_id']) {\n                this.paymentsOrderId = data.response['paypal-order']['mp_order_id'];\n                this.paypalOrderId = data.response['paypal-order'].id;\n\n                this.showPopup({\n                    displayItems: [],\n                    currencyCode: data.response['paypal-order']['currency_code'],\n                    totalPriceStatus: 'FINAL',\n                    totalPrice: Number(data.response['paypal-order']['amount']).toString(),\n                    totalPriceLabel: $t('Total')\n                });\n\n                return this.paypalOrderId;\n            }\n\n            throw new Error();\n        },\n\n        afterOnAuthorize: function (data) {\n\n            this.applePayButton.showLoaderAsync(true)\n                .then(() => {\n                    $.ajax({\n                        type: 'POST',\n                        url: this.placeOrderUrl,\n                    }).then(result => {\n                        customerData.invalidate(['cart']);\n                        document.open();\n                        document.write(result);\n                        document.close();\n                    });\n                })\n                .catch(error => {\n                    this.catchError(error);\n                });\n        },\n\n        /**\n         * Redirect to cart on cancel.\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         */\n        onCancel: function () {\n            customerData.invalidate(['cart']);\n            window.location = this.cancelUrl;\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/smart-buttons-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'underscore',\n    'jquery',\n    'mageUtils',\n    'Magento_PaymentServicesPaypal/js/view/payment/paypal-abstract',\n    'scriptLoader',\n    'Magento_PaymentServicesPaypal/js/view/payment/methods/smart-buttons',\n    'mage/translate',\n    'Magento_Customer/js/customer-data',\n    'Magento_PaymentServicesPaypal/js/view/errors/response-error'\n], function (_, $, utils, Component, loadSdkScript, SmartButtons, $t, customerData, ResponseError) {\n    'use strict';\n\n    var refreshCustomerData = function (url) {\n        // Trigger ajaxComplete event to update customer data\n        customerData.onAjaxComplete(\n            {},\n            {\n                type: 'POST',\n                url: url,\n            }\n        );\n    }\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypalCart',\n            buttonsContainerId: 'smart-buttons-${ $.uid }',\n            element: null,\n            paymentActionError: $t('Something went wrong with your request. Please try again later.'),\n            isErrorDisplayed: false\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config, element) {\n            _.bindAll(this, 'renderButtons', 'initSmartButtons', 'catchError', 'beforeCreateOrder', 'afterCreateOrder',\n                'beforeOnAuthorize', 'afterOnAuthorize', 'onCancel');\n            config.uid = utils.uniqueid();\n            this._super();\n            this.element = element;\n            this.element.id = this.buttonsContainerId;\n            this.getSdkParams()\n                .then(this.initSmartButtons)\n                .then(this.renderButtons)\n                .catch(function (e) {\n                    console.log(e);\n                });\n\n            return this;\n        },\n\n        /**\n         * Create instance of smart buttons.\n         */\n        initSmartButtons: function () {\n            this.buttons = new SmartButtons({\n                sdkNamespace: this.sdkNamespace,\n                scriptParams: this.sdkParams,\n                styles: this.styles,\n                createOrderUrl: this.createOrderUrl,\n                authorizeOrderUrl: this.authorizeOrderUrl,\n                beforeCreateOrder: this.beforeCreateOrder,\n                afterCreateOrder: this.afterCreateOrder,\n                catchCreateOrder: this.catchError,\n                finallyCreateOrder: this.showLoader.bind(this, false),\n                beforeOnAuthorize: this.beforeOnAuthorize,\n                afterOnAuthorize: this.afterOnAuthorize,\n                catchOnAuthorize: this.catchError,\n                finallyOnAuthorize: this.showLoader.bind(this, false),\n                onError: this.catchError,\n                onCancel: this.onCancel\n            });\n        },\n\n        /**\n         * Render buttons\n         */\n        renderButtons: function () {\n            this.buttons.sdkLoaded.then(function () {\n                this.buttons && this.buttons.render('#' + this.buttonsContainerId);\n            }.bind(this)).catch(function () {\n                console.log('Error: Failed to load PayPal SDK script!');\n            });\n        },\n\n        /**\n         * Show/hide loader.\n         *\n         * @param {Boolean} show\n         */\n        showLoader: function (show) {\n            var event = show ? 'processStart' : 'processStop';\n\n            $('body').trigger(event);\n        },\n\n        /**\n         * Catch errors.\n         *\n         * @param {*} error\n         */\n        catchError: function (error) {\n            var message = error instanceof ResponseError ? error.message : this.paymentActionError;\n\n            this.showLoader(false);\n\n            if (this.isErrorDisplayed) {\n                return;\n            }\n            this.addMessage(message);\n            this.isErrorDisplayed = true;\n        },\n\n        /**\n         * Add message to customer data.\n         *\n         * @param {String} message\n         * @param {String} [type]\n         */\n        addMessage: function (message, type) {\n            type = type || 'error';\n            customerData.set('messages', {\n                messages: [{\n                    type: type,\n                    text: message\n                }],\n                'data_id': Math.floor(Date.now() / 1000)\n            });\n        },\n\n        /**\n         * Before create order.\n         *\n         * @return {Promise}\n         */\n        beforeCreateOrder: function () {\n            this.isErrorDisplayed = false;\n            this.showLoader(true);\n\n            return Promise.resolve();\n        },\n\n        /**\n         * After order id created.\n         *\n         * @param {Object} res\n         * @return {*}\n         */\n        afterCreateOrder: function (res) {\n            if (res.response['is_successful']) {\n                refreshCustomerData(this.createOrderUrl);\n\n                return res.response['paypal-order'].id;\n            }\n\n            throw new ResponseError(res.response.error);\n        },\n\n        /**\n         * Before onAuthorize execute\n         *\n         * @param {Object} data\n         * @return {Promise}\n         */\n        beforeOnAuthorize: function (data) {\n            this.showLoader(true);\n\n            return Promise.resolve(data);\n        },\n\n        /**\n         * After onAuthorize execute\n         *\n         * @param {Object} res\n         * @param {Object} actions\n         * @return {*}\n         */\n        afterOnAuthorize: function (res, actions) {\n            if (res.success) {\n                return actions.redirect(res.redirectUrl);\n            }\n\n            throw new ResponseError(res.error);\n        },\n\n        /**\n         * Redirect to cart on cancel.\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         */\n        onCancel: function (data, actions) {\n            customerData.invalidate(['cart']);\n            actions.redirect(this.cancelUrl);\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/message-product.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_PaymentServicesPaypal/js/view/payment/paypal-abstract',\n    'Magento_PaymentServicesPaypal/js/view/payment/message',\n    'Magento_PaymentServicesPaypal/js/view/product/product-data-provider',\n    'Magento_PaymentServicesPaypal/js/view/product/grouped-product-data-provider',\n    'Magento_PaymentServicesPaypal/js/view/product/bundle-product-data-provider',\n    'Magento_PaymentServicesPaypal/js/view/product/gift-card-product-data-provider'\n], function (\n    Component,\n    Message,\n    ProductDataProvider,\n    GroupedProductDataProvider,\n    BundledProductDataProvider,\n    GiftCardProductDataProvider\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypalProduct',\n            element: null,\n            message: null\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config, element) {\n            var providerOptions = {\n                updateAmount: this.updateAmount.bind(this)\n            };\n\n            this.element = element;\n            this._super();\n\n            if (GroupedProductDataProvider.prototype.isProductGrouped()) {\n                this.provider = new GroupedProductDataProvider(providerOptions);\n            } else if (BundledProductDataProvider.prototype.isBundleProduct()) {\n                this.provider = new BundledProductDataProvider(providerOptions);\n            }  else if (GiftCardProductDataProvider.prototype.isProductGiftCard()) {\n                this.provider = new GiftCardProductDataProvider(providerOptions);\n            } else {\n                this.provider = new ProductDataProvider(providerOptions);\n            }\n            this.getSdkParams()\n                .then(this.initMessage.bind(this))\n                .then(this.render.bind(this));\n        },\n\n        /**\n         * Create instance of messages.\n         */\n        initMessage: function () {\n            this.message = new Message({\n                sdkNamespace: this.sdkNamespace,\n                scriptParams: this.sdkParams,\n                element: this.element,\n                renderContainer: this.renderContainer,\n                styles: this.styles,\n                placement: this.placement,\n                amount: this.provider.getAmount()\n            });\n        },\n\n        /**\n         * Update message amount.\n         */\n        updateAmount: function () {\n            this.message && this.message.updateAmount(this.provider.getAmount());\n        },\n\n        /**\n         * Render the message\n         */\n        render: function () {\n            this.message.render();\n            this.provider.updatePrice();\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/paypal-abstract.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiComponent',\n    'Magento_PaymentServicesPaypal/js/view/payment/actions/get-sdk-params'\n], function (Component, getSdkParams) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            sdkParamsKey: 'paypal',\n            sdkParams: [],\n            cacheTtl: 30000\n        },\n\n        /**\n         * Get sdk params\n         *\n         * @return {Promise<Object>}\n         */\n        getSdkParams: function () {\n            return getSdkParams(this.cacheTtl)\n                .then(function (sdkParams) {\n                    this.sdkParams = sdkParams[this.sdkParamsKey];\n                }.bind(this));\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/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\n/* eslint-disable no-undef */\ndefine([\n    'jquery',\n    'underscore',\n    'mage/translate',\n    'Magento_Checkout/js/view/payment/default',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'Magento_PaymentServicesPaypal/js/view/payment/methods/hosted-fields',\n    'Magento_PaymentServicesPaypal/js/view/errors/response-error',\n    'Magento_Checkout/js/action/set-billing-address',\n    'Magento_Ui/js/model/messageList',\n    'Magento_Vault/js/view/payment/vault-enabler',\n    'Magento_Checkout/js/model/payment/additional-validators',\n], function (\n    $,\n    _,\n    $t,\n    Component,\n    quote,\n    loader,\n    HostedFields,\n    ResponseError,\n    setBillingAddressAction,\n    globalMessageList,\n    VaultEnabler,\n    additionalValidators\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            isFormValid: false,\n            invalidFields: [],\n            isAvailable: false,\n            isFormRendered: false,\n            fields: {\n                number: {\n                    class: 'card-number-field',\n                    label: $t('Credit Card Number'),\n                    errorMessage: $t('Please enter a valid credit card number.'),\n                    selector: '#${ $.formId } .${ $.fields.number.class }',\n                    placeholder: '',\n                    showLockIcon: true\n                },\n                expirationDate: {\n                    class: 'expiration-date-field',\n                    selector: '#${ $.formId } .expiration-date-field',\n                    label: $t('Expiration Date'),\n                    errorMessage: $t('Incorrect credit card expiration date.'),\n                    placeholder: 'MM/YY'\n                },\n                cvv: {\n                    class: 'cvv-field',\n                    selector: '#${ $.formId } .cvv-field',\n                    label: $t('Card Security Code'),\n                    errorMessage: $t('Please enter a valid credit card security code.'),\n                    tooltip: {\n                        title: $t('What is this?'),\n                        src:  $.cvvImgUrl,\n                        contentUnsanitizedHtml: '<img src=\"${ $.cvvImgUrl }\" ' +\n                            'alt=\"${ $.cvvTitle }\" title=\"${ $.cvvTitle }\" />'\n                    },\n                    placeholder: ''\n                }\n            },\n            fieldsLayout: {\n                first: ['number'],\n                second: ['expirationDate', 'cvv']\n            },\n            cards: {\n                AE: {\n                    eligibilityCode: 'amex',\n                    typeCode: 'american-express'\n                },\n                DI: {\n                    eligibilityCode: 'discover',\n                    typeCode: 'discover'\n                },\n                ELO: {\n                    eligibilityCode: 'elo',\n                    typeCode: 'elo'\n                },\n                HC: {\n                    eligibilityCode: 'hiper',\n                    typeCode: 'hiper'\n                },\n                JCB: {\n                    eligibilityCode: 'jcb',\n                    typeCode: 'jcb'\n                },\n                MC: {\n                    eligibilityCode: 'mastercard',\n                    typeCode: 'master-card'\n                },\n                VI: {\n                    eligibilityCode: 'visa',\n                    typeCode: 'visa'\n                }\n            },\n            availableCards: [],\n            threeDSMode: window.checkoutConfig.payment['payment_services_paypal_hosted_fields'].threeDS,\n            createOrderUrl: window.checkoutConfig.payment['payment_services_paypal_hosted_fields'].createOrderUrl,\n            getOrderDetailsUrl: window.checkoutConfig.payment['payment_services_paypal_hosted_fields'].getOrderDetailsUrl, // eslint-disable-line max-len\n            requiresCardDetails: window.checkoutConfig.payment['payment_services_paypal_hosted_fields'].requiresCardDetails, // eslint-disable-line max-len\n            ccIcons: window.checkoutConfig.payment['payment_services_paypal_hosted_fields'].ccIcons,\n            paymentSource: window.checkoutConfig.payment['payment_services_paypal_hosted_fields'].paymentSource,\n            cvvImgUrl:  window.checkoutConfig.payment['payment_services_paypal_hosted_fields'].cvvImageUrl,\n            scriptParams:  window.checkoutConfig.payment['payment_services_paypal_hosted_fields'].sdkParams,\n            sdkNamespace: 'paypalCheckoutHostedFields',\n            isCommerceVaultEnabled: window.checkoutConfig.payment['payment_services_paypal_hosted_fields'].isCommerceVaultEnabled, // eslint-disable-line max-len\n            emptyErrorMessage: $t('This is a required field.'),\n            paymentTypeIconUrl:  window.checkoutConfig.payment['payment_services_paypal_hosted_fields'].paymentTypeIconUrl, // eslint-disable-line max-len\n            paymentTypeIconTitle: $t('Pay with credit card'),\n            lockTitle: $t('Secure transaction'),\n            cvvTitle: $t('The card security code is a three or four digit number printed on a credit card. Visa, Mastercard, and Discover cards have a three digit code on the card back. American Express cards have a four digit code on the card front.'), // eslint-disable-line max-len\n            paymentMethodValidationError: $t('Your payment was not successful. Ensure you have entered your details correctly and try again, or try a different payment method. If you have continued problems, contact the issuing bank for your payment method.'), // eslint-disable-line max-len\n            notEligibleErrorMessage: $t('This payment option is currently unavailable.'),\n            generalErrorMessage: '${ $.paymentMethodValidationError }',\n            placeOrderTitle: $t('Place Order'),\n            formId: 'hosted-fields-form',\n            template: 'Magento_PaymentServicesPaypal/payment/credit-card',\n            ccType: '',\n            billingAddress: quote.billingAddress,\n            paymentsOrderId: null,\n            paypalOrderId: null,\n            cardBin: null,\n            holderName: null,\n            cardLast4: null,\n            cardExpiryMonth: null,\n            cardExpiryYear: null,\n            hostedFields: null,\n            shouldCardBeVaulted: false\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            // config\n\n            _.bindAll(\n                this,\n                'onSuccess',\n                'onError',\n                'afterHostedFieldsRender',\n                'onOrderSuccess',\n                'beforeCreateOrder',\n                'getOrderCardDetails'\n            );\n            this._super();\n            this.initHostedFields();\n            this.vaultEnabler = new VaultEnabler();\n            this.vaultEnabler.isActivePaymentTokenEnabler(false);\n            this.vaultEnabler.setPaymentCode(window.checkoutConfig.payment[this.getCode()].ccVaultCode);\n\n            return this;\n        },\n\n        /**\n         * Initialize Hosted Fields.\n         */\n        initHostedFields: function () {\n            this.hostedFields = new HostedFields({\n                formId: this.formId,\n                fields: this.fields,\n                sdkNamespace: this.sdkNamespace,\n                scriptParams: this.scriptParams,\n                beforeCreateOrder: this.beforeCreateOrder,\n                onOrderSuccess: this.onOrderSuccess,\n                createOrderUrl: this.createOrderUrl,\n                shouldCardBeVaulted: this.shouldCardBeVaulted,\n                paymentSource: this.paymentSource\n            });\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super()\n                .observe('billingAddress paymentsOrderId paypalOrderId cardBin ' +\n                    'holderName cardLast4 cardExpiryMonth cardExpiryYear ' +\n                    'ccType isFormValid invalidFields availableCards isAvailable isFormRendered shouldCardBeVaulted');\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        getCode: function () {\n            return 'payment_services_paypal_hosted_fields';\n        },\n\n        /** @inheritdoc */\n        getData: function () {\n            var data = this._super();\n\n            data['additional_data'] = {\n                payments_order_id: this.paymentsOrderId(),\n                paypal_order_id: this.paypalOrderId(),\n                payment_source: this.paymentSource\n            };\n\n            if (this.cardBin()) {\n                data['additional_data']['cardBin'] = this.cardBin();\n            }\n\n            if (this.holderName()) {\n                data['additional_data']['holderName'] = this.holderName();\n            }\n\n            if (this.cardLast4()) {\n                data['additional_data']['cardLast4'] = this.cardLast4();\n            }\n\n            if (this.cardExpiryMonth()) {\n                data['additional_data']['cardExpiryMonth'] = this.cardExpiryMonth();\n            }\n\n            if (this.cardExpiryYear()) {\n                data['additional_data']['cardExpiryYear'] = this.cardExpiryYear();\n            }\n\n            this.vaultEnabler.visitAdditionalData(data);\n            return data;\n        },\n\n        /**\n         * Get payment related data.\n         *\n         * @return {Object}\n         */\n        getPaymentData: function () {\n            const paymentData = {\n                vault: this.isCommerceVaultEnabled && this.checkShouldCardBeVaulted(),\n                cardholderName: this.billingAddress().firstname + ' ' + this.billingAddress().lastname,\n                billingAddress: {\n                    streetAddress: this.billingAddress().street[0],\n                    extendedAddress: this.billingAddress().street[1],\n                    region: this.billingAddress().region,\n                    locality: this.billingAddress().city,\n                    postalCode: this.billingAddress().postcode,\n                    countryCodeAlpha2: this.billingAddress().countryId\n                }\n            };\n\n            if (this.threeDSMode) {\n                paymentData.contingencies = [this.threeDSMode];\n            }\n\n            return paymentData;\n        },\n\n        /** @inheritdoc */\n        afterRender: function () {\n            this.$form = $('#' + this.formId);\n\n            this.hostedFields.sdkLoaded.then(function () {\n                this.isAvailable(this.hostedFields.isEligible());\n\n                if (this.isAvailable()) {\n                    this.hostedFields.render()\n                        .then(this.afterHostedFieldsRender.bind(this));\n                }\n            }.bind(this)).catch(function () {\n                this.isAvailable(false);\n            }.bind(this)).finally(function () {\n                this.isFormRendered(true);\n            }.bind(this));\n        },\n\n        /**\n         * Bind events after hostedFields rendered.\n         *\n         * @param {Object} hostedFields\n         */\n        afterHostedFieldsRender: function (hostedFields) {\n            this.processAvailableCards(hostedFields.getCardTypes());\n            hostedFields.on('cardTypeChange', this.onCardTypeChange.bind(this, hostedFields));\n            hostedFields.on('validityChange', this.onValidityChange.bind(this, hostedFields));\n            hostedFields.on('blur', this.validateField.bind(this, hostedFields));\n            hostedFields.on('inputSubmitRequest', function (e) {\n                this.validateField(hostedFields, e);\n                this.submitForm(hostedFields);\n            }.bind(this));\n            this.$form.off('submit');\n            this.$form.on('submit', function (e) {\n                e.preventDefault();\n\n                this.submitForm(hostedFields);\n            }.bind(this));\n        },\n\n        /**\n         * Filter eligible cards, convert to internal codes and set to available cards.\n         *\n         * @param {Object} cardTypes\n         */\n        processAvailableCards: function (cardTypes) {\n            const cards = _.keys(cardTypes).sort(),\n                eligibleCards  = _.chain(cards)\n                    .filter(function (ccCode) {\n                        return cardTypes[ccCode].eligible;\n                    })\n                    .map(function (ccCode) {\n                        return _.findKey(this.cards, function (val) {\n                            return val.eligibilityCode === ccCode;\n                        }) || ccCode;\n                    }, this)\n                    .value();\n\n            this.availableCards(eligibleCards);\n        },\n\n        /**\n         * Validity change handler.\n         *\n         * @param {Object} hostedFields\n         * @param {Object} event\n         */\n        onValidityChange: function (hostedFields, event) {\n            const invalidFields = _.where(event.fields, {\n                isValid: false\n            });\n\n            this.isFormValid(!invalidFields.length);\n            this.isFormValid() && this.invalidFields([]);\n        },\n\n        /**\n         * Check if field is valid.\n         *\n         * @param {String} fieldName\n         * @return {Boolean}\n         */\n        isFieldValid: function (fieldName) {\n            return !this.invalidFields.findWhere({\n                name: fieldName\n            });\n        },\n\n        /**\n         * Get error message for field.\n         *\n         * @param {String} fieldName\n         * @return {String}\n         */\n        getFieldErrorMessage: function (fieldName) {\n            return !this.isFieldValid(fieldName) ? this.invalidFields.findWhere({\n                name: fieldName\n            }).message : '';\n        },\n\n        /**\n         * Validate credit card field.\n         *\n         * @param {Object} hostedFields\n         * @param {Object} event\n         */\n        validateField: function (hostedFields, event) {\n            var fieldName = event.emittedBy,\n                fieldValid = event.fields[fieldName].isValid,\n                isEmpty = event.fields[fieldName].isEmpty,\n                invalidFields = _.filter(this.invalidFields(), function (field) {\n                    return field.name !== fieldName;\n                });\n\n            if (!fieldValid) {\n                invalidFields.push({\n                    name: fieldName,\n                    message: isEmpty ? this.emptyErrorMessage : this.fields[fieldName].errorMessage\n                });\n            }\n\n            this.invalidFields(invalidFields);\n        },\n\n        /**\n         * Card type changes handler.\n         *\n         * @param {Object} hostedFields\n         * @param {Object} event\n         */\n        onCardTypeChange: function (hostedFields, event) {\n            var code = '';\n\n            if (event.cards.length === 1) {\n                code = _.findKey(this.cards, function (val) {\n                    return val.typeCode === event.cards[0].type;\n                });\n            }\n\n            this.ccType(code);\n        },\n\n        /**\n         * Form submit handler\n         *\n         * @param {Object} hostedFields\n         */\n        submitForm: function (hostedFields) {\n            if (this.canProceedWithOrder()) {\n                loader.startLoader();\n                hostedFields.submit(\n                    this.getPaymentData()\n                ).then(this.getOrderCardDetails).then(this.onSuccess).catch(this.onError).finally(loader.stopLoader);\n            }\n        },\n\n        /**\n         * Before order created.\n         *\n         * @return {Promise}\n         */\n        beforeCreateOrder: function () {\n            return new Promise(function (resolve, reject) {\n                return setBillingAddressAction(globalMessageList).done(resolve).fail(reject);\n            });\n        },\n\n        getOrderCardDetails: function (response) {\n            if (!this.requiresCardDetails) {\n                return Promise.resolve(response);\n            }\n\n            return fetch(`${this.getOrderDetailsUrl}`, {\n                method: 'GET'\n            }).then(function (res) {\n                return res.json();\n            }).then(function (data) {\n                if (data.response['is_successful'] && data.response['paypal-order']) {\n                    const order = data.response['paypal-order'];\n\n                    this.cardBin(order?.payment_source_details?.card?.bin_details?.bin);\n                    this.holderName(order?.payment_source_details?.card?.name);\n                    this.cardLast4(order?.payment_source_details?.card?.last_digits);\n                    this.cardExpiryMonth(order?.payment_source_details?.card?.card_expiry_month);\n                    this.cardExpiryYear(order?.payment_source_details?.card?.card_expiry_year);\n                }\n\n                return response;\n            }.bind(this)).catch(function (err) {\n                console.log(\n                    'Could not get order details. Proceeding with order placement without card details',\n                    err\n                );\n                return response;\n            });\n        },\n\n        /**\n         * Success callback for transaction.\n         *\n         * @param {Object} response\n         */\n        onSuccess: function (response) {\n            if (!this.threeDSMode) {\n                this.placeOrder();\n                return;\n            }\n\n            if (response.liabilityShift === 'POSSIBLE' || response.liabilityShift === undefined) {\n                this.placeOrder();\n            } else {\n                this.onError(new ResponseError(this.paymentMethodValidationError));\n            }\n        },\n\n        /**\n         * On PayPal order creation success.\n         *\n         * @param {Object} order\n         */\n        onOrderSuccess: function (order) {\n            this.paymentsOrderId(order['mp_order_id']);\n            this.paypalOrderId(order.id);\n        },\n\n        /**\n         * Error callback for transaction.\n         */\n        onError: function (error) {\n            var message = this.generalErrorMessage;\n\n            if (error instanceof ResponseError) {\n                message = error.message;\n                this.reRender();\n            } else if (error['debug_id']) {\n                message = this.paymentMethodValidationError;\n            }\n\n            this.messageContainer.addErrorMessage({\n                message: message\n            });\n\n            if (error instanceof Error) {\n                console.log(error.toString());\n            } else {\n                console.log('Error' + JSON.stringify(error));\n            }\n        },\n\n        /**\n         * Re-render hosted fields in case of order creation error.\n         */\n        reRender: function () {\n            this.hostedFields.instance.teardown().then(function () {\n                this.hostedFields.destroy();\n                this.isFormValid(false);\n                this.ccType('');\n                this.invalidFields([]);\n                this.initHostedFields();\n                this.afterRender();\n            }.bind(this));\n        },\n\n        /**\n         * Place order\n         */\n        placeOrderClick: function () {\n            if (this.isPlaceOrderActionAllowed() === true) {\n                $('#' + this.formId).trigger('submit');\n            }\n        },\n\n        /**\n         * Check if customer checks the \"Save for later\" box upon checkout\n         *\n         * @returns {*}\n         */\n        checkShouldCardBeVaulted: function () {\n            const checked = this.vaultEnabler.isActivePaymentTokenEnabler();\n\n            this.shouldCardBeVaulted(checked);\n            return checked;\n        },\n\n        canProceedWithOrder: function () {\n            return this.validate() && additionalValidators.validate() && this.isFormValid() && this.isPlaceOrderActionAllowed();\n        }\n\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/method-renderer/smart-buttons.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'Magento_Checkout/js/view/payment/default',\n    'jquery',\n    'underscore',\n    'mageUtils',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'mage/translate',\n    'Magento_PaymentServicesPaypal/js/view/payment/methods/smart-buttons',\n    'Magento_PaymentServicesPaypal/js/view/payment/message',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Checkout/js/action/set-billing-address',\n    'Magento_Ui/js/model/messageList',\n    'uiRegistry',\n    'Magento_Customer/js/customer-data'\n], function (\n    Component,\n    $,\n    _,\n    utils,\n    quote,\n    fullScreenLoader,\n    $t,\n    SmartButtons,\n    Message,\n    additionalValidators,\n    setBillingAddressAction,\n    globalMessageList,\n    registry,\n    customerData\n) {\n    'use strict';\n\n    var refreshCustomerData = function (url) {\n        // Trigger ajaxComplete event to update customer data\n        customerData.onAjaxComplete(\n            {},\n            {\n                type: 'POST',\n                url: url,\n            }\n        );\n    }\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypalCheckoutButtons',\n            buttonsContainerId: 'smart-buttons-${ $.uid }',\n            payLaterMessageContainerId: 'pay-later-message-${ $.uid }',\n            template: 'Magento_PaymentServicesPaypal/payment/smart-buttons',\n            isAvailable: false,\n            isButtonsRendered: false,\n            grandTotalAmount: null,\n            paymentsOrderId: null,\n            paypalOrderId: null,\n            requestProcessingError: $t('Error happened when processing the request. Please try again later.'),\n            notEligibleErrorMessage: $t('This payment option is currently unavailable.'),\n            paymentTypeIconUrl: window.checkoutConfig.payment['payment_services_paypal_smart_buttons'].paymentTypeIconUrl, // eslint-disable-line max-len\n            paymentTypeIconTitle: $t('Pay with PayPal')\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config) {\n            _.bindAll(this, 'onClick', 'onInit', 'catchError', 'beforeCreateOrder', 'afterCreateOrder');\n            config.uid = utils.uniqueid();\n            this._super();\n            this.initSmartButtons();\n            this.initMessage();\n            quote.totals.subscribe(function (totals) {\n                this.grandTotalAmount(totals['base_grand_total']);\n                this.message.updateAmount(totals['base_grand_total']);\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Initialize observables\n         *\n         * @returns {Component} Chainable.\n         */\n        initObservable: function () {\n            this._super().observe('grandTotalAmount isAvailable isButtonsRendered');\n            this.grandTotalAmount(quote.totals()['base_grand_total']);\n\n            return this;\n        },\n\n        /**\n         * Create instance of smart buttons.\n         */\n        initSmartButtons: function () {\n            this.buttons = new SmartButtons({\n                sdkNamespace: this.sdkNamespace,\n                scriptParams: window.checkoutConfig.payment['payment_services_paypal_smart_buttons'].sdkParams,\n                createOrderUrl: window.checkoutConfig.payment['payment_services_paypal_smart_buttons'].createOrderUrl,\n                styles: window.checkoutConfig.payment['payment_services_paypal_smart_buttons'].buttonStyles,\n                onInit: this.onInit,\n                onClick: this.onClick,\n                beforeCreateOrder: this.beforeCreateOrder,\n                afterCreateOrder: this.afterCreateOrder,\n                catchCreateOrder: this.catchError,\n                onApprove: function () {\n                    this.placeOrder();\n                }.bind(this),\n                onError: this.catchError\n            });\n        },\n\n        /**\n         * Initialize message component\n         */\n        initMessage: function () {\n            this.message = new Message({\n                scriptParams: window.checkoutConfig.payment['payment_services_paypal_smart_buttons'].sdkParams,\n                element: this.element,\n                renderContainer: '#' + this.payLaterMessageContainerId,\n                styles: window.checkoutConfig.payment['payment_services_paypal_smart_buttons'].messageStyles,\n                placement: 'payment',\n                amount: this.grandTotalAmount()\n            });\n        },\n\n        /**\n         * Get method code\n         *\n         * @return {String}\n         */\n        getCode: function () {\n            return 'payment_services_paypal_smart_buttons';\n        },\n\n        /**\n         * Get method data\n         *\n         * @return {Object}\n         */\n        getData: function () {\n            return {\n                'method': this.item.method,\n                'additional_data': {\n                    'payments_order_id': this.paymentsOrderId,\n                    'paypal_order_id': this.paypalOrderId,\n                    'payment_source': this.buttons.paymentSource\n                }\n            };\n        },\n\n        /**\n         * Render buttons\n         */\n        afterRender: function () {\n            this.buttons.sdkLoaded.then(function () {\n                this.buttons.render('#' + this.buttonsContainerId);\n                this.renderMessage();\n                this.isAvailable(!!this.buttons.instance && this.buttons.instance.isEligible());\n            }.bind(this)).catch(function () {\n                this.isAvailable(false);\n\n                return this.buttons;\n            }.bind(this)).finally(function () {\n                this.isButtonsRendered(true);\n            }.bind(this));\n        },\n\n        /**\n         * Render message\n         */\n        renderMessage: function () {\n            if (window.checkoutConfig.payment['payment_services_paypal_smart_buttons'].canDisplayMessage) {\n                this.message.render();\n            }\n        },\n\n        /**\n         * Enable/disable buttons.\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         */\n        onInit: function (data, actions) {\n            if (!this.isPlaceOrderActionAllowed()) {\n                actions.disable();\n            }\n\n            this.isPlaceOrderActionAllowed.subscribe(function (isAllowed) {\n                if (isAllowed) {\n                    actions.enable();\n                } else {\n                    actions.disable();\n                }\n            });\n        },\n\n        /**\n         * @inheritdoc\n         */\n        validate: function () {\n            var isShippingValid = true,\n                source, shippingAddress;\n\n            if (!this._super()) {\n                return false;\n            }\n            source = registry.get('checkoutProvider');\n            shippingAddress = registry.get('index = shippingAddress');\n\n            if (source && shippingAddress) {\n                source.set('params.invalid', false);\n                if (quote.billingAddress() === null) {\n                    this.triggerBillingValidation(source);\n                }\n\n                // skip shipping validation if quote is virtual or in-store pickup\n                if (!quote.isVirtual() && !quote.shippingMethod()['method_code'] === 'pickup') {\n                    isShippingValid = shippingAddress.validateShippingInformation();\n                }\n\n                return isShippingValid && !source.get('params.invalid');\n            }\n\n            return true;\n        },\n\n        /**\n         * Trigger billing address validation\n         *\n         * @param {Object} source\n         */\n        triggerBillingValidation: function (source) {\n            var dataScope = `billingAddress${ window.checkoutConfig.displayBillingOnPaymentMethod ?\n                this.getCode() : 'shared'}`;\n\n            source.trigger(`${ dataScope }.data.validate`);\n\n            if (source.get(`${dataScope}.custom_attributes`)) {\n                source.trigger(`${dataScope}.custom_attributes.data.validate`);\n            }\n        },\n\n        /**\n         * Validate form onClick\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         * @return {*}\n         */\n        onClick: function (data, actions) {\n            if (this.validate() && additionalValidators.validate()) {\n                return actions.resolve();\n            }\n\n            return actions.reject();\n        },\n\n        /**\n         * Before order created.\n         *\n         * @return {Promise}\n         */\n        beforeCreateOrder: function () {\n            return new Promise(function (resolve, reject) {\n                setBillingAddressAction(globalMessageList).done(resolve.bind(null, null)).fail(reject);\n            });\n        },\n\n        /**\n         * After order created.\n         *\n         * @param {Object} data\n         * @return {String}\n         */\n        afterCreateOrder: function (data) {\n            if (data.response['paypal-order'] && data.response['paypal-order']['mp_order_id']) {\n                refreshCustomerData(window.checkoutConfig.payment[this.getCode()].createOrderUrl);\n\n                this.paymentsOrderId = data.response['paypal-order']['mp_order_id'];\n                this.paypalOrderId = data.response['paypal-order'].id;\n\n                return this.paypalOrderId;\n            }\n\n            throw new Error();\n        },\n\n        /**\n         * Catch error.\n         *\n         * @param {Error} error\n         */\n        catchError: function (error) {\n            this.messageContainer.addErrorMessage({\n                message: this.requestProcessingError\n            });\n            console.log('Error: ', error.message);\n        }\n\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/method-renderer/vault.js":"/**\n * Copyright \u00a9 2013-2017 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'mage/translate',\n    'Magento_Vault/js/view/payment/method-renderer/vault',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'Magento_PaymentServicesPaypal/js/view/errors/response-error'\n], function (\n    $t,\n    VaultComponent,\n    loader,\n    ResponseError\n) {\n   'use strict';\n\n   return VaultComponent.extend({\n       defaults: {\n           template: 'Magento_PaymentServicesPaypal/payment/vault',\n           paymentSource: 'vault',\n           paypalOrderId: null,\n           paymentsOrderId: null,\n           generalErrorMessage: $t('An error occurred. Refresh the page and try again.'),\n           paymentMethodValidationError: $t('Your payment was not successful. Try again.')\n       },\n\n       /**\n        * Get card brand\n        * @returns {String}\n        */\n       getCardBrand: function () {\n           return this.mapCardBrand(this.details.brand);\n       },\n\n       /**\n        * Map the credit card brand received from PayPal to the Commerce standard\n        * @param payPalCardBrand\n        * @returns {*}\n        */\n       mapCardBrand: function (payPalCardBrand) {\n           const cardBrandMapping = {\n               AMEX: 'AE',\n               DISCOVER: 'DI',\n               DINERS: 'DN',\n               ELO: 'ELO',\n               HIPER: 'HC',\n               JCB: 'JCB',\n               MAESTRO: 'MI',\n               MASTER_CARD: 'MC',\n               MASTERCARD: 'MC',\n               VISA: 'VI'\n           };\n\n           return cardBrandMapping[payPalCardBrand];\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 PayPal order ID\n        */\n       getData: function () {\n          let data = this._super();\n\n          data['additional_data']['paypal_order_id'] = this.paypalOrderId;\n          data['additional_data']['payments_order_id'] = this.paymentsOrderId;\n          data['additional_data']['public_hash'] = this.publicHash;\n          data['additional_data']['payment_source'] = this.paymentSource;\n          return data;\n       },\n\n       /**\n        * Place order\n        */\n       onPlaceOrder: function () {\n           loader.startLoader();\n           this.createOrder()\n               .then(function (order) {\n                   this.onOrderSuccess(order);\n               }.bind(this))\n               .then(function () {\n                   this.placeOrder();\n               }.bind(this))\n               .catch(this.onError.bind(this))\n               .finally(loader.stopLoader);\n       },\n\n       /**\n        * Create PayPal order\n        * @returns {Promise<any>}\n        */\n       createOrder: function () {\n           var orderData = new FormData();\n\n           orderData.append('payment_source', this.paymentSource);\n\n           return fetch(this.createOrderUrl, {\n               method: 'POST',\n               headers: {},\n               body: orderData,\n               credentials: 'same-origin'\n           }).then(function (res) {\n               return res.json();\n           }).then(function (data) {\n               if (data.response['is_successful']) {\n                   return data.response['paypal-order'];\n               }\n           });\n       },\n\n       /**\n        * populate PayPal order ID and trigger Commerce order flow\n        * @param order\n        */\n       onOrderSuccess: function (order) {\n           this.paypalOrderId = order['id'];\n           this.paymentsOrderId = order['mp_order_id'];\n       },\n\n       /**\n        * handle payment error\n        * @param error\n        */\n       onError: function (error) {\n           var message = this.generalErrorMessage;\n\n           if (error instanceof ResponseError) {\n               message = error.message;\n           } else if (error['debug_id']) {\n               message = this.paymentMethodValidationError;\n           }\n\n           this.messageContainer.addErrorMessage({\n               message: message\n           });\n           console.log(error['debug_id'] ? 'Error' + JSON.stringify(error) : error.toString());\n       }\n   });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/method-renderer/apple-pay.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'Magento_Checkout/js/view/payment/default',\n    'jquery',\n    'underscore',\n    'mageUtils',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'mage/translate',\n    'Magento_PaymentServicesPaypal/js/view/payment/methods/apple-pay',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Checkout/js/action/set-billing-address',\n    'Magento_Ui/js/model/messageList',\n    'Magento_Customer/js/customer-data'\n], function (\n    Component,\n    $,\n    _,\n    utils,\n    quote,\n    fullScreenLoader,\n    $t,\n    ApplePayButton,\n    additionalValidators,\n    setBillingAddressAction,\n    globalMessageList,\n    customerData\n) {\n    'use strict';\n\n    var refreshCustomerData = function (url) {\n        // Trigger ajaxComplete event to update customer data\n        customerData.onAjaxComplete(\n            {},\n            {\n                type: 'POST',\n                url: url,\n            }\n        );\n    }\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypalApplePay',\n            fundingSource: 'applepay',\n            buttonContainerId: 'apple-pay-${ $.uid }',\n            template: 'Magento_PaymentServicesPaypal/payment/apple-pay',\n            isAvailable: false,\n            isButtonRendered: false,\n            grandTotalAmount: null,\n            paymentsOrderId: null,\n            paypalOrderId: null,\n            paymentTypeIconTitle: $t('Pay with Apple Pay'),\n            requestProcessingError: $t('Error happened when processing the request. Please try again later.'),\n            notEligibleErrorMessage: $t('This payment option is currently unavailable.'),\n            paymentTypeIconUrl: window.checkoutConfig.payment['payment_services_paypal_apple_pay'].paymentTypeIconUrl\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config) {\n            _.bindAll(this, 'catchError', 'beforeCreateOrder', 'afterCreateOrder', 'placeOrder', 'onClick');\n            config.uid = utils.uniqueid();\n            this._super();\n            this.initApplePayButton();\n\n            return this;\n        },\n\n        /**\n         * Initialize observables\n         *\n         * @returns {Component} Chainable.\n         */\n        initObservable: function () {\n            this._super().observe('grandTotalAmount isAvailable isButtonRendered');\n            this.grandTotalAmount(quote.totals()['base_grand_total']);\n\n            return this;\n        },\n\n        /**\n         * Create instance of smart buttons.\n         */\n        initApplePayButton: function () {\n            this.applePayButton = new ApplePayButton({\n                scriptParams: window.checkoutConfig.payment[this.getCode()].sdkParams,\n                createOrderUrl: window.checkoutConfig.payment[this.getCode()].createOrderUrl,\n                estimateShippingMethodsWhenLoggedInUrl: window.checkoutConfig.payment[this.getCode()].estimateShippingMethodsWhenLoggedInUrl,\n                estimateShippingMethodsWhenGuestUrl: window.checkoutConfig.payment[this.getCode()].estimateShippingMethodsWhenGuestUrl,\n                shippingInformationWhenLoggedInUrl: window.checkoutConfig.payment[this.getCode()].shippingInformationWhenLoggedInUrl,\n                shippingInformationWhenGuestUrl: window.checkoutConfig.payment[this.getCode()].shippingInformationWhenGuestUrl,\n                updatePayPalOrderUrl: window.checkoutConfig.payment[this.getCode()].updatePayPalOrderUrl,\n                countriesUrl: window.checkoutConfig.payment[this.getCode()].countriesUrl,\n                onClick: this.onClick,\n                beforeCreateOrder: this.beforeCreateOrder,\n                afterCreateOrder: this.afterCreateOrder,\n                catchCreateOrder: this.catchError,\n                onError: this.catchError,\n                buttonContainerId: this.buttonContainerId,\n                onApprove: this.placeOrder,\n                styles: window.checkoutConfig.payment[this.getCode()].buttonStyles\n            });\n        },\n\n        /**\n         * Get method code\n         *\n         * @return {String}\n         */\n        getCode: function () {\n            return 'payment_services_paypal_apple_pay';\n        },\n\n        /**\n         * Get method data\n         *\n         * @return {Object}\n         */\n        getData: function () {\n            return {\n                'method': this.item.method,\n                'additional_data': {\n                    'payments_order_id': this.paymentsOrderId,\n                    'paypal_order_id': this.paypalOrderId,\n                    'payment_source': this.fundingSource\n                }\n            };\n        },\n\n        /**\n         * Render buttons\n         */\n        afterRender: function () {\n            this.applePayButton.sdkLoaded\n                .then(this.applePayButton.initAppleSDK)\n                .then(function () {\n                        this.isAvailable(true);\n                        this.isButtonRendered(true);\n                    }.bind(this)\n                ).catch(function () {\n                this.isAvailable(false);\n            }.bind(this)).finally(function () {\n                this.isButtonRendered(true);\n            }.bind(this));\n        },\n\n        /**\n         * Enable/disable buttons.\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         */\n        onInit: function (data, actions) {\n            if (!this.isPlaceOrderActionAllowed()) {\n                actions.disable();\n            }\n\n            this.isPlaceOrderActionAllowed.subscribe(function (isAllowed) {\n                if (isAllowed) {\n                    actions.enable();\n                } else {\n                    actions.disable();\n                }\n            });\n        },\n\n        /**\n         * Validate form onClick\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         * @return {*}\n         */\n        onClick: function (data, actions) {\n            this.applePayButton.showLoaderAsync(true)\n                .then(() => {\n                    this.applePayButton.createOrder();\n                })\n                .then(() => {\n                    refreshCustomerData(window.checkoutConfig.payment[this.getCode()].createOrderUrl);\n                })\n                .catch(error => {\n                    this.catchError(error);\n                });\n        },\n\n        /**\n         * Before order created.\n         *\n         * @return {Promise}\n         */\n        beforeCreateOrder: function () {\n            if (this.validate() && this.isPlaceOrderActionAllowed() && additionalValidators.validate()) {\n                return new Promise(function (resolve, reject) {\n                    setBillingAddressAction(globalMessageList).done(resolve.bind(null, null)).fail(reject);\n                });\n            } else {\n                throw {message: 'before create order validation failed', hidden: true};\n            }\n        },\n\n        /**\n         * After order created.\n         *\n         * @param {Object} data\n         * @return {String}\n         */\n        afterCreateOrder: function (data) {\n            if (data.response['paypal-order'] && data.response['paypal-order']['mp_order_id']) {\n                this.paymentsOrderId = data.response['paypal-order']['mp_order_id'];\n                this.paypalOrderId = data.response['paypal-order'].id;\n\n                this.applePayButton.showPopup(data, quote);\n\n                return this.paypalOrderId;\n            }\n\n            throw new Error();\n        },\n\n        /**\n         * Catch error.\n         *\n         * @param {Error} error\n         */\n        catchError: function (error) {\n            this.messageContainer.addErrorMessage({\n                message: this.requestProcessingError\n            });\n            console.log('Error: ', error.message);\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/method-renderer/google-pay.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'Magento_Checkout/js/view/payment/default',\n    'jquery',\n    'underscore',\n    'mageUtils',\n    'Magento_Checkout/js/model/quote',\n    'mage/translate',\n    'Magento_PaymentServicesPaypal/js/view/payment/methods/google-pay',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Checkout/js/action/set-billing-address',\n    'Magento_Ui/js/model/messageList',\n    'uiRegistry',\n    'Magento_Customer/js/customer-data'\n], function (\n    Component,\n    $,\n    _,\n    utils,\n    quote,\n    $t,\n    GooglePayButton,\n    additionalValidators,\n    setBillingAddressAction,\n    globalMessageList,\n    registry,\n    customerData\n) {\n    'use strict';\n\n    var refreshCustomerData = function (url) {\n        // Trigger ajaxComplete event to update customer data\n        customerData.onAjaxComplete(\n            {},\n            {\n                type: 'POST',\n                url: url,\n            }\n        );\n    }\n\n    return Component.extend({\n        defaults: {\n            buttonContainerId: 'google-pay-${ $.uid }',\n            template: 'Magento_PaymentServicesPaypal/payment/google-pay',\n            isAvailable: false,\n            isButtonRendered: false,\n            paymentsOrderId: null,\n            paypalOrderId: null,\n            paymentTypeIconTitle: $t('Pay with Google Pay'),\n            requestProcessingError: $t('Error happened when processing the request. Please try again later.'),\n            notEligibleErrorMessage: $t('This payment option is currently unavailable.'),\n            paymentTypeIconUrl:  window.checkoutConfig.payment['payment_services_paypal_google_pay'].paymentTypeIconUrl,\n            fundingSource: window.checkoutConfig.payment['payment_services_paypal_google_pay'].paymentSource\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function (config) {\n            _.bindAll(this, 'catchError', 'beforeCreateOrder', 'afterCreateOrder', 'placeOrder', 'onClick');\n            config.uid = utils.uniqueid();\n            this._super();\n            this.initGooglePayButton();\n\n            return this;\n        },\n\n        /**\n         * Initialize observables\n         *\n         * @returns {Component} Chainable.\n         */\n        initObservable: function () {\n            this._super().observe('isAvailable isButtonRendered');\n\n            return this;\n        },\n\n        initGooglePayButton: function () {\n            this.googlePayButton = new GooglePayButton({\n                scriptParams: window.checkoutConfig.payment[this.getCode()].sdkParams,\n                createOrderUrl: window.checkoutConfig.payment[this.getCode()].createOrderUrl,\n                onClick: this.onClick,\n                beforeCreateOrder: this.beforeCreateOrder,\n                afterCreateOrder: this.afterCreateOrder,\n                catchCreateOrder: this.catchError,\n                onError: this.catchError,\n                buttonContainerId: this.buttonContainerId,\n                onApprove: this.placeOrder,\n                styles: window.checkoutConfig.payment[this.getCode()].styles,\n                mode: window.checkoutConfig.payment[this.getCode()].mode,\n                shippingAddressRequired: false\n            });\n\n            if (!this.isPlaceOrderActionAllowed()) {\n                this.googlePayButton.disableButton();\n            }\n\n            this.isPlaceOrderActionAllowed.subscribe(function (isAllowed) {\n                if (isAllowed) {\n                    this.googlePayButton.enableButton();\n                } else {\n                    this.googlePayButton.disableButton();\n                }\n            }.bind(this));\n        },\n\n        /**\n         * Get method code\n         *\n         * @return {String}\n         */\n        getCode: function () {\n            return 'payment_services_paypal_google_pay';\n        },\n\n        /**\n         * Get method data\n         *\n         * @return {Object}\n         */\n        getData: function () {\n            return {\n                'method': this.item.method,\n                'additional_data': {\n                    'payments_order_id': this.paymentsOrderId,\n                    'paypal_order_id': this.paypalOrderId,\n                    'payment_source': this.fundingSource\n                }\n            };\n        },\n\n        onClick: function () {\n            this.googlePayButton.showLoaderAsync(true)\n                .then(() => {\n                    return this.googlePayButton.createOrder();\n                })\n                .then(() => {\n                    refreshCustomerData(window.checkoutConfig.payment[this.getCode()].createOrderUrl);\n                })\n                .catch(error => {\n                    this.catchError(error);\n                });\n        },\n\n        /**\n         * Render buttons\n         */\n        afterRender: function () {\n            this.googlePayButton.sdkLoaded\n                .then(function () {\n                    this.googlePayButton.initGoogleSDK()\n                        .then(function () {\n                            this.isAvailable(this.googlePayButton.isEligible());\n                        }.bind(this)).catch(function () {\n                            this.isAvailable(false);\n                        }.bind(this)).finally(function () {\n                            this.isButtonRendered(true);\n                        }.bind(this)\n                    );\n                }.bind(this));\n        },\n\n        /**\n         * Before order created.\n         *\n         * @return {Promise}\n         */\n        beforeCreateOrder: function () {\n            if (this.validate() && this.isPlaceOrderActionAllowed() && additionalValidators.validate()) {\n                setBillingAddressAction(globalMessageList)\n                    .fail(function () {\n                        throw {message: 'Failed to set billing address'};\n                    });\n            } else {\n                throw {message: 'before create order validation failed', hidden: true};\n            }\n        },\n\n        /**\n         * @inheritdoc\n         */\n        validate: function () {\n            var isShippingValid = true,\n                source, shippingAddress;\n\n            if (!this._super()) {\n                return false;\n            }\n            source = registry.get('checkoutProvider');\n            shippingAddress = registry.get('index = shippingAddress');\n\n            if (source && shippingAddress) {\n                source.set('params.invalid', false);\n                if (quote.billingAddress() === null) {\n                    this.triggerBillingValidation(source);\n                }\n\n                // skip shipping validation if quote is virtual or in-store pickup\n                if (!quote.isVirtual() && !quote.shippingMethod()['method_code'] === 'pickup') {\n                    isShippingValid = shippingAddress.validateShippingInformation();\n                }\n\n                return isShippingValid && !source.get('params.invalid');\n            }\n\n            return true;\n        },\n\n        /**\n         * Trigger billing address validation\n         *\n         * @param {Object} source\n         */\n        triggerBillingValidation: function (source) {\n            var dataScope = `billingAddress${ window.checkoutConfig.displayBillingOnPaymentMethod ?\n                this.getCode() : 'shared'}`;\n\n            source.trigger(`${ dataScope }.data.validate`);\n\n            if (source.get(`${dataScope}.custom_attributes`)) {\n                source.trigger(`${dataScope}.custom_attributes.data.validate`);\n            }\n        },\n\n        /**\n         * After order created.\n         *\n         * @param {Object} data\n         * @return {String}\n         */\n        afterCreateOrder: function (data) {\n            if (data.response['paypal-order'] && data.response['paypal-order']['mp_order_id']) {\n                this.paymentsOrderId = data.response['paypal-order']['mp_order_id'];\n                this.paypalOrderId = data.response['paypal-order'].id;\n\n                let displayItems = [],\n                    subTotal = this.getTotalsSegment('subtotal'),\n                    shippingTotal = this.getTotalsSegment('shipping'),\n                    taxTotal = this.getTotalsSegment('tax'),\n                    discountTotal = this.getTotalsSegment('discount');\n\n                if (subTotal != null) {\n                    displayItems.push(\n                        {\n                            label: $t('Subtotal'),\n                            type: 'SUBTOTAL',\n                            price: subTotal.value.toString()\n                        }\n                    );\n                }\n                if (taxTotal != null) {\n                    displayItems.push(\n                        {\n                            label: $t('Tax'),\n                            type: 'TAX',\n                            price: taxTotal.value.toString()\n                        }\n                    );\n                }\n\n                if (shippingTotal != null) {\n                    displayItems.push(\n                        {\n                            label: $t('Shipping'),\n                            type: 'LINE_ITEM',\n                            price: shippingTotal.value.toString()\n                        }\n                    );\n                }\n\n                if (discountTotal != null) {\n                    displayItems.push(\n                        {\n                            label: $t('Discount'),\n                            type: 'LINE_ITEM',\n                            price: discountTotal.value.toString()\n                        }\n                    );\n                }\n\n                this.googlePayButton.showPopup({\n                    displayItems: displayItems,\n                    currencyCode: quote.totals()['base_currency_code'].toString(),\n                    totalPriceStatus: 'FINAL',\n                    totalPrice: quote.totals()['base_grand_total'].toString(),\n                    totalPriceLabel: $t('Total')\n                });\n\n                return this.paypalOrderId;\n            }\n\n            throw new Error();\n        },\n\n        /**\n         * Catch error.\n         *\n         * @param {Error} error\n         */\n        catchError: function (error) {\n            if (error.hidden === undefined || !error.hidden) {\n                this.messageContainer.addErrorMessage({\n                    message: this.requestProcessingError\n                });\n            }\n\n            this.googlePayButton.showLoader(false);\n\n            console.log('Error: ', error);\n        },\n\n        getTotalsSegment: function (code) {\n            var segment = null;\n\n            if (!('total_segments' in quote.totals())) {\n                return null;\n            }\n\n            quote.totals()['total_segments'].forEach(function (s) {\n                if (s.code === code) {\n                    segment = s;\n                }\n            });\n\n            return segment;\n        }\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/methods/hosted-fields.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'underscore',\n    'uiComponent',\n    'mage/translate',\n    'Magento_PaymentServicesPaypal/js/view/errors/response-error',\n    'scriptLoader'\n], function (_, Class, $t, ResponseError, loadSdkScript) {\n    'use strict';\n\n    return Class.extend({\n        defaults: {\n            sdkNamespace: 'paypal',\n            paypal: null,\n            formId: 'hosted-fields-form',\n            instance: undefined,\n            createOrderUrl: null,\n            orderCreateErrorMessage: {\n                default: $t('Failed to place order. Try again or refresh the page if that does not resolve the issue.'), // eslint-disable-line max-len,\n                //TODO: Update messages\n                'POSTAL_CODE_REQUIRED': $t('Postal code is required.'),\n                'CITY_REQUIRED': $t('City is required.')\n            },\n            styles: {\n                input: {\n                    color: '#ccc',\n                    'font-family': '\"Open Sans\",\"Helvetica Neue\",Helvetica,Arial,sans-serif',\n                    'font-size': '16px',\n                    'font-weight': '400'\n                },\n                ':focus': {\n                    color: '#333'\n                },\n                '.valid': {\n                    color: '#333'\n                }\n            },\n            fields: {\n                number: {\n                    class: 'number',\n                    selector: '#${ $.formId } .${ $.fields.number.class }',\n                    placeholder: ''\n                },\n                expirationDate: {\n                    class: 'expiration-date',\n                    selector: '#${ $.formId } .${ $.fields.expirationDate.class }',\n                    placeholder: 'MM/YY'\n                },\n                cvv: {\n                    class: 'cvv',\n                    selector: '#${ $.formId } .${ $.fields.cvv.class }',\n                    placeholder: ''\n                }\n            },\n            scriptParams: [],\n            sdkLoaded: null,\n            shouldCardBeVaulted: false\n        },\n\n        /** @inheritdoc */\n        initialize: function (config) {\n            _.bindAll(this, 'createOrder');\n\n            if (config.fields) {\n                this.constructor.defaults.fields = config.fields;\n            }\n            this._super();\n            this.sdkLoaded = loadSdkScript(this.scriptParams, this.sdkNamespace).then(function (sdkScript) {\n                this.paypal = sdkScript;\n            }.bind(this));\n            return this;\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super()\n                .observe('shouldCardBeVaulted');\n\n            return this;\n        },\n\n        /**\n         * Check if eligible\n         *\n         * @return {Boolean}\n         */\n        isEligible: function () {\n            return typeof this.paypal !== 'undefined' &&\n                this.paypal.HostedFields &&\n                this.paypal.HostedFields.isEligible();\n        },\n\n        /**\n         * Render fields.\n         *\n         * @return {*}\n         */\n        render: function () {\n            return this.paypal.HostedFields.render({\n                createOrder: this.createOrder,\n                styles: this.styles,\n                fields: this.fields\n            }).then(function (instance) {\n                this.instance = instance;\n\n                return instance;\n            }.bind(this));\n        },\n\n        /**\n         * Calls before create order.\n         *\n         * @return {Promise}\n         */\n        beforeCreateOrder: function () {\n            return Promise.resolve();\n        },\n\n        /**\n         * Create order in payment service / PayPal\n         *\n         * @returns {Promise<any>}\n         */\n        createOrder: function () {\n            return this.beforeCreateOrder()\n                .then(function () {\n                    const shouldCardBeVaulted = this.shouldCardBeVaulted(),\n                        orderData = new FormData();\n\n                    orderData.append('payment_source', this.paymentSource);\n\n                    return fetch(`${this.createOrderUrl}?vault=${shouldCardBeVaulted}`, {\n                        method: 'POST',\n                        headers: {},\n                        body: orderData\n                    });\n                }.bind(this)).then(function (res) {\n                    return res.json();\n                }).then(function (data) {\n                    if (data.response['is_successful']) {\n                        this.onOrderSuccess(data.response['paypal-order']);\n                    } else {\n                        throw new ResponseError(\n                            this.orderCreateErrorMessage[data.response.message] || this.orderCreateErrorMessage.default\n                        );\n                    }\n\n                    return data.response['paypal-order'].id;\n                }.bind(this)).catch(function (error) {\n                    if (error instanceof ResponseError) {\n                        throw error;\n                    }\n                    throw new ResponseError(this.orderCreateErrorMessage.default);\n                }.bind(this));\n        },\n\n        /**\n         * Customizable handler for order creation.\n         */\n        onOrderSuccess: function () {}\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/methods/smart-buttons.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'jquery',\n    'underscore',\n    'uiComponent',\n    'scriptLoader',\n    'mage/cookies'\n], function ($, _, Component, loadSdkScript) {\n    'use strict';\n\n    /**\n     * Create order request.\n     *\n     * @param {String} url\n     * @param {Object} payPalOrderData\n     * @param {FormData} orderData\n     * @return {Promise<Object>}\n     */\n    var performCreateOrder = function (url, payPalOrderData, orderData) {\n            orderData = orderData || new FormData();\n            orderData.append('form_key', $.mage.cookies.get('form_key'));\n            orderData.append('payment_source', payPalOrderData['paymentSource']);\n\n            return fetch(url, {\n                method: 'POST',\n                headers: {},\n                body: orderData || new FormData(),\n                credentials: 'same-origin'\n            }).then(function (response) {\n                return response.json();\n            });\n        },\n\n        /**\n         * Payment authorization request.\n         *\n         * @return {Promise<Object>}\n         */\n        performAuthorization = function (url, data) {\n            var orderData = new FormData();\n\n            orderData.append('form_key', $.mage.cookies.get('form_key'));\n            orderData.append('paypal_order_id', data.orderID);\n            orderData.append('paypal_payer_id', data.payerID);\n\n            return fetch(url, {\n                method: 'POST',\n                headers: {},\n                body: orderData,\n                credentials: 'same-origin'\n            }).then(function (response) {\n                return response.json();\n            });\n        };\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypal',\n            paypal: null,\n            paymentSource: '',\n            creatOrderUrl: '',\n            authorizeOrderUrl: '',\n            style: {},\n            paymentRequest: {\n                applepay: {\n                    requiredShippingContactFields: []\n                }\n            },\n            element: null,\n            instance: null\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            _.bindAll(this, 'createOrder', 'onApprove', 'onError', 'onCancel');\n            this._super();\n            this.sdkLoaded = loadSdkScript(this.scriptParams, this.sdkNamespace).then(function (sdkScript) {\n                this.paypal = sdkScript;\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         * In the case where the button color is not supported by Apple (black or white)\n         * Map the button color to black (same behavior as PayPal SDK script)\n         *\n         * @param buttonStyles\n         * @returns {(*&{color: string})|*}\n         */\n        mapButtonColorForApplePay: function (buttonStyles) {\n            var buttonColor = buttonStyles.color;\n\n            if (buttonColor === 'black' || buttonColor === 'white') {\n                return buttonStyles;\n            }\n            return {\n                ...buttonStyles,\n                color: 'black'\n            };\n        },\n\n        /**\n         * Render Smart Buttons.\n         *\n         * @param {HTMLElement} element\n         * @return {*}\n         */\n        render: function (element) {\n            var buttonsConfig;\n\n            if (typeof this.paypal === 'undefined' || !this.paypal.Buttons) {\n                return null;\n            }\n\n            if (element) {\n                this.element = element;\n            }\n\n            buttonsConfig = {\n                element: this.element,\n                paymentRequest: this.paymentRequest,\n                style: this.styles,\n                onClick: this.onClick,\n                createOrder: this.createOrder,\n                onApprove: this.onApprove,\n                onError: this.onError,\n                onCancel: this.onCancel,\n                onInit: this.onInit\n            };\n\n            if (this.onShippingChange) {\n                buttonsConfig.onShippingChange = this.onShippingChange.bind(this);\n            }\n            if (this.fundingSource) {\n                buttonsConfig.fundingSource = this.fundingSource;\n                if (this.fundingSource === 'applepay') {\n                    buttonsConfig.style = this.mapButtonColorForApplePay(this.styles);\n                }\n            }\n\n            this.instance = this.paypal.Buttons(buttonsConfig);\n\n            if (this.instance.isEligible()) {\n                this.instance.render(this.element);\n            }\n\n            return this.instance;\n        },\n\n        /**\n         * Calls when smart buttons initializing\n         */\n        onInit: function () {\n        },\n\n        /**\n         * Calls when user click paypal button.\n         */\n        onClick: function () {\n        },\n\n        /**\n         * Calls before create order.\n         *\n         * @return {Promise}\n         */\n        beforeCreateOrder: function () {\n            return Promise.resolve();\n        },\n\n        /**\n         * Create order.\n         *\n         * @return {Promise}\n         */\n        createOrder: function (data) {\n            this.paymentSource = data['paymentSource'];\n\n            return this.beforeCreateOrder()\n                .then(performCreateOrder.bind(this, this.createOrderUrl, data))\n                .then(function (orderData) {\n                    return this.afterCreateOrder(orderData);\n                }.bind(this)).catch(function (error) {\n                    return this.catchCreateOrder(error);\n                }.bind(this)).finally(function (error) {\n                    return this.finallyCreateOrder(error);\n                }.bind(this));\n        },\n\n        /**\n         * After order created.\n         *\n         * @param {Object} data\n         * @return {*}\n         */\n        afterCreateOrder: function (data) {\n            return data.orderId;\n        },\n\n        /**\n         * Catch error on order creation.\n         */\n        catchCreateOrder: function () {\n        },\n\n        /**\n         * Finally for order creation.\n         *\n         */\n        finallyCreateOrder: function () {\n        },\n\n        /**\n         * Before authorization call.\n         *\n         * @return {Promise}\n         */\n        beforeOnAuthorize: function (data) {\n            return Promise.resolve(data);\n        },\n\n        /**\n         * On payment approve.\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         * @return {Promise}\n         */\n        onApprove: function (data, actions) {\n            return this.beforeOnAuthorize(data, actions)\n                .then(performAuthorization.bind(this, this.authorizeOrderUrl))\n                .then(function (authData) {\n                    return this.afterOnAuthorize(authData, actions);\n                }.bind(this)).catch(function (error) {\n                    return this.catchOnAuthorize(error);\n                }.bind(this)).finally(function (error) {\n                    return this.finallyOnAuthorize(error);\n                }.bind(this));\n        },\n\n        /**\n         * Calls after successful payment authorization.\n         *\n         * @param {Object} authData\n         * @return {*}\n         */\n        afterOnAuthorize: function (authData) {\n            return authData;\n        },\n\n        /**\n         * Catch payment authorization errors.\n         */\n        catchOnAuthorize: function () {\n        },\n\n        /**\n         * Finally for payment authorization.\n         */\n        finallyOnAuthorize: function () {\n        },\n\n        /**\n         * Calls when shipping address chenges..\n         *\n         * @param {Object} data\n         */\n        onShippingChange: undefined,\n\n        /**\n         * Calls when error happened on paypal side.\n         *\n         * @param {Error} error\n         */\n        onError: function (error) {\n            console.log('Error: ', error.message);\n        },\n\n        /**\n         * Calls when user canceled payment.\n         */\n        onCancel: function () {}\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/methods/apple-pay.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'jquery',\n    'underscore',\n    'uiComponent',\n    'scriptLoader',\n    'Magento_PaymentServicesPaypal/js/lib/script-loader',\n    'Magento_Customer/js/customer-data',\n    'Magento_Customer/js/model/customer',\n    'mage/translate',\n], function ($, _, Component, loadSdkScript, scriptLoader, customerData, customer, $t) {\n    'use strict';\n\n    const HTTP_STATUS_CREATED = 201;\n\n    const APPLE_PAY_VERSION_NUMBER = 4; // See https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/creating_an_apple_pay_session\n    const appleSDKSrc = 'https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js';\n\n    /**\n     * Create order request.\n     *\n     * @param {String} url\n     * @param {Object} payPalOrderData\n     * @param {FormData} orderData\n     * @return {Object}\n     */\n    var performCreateOrder = function (url, payPalOrderData, orderData) {\n\n            orderData = orderData || new FormData();\n            orderData.append('form_key', $.mage.cookies.get('form_key'));\n            orderData.append('payment_source', payPalOrderData['paymentSource']);\n\n            let xhr = new XMLHttpRequest();\n            xhr.open('POST', url, false);\n            xhr.send(orderData);\n\n            if (xhr.status !== HTTP_STATUS_CREATED) {\n                throw new Error('Request failed');\n            } else {\n                return JSON.parse(xhr.responseText);\n            }\n        },\n\n        /**\n         * Payment authorization request.\n         *\n         * @return {Promise<Object>}\n         */\n        performOnAuthorize = function (url, data) {\n            var orderData = new FormData();\n\n            orderData.append('form_key', $.mage.cookies.get('form_key'));\n            orderData.append('paypal_order_id', data.orderID);\n\n            return fetch(url, {\n                method: 'POST',\n                headers: {},\n                body: orderData,\n                credentials: 'same-origin'\n            }).then(function (response) {\n                return response.json();\n            });\n        };\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypal',\n            paypal: null,\n            paymentSource: 'applepay',\n            createOrderUrl: '',\n            placeOrderUrl: '',\n            updateQuoteUrl: '',\n            estimateShippingMethodsWhenLoggedInUrl: '',\n            estimateShippingMethodsWhenGuestUrl: '',\n            shippingInformationWhenLoggedInUrl: '',\n            shippingInformationWhenGuestUrl: '',\n            updatePaypalOrderUrl: '',\n            setQuoteAsInactiveUrl: '',\n            countriesUrl: '',\n            instance: null,\n            scriptParams: {},\n            allowedPaymentMethods: null,\n            merchantInfo: null,\n            buttonContainerId: null,\n            paypalOrderId: null,\n            eligible: false,\n            applePayInstance: null,\n            applePayConfig: null,\n            appleSession: null,\n            applePayVersionNumber: APPLE_PAY_VERSION_NUMBER,\n            countryCode: null,\n            regionCode: null,\n            regionId: null,\n            postalCode: null,\n            requestProcessingError: $t('Something went wrong with your request. Please try again later.'),\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            _.bindAll(this, 'createOrder', 'onApprove', 'onError', 'initAppleSDK', 'performAuthorization',\n                'onClick', 'beforeOnAuthorize', 'afterOnAuthorize', 'onCancel');\n            this._super();\n            this.sdkLoaded = Promise.all([this.loadPayPalSDK(), this.loadAppleSDK()]);\n\n            return this;\n        },\n\n        loadPayPalSDK: function () {\n            return loadSdkScript(this.scriptParams, this.sdkNamespace)\n                .then(function (sdkScript) {\n                    this.paypal = sdkScript;\n                }.bind(this))\n                .catch(function (e) {\n                    this.onError(e);\n                });\n        },\n\n        loadAppleSDK: function () {\n            return scriptLoader.loadCustom({url: appleSDKSrc})\n                .catch(function (e) {\n                    this.onError(e);\n                });\n        },\n\n        isCustomerLoggedIn: function () {\n            return customer.isLoggedIn();\n        },\n\n        initAppleSDK: function () {\n            if (!window.ApplePaySession) {\n                console.error('This device does not support Apple Pay');\n                return;\n            }\n\n            if (!ApplePaySession.canMakePayments()) {\n                console.error('This device is not capable of making Apple Pay payments');\n            }\n\n            this.applePayInstance = this.paypal.Applepay();\n            return this.applePayInstance.config()\n                .then(applePayConfig => {\n                    this.applePayConfig = applePayConfig;\n                    this.renderApplePayButton();\n                })\n                .catch(applepayConfigError => {\n                    console.error('Error while fetching Apple Pay configuration.');\n                });\n        },\n\n        onApplePayValidateMerchant: function (applePaySession) {\n            applePaySession.onvalidatemerchant = (event) => {\n                this.applePayInstance\n                    .validateMerchant({\n                        validationUrl: event.validationURL,\n                    })\n                    .then((payload) => {\n                        applePaySession.completeMerchantValidation(payload.merchantSession);\n                    })\n                    .catch((error) => {\n                        applePaySession.abort();\n                        this.isErrorDisplayed = false;\n                        this.catchError(error)\n                    });\n            };\n        },\n\n        onApplePayPaymentAuthorized: function (applePaySession, paypalOrderId = null) {\n            applePaySession.onpaymentauthorized = async (event) => {\n                try {\n                    await this.applePayInstance.confirmOrder({\n                        orderId: paypalOrderId !== null ? paypalOrderId : this.paypalOrderId,\n                        token: event.payment.token,\n                        billingContact: event.payment.billingContact,\n                        shippingContact: event.payment.shippingContact\n                    });\n\n                    applePaySession.completePayment({\n                        status: window.ApplePaySession.STATUS_SUCCESS,\n                    });\n\n                    await this.onApprove();\n                } catch (error) {\n                    applePaySession.completePayment({\n                        status: window.ApplePaySession.STATUS_FAILURE,\n                    });\n                    this.isErrorDisplayed = false;\n                    this.catchError(error)\n                }\n            };\n        },\n\n        onApplePayPaymentMethodSelected: function (applePaySession, total) {\n            applePaySession.onpaymentmethodselected = (event) => {\n                applePaySession.completePaymentMethodSelection({\n                    newTotal: total,\n                });\n            };\n        },\n\n        onApplePayShippingContactSelected: function (applePaySession, quoteId, total, isVirtual) {\n            applePaySession.onshippingcontactselected = (event) => {\n\n                const shippingMethods = [];\n\n                let estimateShippingMethodURL = (this.isCustomerLoggedIn())\n                    ? this.estimateShippingMethodsWhenLoggedInUrl\n                    : this.estimateShippingMethodsWhenGuestUrl.replace(':cartId', quoteId);\n\n                if (this.pageType === 'product') {\n                    // Product Page: we need to use guest cart quote because it is created outside the checkout process\n                    estimateShippingMethodURL = this.estimateShippingMethodsWhenGuestUrl.replace(':cartId', quoteId);\n                }\n\n                this.countryCode = event.shippingContact.countryCode;\n                this.regionCode = event.shippingContact.administrativeArea;\n                this.postalCode = event.shippingContact.postalCode;\n\n                this.getRegionIdByCode(this.regionCode, this.countryCode)\n                    .then((regionId) => {\n                        this.regionId = regionId;\n                    })\n                    .catch((error)=>  {\n                        // If the Apple region Code doesn't match to the one in Commerce\n                        // we set the regionId to null to still apply the taxes of the country\n                        // to continue with the checkout\n                        console.log(error);\n                        this.regionId = null;\n                    });\n\n                $.ajax({\n                    type: 'POST',\n                    url: estimateShippingMethodURL,\n                    headers: {\n                        'Content-Type': 'application/json',\n                    },\n                    data: JSON.stringify({\n                        address: {\n                            country_id: event.shippingContact.countryCode,\n                            postcode: event.shippingContact.postalCode,\n                            city: event.shippingContact.locality\n                        }\n                    })\n                }).then(estimateShippingMethods => {\n\n                    estimateShippingMethods.forEach(method => {\n                        shippingMethods.push({\n                            label: method.method_title,\n                            detail: method.carrier_title,\n                            amount: method.amount.toString(),\n                            identifier: method.carrier_code + '_' + method.method_code,\n                        });\n                    });\n\n                    applePaySession.completeShippingContactSelection({\n                        newShippingMethods: shippingMethods,\n                        newTotal: total,\n                    })\n\n                }, error => {\n                    this.isErrorDisplayed = false;\n                    applePaySession.abort();\n                    this.catchError(error);\n                });\n\n                if (isVirtual) {\n                    // If Quote is virtual, no need to select shipping\n                    // We can already create the order\n                    this.createOrder();\n                }\n            }\n        },\n\n        onApplePayShippingMethodSelectedInCartPage: function (applePaySession, quoteId) {\n            this.onApplePayShippingMethodSelected(applePaySession, quoteId, null,null);\n        },\n\n        onApplePayShippingMethodSelected: function (applePaySession, quoteId, quoteMaskedId, paypalOrderId) {\n           applePaySession.onshippingmethodselected = (event) => {\n\n                let shippingInformationURL = (this.isCustomerLoggedIn())\n                    ? this.shippingInformationWhenLoggedInUrl\n                    : this.shippingInformationWhenGuestUrl.replace(':quoteId', quoteId);\n\n                if (this.pageType === 'product') {\n                    // Product Page: we need to use quoteMaskedId as the quote is created outside the checkout process\n                    shippingInformationURL = this.shippingInformationWhenGuestUrl.replace(':quoteId', quoteMaskedId);\n                }\n\n                $.ajax({\n                    type: 'POST',\n                    url: shippingInformationURL,\n                    headers: {\n                        'Content-Type': 'application/json',\n                    },\n                    data: JSON.stringify({\n                        addressInformation: {\n                            shipping_address: {\"country_id\": this.countryCode, \"region_id\": this.regionId, \"postcode\": this.postalCode},\n                            shipping_method_code: event.shippingMethod.identifier.split('_')[1],\n                            shipping_carrier_code: event.shippingMethod.identifier.split('_')[0],\n                            extension_attributes: {}\n                        }\n                    })\n                }).then(result => {\n\n                    let items = [];\n\n                    result['totals']['items'].forEach(item => {\n                        items.push({\n                            label: item.name + ' ( x ' + item.qty + ' )',\n                            type: \"final\",\n                            amount: item.row_total\n                        });\n                    });\n\n                    items.push({\n                        label: \"Shipping\",\n                        type: \"final\",\n                        amount: result['totals']['shipping_amount'],\n                    });\n\n                    if (result['totals']['tax_amount'] !== 0) {\n                        items.push({\n                            label: \"Tax\",\n                            type: \"final\",\n                            amount: result['totals']['tax_amount'],\n                        });\n                    }\n\n                    applePaySession.completeShippingMethodSelection({\n                        newLineItems: items,\n                        newTotal: {\n                            label: \"Summary\",\n                            type: \"final\",\n                            amount: result['totals']['grand_total'],\n                        },\n                    });\n\n                    if (this.pageType === 'product') {\n                        // In the product page, the paypal order has been created on the onClick handler\n                        // so we just need to update the amount with the shipping selected\n                        this.updatePaypalOrder();\n                    } else {\n                        // In Cart and Minicart, we need to create the Paypal Order\n                        this.createOrder();\n                    }\n\n                }).catch(error => {\n                    applePaySession.abort();\n                    this.isErrorDisplayed = false;\n                    this.catchError(error);\n                });\n            };\n        },\n\n        updatePaypalOrder: function() {\n\n            // Update PayPal Order Amount as the shipping method has been selected and the price changed\n            // Without the update, the payment is failing as the order amount could be different\n            $.ajax({\n                type: 'POST',\n                url: this.updatePayPalOrderUrl,\n            }).catch(error => {\n                this.catchError(error);\n            });\n        },\n\n        onApplePayCancel: function (applePaySession, callback) {\n            applePaySession.oncancel = () => {\n                if (typeof callback === 'function') {\n                    callback();\n                }\n\n                this.showLoader(false);\n            }\n        },\n\n        getApplePaymentRequestLineItems: function (quote){\n            let items = [];\n\n            quote.getItems().forEach(item => {\n                items.push({\n                    label: item.name + ' ( x ' + item.qty + ' )',\n                    type: \"final\",\n                    amount: item.price * item.qty,\n                });\n            });\n\n            items.push({\n                label: $t(\"Shipping\"),\n                type: \"final\",\n                amount: quote.getTotals()()['shipping_amount'],\n            });\n\n            if (quote.getTotals()['tax_amount'] !== 0) {\n                items.push({\n                    label: $t(\"Tax\"),\n                    type: \"final\",\n                    amount: quote.getTotals()()['tax_amount'],\n                });\n            }\n\n            return items;\n        },\n\n        showPopup: function (paymentData, quote) {\n            const paymentRequest = {\n                countryCode: this.applePayConfig.countryCode,\n                merchantCapabilities: this.applePayConfig.merchantCapabilities,\n                supportedNetworks: this.applePayConfig.supportedNetworks,\n                currencyCode: paymentData.response['paypal-order']['currency_code'],\n                lineItems: this.getApplePaymentRequestLineItems(quote),\n                requiredBillingContactFields: [\"postalAddress\"],\n                shippingContact: {\n                    countryCode: quote.shippingAddress().countryId,\n                    postalCode: quote.shippingAddress().postcode,\n                    locality: quote.shippingAddress().city,\n                    administrativeArea: quote.shippingAddress().regionCode,\n                    familyName: quote.shippingAddress().lastname,\n                    givenName: quote.shippingAddress().firstname,\n                    addressLines: quote.shippingAddress().street,\n                },\n                total: {\n                    label: $t(\"Summary\"),\n                    type: \"final\",\n                    amount: Number(paymentData.response['paypal-order']['amount']).toString(),\n                }\n            };\n\n            // See https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession\n            this.applePaySession = new ApplePaySession(APPLE_PAY_VERSION_NUMBER, paymentRequest);\n            this.onApplePayValidateMerchant(this.applePaySession);\n            this.onApplePayPaymentAuthorized(this.applePaySession, paymentData.response['paypal-order']['id']);\n            this.onApplePayCancel(this.applePaySession);\n\n            this.applePaySession.begin();\n        },\n\n        onCancel: function () {\n            window.location = data.redirectUrl;\n            this.showLoader(false);\n        },\n\n        renderApplePayButton: function () {\n            if (this.applePayConfig.isEligible) {\n                const buttonStyle = this.mapButtonStyle();\n                const buttonType = this.mapButtonType();\n                const height = this.styles.height > 0\n                    ? this.styles.height + \"px\"\n                    : \"40px\";\n\n                document.getElementById(this.buttonContainerId).innerHTML = `\n                <apple-pay-button\n                    id=\"btn-appl\"\n                    buttonstyle=\"${buttonStyle}\"\n                    type=\"${buttonType}\"\n                    locale=\"${window.LOCALE}\"\n                    style=\" --apple-pay-button-width: 100%; --apple-pay-button-height: ${height}\"\n                >`;\n                document.getElementById(\"btn-appl\").addEventListener(\"click\", this.onClick);\n            }\n        },\n\n        mapButtonStyle: function () {\n            return this.styles.color === 'white' ? 'white' : 'black';\n        },\n\n        mapButtonType: function () {\n            switch (this.styles.label) {\n                case 'paypal':\n                case 'installment':\n                    return 'plain';\n                case 'checkout':\n                    return 'check-out';\n                case 'buynow':\n                    return 'buy';\n                default:\n                    return 'pay';\n            }\n        },\n\n        enableButton: function () {\n            $('#' + this.buttonContainerId).find('button').prop('disabled', false);\n        },\n\n        disableButton: function () {\n            $('#' + this.buttonContainerId).find('button').prop('disabled', true);\n        },\n\n        performAuthorization: function (paymentData) {},\n\n        onClick: function () {},\n\n        /**\n         * Calls before create order.\n         */\n        beforeCreateOrder: function () {},\n\n        /**\n         * Create order.\n         *\n         * @return {String}\n         */\n        createOrder: function () {\n            let data = {'paymentSource': this.paymentSource};\n\n            try {\n                this.beforeCreateOrder();\n                let orderData = performCreateOrder(this.createOrderUrl, data, null);\n                this.paypalOrderId = this.afterCreateOrder(orderData);\n                return this.paypalOrderId;\n            } catch (error) {\n                this.isErrorDisplayed = false;\n                this.catchError(error);\n\n                // Propagate the error to be caught in the promise chain\n                return Promise.reject(error);\n            }\n        },\n\n        /**\n         * After order created.\n         *\n         * @param {Object} data\n         * @return {String}\n         */\n        afterCreateOrder: function (data) {},\n\n        /**\n         * Catch error on order creation.\n         */\n        catchCreateOrder: function () {},\n\n        /**\n         * On payment approve.\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         * @return {Promise}\n         */\n        onApprove: function () {\n            const data = {orderID: this.paypalOrderId};\n\n            return this.beforeOnAuthorize()\n                .then(performOnAuthorize.bind(this, this.updateQuoteUrl, data))\n                .then(this.afterOnAuthorize)\n                .catch(this.onError);\n        },\n\n        beforeOnAuthorize: function () {\n            return Promise.resolve();\n        },\n\n        afterOnAuthorize: function () {\n            return Promise.resolve();\n        },\n\n        /**\n         * Calls when error happened on paypal side.\n         *\n         * @param {Error} error\n         */\n        onError: function (error) {\n            console.log('Error: ', error.message);\n        },\n\n        isEligible: function () {\n            return this.eligible;\n        },\n\n        /**\n         * Async Show/hide loader\n         *\n         * @param {Boolean} show\n         */\n        showLoaderAsync: function (show) {\n            return new Promise(function (resolve, reject) {\n                var event = show ? 'processStart' : 'processStop';\n                $('body').trigger(event);\n\n                // Set minimum time for loader to show\n                setTimeout(() => {\n                    resolve();\n                }, 10);\n            });\n        },\n\n        /**\n         * Show/hide loader.\n         *\n         * @param {Boolean} show\n         */\n        showLoader: function (show) {\n            var event = show ? 'processStart' : 'processStop';\n\n            $('body').trigger(event);\n        },\n\n        /**\n         *  Get region ID by region code and country code\n         *\n         * @param regionCode\n         * @param countryCode\n         * @returns {null}\n         */\n        getRegionIdByCode: function (regionCode, countryCode) {\n            return new Promise(function (resolve, reject) {\n                $.ajax({\n                    url: this.countriesUrl.replace(':countryCode', countryCode),\n                    method: 'GET',\n                    success: function (response) {\n                        if (response.available_regions && response.available_regions.length) {\n                            var matchedRegion = response.available_regions.find(function (region) {\n                                return region.code === regionCode;\n                            });\n\n                            if (matchedRegion) {\n                                resolve(matchedRegion.id);\n                            } else {\n                                reject('Region not found');\n                            }\n                        } else {\n                            reject('No regions available for country: ' + countryCode);\n                        }\n                    },\n                    error: function () {\n                        reject('Error fetching regions for country: ' + countryCode);\n                    }\n                });\n            }.bind(this));\n        },\n\n        /**\n         * Catch errors.\n         *\n         * @param {*} error\n         */\n        catchError: function (error) {\n            this.showLoader(false);\n\n            if (this.isErrorDisplayed) {\n                return;\n            }\n\n            if (error.hidden === undefined || !error.hidden) {\n                this.addMessage(this.requestProcessingError);\n            }\n\n            this.isErrorDisplayed = true;\n        },\n\n        /**\n         * Add message to customer data.\n         *\n         * @param {String} message\n         * @param {String} [type]\n         */\n        addMessage: function (message, type) {\n            type = type || 'error';\n\n            // Need to set a slight delay to avoid refresh from core\n            setTimeout(function () {\n                customerData.set('messages', {\n                    messages: [{\n                        text: message,\n                        type: type\n                    }]\n                });\n            }, 1000);\n        },\n\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/methods/google-pay.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'jquery',\n    'underscore',\n    'uiComponent',\n    'scriptLoader',\n    'Magento_PaymentServicesPaypal/js/lib/script-loader',\n    'mage/translate',\n    'mage/cookies'\n], function ($, _, Component, loadSdkScript, scriptLoader, $t) {\n    'use strict';\n\n    const HTTP_STATUS_CREATED = 201;\n\n    const googleSDKSrc = 'https://pay.google.com/gp/p/js/pay.js',\n        baseRequest = {\n            apiVersion: 2,\n            apiVersionMinor: 0,\n            callbackIntents: ['PAYMENT_AUTHORIZATION'],\n            emailRequired: true,\n            shippingAddressParameters: {phoneNumberRequired: true}\n        };\n\n    /**\n     * Create order request.\n     *\n     * @param {String} url\n     * @param {Object} payPalOrderData\n     * @param {FormData} orderData\n     * @return {Object}\n     */\n    var performCreateOrder = function (url, payPalOrderData, orderData) {\n            orderData = orderData || new FormData();\n            orderData.append('form_key', $.mage.cookies.get('form_key'));\n            orderData.append('payment_source', payPalOrderData['paymentSource']);\n\n            let xhr = new XMLHttpRequest();\n            xhr.open('POST', url, false);\n            xhr.send(orderData);\n\n            if (xhr.status !== HTTP_STATUS_CREATED) {\n                throw new Error('Request failed');\n            } else {\n                return JSON.parse(xhr.responseText);\n            }\n        },\n\n        /**\n         * Payment authorization request.\n         *\n         * @return {Promise<Object>}\n         */\n        performOnAuthorize = function (url, data) {\n            var orderData = new FormData();\n\n            orderData.append('form_key', $.mage.cookies.get('form_key'));\n            orderData.append('paypal_order_id', data.orderID);\n\n            return fetch(url, {\n                method: 'POST',\n                headers: {},\n                body: orderData,\n                credentials: 'same-origin'\n            }).then(function (response) {\n                return response.json();\n            });\n        };\n\n    return Component.extend({\n        defaults: {\n            sdkNamespace: 'paypal',\n            paypal: null,\n            paymentSource: 'googlepay',\n            createOrderUrl: '',\n            updateQuoteUrl: '',\n            instance: null,\n            scriptParams: {},\n            allowedPaymentMethods: null,\n            merchantInfo: null,\n            buttonContainerId: null,\n            paypalOrderId: null,\n            eligible: false,\n            mode: 'TEST',\n            shippingAddressRequired: true\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            _.bindAll(this, 'createOrder', 'onApprove', 'onError', 'initGoogleSDK', 'performAuthorization',\n                'onClick', 'beforeOnAuthorize', 'afterOnAuthorize', 'onCancel');\n            this._super();\n            this.sdkLoaded = Promise.all([this.loadPayPalSDK(), this.loadGoogleSDK()]);\n\n            return this;\n        },\n\n        loadPayPalSDK: function () {\n            return loadSdkScript(this.scriptParams, this.sdkNamespace)\n                .then(function (sdkScript) {\n                    this.paypal = sdkScript;\n                }.bind(this))\n                .catch(function (e) {\n                    this.onError(e);\n                });\n        },\n\n        loadGoogleSDK: function () {\n            return scriptLoader.loadCustom({url: googleSDKSrc})\n                .catch(function (e) {\n                    this.onError(e);\n                });\n        },\n\n        initGoogleSDK: function () {\n            return this.getGooglePayConfig()\n                .then(config =>\n                    this.getGooglePaymentsClient()\n                        .isReadyToPay(this.getGoogleIsReadyToPayRequest(config.allowedPaymentMethods))\n                        .then(function (response) {\n                            if (response.result) {\n                                this.renderGooglePayButton();\n                            }\n                        }.bind(this))\n                ).catch(function (e) {\n                    this.onError({\n                        hidden: true,\n                        error: e\n                    });\n                }.bind(this));\n        },\n\n        getGooglePaymentsClient: function () {\n            if (this.instance === null) {\n                this.instance = new google.payments.api.PaymentsClient({\n                    environment: this.mode,\n                     paymentDataCallbacks: {\n                        onPaymentAuthorized: this.performAuthorization\n                    }\n                });\n            }\n            return this.instance;\n        },\n\n        showPopup: function (paymentData) {\n            this.getGooglePaymentDataRequest(paymentData)\n                .then((data) => {\n                    this.getGooglePaymentsClient()\n                        .loadPaymentData(data)\n                        .catch(this.onCancel);\n                }).catch(this.onError);\n        },\n\n        onCancel: function () {\n            this.showLoader(false);\n        },\n\n        getGooglePaymentDataRequest: async function (transactionInfo) {\n            const paymentDataRequest = Object.assign({}, baseRequest),\n                { allowedPaymentMethods, merchantInfo } = await this.getGooglePayConfig();\n\n            paymentDataRequest.allowedPaymentMethods = allowedPaymentMethods;\n            paymentDataRequest.transactionInfo = transactionInfo;\n            paymentDataRequest.merchantInfo = merchantInfo;\n            paymentDataRequest.shippingAddressRequired = this.shippingAddressRequired;\n\n            return paymentDataRequest;\n        },\n\n        getGooglePayConfig: async function () {\n            if (this.allowedPaymentMethods === null || this.merchantInfo === null) {\n                const googlePayConfig = await this.paypal.Googlepay().config();\n\n                this.allowedPaymentMethods = googlePayConfig.allowedPaymentMethods;\n                this.merchantInfo = googlePayConfig.merchantInfo;\n            }\n\n            return {\n                allowedPaymentMethods: this.allowedPaymentMethods,\n                merchantInfo: this.merchantInfo\n            };\n        },\n\n        getGoogleIsReadyToPayRequest: function (allowedPaymentMethods) {\n            return Object.assign({}, baseRequest, {\n                allowedPaymentMethods: allowedPaymentMethods\n            });\n        },\n\n        renderGooglePayButton: function () {\n            const buttonContainer = $('#' + this.buttonContainerId);\n\n            let buttonProps = {\n                onClick: this.onClick,\n                buttonColor: this.styles.button_color,\n                buttonType: this.styles.button_type\n            };\n\n            buttonProps.buttonSizeMode = 'fill';\n\n            if (this.styles.button_custom_height) {\n                buttonContainer.height(this.styles.button_custom_height);\n            }\n\n            buttonContainer.append(\n                this.getGooglePaymentsClient().createButton(buttonProps)\n            );\n            this.eligible = true;\n        },\n\n        enableButton: function () {\n            $('#' + this.buttonContainerId).find('button').prop('disabled', false);\n        },\n\n        disableButton: function () {\n            $('#' + this.buttonContainerId).find('button').prop('disabled', true);\n        },\n\n        performAuthorization: function (paymentData) {\n            return new Promise(function (resolve) {\n                this.processPayment(paymentData)\n                    .then(resolve)\n                    .catch(function () {\n                        this.onError(new Error('couldn\\'t process payment'));\n                        resolve({ transactionState: 'ERROR' });\n                    }.bind(this));\n            }.bind(this));\n        },\n\n        processPayment: async function (paymentData) {\n            try {\n                const { status } = await this.paypal.Googlepay().confirmOrder({\n                    orderId: this.paypalOrderId,\n                    paymentMethodData: paymentData.paymentMethodData,\n                    shippingAddress: paymentData.shippingAddress,\n                    email: paymentData.email\n                });\n\n                if (status === 'APPROVED') {\n                    this.onApprove(paymentData);\n                    return { transactionState: 'SUCCESS' };\n                }\n\n                this.onError(new Error('couldn\\'t approve order'));\n                return { transactionState: 'ERROR' };\n            } catch (err) {\n                this.onError(err);\n                return {\n                    transactionState: 'ERROR',\n                    error: {\n                        message: err.message\n                    }\n                };\n            }\n        },\n\n        onClick: function () {},\n\n        /**\n         * Calls before create order.\n         */\n        beforeCreateOrder: function () {},\n\n        /**\n         * Create order.\n         *\n         * @return {String}\n         */\n        createOrder: function () {\n            let data = {'paymentSource': this.paymentSource};\n\n            try {\n                this.beforeCreateOrder();\n                let orderData = performCreateOrder(this.createOrderUrl, data, null);\n                this.paypalOrderId = this.afterCreateOrder(orderData);\n                return this.paypalOrderId;\n            } catch (error) {\n                return this.catchCreateOrder(error);\n            }\n        },\n\n        /**\n         * After order created.\n         *\n         * @param {Object} data\n         * @return {String}\n         */\n        afterCreateOrder: function (data) {\n            if (data.response['paypal-order'] && data.response['paypal-order']['mp_order_id']) {\n                this.paymentsOrderId = data.response['paypal-order']['mp_order_id'];\n                this.paypalOrderId = data.response['paypal-order'].id;\n\n                this.showPopup({\n                    displayItems: [],\n                    currencyCode: data.response['paypal-order']['currency_code'],\n                    totalPriceStatus: 'FINAL',\n                    totalPrice: Number(data.response['paypal-order']['amount']).toString(),\n                    totalPriceLabel: $t('Total')\n                });\n\n                return this.paypalOrderId;\n            }\n\n            throw new Error();\n        },\n\n        /**\n         * Catch error on order creation.\n         */\n        catchCreateOrder: function () {},\n\n        /**\n         * On payment approve.\n         *\n         * @param {Object} data\n         * @param {Object} actions\n         * @return {Promise}\n         */\n        onApprove: function () {\n            const data = {orderID: this.paypalOrderId};\n\n            return this.beforeOnAuthorize()\n                .then(performOnAuthorize.bind(this, this.updateQuoteUrl, data))\n                .then(this.afterOnAuthorize)\n                .catch(this.onError);\n        },\n\n        beforeOnAuthorize: function () {\n            return Promise.resolve();\n        },\n\n        afterOnAuthorize: function () {\n            return Promise.resolve();\n        },\n\n        /**\n         * Calls when error happened on paypal side.\n         *\n         * @param {Error} error\n         */\n        onError: function (error) {\n            console.log('Error: ', error.message);\n        },\n\n        isEligible: function () {\n            return this.eligible;\n        },\n\n        /**\n         * Async Show/hide loader\n         *\n         * @param {Boolean} show\n         */\n        showLoaderAsync: function (show) {\n            return new Promise(function (resolve, reject) {\n                var event = show ? 'processStart' : 'processStop';\n                $('body').trigger(event);\n\n                // Set minimum time for loader to show\n                setTimeout(() => {\n                    resolve();\n                }, 10);\n            });\n        },\n\n        /**\n         * Show/hide loader.\n         *\n         * @param {Boolean} show\n         */\n        showLoader: function (show) {\n            var event = show ? 'processStart' : 'processStop';\n\n            $('body').trigger(event);\n        },\n    });\n});\n","Magento_PaymentServicesPaypal/js/view/payment/actions/get-sdk-params.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'jquery',\n    'underscore',\n    'Magento_Customer/js/customer-data',\n    'jquery/jquery-storageapi'\n], function ($, _, customerData) {\n    'use strict';\n\n    var promise = null,\n        timeoutKey = 'payments-sdk-params-timeout',\n        paymentsKey = 'payments',\n        sdkParamsKey = 'sdkParams';\n\n    return function (cacheTtl) {\n        if (!promise) {\n            promise = new Promise(function (resolve, reject) {\n                var dateNow = Date.now(),\n                    dateTo = dateNow + cacheTtl,\n                    timeout = $.localStorage.get(timeoutKey);\n                if (timeout < dateNow || !timeout) {\n                    return customerData.reload([paymentsKey]).done(function () {\n                        $.localStorage.set(timeoutKey, dateTo);\n                        resolve(customerData.get(paymentsKey)()[sdkParamsKey]);\n                    }).fail(reject.bind(this, []));\n                }\n\n                if (!_.isEmpty(customerData.get(paymentsKey)())) {\n                    return resolve(customerData.get(paymentsKey)()[sdkParamsKey]);\n                }\n\n                customerData.get(paymentsKey).subscribe(function (payments) {\n                    resolve(payments[sdkParamsKey]);\n                });\n\n            });\n        }\n\n        return promise;\n    };\n});\n","Magento_PaymentServicesPaypal/js/model/payment-service-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine([\n    'underscore',\n    'mage/utils/wrapper'\n], function (_, wrapper) {\n    'use strict';\n\n    /**\n     * Free method filter\n     * @param {Object} paymentMethod\n     * @return {Boolean}\n     */\n    var paymentServicesMethods = [\n            'payment_services_paypal_smart_buttons',\n            'payment_services_paypal_apple_pay',\n            'payment_services_paypal_google_pay',\n            'payment_services_paypal_hosted_fields'\n        ],\n\n        /**\n         * Check if payment method is from payment services.\n         *\n         * @param {String} needleName\n         * @param {String} paymentMethod\n         * @returns {Boolean}\n         */\n        isPaymentServicesButtonsPaymentMethod = function (needleName, paymentMethod) {\n            return paymentMethod.method === needleName;\n        },\n\n        /**\n         * Check if Apple Pay method is available.\n         */\n        checkApplePayAvailability = function () {\n            window.checkoutConfig.payment['payment_services_paypal_apple_pay'].isVisible = !!(\n                window.checkoutConfig.payment['payment_services_paypal_apple_pay'].isVisible &&\n                window.ApplePaySession\n            );\n            !window.ApplePaySession && console.log('Apple Pay is not supported or not available');\n        },\n\n        extender = {\n            /**\n             * Filter hidden payment methods.\n             *\n             * @param {Function} originFn - Original method.\n             * @param {Array} methods\n             */\n            setPaymentMethods: function (originFn, methods) {\n                var paymentServicesButtonMethodIndex;\n\n                checkApplePayAvailability();\n\n                _.each(paymentServicesMethods, function (paymentMethod) {\n                    if (!window.checkoutConfig.payment[paymentMethod].isVisible) {\n                        paymentServicesButtonMethodIndex = _.findIndex(\n                            methods,\n                            isPaymentServicesButtonsPaymentMethod.bind(null, paymentMethod)\n                        );\n                        paymentServicesButtonMethodIndex >= 0 && methods.splice(paymentServicesButtonMethodIndex, 1);\n                    }\n                });\n\n                return originFn(methods);\n            }\n    };\n\n    return function (target) {\n        return wrapper.extend(target, extender);\n    };\n});\n","Magento_PaymentServicesPaypal/js/lib/script-loader-wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\ndefine(['underscore', 'Magento_PaymentServicesPaypal/js/lib/script-loader'], function (_, scriptLoader) {\n    'use strict';\n\n    var promises = {},\n        defaultNamespace = 'paypal';\n\n    /**\n     * Parse src query string and move all params to object\n     *\n     * @param {Object} params\n     * @return {Object}\n     */\n    function processParamsSrc(params) {\n        var processedParams = _.clone(params),\n            url = new URL(params.src),\n            queryString = url.search.substring(1),\n            urlParams = JSON.parse('{\"' +\n                decodeURI(queryString).replace(/\"/g, '\\\\\"').replace(/&/g, '\",\"').replace(/=/g, '\":\"') +\n                '\"}');\n\n        _.extend(processedParams, urlParams);\n        delete processedParams.src;\n\n        return processedParams;\n    }\n\n    /**\n     * Convert params to object key => value format\n     *\n     * @param {Object} params\n     * @return {Object}\n     */\n    function convertToParamsObject(params) {\n        var processedParams = {};\n\n        _.each(params, function (param) {\n            processedParams[param.name] = param.value;\n        });\n\n        return processedParams;\n    }\n\n    /**\n     * Load PayPal sdk with params.\n     *\n     * @param {Array} params\n     * @param {String} sdkNamespace\n     * @return {Promise}\n     */\n    return function (params, sdkNamespace) {\n        var src;\n\n        if (!params || !params.length) {\n            return Promise.reject();\n        }\n\n        params = convertToParamsObject(params);\n        params['data-namespace'] = sdkNamespace || defaultNamespace;\n\n        if (!params || !params.src) {\n            return Promise.reject();\n        }\n\n        src = params.src;\n\n        if (!promises[src]) {\n            params = processParamsSrc(params);\n\n            promises[src] = scriptLoader.load(params);\n        }\n\n        return promises[src];\n    };\n});\n","Magento_PaymentServicesPaypal/js/lib/script-loader.js":"/*eslint-disable */\n/* jscs:disable */\n/*!\n * paypal-js v3.1.1 (2021-03-14T21:08:07.006Z)\n * Copyright 2020-present, PayPal, Inc. 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 * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nvar paypalLoadScript = (function (exports) {\n    'use strict';\n\n    function findScript(url, attributes) {\n        var currentScript = document.querySelector(\"script[src=\\\"\".concat(url, \"\\\"]\"));\n        if (currentScript === null) return null;\n        var nextScript = createScriptElement(url, attributes); // check if the new script has the same number of data attributes\n\n        if (Object.keys(currentScript.dataset).length !== Object.keys(nextScript.dataset).length) {\n            return null;\n        }\n\n        var isExactMatch = true; // check if the data attribute values are the same\n\n        Object.keys(currentScript.dataset).forEach(function (key) {\n            if (currentScript.dataset[key] !== nextScript.dataset[key]) {\n                isExactMatch = false;\n            }\n        });\n        return isExactMatch ? currentScript : null;\n    }\n    function insertScriptElement(_ref) {\n        var url = _ref.url,\n            attributes = _ref.attributes,\n            onSuccess = _ref.onSuccess,\n            onError = _ref.onError;\n        var newScript = createScriptElement(url, attributes);\n        newScript.onerror = onError;\n        newScript.onload = onSuccess;\n        document.head.insertBefore(newScript, document.head.firstElementChild);\n    }\n    function processOptions(options) {\n        var sdkBaseURL = \"https://www.paypal.com/sdk/js\";\n\n        if (options.sdkBaseURL) {\n            sdkBaseURL = options.sdkBaseURL;\n            delete options.sdkBaseURL;\n        }\n\n        var processedMerchantIDAttributes = processMerchantID(options[\"merchant-id\"], options[\"data-merchant-id\"]);\n        var newOptions = Object.assign(options, processedMerchantIDAttributes);\n\n        var _Object$keys$filter$r = Object.keys(newOptions).filter(function (key) {\n                return typeof newOptions[key] !== \"undefined\" && newOptions[key] !== null && newOptions[key] !== \"\";\n            }).reduce(function (accumulator, key) {\n                var value = newOptions[key].toString();\n\n                if (key.substring(0, 5) === \"data-\") {\n                    accumulator.dataAttributes[key] = value;\n                } else {\n                    accumulator.queryParams[key] = value;\n                }\n\n                return accumulator;\n            }, {\n                queryParams: {},\n                dataAttributes: {}\n            }),\n            queryParams = _Object$keys$filter$r.queryParams,\n            dataAttributes = _Object$keys$filter$r.dataAttributes;\n\n        return {\n            url: \"\".concat(sdkBaseURL, \"?\").concat(objectToQueryString(queryParams)),\n            dataAttributes: dataAttributes\n        };\n    }\n    function objectToQueryString(params) {\n        var queryString = \"\";\n        Object.keys(params).forEach(function (key) {\n            if (queryString.length !== 0) queryString += \"&\";\n            queryString += key + \"=\" + params[key];\n        });\n        return queryString;\n    }\n\n    function createScriptElement(url) {\n        var attributes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n        var newScript = document.createElement(\"script\");\n        newScript.src = url;\n        Object.keys(attributes).forEach(function (key) {\n            newScript.setAttribute(key, attributes[key]);\n\n            if (key === \"data-csp-nonce\") {\n                newScript.setAttribute(\"nonce\", attributes[\"data-csp-nonce\"]);\n            }\n        });\n        return newScript;\n    }\n\n    function processMerchantID(merchantID, dataMerchantID) {\n        var newMerchantID = \"\";\n        var newDataMerchantID = \"\";\n\n        if (Array.isArray(merchantID)) {\n            if (merchantID.length > 1) {\n                newMerchantID = \"*\";\n                newDataMerchantID = merchantID.toString();\n            } else {\n                newMerchantID = merchantID.toString();\n            }\n        } else if (typeof merchantID === \"string\" && merchantID.length > 0) {\n            newMerchantID = merchantID;\n        } else if (typeof dataMerchantID === \"string\" && dataMerchantID.length > 0) {\n            newMerchantID = \"*\";\n            newDataMerchantID = dataMerchantID;\n        }\n\n        return {\n            \"merchant-id\": newMerchantID,\n            \"data-merchant-id\": newDataMerchantID\n        };\n    }\n\n    /**\n     * Load the Paypal JS SDK script asynchronously.\n     *\n     * @param {Object} options - used to configure query parameters and data attributes for the JS SDK.\n     * @param {PromiseConstructor} [PromisePonyfill=window.Promise] - optional Promise Constructor ponyfill.\n     * @return {Promise<Object>} paypalObject - reference to the global window PayPal object.\n     */\n\n    function loadScript(options) {\n        var PromisePonyfill = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getDefaultPromiseImplementation();\n        validateArguments(options, PromisePonyfill); // resolve with null when running in Node\n\n        if (typeof window === \"undefined\") return PromisePonyfill.resolve(null);\n\n        var _processOptions = processOptions(options),\n            url = _processOptions.url,\n            dataAttributes = _processOptions.dataAttributes;\n\n        var namespace = dataAttributes[\"data-namespace\"] || \"paypal\";\n        var existingWindowNamespace = getPayPalWindowNamespace(namespace); // resolve with the existing global paypal namespace when a script with the same params already exists\n\n        if (findScript(url, dataAttributes) && existingWindowNamespace) {\n            return PromisePonyfill.resolve(existingWindowNamespace);\n        }\n\n        return loadCustomScript({\n            url: url,\n            attributes: dataAttributes\n        }, PromisePonyfill).then(function () {\n            var newWindowNamespace = getPayPalWindowNamespace(namespace);\n\n            if (newWindowNamespace) {\n                return newWindowNamespace;\n            }\n\n            throw new Error(\"The window.\".concat(namespace, \" global variable is not available.\"));\n        });\n    }\n    /**\n     * Load a custom script asynchronously.\n     *\n     * @param {Object} options - used to set the script url and attributes.\n     * @param {PromiseConstructor} [PromisePonyfill=window.Promise] - optional Promise Constructor ponyfill.\n     * @return {Promise<void>} returns a promise to indicate if the script was successfully loaded.\n     */\n\n    function loadCustomScript(options) {\n        var PromisePonyfill = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getDefaultPromiseImplementation();\n        validateArguments(options, PromisePonyfill);\n        var url = options.url,\n            attributes = options.attributes;\n\n        if (typeof url !== \"string\" || url.length === 0) {\n            throw new Error(\"Invalid url.\");\n        }\n\n        if (typeof attributes !== \"undefined\" && typeof attributes !== \"object\") {\n            throw new Error(\"Expected attributes to be an object.\");\n        }\n\n        return new PromisePonyfill(function (resolve, reject) {\n            // resolve with undefined when running in Node\n            if (typeof window === \"undefined\") return resolve();\n            insertScriptElement({\n                url: url,\n                attributes: attributes,\n                onSuccess: function onSuccess() {\n                    return resolve();\n                },\n                onError: function onError() {\n                    return reject(new Error(\"The script \\\"\".concat(url, \"\\\" failed to load.\")));\n                }\n            });\n        });\n    }\n\n    function getDefaultPromiseImplementation() {\n        if (typeof Promise === \"undefined\") {\n            throw new Error(\"Promise is undefined. To resolve the issue, use a Promise polyfill.\");\n        }\n\n        return Promise;\n    }\n\n    function getPayPalWindowNamespace(namespace) {\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        return window[namespace];\n    }\n\n    function validateArguments(options, PromisePonyfill) {\n        if (typeof options !== \"object\" || options === null) {\n            throw new Error(\"Expected an options object.\");\n        }\n\n        if (typeof PromisePonyfill !== \"undefined\" && typeof PromisePonyfill !== \"function\") {\n            throw new Error(\"Expected PromisePonyfill to be a function.\");\n        }\n    }\n\n    var version = \"3.1.1\";\n\n    exports.loadCustomScript = loadCustomScript;\n    exports.loadScript = loadScript;\n    exports.version = version;\n\n    Object.defineProperty(exports, '__esModule', { value: true });\n\n    return exports;\n\n}({}));\nwindow.paypalLoadCustomScript = paypalLoadScript.loadCustomScript;\nwindow.paypalLoadScript = paypalLoadScript.loadScript;\n","Magento_PaymentServicesPaypal/js/lib/script-loader.min.js":"/*!\n * paypal-js v3.1.1 (2021-03-14T21:08:07.006Z)\n * Copyright 2020-present, PayPal, Inc. 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 * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nvar paypalLoadScript=function(t){\"use strict\";function e(t,e){var r=document.querySelector('script[src=\"'.concat(t,'\"]'));if(null===r)return null;var n=a(t,e);if(Object.keys(r.dataset).length!==Object.keys(n.dataset).length)return null;var o=!0;return Object.keys(r.dataset).forEach((function(t){r.dataset[t]!==n.dataset[t]&&(o=!1)})),o?r:null}function r(t){var e=t.url,r=t.attributes,n=t.onSuccess,o=t.onError,i=a(e,r);i.onerror=o,i.onload=n,document.head.insertBefore(i,document.head.firstElementChild)}function n(t){var e=\"https://www.paypal.com/sdk/js\";t.sdkBaseURL&&(e=t.sdkBaseURL,delete t.sdkBaseURL);var r=function(t,e){var r=\"\",n=\"\";Array.isArray(t)?t.length>1?(r=\"*\",n=t.toString()):r=t.toString():\"string\"==typeof t&&t.length>0?r=t:\"string\"==typeof e&&e.length>0&&(r=\"*\",n=e);return{\"merchant-id\":r,\"data-merchant-id\":n}}(t[\"merchant-id\"],t[\"data-merchant-id\"]),n=Object.assign(t,r),a=Object.keys(n).filter((function(t){return void 0!==n[t]&&null!==n[t]&&\"\"!==n[t]})).reduce((function(t,e){var r=n[e].toString();return\"data-\"===e.substring(0,5)?t.dataAttributes[e]=r:t.queryParams[e]=r,t}),{queryParams:{},dataAttributes:{}}),i=a.queryParams,u=a.dataAttributes;return{url:\"\".concat(e,\"?\").concat(o(i)),dataAttributes:u}}function o(t){var e=\"\";return Object.keys(t).forEach((function(r){0!==e.length&&(e+=\"&\"),e+=r+\"=\"+t[r]})),e}function a(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=document.createElement(\"script\");return r.src=t,Object.keys(e).forEach((function(t){r.setAttribute(t,e[t]),\"data-csp-nonce\"===t&&r.setAttribute(\"nonce\",e[\"data-csp-nonce\"])})),r}function i(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:u();s(t,e);var n=t.url,o=t.attributes;if(\"string\"!=typeof n||0===n.length)throw new Error(\"Invalid url.\");if(void 0!==o&&\"object\"!=typeof o)throw new Error(\"Expected attributes to be an object.\");return new e((function(t,e){if(\"undefined\"==typeof window)return t();r({url:n,attributes:o,onSuccess:function(){return t()},onError:function(){return e(new Error('The script \"'.concat(n,'\" failed to load.')))}})}))}function u(){if(\"undefined\"==typeof Promise)throw new Error(\"Promise is undefined. To resolve the issue, use a Promise polyfill.\");return Promise}function c(t){return window[t]}function s(t,e){if(\"object\"!=typeof t||null===t)throw new Error(\"Expected an options object.\");if(void 0!==e&&\"function\"!=typeof e)throw new Error(\"Expected PromisePonyfill to be a function.\")}return t.loadCustomScript=i,t.loadScript=function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:u();if(s(t,r),\"undefined\"==typeof window)return r.resolve(null);var o=n(t),a=o.url,d=o.dataAttributes,l=d[\"data-namespace\"]||\"paypal\",f=c(l);return e(a,d)&&f?r.resolve(f):i({url:a,attributes:d},r).then((function(){var t=c(l);if(t)return t;throw new Error(\"The window.\".concat(l,\" global variable is not available.\"))}))},t.version=\"3.1.1\",Object.defineProperty(t,\"__esModule\",{value:!0}),t}({});window.paypalLoadCustomScript=paypalLoadScript.loadCustomScript,window.paypalLoadScript=paypalLoadScript.loadScript;\n","Magento_Payment/js/transparent.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'jquery',\n    'mage/template',\n    'Magento_Ui/js/modal/alert',\n    'jquery-ui-modules/widget',\n    'Magento_Payment/js/model/credit-card-validation/validator',\n    'Magento_Checkout/js/model/full-screen-loader'\n], function ($, mageTemplate, alert, ui, validator, fullScreenLoader) {\n    'use strict';\n\n    $.widget('mage.transparent', {\n        options: {\n            context: null,\n            placeOrderSelector: '[data-role=\"review-save\"]',\n            paymentFormSelector: '#co-payment-form',\n            updateSelectorPrefix: '#checkout-',\n            updateSelectorSuffix: '-load',\n            hiddenFormTmpl:\n                '<form target=\"<%= data.target %>\" action=\"<%= data.action %>\" method=\"POST\" ' +\n                'hidden enctype=\"application/x-www-form-urlencoded\" class=\"no-display\">' +\n                    '<% _.each(data.inputs, function(val, key){ %>' +\n                    '<input value=\"<%= val %>\" name=\"<%= key %>\" type=\"hidden\">' +\n                    '<% }); %>' +\n                '</form>',\n            reviewAgreementForm: '#checkout-agreements',\n            cgiUrl: null,\n            orderSaveUrl: null,\n            controller: null,\n            gateway: null,\n            dateDelim: null,\n            cardFieldsMap: null,\n            expireYearLength: 2\n        },\n\n        /**\n         * {Function}\n         * @private\n         */\n        _create: function () {\n            this.hiddenFormTmpl = mageTemplate(this.options.hiddenFormTmpl);\n\n            if (this.options.context) {\n                this.options.context.setPlaceOrderHandler($.proxy(this._orderSave, this));\n                this.options.context.setValidateHandler($.proxy(this._validateHandler, this));\n            } else {\n                $(this.options.placeOrderSelector)\n                    .off('click')\n                    .on('click', $.proxy(this._placeOrderHandler, this));\n            }\n\n            this.element.validation();\n            $('[data-container=\"' + this.options.gateway + '-cc-number\"]').on('focusout', function () {\n                $(this).valid();\n            });\n        },\n\n        /**\n         * handler for credit card validation\n         * @return {Boolean}\n         * @private\n         */\n        _validateHandler: function () {\n            return this.element.validation && this.element.validation('isValid');\n        },\n\n        /**\n         * handler for Place Order button to call gateway for credit card validation\n         * @return {Boolean}\n         * @private\n         */\n        _placeOrderHandler: function () {\n            if (this._validateHandler()) {\n                this._orderSave();\n            }\n\n            return false;\n        },\n\n        /**\n         * Save order and generate post data for gateway call\n         * @private\n         */\n        _orderSave: function () {\n            var postData = $(this.options.paymentFormSelector).serialize();\n\n            if ($(this.options.reviewAgreementForm).length) {\n                postData += '&' + $(this.options.reviewAgreementForm).serialize();\n            }\n            postData += '&controller=' + this.options.controller;\n            postData += '&cc_type=' + this.element.find(\n                '[data-container=\"' + this.options.gateway + '-cc-type\"]'\n            ).val();\n\n            return $.ajax({\n                url: this.options.orderSaveUrl,\n                type: 'post',\n                context: this,\n                data: postData,\n                dataType: 'json',\n\n                /**\n                 * {Function}\n                 */\n                beforeSend: function () {\n                    fullScreenLoader.startLoader();\n                },\n\n                /**\n                 * {Function}\n                 */\n                success: function (response) {\n                    var preparedData,\n                        msg,\n\n                        /**\n                         * {Function}\n                         */\n                        alertActionHandler = function () {\n                            // default action\n                        };\n\n                    if (response.success && response[this.options.gateway]) {\n                        preparedData = this._preparePaymentData(\n                            response[this.options.gateway].fields,\n                            this.options.cardFieldsMap\n                        );\n                        this._postPaymentToGateway(preparedData);\n                    } else {\n                        fullScreenLoader.stopLoader(true);\n\n                        msg = response['error_messages'];\n\n                        if (this.options.context) {\n                            this.options.context.clearTimeout().fail();\n                            alertActionHandler = this.options.context.alertActionHandler;\n                        }\n\n                        if (typeof msg === 'object') {\n                            msg = msg.join('\\n');\n                        }\n\n                        if (msg) {\n                            alert(\n                                {\n                                    content: msg,\n                                    actions: {\n\n                                        /**\n                                         * {Function}\n                                         */\n                                        always: alertActionHandler\n                                    }\n                                }\n                            );\n                        }\n                    }\n                }.bind(this)\n            });\n        },\n\n        /**\n         * Post data to gateway for credit card validation\n         * @param {Object} data\n         * @private\n         */\n        _postPaymentToGateway: function (data) {\n            var tmpl,\n                iframeSelector = '[data-container=\"' + this.options.gateway + '-transparent-iframe\"]';\n\n            tmpl = this.hiddenFormTmpl({\n                data: {\n                    target: $(iframeSelector).attr('name'),\n                    action: this.options.cgiUrl,\n                    inputs: data\n                }\n            });\n            $(tmpl).appendTo($(iframeSelector)).trigger('submit');\n        },\n\n        /**\n         * Add credit card fields to post data for gateway\n         * @param {Object} data\n         * @param {Object} ccfields\n         * @private\n         */\n        _preparePaymentData: function (data, ccfields) {\n            var preparedata;\n\n            if (this.element.find('[data-container=\"' + this.options.gateway + '-cc-cvv\"]').length) {\n                data[ccfields.cccvv] = this.element.find(\n                    '[data-container=\"' + this.options.gateway + '-cc-cvv\"]'\n                ).val();\n            }\n            preparedata = this._prepareExpDate();\n            data[ccfields.ccexpdate] = preparedata.month + this.options.dateDelim + preparedata.year;\n            data[ccfields.ccnum] = this.element.find(\n                '[data-container=\"' + this.options.gateway + '-cc-number\"]'\n            ).val();\n\n            return data;\n        },\n\n        /**\n         * Grab Month and Year into one\n         * @returns {Object}\n         * @private\n         */\n        _prepareExpDate: function () {\n            var year = this.element.find('[data-container=\"' + this.options.gateway + '-cc-year\"]').val(),\n                month = parseInt(\n                    this.element.find('[data-container=\"' + this.options.gateway + '-cc-month\"]').val(),\n                    10\n                );\n\n            if (year.length > this.options.expireYearLength) {\n                year = year.substring(year.length - this.options.expireYearLength);\n            }\n\n            if (month < 10) {\n                month = '0' + month;\n            }\n\n            return {\n                month: month, year: year\n            };\n        }\n    });\n\n    return $.mage.transparent;\n});\n","Magento_Payment/js/cc-type.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.creditCardType', {\n        options: {\n            typeCodes: ['SS', 'SM', 'SO'] // Type codes for Switch/Maestro/Solo credit cards.\n        },\n\n        /**\n         * Bind change handler to select element and trigger the event to show/hide\n         * the Switch/Maestro or Solo credit card type container for those credit card types.\n         * @private\n         */\n        _create: function () {\n            this.element.on('change', $.proxy(this._toggleCardType, this)).trigger('change');\n        },\n\n        /**\n         * Toggle the Switch/Maestro and Solo credit card type container depending on which\n         * credit card type is selected.\n         * @private\n         */\n        _toggleCardType: function () {\n            $(this.options.creditCardTypeContainer)\n                .toggle($.inArray(this.element.val(), this.options.typeCodes) !== -1);\n        }\n    });\n\n    return $.mage.creditCardType;\n});\n","Magento_Payment/js/view/payment/cc-form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'underscore',\n    'Magento_Checkout/js/view/payment/default',\n    'Magento_Payment/js/model/credit-card-validation/credit-card-data',\n    'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator',\n    'mage/translate'\n], function (_, Component, creditCardData, cardNumberValidator, $t) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            creditCardType: '',\n            creditCardExpYear: '',\n            creditCardExpMonth: '',\n            creditCardNumber: '',\n            creditCardSsStartMonth: '',\n            creditCardSsStartYear: '',\n            creditCardSsIssue: '',\n            creditCardVerificationNumber: '',\n            selectedCardType: null\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super()\n                .observe([\n                    'creditCardType',\n                    'creditCardExpYear',\n                    'creditCardExpMonth',\n                    'creditCardNumber',\n                    'creditCardVerificationNumber',\n                    'creditCardSsStartMonth',\n                    'creditCardSsStartYear',\n                    'creditCardSsIssue',\n                    'selectedCardType'\n                ]);\n\n            return this;\n        },\n\n        /**\n         * Init component\n         */\n        initialize: function () {\n            var self = this;\n\n            this._super();\n\n            //Set credit card number to credit card data object\n            this.creditCardNumber.subscribe(function (value) {\n                var result;\n\n                self.selectedCardType(null);\n\n                if (value === '' || value === null) {\n                    return false;\n                }\n                result = cardNumberValidator(value);\n\n                if (!result.isPotentiallyValid && !result.isValid) {\n                    return false;\n                }\n\n                if (result.card !== null) {\n                    self.selectedCardType(result.card.type);\n                    creditCardData.creditCard = result.card;\n                }\n\n                if (result.isValid) {\n                    creditCardData.creditCardNumber = value;\n                    self.creditCardType(result.card.type);\n                }\n            });\n\n            //Set expiration year to credit card data object\n            this.creditCardExpYear.subscribe(function (value) {\n                creditCardData.expirationYear = value;\n            });\n\n            //Set expiration month to credit card data object\n            this.creditCardExpMonth.subscribe(function (value) {\n                creditCardData.expirationMonth = value;\n            });\n\n            //Set cvv code to credit card data object\n            this.creditCardVerificationNumber.subscribe(function (value) {\n                creditCardData.cvvCode = value;\n            });\n        },\n\n        /**\n         * Get code\n         * @returns {String}\n         */\n        getCode: function () {\n            return 'cc';\n        },\n\n        /**\n         * Get data\n         * @returns {Object}\n         */\n        getData: function () {\n            return {\n                'method': this.item.method,\n                'additional_data': {\n                    'cc_cid': this.creditCardVerificationNumber(),\n                    'cc_ss_start_month': this.creditCardSsStartMonth(),\n                    'cc_ss_start_year': this.creditCardSsStartYear(),\n                    'cc_ss_issue': this.creditCardSsIssue(),\n                    'cc_type': this.creditCardType(),\n                    'cc_exp_year': this.creditCardExpYear(),\n                    'cc_exp_month': this.creditCardExpMonth(),\n                    'cc_number': this.creditCardNumber()\n                }\n            };\n        },\n\n        /**\n         * Get list of available credit card types\n         * @returns {Object}\n         */\n        getCcAvailableTypes: function () {\n            return window.checkoutConfig.payment.ccform.availableTypes[this.getCode()];\n        },\n\n        /**\n         * Get payment icons\n         * @param {String} type\n         * @returns {Boolean}\n         */\n        getIcons: function (type) {\n            return window.checkoutConfig.payment.ccform.icons.hasOwnProperty(type) ?\n                window.checkoutConfig.payment.ccform.icons[type]\n                : false;\n        },\n\n        /**\n         * Get list of months\n         * @returns {Object}\n         */\n        getCcMonths: function () {\n            return window.checkoutConfig.payment.ccform.months[this.getCode()];\n        },\n\n        /**\n         * Get list of years\n         * @returns {Object}\n         */\n        getCcYears: function () {\n            return window.checkoutConfig.payment.ccform.years[this.getCode()];\n        },\n\n        /**\n         * Check if current payment has verification\n         * @returns {Boolean}\n         */\n        hasVerification: function () {\n            return window.checkoutConfig.payment.ccform.hasVerification[this.getCode()];\n        },\n\n        /**\n         * @deprecated\n         * @returns {Boolean}\n         */\n        hasSsCardType: function () {\n            return window.checkoutConfig.payment.ccform.hasSsCardType[this.getCode()];\n        },\n\n        /**\n         * Get image url for CVV\n         * @returns {String}\n         */\n        getCvvImageUrl: function () {\n            return window.checkoutConfig.payment.ccform.cvvImageUrl[this.getCode()];\n        },\n\n        /**\n         * Get image for CVV\n         * @returns {String}\n         */\n        getCvvImageHtml: function () {\n            return '<img src=\"' + this.getCvvImageUrl() +\n                '\" alt=\"' + $t('Card Verification Number Visual Reference') +\n                '\" title=\"' + $t('Card Verification Number Visual Reference') +\n                '\" />';\n        },\n\n        /**\n         * Get unsanitized html for image for CVV\n         * @returns {String}\n         */\n        getCvvImageUnsanitizedHtml: function () {\n            return this.getCvvImageHtml();\n        },\n\n        /**\n         * @deprecated\n         * @returns {Object}\n         */\n        getSsStartYears: function () {\n            return window.checkoutConfig.payment.ccform.ssStartYears[this.getCode()];\n        },\n\n        /**\n         * Get list of available credit card types values\n         * @returns {Object}\n         */\n        getCcAvailableTypesValues: function () {\n            return _.map(this.getCcAvailableTypes(), function (value, key) {\n                return {\n                    'value': key,\n                    'type': value\n                };\n            });\n        },\n\n        /**\n         * Get list of available month values\n         * @returns {Object}\n         */\n        getCcMonthsValues: function () {\n            return _.map(this.getCcMonths(), function (value, key) {\n                return {\n                    'value': key,\n                    'month': value\n                };\n            });\n        },\n\n        /**\n         * Get list of available year values\n         * @returns {Object}\n         */\n        getCcYearsValues: function () {\n            return _.map(this.getCcYears(), function (value, key) {\n                return {\n                    'value': key,\n                    'year': value\n                };\n            });\n        },\n\n        /**\n         * @deprecated\n         * @returns {Object}\n         */\n        getSsStartYearsValues: function () {\n            return _.map(this.getSsStartYears(), function (value, key) {\n                return {\n                    'value': key,\n                    'year': value\n                };\n            });\n        },\n\n        /**\n         * Is legend available to display\n         * @returns {Boolean}\n         */\n        isShowLegend: function () {\n            return false;\n        },\n\n        /**\n         * Get available credit card type by code\n         * @param {String} code\n         * @returns {String}\n         */\n        getCcTypeTitleByCode: function (code) {\n            var title = '',\n                keyValue = 'value',\n                keyType = 'type';\n\n            _.each(this.getCcAvailableTypesValues(), function (value) {\n                if (value[keyValue] === code) {\n                    title = value[keyType];\n                }\n            });\n\n            return title;\n        },\n\n        /**\n         * Prepare credit card number to output\n         * @param {String} number\n         * @returns {String}\n         */\n        formatDisplayCcNumber: function (number) {\n            return 'xxxx-' + number.substr(-4);\n        },\n\n        /**\n         * Get credit card details\n         * @returns {Array}\n         */\n        getInfo: function () {\n            return [\n                {\n                    'name': 'Credit Card Type', value: this.getCcTypeTitleByCode(this.creditCardType())\n                },\n                {\n                    'name': 'Credit Card Number', value: this.formatDisplayCcNumber(this.creditCardNumber())\n                }\n            ];\n        }\n    });\n});\n","Magento_Payment/js/view/payment/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: 'free',\n            component: 'Magento_Payment/js/view/payment/method-renderer/free-method'\n        }\n    );\n\n    /** Add view logic here if needed */\n    return Component.extend({});\n});\n","Magento_Payment/js/view/payment/iframe.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'jquery',\n    'Magento_Payment/js/view/payment/cc-form',\n    'Magento_Ui/js/model/messageList',\n    'mage/translate',\n    'Magento_Checkout/js/model/full-screen-loader',\n    'Magento_Checkout/js/action/set-payment-information',\n    'Magento_Checkout/js/model/payment/additional-validators',\n    'Magento_Ui/js/modal/alert'\n], function (\n    $,\n    Component,\n    messageList,\n    $t,\n    fullScreenLoader,\n    setPaymentInformationAction,\n    additionalValidators,\n    alert\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Payment/payment/iframe',\n            timeoutId: null,\n            timeoutMessage: 'Sorry, but something went wrong.'\n        },\n\n        /**\n         * @returns {String}\n         */\n        getSource: function () {\n            return window.checkoutConfig.payment.iframe.source[this.getCode()];\n        },\n\n        /**\n         * @returns {String}\n         */\n        getControllerName: function () {\n            return window.checkoutConfig.payment.iframe.controllerName[this.getCode()];\n        },\n\n        /**\n         * @returns {String}\n         */\n        getPlaceOrderUrl: function () {\n            return window.checkoutConfig.payment.iframe.placeOrderUrl[this.getCode()];\n        },\n\n        /**\n         * @returns {String}\n         */\n        getCgiUrl: function () {\n            return window.checkoutConfig.payment.iframe.cgiUrl[this.getCode()];\n        },\n\n        /**\n         * @returns {String}\n         */\n        getSaveOrderUrl: function () {\n            return window.checkoutConfig.payment.iframe.saveOrderUrl[this.getCode()];\n        },\n\n        /**\n         * @returns {String}\n         */\n        getDateDelim: function () {\n            return window.checkoutConfig.payment.iframe.dateDelim[this.getCode()];\n        },\n\n        /**\n         * @returns {String}\n         */\n        getCardFieldsMap: function () {\n            return window.checkoutConfig.payment.iframe.cardFieldsMap[this.getCode()];\n        },\n\n        /**\n         * @returns {String}\n         */\n        getExpireYearLength: function () {\n            return window.checkoutConfig.payment.iframe.expireYearLength[this.getCode()];\n        },\n\n        /**\n         * @param {Object} parent\n         * @returns {Function}\n         */\n        originalPlaceOrder: function (parent) {\n            return parent.placeOrder.bind(parent);\n        },\n\n        /**\n         * @returns {Number}\n         */\n        getTimeoutTime: function () {\n            return window.checkoutConfig.payment.iframe.timeoutTime[this.getCode()];\n        },\n\n        /**\n         * @returns {String}\n         */\n        getTimeoutMessage: function () {\n            return $t(this.timeoutMessage);\n        },\n\n        /**\n         * @override\n         */\n        placeOrder: function () {\n            var self = this;\n\n            if (this.validateHandler() &&\n                additionalValidators.validate() &&\n                this.isPlaceOrderActionAllowed() === true\n            ) {\n                fullScreenLoader.startLoader();\n\n                this.isPlaceOrderActionAllowed(false);\n\n                $.when(\n                    this.setPaymentInformation()\n                ).done(\n                    this.done.bind(this)\n                ).fail(\n                    this.fail.bind(this)\n                ).always(\n                    function () {\n                        self.isPlaceOrderActionAllowed(true);\n                    }\n                );\n\n                this.initTimeoutHandler();\n            }\n        },\n\n        /**\n         * {Function}\n         */\n        setPaymentInformation: function () {\n            return setPaymentInformationAction(\n                this.messageContainer,\n                {\n                    method: this.getCode()\n                }\n            );\n        },\n\n        /**\n         * {Function}\n         */\n        initTimeoutHandler: function () {\n            this.timeoutId = setTimeout(\n                this.timeoutHandler.bind(this),\n                this.getTimeoutTime()\n            );\n\n            $(window).off('clearTimeout')\n                .on('clearTimeout', this.clearTimeout.bind(this));\n        },\n\n        /**\n         * {Function}\n         */\n        clearTimeout: function () {\n            clearTimeout(this.timeoutId);\n            this.fail();\n\n            return this;\n        },\n\n        /**\n         * {Function}\n         */\n        timeoutHandler: function () {\n            this.clearTimeout();\n\n            alert(\n                {\n                    content: this.getTimeoutMessage(),\n                    actions: {\n\n                        /**\n                         * {Function}\n                         */\n                        always: this.alertActionHandler.bind(this)\n                    }\n                }\n            );\n\n            this.fail();\n        },\n\n        /**\n         * {Function}\n         */\n        alertActionHandler: function () {\n            fullScreenLoader.startLoader();\n            window.location.reload();\n        },\n\n        /**\n         * {Function}\n         */\n        fail: function () {\n            fullScreenLoader.stopLoader();\n\n            return this;\n        },\n\n        /**\n         * {Function}\n         */\n        done: function () {\n            this.placeOrderHandler().fail(function () {\n                fullScreenLoader.stopLoader();\n            });\n\n            return this;\n        }\n    });\n});\n","Magento_Payment/js/view/payment/method-renderer/free-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    'Magento_Checkout/js/model/quote'\n], function (Component, quote) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Payment/payment/free'\n        },\n\n        /** Returns is method available */\n        isAvailable: function () {\n            return quote.totals()['grand_total'] <= 0;\n        }\n    });\n});\n","Magento_Payment/js/model/credit-card-validation/credit-card-number-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'mageUtils',\n    'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator',\n    'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator/credit-card-type'\n], function (utils, luhn10, creditCardTypes) {\n    'use strict';\n\n    /**\n     * @param {*} card\n     * @param {*} isPotentiallyValid\n     * @param {*} isValid\n     * @return {Object}\n     */\n    function resultWrapper(card, isPotentiallyValid, isValid) {\n        return {\n            card: card,\n            isValid: isValid,\n            isPotentiallyValid: isPotentiallyValid\n        };\n    }\n\n    return function (value) {\n        var potentialTypes,\n            cardType,\n            valid,\n            i,\n            maxLength;\n\n        if (utils.isEmpty(value)) {\n            return resultWrapper(null, false, false);\n        }\n\n        value = value.replace(/\\s+/g, '');\n\n        if (!/^\\d*$/.test(value)) {\n            return resultWrapper(null, false, false);\n        }\n\n        potentialTypes = creditCardTypes.getCardTypes(value);\n\n        if (potentialTypes.length === 0) {\n            return resultWrapper(null, false, false);\n        } else if (potentialTypes.length !== 1) {\n            return resultWrapper(null, true, false);\n        }\n\n        cardType = potentialTypes[0];\n\n        if (cardType.type === 'unionpay') {  // UnionPay is not Luhn 10 compliant\n            valid = true;\n        } else {\n            valid = luhn10(value);\n        }\n\n        for (i = 0; i < cardType.lengths.length; i++) {\n            if (cardType.lengths[i] === value.length) {\n                return resultWrapper(cardType, valid, valid);\n            }\n        }\n\n        maxLength = Math.max.apply(null, cardType.lengths);\n\n        if (value.length < maxLength) {\n            return resultWrapper(cardType, true, false);\n        }\n\n        return resultWrapper(cardType, false, false);\n    };\n});\n","Magento_Payment/js/model/credit-card-validation/cvv-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([], function () {\n    'use strict';\n\n    /**\n     * @param {*} isValid\n     * @param {*} isPotentiallyValid\n     * @return {Object}\n     */\n    function resultWrapper(isValid, isPotentiallyValid) {\n        return {\n            isValid: isValid,\n            isPotentiallyValid: isPotentiallyValid\n        };\n    }\n\n    /**\n     * CVV number validation.\n     * Validate digit count for CVV code.\n     *\n     * @param {*} value\n     * @param {Number} maxLength\n     * @return {Object}\n     */\n    return function (value, maxLength) {\n        var DEFAULT_LENGTH = 3;\n\n        maxLength = maxLength || DEFAULT_LENGTH;\n\n        if (!/^\\d*$/.test(value)) {\n            return resultWrapper(false, false);\n        }\n\n        if (value.length === maxLength) {\n            return resultWrapper(true, true);\n        }\n\n        if (value.length < maxLength) {\n            return resultWrapper(false, true);\n        }\n\n        if (value.length > maxLength) {\n            return resultWrapper(false, false);\n        }\n    };\n});\n","Magento_Payment/js/model/credit-card-validation/validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'jquery',\n    'Magento_Payment/js/model/credit-card-validation/cvv-validator',\n    'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator',\n    'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator',\n    'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator',\n    'Magento_Payment/js/model/credit-card-validation/credit-card-data',\n    'mage/translate'\n], function ($, cvvValidator, creditCardNumberValidator, yearValidator, monthValidator, creditCardData) {\n    'use strict';\n\n    $('.payment-method-content input[type=\"number\"]').on('keyup', function () {\n        if ($(this).val() < 0) {\n            $(this).val($(this).val().replace(/^-/, ''));\n        }\n    });\n\n    $.each({\n        'validate-card-type': [\n            function (number, item, allowedTypes) {\n                var cardInfo,\n                    i,\n                    l;\n\n                if (!creditCardNumberValidator(number).isValid) {\n                    return false;\n                }\n\n                cardInfo = creditCardNumberValidator(number).card;\n\n                for (i = 0, l = allowedTypes.length; i < l; i++) {\n                    if (cardInfo.title == allowedTypes[i].type) { //eslint-disable-line eqeqeq\n                        return true;\n                    }\n                }\n\n                return false;\n            },\n            $.mage.__('Please enter a valid credit card type number.')\n        ],\n        'validate-card-number': [\n\n            /**\n             * Validate credit card number based on mod 10\n             *\n             * @param {*} number - credit card number\n             * @return {Boolean}\n             */\n            function (number) {\n                return creditCardNumberValidator(number).isValid;\n            },\n            $.mage.__('Please enter a valid credit card number.')\n        ],\n        'validate-card-date': [\n\n            /**\n             * Validate credit card expiration month\n             *\n             * @param {String} date - month\n             * @return {Boolean}\n             */\n            function (date) {\n                return monthValidator(date).isValid;\n            },\n            $.mage.__('Incorrect credit card expiration month.')\n        ],\n        'validate-card-cvv': [\n\n            /**\n             * Validate cvv\n             *\n             * @param {String} cvv - card verification value\n             * @return {Boolean}\n             */\n            function (cvv) {\n                var maxLength = creditCardData.creditCard ? creditCardData.creditCard.code.size : 3;\n\n                return cvvValidator(cvv, maxLength).isValid;\n            },\n            $.mage.__('Please enter a valid credit card verification number.')\n        ],\n        'validate-card-year': [\n\n            /**\n             * Validate credit card expiration year\n             *\n             * @param {String} date - year\n             * @return {Boolean}\n             */\n            function (date) {\n                return yearValidator(date).isValid;\n            },\n            $.mage.__('Incorrect credit card expiration year.')\n        ]\n\n    }, function (i, rule) {\n        rule.unshift(i);\n        $.validator.addMethod.apply($.validator, rule);\n    });\n});\n","Magento_Payment/js/model/credit-card-validation/credit-card-data.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([], function () {\n    'use strict';\n\n    return {\n        creditCard: null,\n        creditCardNumber: null,\n        expirationMonth: null,\n        expirationYear: null,\n        cvvCode: null\n    };\n});\n","Magento_Payment/js/model/credit-card-validation/expiration-date-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'mageUtils',\n    'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/parse-date',\n    'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator',\n    'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator'\n], function (utils, parseDate, expirationMonth, expirationYear) {\n    'use strict';\n\n    /**\n     * @param {*} isValid\n     * @param {*} isPotentiallyValid\n     * @param {*} month\n     * @param {*} year\n     * @return {Object}\n     */\n    function resultWrapper(isValid, isPotentiallyValid, month, year) {\n        return {\n            isValid: isValid,\n            isPotentiallyValid: isPotentiallyValid,\n            month: month,\n            year: year\n        };\n    }\n\n    return function (value) {\n        var date,\n            monthValid,\n            yearValid;\n\n        if (utils.isEmpty(value)) {\n            return resultWrapper(false, false, null, null);\n        }\n\n        value = value.replace(/^(\\d\\d) (\\d\\d(\\d\\d)?)$/, '$1/$2');\n        date = parseDate(value);\n        monthValid = expirationMonth(date.month);\n        yearValid = expirationYear(date.year);\n\n        if (monthValid.isValid && yearValid.isValid) {\n            return resultWrapper(true, true, date.month, date.year);\n        }\n\n        if (monthValid.isPotentiallyValid && yearValid.isPotentiallyValid) {\n            return resultWrapper(false, true, null, null);\n        }\n\n        return resultWrapper(false, false, null, null);\n    };\n});\n","Magento_Payment/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    /**\n     * Luhn algorithm verification\n     */\n    return function (a, b, c, d, e) {\n        for (d = +a[b = a.length - 1], e = 0; b--;) {\n            c = +a[b];\n            d += ++e % 2 ? 2 * c % 10 + (c > 4) : c;\n        }\n\n        return !(d % 10);\n    };\n});\n","Magento_Payment/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* @api */\ndefine([\n    'jquery',\n    'mageUtils'\n], function ($, utils) {\n    'use strict';\n\n    var types = [\n        {\n            title: 'Visa',\n            type: 'VI',\n            pattern: '^4\\\\d*$',\n            gaps: [4, 8, 12],\n            lengths: [16],\n            code: {\n                name: 'CVV',\n                size: 3\n            }\n        },\n        {\n            title: 'MasterCard',\n            type: 'MC',\n            pattern: '^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$',\n            gaps: [4, 8, 12],\n            lengths: [16],\n            code: {\n                name: 'CVC',\n                size: 3\n            }\n        },\n        {\n            title: 'American Express',\n            type: 'AE',\n            pattern: '^3([47]\\\\d*)?$',\n            isAmex: true,\n            gaps: [4, 10],\n            lengths: [15],\n            code: {\n                name: 'CID',\n                size: 4\n            }\n        },\n        {\n            title: 'Diners',\n            type: 'DN',\n            pattern: '^(3(0[0-5]|095|6|[8-9]))\\\\d*$',\n            gaps: [4, 10],\n            lengths: [14, 16, 17, 18, 19],\n            code: {\n                name: 'CVV',\n                size: 3\n            }\n        },\n        {\n            title: 'Discover',\n            type: 'DI',\n            pattern: '^(6011(0|[2-4]|74|7[7-9]|8[6-9]|9)|6(4[4-9]|5))\\\\d*$',\n            gaps: [4, 8, 12],\n            lengths: [16, 17, 18, 19],\n            code: {\n                name: 'CID',\n                size: 3\n            }\n        },\n        {\n            title: 'JCB',\n            type: 'JCB',\n            pattern: '^35(2[8-9]|[3-8])\\\\d*$',\n            gaps: [4, 8, 12],\n            lengths: [16, 17, 18, 19],\n            code: {\n                name: 'CVV',\n                size: 3\n            }\n        },\n        {\n            title: 'UnionPay',\n            type: 'UN',\n            pattern: '^(622(1(2[6-9]|[3-9])|[3-8]|9([[0-1]|2[0-5]))|62[4-6]|628([2-8]))\\\\d*?$',\n            gaps: [4, 8, 12],\n            lengths: [16, 17, 18, 19],\n            code: {\n                name: 'CVN',\n                size: 3\n            }\n        },\n        {\n            title: 'Maestro International',\n            type: 'MI',\n            pattern: '^(5(0|[6-9])|63|67(?!59|6770|6774))\\\\d*$',\n            gaps: [4, 8, 12],\n            lengths: [12, 13, 14, 15, 16, 17, 18, 19],\n            code: {\n                name: 'CVC',\n                size: 3\n            }\n        },\n        {\n            title: 'Maestro Domestic',\n            type: 'MD',\n            pattern: '^6759(?!24|38|40|6[3-9]|70|76)|676770|676774\\\\d*$',\n            gaps: [4, 8, 12],\n            lengths: [12, 13, 14, 15, 16, 17, 18, 19],\n            code: {\n                name: 'CVC',\n                size: 3\n            }\n        },\n        {\n            title: 'Hipercard',\n            type: 'HC',\n            pattern: '^((606282)|(637095)|(637568)|(637599)|(637609)|(637612))\\\\d*$',\n            gaps: [4, 8, 12],\n            lengths: [13, 16],\n            code: {\n                name: 'CVC',\n                size: 3\n            }\n        },\n        {\n            title: 'Elo',\n            type: 'ELO',\n            pattern: '^((509091)|(636368)|(636297)|(504175)|(438935)|(40117[8-9])|(45763[1-2])|' +\n                '(457393)|(431274)|(50990[0-2])|(5099[7-9][0-9])|(50996[4-9])|(509[1-8][0-9][0-9])|' +\n                '(5090(0[0-2]|0[4-9]|1[2-9]|[24589][0-9]|3[1-9]|6[0-46-9]|7[0-24-9]))|' +\n                '(5067(0[0-24-8]|1[0-24-9]|2[014-9]|3[0-379]|4[0-9]|5[0-3]|6[0-5]|7[0-8]))|' +\n                '(6504(0[5-9]|1[0-9]|2[0-9]|3[0-9]))|' +\n                '(6504(8[5-9]|9[0-9])|6505(0[0-9]|1[0-9]|2[0-9]|3[0-8]))|' +\n                '(6505(4[1-9]|5[0-9]|6[0-9]|7[0-9]|8[0-9]|9[0-8]))|' +\n                '(6507(0[0-9]|1[0-8]))|(65072[0-7])|(6509(0[1-9]|1[0-9]|20))|' +\n                '(6516(5[2-9]|6[0-9]|7[0-9]))|(6550(0[0-9]|1[0-9]))|' +\n                '(6550(2[1-9]|3[0-9]|4[0-9]|5[0-8])))\\\\d*$',\n            gaps: [4, 8, 12],\n            lengths: [16],\n            code: {\n                name: 'CVC',\n                size: 3\n            }\n        },\n        {\n            title: 'Aura',\n            type: 'AU',\n            pattern: '^5078\\\\d*$',\n            gaps: [4, 8, 12],\n            lengths: [19],\n            code: {\n                name: 'CVC',\n                size: 3\n            }\n        }\n    ];\n\n    return {\n        /**\n         * @param {*} cardNumber\n         * @return {Array}\n         */\n        getCardTypes: function (cardNumber) {\n            var i, value,\n                result = [];\n\n            if (utils.isEmpty(cardNumber)) {\n                return result;\n            }\n\n            if (cardNumber === '') {\n                return $.extend(true, {}, types);\n            }\n\n            for (i = 0; i < types.length; i++) {\n                value = types[i];\n\n                if (new RegExp(value.pattern).test(cardNumber)) {\n                    result.push($.extend(true, {}, value));\n                }\n            }\n\n            return result;\n        }\n    };\n});\n","Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    /**\n     * @param {*} isValid\n     * @param {*} isPotentiallyValid\n     * @return {Object}\n     */\n    function resultWrapper(isValid, isPotentiallyValid) {\n        return {\n            isValid: isValid,\n            isPotentiallyValid: isPotentiallyValid\n        };\n    }\n\n    return function (value) {\n        var month,\n            monthValid;\n\n        if (value.replace(/\\s/g, '') === '' || value === '0') {\n            return resultWrapper(false, true);\n        }\n\n        if (!/^\\d*$/.test(value)) {\n            return resultWrapper(false, false);\n        }\n\n        if (isNaN(value)) {\n            return resultWrapper(false, false);\n        }\n\n        month = parseInt(value, 10);\n        monthValid = month > 0 && month < 13;\n\n        return resultWrapper(monthValid, monthValid);\n    };\n});\n","Magento_Payment/js/model/credit-card-validation/expiration-date-validator/parse-date.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    return function (value) {\n        var month, len;\n\n        if (value.match('/')) {\n            value = value.split(/\\s*\\/\\s*/g);\n\n            return {\n                month: value[0],\n                year: value.slice(1).join()\n            };\n        }\n\n        len = value[0] === '0' || value.length > 5 || value.length === 4 || value.length === 3 ? 2 : 1;\n        month = value.substr(0, len);\n\n        return {\n            month: month,\n            year: value.substr(month.length, 4)\n        };\n    };\n});\n","Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    /**\n     * @param {*} isValid\n     * @param {*} isPotentiallyValid\n     * @return {Object}\n     */\n    function resultWrapper(isValid, isPotentiallyValid) {\n        return {\n            isValid: isValid,\n            isPotentiallyValid: isPotentiallyValid\n        };\n    }\n\n    return function (value) {\n        var currentYear = new Date().getFullYear(),\n            len = value.length,\n            valid,\n            expMaxLifetime = 19;\n\n        if (value.replace(/\\s/g, '') === '') {\n            return resultWrapper(false, true);\n        }\n\n        if (!/^\\d*$/.test(value)) {\n            return resultWrapper(false, false);\n        }\n\n        if (len !== 4) {\n            return resultWrapper(false, true);\n        }\n\n        value = parseInt(value, 10);\n        valid = value >= currentYear && value <= currentYear + expMaxLifetime;\n\n        return resultWrapper(valid, valid);\n    };\n});\n","Magento_ReCaptchaStorePickup/js/reCaptchaStorePickup.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['Magento_ReCaptchaFrontendUi/js/reCaptcha'], function (reCaptcha) {\n    'use strict';\n\n    return reCaptcha.extend({\n\n        /**\n         * @inheritdoc\n         */\n        renderReCaptcha: function () {\n            this.captchaInitialized = false;\n            this._super();\n        }\n    });\n});\n","js-cookie/cookie-wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'js-cookie/js.cookie'\n], function ($, cookie) {\n    'use strict';\n\n    window.Cookies = window.Cookies || cookie;\n\n    var config = $.cookie = function (key, value, options) {\n        if (value !== undefined) {\n            options = $.extend({}, config.defaults, options);\n\n            return cookie.set(key, value, options);\n        }\n\n        var result = key ? undefined : {},\n            cookies = document.cookie ? document.cookie.split('; ') : [],\n            i;\n\n        for (i = 0; i < cookies.length; i++) {\n            var parts = cookies[i].split('='),\n                name = config.raw ? parts.shift() : decodeURIComponent(parts.shift()),\n                cookieValue = parts.join('=');\n\n            if (key && key === name) {\n                result = decodeURIComponent(cookieValue.replace('/\\\\+/g', ' '));\n                break;\n            }\n\n            if (!key && (cookieValue = decodeURIComponent(cookieValue.replace('/\\\\+/g', ' '))) !== undefined) {\n                result[name] = cookieValue;\n            }\n        }\n\n        return result;\n    };\n\n    config.defaults = {};\n\n    $.removeCookie = function (key, options) {\n        if ($.cookie(key) === undefined) {\n            return false;\n        }\n\n        $.cookie(key, '', $.extend({}, options, { expires: -1 }));\n        return !$.cookie(key);\n    };\n});\n","js-cookie/js.cookie.js":"/*! js-cookie v3.0.5 | MIT */\n;\n(function (global, factory) {\n    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n        typeof define === 'function' && define.amd ? define(factory) :\n            (global = typeof globalThis !== 'undefined' ? globalThis : global || self, (function () {\n                var current = global.Cookies;\n                var exports = global.Cookies = factory();\n                exports.noConflict = function () { global.Cookies = current; return exports; };\n            })());\n})(this, (function () { 'use strict';\n\n    /* eslint-disable no-var */\n    function assign (target) {\n        for (var i = 1; i < arguments.length; i++) {\n            var source = arguments[i];\n            for (var key in source) {\n                target[key] = source[key];\n            }\n        }\n        return target\n    }\n    /* eslint-enable no-var */\n\n    /* eslint-disable no-var */\n    var defaultConverter = {\n        read: function (value) {\n            if (value[0] === '\"') {\n                value = value.slice(1, -1);\n            }\n            return value.replace(/(%[\\dA-F]{2})+/gi, decodeURIComponent)\n        },\n        write: function (value) {\n            return encodeURIComponent(value).replace(\n                /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,\n                decodeURIComponent\n            )\n        }\n    };\n    /* eslint-enable no-var */\n\n    /* eslint-disable no-var */\n\n    function init (converter, defaultAttributes) {\n        function set (name, value, attributes) {\n            if (typeof document === 'undefined') {\n                return\n            }\n\n            attributes = assign({}, defaultAttributes, attributes);\n\n            if (typeof attributes.expires === 'number') {\n                attributes.expires = new Date(Date.now() + attributes.expires * 864e5);\n            }\n            if (attributes.expires) {\n                attributes.expires = attributes.expires.toUTCString();\n            }\n\n            name = encodeURIComponent(name)\n                .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)\n                .replace(/[()]/g, escape);\n\n            var stringifiedAttributes = '';\n            for (var attributeName in attributes) {\n                if (!attributes[attributeName]) {\n                    continue\n                }\n\n                stringifiedAttributes += '; ' + attributeName;\n\n                if (attributes[attributeName] === true) {\n                    continue\n                }\n\n                // Considers RFC 6265 section 5.2:\n                // ...\n                // 3.  If the remaining unparsed-attributes contains a %x3B (\";\")\n                //     character:\n                // Consume the characters of the unparsed-attributes up to,\n                // not including, the first %x3B (\";\") character.\n                // ...\n                stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];\n            }\n\n            return (document.cookie =\n                name + '=' + converter.write(value, name) + stringifiedAttributes)\n        }\n\n        function get (name) {\n            if (typeof document === 'undefined' || (arguments.length && !name)) {\n                return\n            }\n\n            // To prevent the for loop in the first place assign an empty array\n            // in case there are no cookies at all.\n            var cookies = document.cookie ? document.cookie.split('; ') : [];\n            var jar = {};\n            for (var i = 0; i < cookies.length; i++) {\n                var parts = cookies[i].split('=');\n                var value = parts.slice(1).join('=');\n\n                try {\n                    var found = decodeURIComponent(parts[0]);\n                    jar[found] = converter.read(value, found);\n\n                    if (name === found) {\n                        break\n                    }\n                } catch (e) {}\n            }\n\n            return name ? jar[name] : jar\n        }\n\n        return Object.create(\n            {\n                set,\n                get,\n                remove: function (name, attributes) {\n                    set(\n                        name,\n                        '',\n                        assign({}, attributes, {\n                            expires: -1\n                        })\n                    );\n                },\n                withAttributes: function (attributes) {\n                    return init(this.converter, assign({}, this.attributes, attributes))\n                },\n                withConverter: function (converter) {\n                    return init(assign({}, this.converter, converter), this.attributes)\n                }\n            },\n            {\n                attributes: { value: Object.freeze(defaultAttributes) },\n                converter: { value: Object.freeze(converter) }\n            }\n        )\n    }\n\n    var api = init(defaultConverter, { path: '/' });\n    /* eslint-enable no-var */\n\n    return api;\n\n}));\n","Magento_InstantPurchase/js/view/instant-purchase.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    'underscore',\n    'uiComponent',\n    'Magento_Ui/js/modal/confirm',\n    'Magento_Customer/js/customer-data',\n    'mage/url',\n    'mage/template',\n    'mage/translate',\n    'text!Magento_InstantPurchase/template/confirmation.html',\n    'mage/validation'\n], function (ko, $, _, Component, confirm, customerData, urlBuilder, mageTemplate, $t, confirmationTemplate) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_InstantPurchase/instant-purchase',\n            buttonText: $t('Instant Purchase'),\n            purchaseUrl: urlBuilder.build('instantpurchase/button/placeOrder'),\n            showButton: false,\n            paymentToken: null,\n            shippingAddress: null,\n            billingAddress: null,\n            shippingMethod: null,\n            productFormSelector: '#product_addtocart_form',\n            confirmationTitle: $t('Instant Purchase Confirmation'),\n            confirmationData: {\n                message: $t('Are you sure you want to place order and pay?'),\n                shippingAddressTitle: $t('Shipping Address'),\n                billingAddressTitle: $t('Billing Address'),\n                paymentMethodTitle: $t('Payment Method'),\n                shippingMethodTitle: $t('Shipping Method')\n            }\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            var instantPurchase = customerData.get('instant-purchase');\n\n            this._super();\n\n            this.setPurchaseData(instantPurchase());\n            instantPurchase.subscribe(this.setPurchaseData, this);\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super()\n                .observe('showButton paymentToken shippingAddress billingAddress shippingMethod');\n\n            return this;\n        },\n\n        /**\n         * Set data from customerData.\n         *\n         * @param {Object} data\n         */\n        setPurchaseData: function (data) {\n            this.showButton(data.available);\n            this.paymentToken(data.paymentToken);\n            this.shippingAddress(data.shippingAddress);\n            this.billingAddress(data.billingAddress);\n            this.shippingMethod(data.shippingMethod);\n        },\n\n        /**\n         * Confirmation method\n         */\n        instantPurchase: function () {\n            var form = $(this.productFormSelector),\n                confirmTemplate = mageTemplate(confirmationTemplate),\n                confirmData = _.extend({}, this.confirmationData, {\n                    paymentToken: this.paymentToken().summary,\n                    shippingAddress: this.shippingAddress().summary,\n                    billingAddress: this.billingAddress().summary,\n                    shippingMethod: this.shippingMethod().summary\n                });\n\n            if (!(form.validation() && form.validation('isValid'))) {\n                return;\n            }\n\n            confirm({\n                title: this.confirmationTitle,\n                content: confirmTemplate({\n                    data: confirmData\n                }),\n                actions: {\n                    /** @inheritdoc */\n                    confirm: function () {\n                        $.ajax({\n                            url: this.purchaseUrl,\n                            data: form.serialize(),\n                            type: 'post',\n                            dataType: 'json',\n\n                            /** Show loader before send */\n                            beforeSend: function () {\n                                $('body').trigger('processStart');\n                            }\n                        }).always(function () {\n                            $('body').trigger('processStop');\n                        });\n                    }.bind(this)\n                }\n            });\n        }\n    });\n});\n","Magento_Tax/js/price/adjustment.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/grid/columns/column',\n    'mage/translate'\n], function (Element, $t) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            bodyTmpl: 'Magento_Tax/price/adjustment',\n            taxPriceType: 'final_price',\n            taxPriceCssClass: 'price-including-tax',\n            bothPrices: 3,\n            inclTax: 2,\n            exclTax: 1,\n            modules: {\n                price: '${ $.parentName }'\n            },\n            listens: {\n                price: 'initializePriceAttributes'\n            }\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        initialize: function () {\n            this._super()\n                .initializePriceAttributes();\n\n            return this;\n        },\n\n        /**\n         * Update parent price.\n         *\n         * @returns {Object} Chainable.\n         */\n        initializePriceAttributes: function () {\n            if (this.displayBothPrices && this.price()) {\n                this.price().priceWrapperCssClasses = this.taxPriceCssClass;\n                this.price().priceWrapperAttr = {\n                    'data-label': $t('Incl. Tax')\n                };\n            }\n\n            return this;\n        },\n\n        /**\n         * Get price tax adjustment.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} tax html\n         */\n        getTax: function (row) {\n            return row['price_info']['extension_attributes']['tax_adjustments']['formatted_prices'][this.taxPriceType];\n        },\n\n        /**\n         * UnsanitizedHtml version of getTax.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} tax html\n         */\n        getTaxUnsanitizedHtml: function (row) {\n            return this.getTax(row);\n        },\n\n        /**\n         * Set price tax type.\n         *\n         * @param {String} priceType\n         * @return {Object}\n         */\n        setPriceType: function (priceType) {\n            this.taxPriceType = priceType;\n\n            return this;\n        },\n\n        /**\n         * Return whether display setting is to display\n         * both price including tax and price excluding tax.\n         *\n         * @return {Boolean}\n         */\n        displayBothPrices: function () {\n            return +this.source.data.displayTaxes === this.bothPrices;\n        },\n\n        /**\n         * Return whether display setting is to display price including tax.\n         *\n         * @return {Boolean}\n         */\n        displayPriceIncludeTax: function () {\n            return +this.source.data.displayTaxes === this.inclTax;\n        },\n\n        /**\n         * Return whether display setting is to display price excluding tax.\n         *\n         * @return {Boolean}\n         */\n        displayPriceExclTax: function () {\n            return +this.source.data.displayTaxes === this.exclTax;\n        }\n    });\n});\n","Magento_Tax/js/view/checkout/cart/totals/tax.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'Magento_Tax/js/view/checkout/summary/tax',\n    'Magento_Checkout/js/model/totals'\n], function (Component, totals) {\n    'use strict';\n\n    var isFullTaxSummaryDisplayed = window.checkoutConfig.isFullTaxSummaryDisplayed,\n        isZeroTaxDisplayed = window.checkoutConfig.isZeroTaxDisplayed;\n\n    return Component.extend({\n        /**\n         * @override\n         */\n        ifShowValue: function () {\n            if (this.isFullMode() && this.getPureValue() == 0) { //eslint-disable-line eqeqeq\n                return isZeroTaxDisplayed;\n            }\n\n            return true;\n        },\n\n        /**\n         * @override\n         */\n        ifShowDetails: function () {\n            return this.getPureValue() > 0 && isFullTaxSummaryDisplayed;\n        },\n\n        /**\n         * @override\n         */\n        isCalculated: function () {\n            return this.totals() && totals.getSegment('tax') !== null;\n        }\n    });\n});\n","Magento_Tax/js/view/checkout/cart/totals/shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'Magento_Tax/js/view/checkout/summary/shipping',\n    'Magento_Checkout/js/model/quote'\n], function (Component, quote) {\n    'use strict';\n\n    return Component.extend({\n        /**\n         * @override\n         */\n        isCalculated: function () {\n            return !!quote.shippingMethod();\n        },\n\n        /**\n         * @override\n         */\n        getShippingMethodTitle: function () {\n            return '(' + this._super() + ')';\n        }\n    });\n});\n","Magento_Tax/js/view/checkout/cart/totals/grand-total.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'Magento_Tax/js/view/checkout/summary/grand-total'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        /**\n         * @override\n         */\n        isDisplayed: function () {\n            return true;\n        }\n    });\n});\n","Magento_Tax/js/view/checkout/minicart/subtotal/totals.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'ko',\n    'uiComponent',\n    'Magento_Customer/js/customer-data'\n], function (ko, Component, customerData) {\n    'use strict';\n\n    return Component.extend({\n        displaySubtotal: ko.observable(true),\n\n        /**\n         * @override\n         */\n        initialize: function () {\n            this._super();\n            this.cart = customerData.get('cart');\n        }\n    });\n});\n","Magento_Tax/js/view/checkout/summary/tax.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'ko',\n    'Magento_Checkout/js/view/summary/abstract-total',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/totals',\n    'mage/translate',\n    'underscore'\n], function (ko, Component, quote, totals, $t, _) {\n    'use strict';\n\n    var isTaxDisplayedInGrandTotal = window.checkoutConfig.includeTaxInGrandTotal,\n        isFullTaxSummaryDisplayed = window.checkoutConfig.isFullTaxSummaryDisplayed,\n        isZeroTaxDisplayed = window.checkoutConfig.isZeroTaxDisplayed,\n        taxAmount = 0,\n        rates = 0;\n\n    return Component.extend({\n        defaults: {\n            isTaxDisplayedInGrandTotal: isTaxDisplayedInGrandTotal,\n            notCalculatedMessage: $t('Not yet calculated'),\n            template: 'Magento_Tax/checkout/summary/tax'\n        },\n        totals: quote.getTotals(),\n        isFullTaxSummaryDisplayed: isFullTaxSummaryDisplayed,\n\n        /**\n         * @return {Boolean}\n         */\n        ifShowValue: function () {\n            if (this.isFullMode() && this.getPureValue() == 0) { //eslint-disable-line eqeqeq\n                return isZeroTaxDisplayed;\n            }\n\n            return true;\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        ifShowDetails: function () {\n            if (!this.isFullMode()) {\n                return false;\n            }\n\n            return this.getPureValue() > 0 && isFullTaxSummaryDisplayed;\n        },\n\n        /**\n         * @return {Number}\n         */\n        getPureValue: function () {\n            var amount = 0,\n                taxTotal;\n\n            if (this.totals()) {\n                taxTotal = totals.getSegment('tax');\n\n                if (taxTotal) {\n                    amount = taxTotal.value;\n                }\n            }\n\n            return amount;\n        },\n\n        /**\n         * @return {*|Boolean}\n         */\n        isCalculated: function () {\n            return this.totals() && this.isFullMode() && totals.getSegment('tax') != null;\n        },\n\n        /**\n         * @return {*}\n         */\n        getValue: function () {\n            var amount;\n\n            if (!this.isCalculated()) {\n                return this.notCalculatedMessage;\n            }\n            amount = totals.getSegment('tax').value;\n\n            return this.getFormattedPrice(amount);\n        },\n\n        /**\n         * @param {*} amount\n         * @return {*|String}\n         */\n        formatPrice: function (amount) {\n            return this.getFormattedPrice(amount);\n        },\n\n        /**\n         * @param {*} parent\n         * @param {*} percentage\n         * @return {*|String}\n         */\n        getTaxAmount: function (parent, percentage) {\n            var totalPercentage = 0;\n\n            taxAmount = parent.amount;\n            rates = parent.rates;\n            _.each(rates, function (rate) {\n                totalPercentage += parseFloat(rate.percent);\n            });\n\n            return this.getFormattedPrice(this.getPercentAmount(taxAmount, totalPercentage, percentage));\n        },\n\n        /**\n         * @param {*} amount\n         * @param {*} totalPercentage\n         * @param {*} percentage\n         * @return {*|String}\n         */\n        getPercentAmount: function (amount, totalPercentage, percentage) {\n            return parseFloat(amount * percentage / totalPercentage);\n        },\n\n        /**\n         * @return {Array}\n         */\n        getDetails: function () {\n            var taxSegment = totals.getSegment('tax');\n\n            if (taxSegment && taxSegment['extension_attributes']) {\n                return taxSegment['extension_attributes']['tax_grandtotal_details'];\n            }\n\n            return [];\n        }\n    });\n});\n","Magento_Tax/js/view/checkout/summary/subtotal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'Magento_Checkout/js/view/summary/abstract-total',\n    'Magento_Checkout/js/model/quote'\n], function (Component, quote) {\n    'use strict';\n\n    var displaySubtotalMode = window.checkoutConfig.reviewTotalsDisplayMode;\n\n    return Component.extend({\n        defaults: {\n            displaySubtotalMode: displaySubtotalMode,\n            template: 'Magento_Tax/checkout/summary/subtotal'\n        },\n        totals: quote.getTotals(),\n\n        /**\n         * @return {*|String}\n         */\n        getValue: function () {\n            var price = 0;\n\n            if (this.totals()) {\n                price = this.totals().subtotal;\n            }\n\n            return this.getFormattedPrice(price);\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isBothPricesDisplayed: function () {\n            return this.displaySubtotalMode == 'both'; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isIncludingTaxDisplayed: function () {\n            return this.displaySubtotalMode == 'including'; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * @return {*|String}\n         */\n        getValueInclTax: function () {\n            var price = 0;\n\n            if (this.totals()) {\n                price = this.totals()['subtotal_incl_tax'];\n            }\n\n            return this.getFormattedPrice(price);\n        }\n    });\n});\n","Magento_Tax/js/view/checkout/summary/shipping.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'jquery',\n    'Magento_Checkout/js/view/summary/shipping',\n    'Magento_Checkout/js/model/quote'\n], function ($, Component, quote) {\n    'use strict';\n\n    var displayMode = window.checkoutConfig.reviewShippingDisplayMode;\n\n    return Component.extend({\n        defaults: {\n            displayMode: displayMode,\n            template: 'Magento_Tax/checkout/summary/shipping'\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isBothPricesDisplayed: function () {\n            return this.displayMode == 'both'; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isIncludingDisplayed: function () {\n            return this.displayMode == 'including'; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isExcludingDisplayed: function () {\n            return this.displayMode == 'excluding'; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * @return {*|Boolean}\n         */\n        isCalculated: function () {\n            return this.totals() && this.isFullMode() && quote.shippingMethod() != null;\n        },\n\n        /**\n         * @return {*}\n         */\n        getIncludingValue: function () {\n            var price;\n\n            if (!this.isCalculated()) {\n                return this.notCalculatedMessage;\n            }\n            price = this.totals()['shipping_incl_tax'];\n\n            return this.getFormattedPrice(price);\n        },\n\n        /**\n         * @return {*}\n         */\n        getExcludingValue: function () {\n            var price;\n\n            if (!this.isCalculated()) {\n                return this.notCalculatedMessage;\n            }\n            price = this.totals()['shipping_amount'];\n\n            return this.getFormattedPrice(price);\n        }\n    });\n});\n","Magento_Tax/js/view/checkout/summary/grand-total.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'Magento_Checkout/js/view/summary/abstract-total',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Catalog/js/price-utils',\n    'Magento_Checkout/js/model/totals'\n], function (Component, quote, priceUtils, totals) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            isFullTaxSummaryDisplayed: window.checkoutConfig.isFullTaxSummaryDisplayed || false,\n            template: 'Magento_Tax/checkout/summary/grand-total'\n        },\n        totals: quote.getTotals(),\n        isTaxDisplayedInGrandTotal: window.checkoutConfig.includeTaxInGrandTotal || false,\n\n        /**\n         * @return {*}\n         */\n        isDisplayed: function () {\n            return this.isFullMode();\n        },\n\n        /**\n         * @return {*|String}\n         */\n        getValue: function () {\n            var price = 0;\n\n            if (this.totals()) {\n                price = totals.getSegment('grand_total').value;\n            }\n\n            return this.getFormattedPrice(price);\n        },\n\n        /**\n         * @return {*|String}\n         */\n        getBaseValue: function () {\n            var price = 0;\n\n            if (this.totals()) {\n                price = this.totals()['base_grand_total'];\n            }\n\n            return priceUtils.formatPriceLocale(price, quote.getBasePriceFormat());\n        },\n\n        /**\n         * @return {*}\n         */\n        getGrandTotalExclTax: function () {\n            var total = this.totals(),\n                amount;\n\n            if (!total) {\n                return 0;\n            }\n\n            amount = total['grand_total'] - total['tax_amount'];\n\n            if (amount < 0) {\n                amount = 0;\n            }\n\n            return this.getFormattedPrice(amount);\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isBaseGrandTotalDisplayNeeded: function () {\n            var total = this.totals();\n\n            if (!total) {\n                return false;\n            }\n\n            return total['base_currency_code'] != total['quote_currency_code']; //eslint-disable-line eqeqeq\n        }\n    });\n});\n","Magento_Tax/js/view/checkout/summary/item/details/subtotal.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'Magento_Checkout/js/view/summary/item/details/subtotal'\n], function (subtotal) {\n    'use strict';\n\n    var displayPriceMode = window.checkoutConfig.reviewItemPriceDisplayMode || 'including';\n\n    return subtotal.extend({\n        defaults: {\n            displayPriceMode: displayPriceMode,\n            template: 'Magento_Tax/checkout/summary/item/details/subtotal'\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isPriceInclTaxDisplayed: function () {\n            return displayPriceMode == 'both' || displayPriceMode == 'including'; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        isPriceExclTaxDisplayed: function () {\n            return displayPriceMode == 'both' || displayPriceMode == 'excluding'; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * @param {Object} quoteItem\n         * @return {*|String}\n         */\n        getValueInclTax: function (quoteItem) {\n            return this.getFormattedPrice(quoteItem['row_total_incl_tax']);\n        },\n\n        /**\n         * @param {Object} quoteItem\n         * @return {*|String}\n         */\n        getValueExclTax: function (quoteItem) {\n            return this.getFormattedPrice(quoteItem['row_total']);\n        }\n\n    });\n});\n","Magento_Tax/js/view/checkout/shipping_method/price.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\n\ndefine([\n    'uiComponent',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Catalog/js/price-utils'\n], function (Component, quote, priceUtils) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Magento_Tax/checkout/shipping_method/price'\n        },\n        isDisplayShippingPriceExclTax: window.checkoutConfig.isDisplayShippingPriceExclTax,\n        isDisplayShippingBothPrices: window.checkoutConfig.isDisplayShippingBothPrices,\n\n        /**\n         * @param {Object} item\n         * @return {Boolean}\n         */\n        isPriceEqual: function (item) {\n            return item['price_excl_tax'] != item['price_incl_tax']; //eslint-disable-line eqeqeq\n        },\n\n        /**\n         * @param {*} price\n         * @return {*|String}\n         */\n        getFormattedPrice: function (price) {\n            //todo add format data\n            return priceUtils.formatPriceLocale(price, quote.getPriceFormat());\n        }\n    });\n});\n","Magento_OrderCancellationUi/js/cancel-order-modal.js":"/**\n * Copyright 2023 Adobe\n * All Rights Reserved.\n */\ndefine([\n    'jquery',\n    'Magento_Ui/js/modal/modal',\n    'Magento_Customer/js/customer-data'\n],function ($, modal, customerData) {\n    'use strict';\n\n    return function (config, element) {\n        let order_id = config.order_id,\n            options = {\n                type: 'popup',\n                responsive: true,\n                title: 'Cancel Order',\n                buttons: [{\n                    text: $.mage.__('Close'),\n                    class: 'action-secondary action-dismiss close-modal-button',\n\n                    /** @inheritdoc */\n                    click: function () {\n                        this.closeModal();\n                    }\n                }, {\n                    text: $.mage.__('Confirm'),\n                    class: 'action-primary action-accept cancel-order-button',\n\n                    /** @inheritdoc */\n                    click: function () {\n                        let thisModal = this,\n                            reason = $('#cancel-order-reason-' + order_id).find(':selected').text(),\n                            mutation = `\nmutation cancelOrder($order_id: ID!, $reason: String!) {\n  cancelOrder(input: {order_id: $order_id, reason: $reason}) {\n    error\n    order {\n      status\n    }\n  }\n}`;\n\n                        $.ajax({\n                            showLoader: true,\n                            type: 'POST',\n                            url: `${config.url}graphql`,\n                            contentType: 'application/json',\n                            data: JSON.stringify({\n                                query: mutation,\n                                variables: {\n                                    'order_id': config.order_id,\n                                    'reason': reason\n                                }\n                            }),\n                            complete: function (response) {\n                                let type = 'success',\n                                    message;\n\n                                if (response.responseJSON.data.cancelOrder.error !== null) {\n                                    message = $.mage.__(response.responseJSON.data.cancelOrder.error);\n                                    type = 'error';\n                                } else {\n                                    message = $.mage.__(response.responseJSON.data.cancelOrder.order.status);\n                                    location.reload();\n                                }\n\n                                setTimeout(function () {\n                                    customerData.set('messages', {\n                                        messages: [{\n                                            text: message,\n                                            type: type\n                                        }]\n                                    });\n                                }, 1000);\n                            }\n                        }).always(function () {\n                            thisModal.closeModal(true);\n                        });\n                    }\n                }]\n            };\n\n        $(element).on('click', function () {\n            $('#cancel-order-modal-' + order_id).modal('openModal');\n        });\n\n        modal(options, $('#cancel-order-modal-' + order_id));\n    };\n});\n","Magento_Translation/js/add-class.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(['jquery'], function ($) {\n    'use strict';\n\n    return function (config, element) {\n        $(element).addClass(config.class);\n    };\n});\n","Magento_Translation/js/i18n-config.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n(function () {\n    'use strict';\n\n    require.config({\n        config: {\n            'Magento_Ui/js/lib/knockout/bindings/i18n': {\n                inlineTranslation: true\n            }\n        }\n    });\n})();\n","Magento_Translation/js/mage-translation-dictionary.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'text!js-translation.json'\n], function (dict) {\n    'use strict';\n\n    return JSON.parse(dict);\n});\n","Magento_CatalogSearch/js/search-terms-log.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mageUtils'\n], function ($, utils) {\n    'use strict';\n\n    return function (data) {\n        $.ajax({\n            method: 'GET',\n            url: data.url,\n            data: {\n                'q': utils.getUrlParameters(window.location.href).q\n            }\n        });\n    };\n});\n","Amasty_Rewards/js/guest-highlight.js":"define([\n    'uiComponent',\n    'mage/translate',\n], function (Component, $t) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Amasty_Rewards/guest-highlight',\n            captionStartText : $t('You can earn'),\n            captionAfterText: '',\n            captionRegistrationText: $t('for registration!'),\n            captionEndText: '',\n            frontend_class: '',\n            highlight: []\n        },\n\n        initObservable: function () {\n            this._super().observe([ 'highlight' ]);\n            if (this.highlight._latestValue.need_to_change_message === 1) {\n                this.captionAfterText = $t('for making a purchase! Available for');\n                this.captionRegistrationText = $t('registered');\n                this.captionEndText = $t('customers only.');\n            }\n\n            return this;\n        }\n    });\n});\n","Amasty_Rewards/js/amreward-points.js":"/*jshint browser:true jquery:true*/\ndefine([\n    \"jquery\",\n    \"Magento_Ui/js/modal/modal\"\n], function($){\n    \"use strict\";\n\n    $.widget('mage.amrewardPoints', {\n        options: {\n        },\n        _create: function () {\n            this.rewardAmount = $(this.options.rewardAmount);\n\n            this.removeReward = $(this.options.removeRewardSelector);\n\n            $(this.options.applyButton).on('click', $.proxy(function () {\n                this.rewardAmount.attr('data-validate', '{required:true}');\n\n                this.removeReward.attr('value', '0');\n                $(this.element).validation().submit();\n            }, this));\n\n            $(this.options.cancelButton).on('click', $.proxy(function () {\n                this.rewardAmount.removeAttr('data-validate');\n                this.removeReward.attr('value', '1');\n                this.element.submit();\n            }, this));\n\n            if (!this.isGreaterThanMinimumBalance()) {\n                this.getMinimumRewardNoteDOM().show();\n                this.disableRewardInput();\n\n            }\n        },\n\n        /**\n         *\n         * @returns {boolean}\n         */\n        isGreaterThanMinimumBalance: function () {\n            var realBalance = this.options.customerBalance;\n\n            if (this.options.usedPoints) {\n                realBalance += this.options.usedPoints;\n            }\n\n            return !this.options.minimumBalance || (realBalance >= this.options.minimumBalance);\n        },\n\n        /**\n         * @return void\n         */\n        disableRewardInput: function() {\n            $(this.options.applyButton).prop(\"disabled\", true);\n            $(this.options.rewardAmount).prop(\"disabled\", true);\n        },\n\n        /**\n         *\n         * @returns {*|jQuery|HTMLElement}\n         */\n        getMinimumRewardNoteDOM: function() {\n            return $(this.options.minimumNoteSelector);\n        }\n    });\n\n    return $.mage.amrewardPoints;\n});\n","Amasty_Rewards/js/action/cancel-reward.js":"/**\n * Customer store credit(balance) application\n */\ndefine([\n    'jquery',\n    'Magento_Checkout/js/model/quote',\n    'Magento_Checkout/js/model/url-builder',\n    'Magento_Checkout/js/model/error-processor',\n    'Amasty_Rewards/js/model/payment/reward-messages',\n    'mage/storage',\n    'Magento_Checkout/js/action/get-payment-information',\n    'Magento_Checkout/js/model/totals',\n    'mage/translate',\n    'Magento_Checkout/js/model/full-screen-loader'\n], function ($, quote, urlBuilder, errorProcessor, messageContainer, storage, getPaymentInformationAction, totals, $t,\n             fullScreenLoader\n) {\n    'use strict';\n\n    return function (isApplied) {\n        var url = urlBuilder.createUrl('/carts/mine/points/delete', {}),\n            message = $t('You Canceled Reward.');\n\n        messageContainer.clear();\n        fullScreenLoader.startLoader();\n\n        return storage.delete(\n            url,\n            false\n        ).done(function () {\n            var deferred = $.Deferred();\n\n            totals.isLoading(true);\n            getPaymentInformationAction(deferred);\n            $.when(deferred).done(function () {\n                isApplied(false);\n                totals.isLoading(false);\n                fullScreenLoader.stopLoader();\n            });\n            messageContainer.addSuccessMessage({\n                'message': message\n            });\n        }).fail(function (response) {\n            totals.isLoading(false);\n            fullScreenLoader.stopLoader();\n            errorProcessor.process(response, messageContainer);\n        });\n    };\n});","Amasty_Rewards/js/action/add-reward.js":"define([\n        'ko',\n        'jquery',\n        'Magento_Checkout/js/model/quote',\n        'Amasty_Rewards/js/model/resource-url-manager',\n        'Magento_Checkout/js/model/error-processor',\n        'Amasty_Rewards/js/model/payment/reward-messages',\n        'mage/storage',\n        'mage/translate',\n        'Magento_Checkout/js/action/get-payment-information',\n        'Magento_Checkout/js/model/totals',\n        'Magento_Checkout/js/model/full-screen-loader'\n    ], function (ko, $, quote, urlManager, errorProcessor, messageContainer,\n        storage, $t, getPaymentInformationAction, totals, fullScreenLoader\n    ) {\n        'use strict';\n        return function (points, isApplied, pointsLeftObs, rateForCurrency, noticeMessage) {\n            var quoteId = quote.getQuoteId(),\n                url = urlManager.getRewardsUrl(points(), quoteId);\n\n            messageContainer.clear();\n            fullScreenLoader.startLoader();\n\n            return storage.put(\n                url,\n                {},\n                false\n            ).done(function (response) {\n                var deferred,\n                    pointsUsed = 0;\n\n                if (response) {\n                    pointsUsed = response[1];\n                    noticeMessage($t(response[0]));\n                    $('[data-amrewards-js=\"notice-message\"]').show();\n                    setTimeout(function () {\n                        $('[data-amrewards-js=\"notice-message\"]').hide('blind', {}, 500);\n                    }, 5000);\n\n                    deferred = $.Deferred();\n\n                    if (pointsUsed > 0) {\n                        isApplied(true);\n                        totals.isLoading(true);\n                        getPaymentInformationAction(deferred);\n\n                        $.when(deferred).done(function () {\n                            points((pointsUsed).toFixed(2));\n                            pointsLeftObs((pointsLeftObs() - points()).toFixed(2));\n                            $('#amreward_amount').val(points()).change();\n\n                            fullScreenLoader.stopLoader();\n                            totals.isLoading(false);\n                        });\n                    }\n\n                    fullScreenLoader.stopLoader();\n                }\n            }).fail(function (response) {\n                fullScreenLoader.stopLoader();\n                totals.isLoading(false);\n                errorProcessor.process(response, messageContainer);\n            });\n        };\n    }\n);","Amasty_Rewards/js/view/balance.js":"define([\n    'uiComponent',\n    'Magento_Customer/js/customer-data'\n], function (Component, customerData) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            visible: false,\n            balance: 0,\n            captionText: false\n        },\n\n        initObservable: function () {\n            this._super().observe('visible balance captionText');\n\n            return this;\n        },\n\n        initialize: function () {\n            this._super();\n            var rewardsData = customerData.get('rewards');\n\n            if (rewardsData().balance) {\n                this.balance(rewardsData().balance);\n            }\n\n            rewardsData.subscribe(function (rewardsData) {\n                this.balance(rewardsData.balance);\n            }.bind(this));\n\n            this.visible(true);\n        },\n    });\n});\n","Amasty_Rewards/js/view/checkout/payment/rewards.js":"define([\n    'jquery',\n    'underscore',\n    'uiComponent',\n    'Magento_Checkout/js/model/quote',\n    'Amasty_Rewards/js/action/add-reward',\n    'Amasty_Rewards/js/action/cancel-reward',\n    'Amasty_Rewards/vendor/tooltipster/js/tooltipster.min',\n    'Magento_Ui/js/model/messageList',\n    'mage/translate'\n], function (\n    $,\n    _,\n    Component,\n    quote,\n    setRewardPointAction,\n    cancelRewardPointAction,\n    tooltipster,\n    messageList,\n    $t\n) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Amasty_Rewards/checkout/payment/rewards',\n            isApplied: false,\n            pointsUsed: 0,\n            pointsLeft: 0,\n            noticeMessage: '',\n            minimumPointsValue: 0,\n            disableElem: false,\n            isRewardsTooltipEnabled: false,\n            rewardsTooltipContent: '',\n            selectors: {\n                tooltipElement: '[data-amrewards-js=\"tooltip\"]'\n            }\n        },\n\n        initObservable: function () {\n            this._super();\n            this.observe(['pointsUsed', 'pointsLeft', 'isApplied', 'noticeMessage', 'disableElem']);\n\n            return this;\n        },\n\n        /**\n         * @return {exports}\n         */\n        initialize: function () {\n            this._super();\n            this.isApplied(false);\n\n            if (this.pointsUsed() > 0) {\n                this.isApplied(true);\n            }\n\n            if (_.isUndefined(Number.parseFloat)) {\n                Number.parseFloat = parseFloat;\n            }\n\n            if (this.getMinimumPointsValue() > this.pointsLeft() + Number.parseFloat(this.pointsUsed())) {\n                this.disableElem(true);\n            }\n\n            this.initTooltip();\n\n            return this;\n        },\n\n        /**\n         * @return {*|Boolean}\n         */\n        isDisplayed: function () {\n            return this.customerId;\n        },\n\n        /**\n         * Coupon code application procedure\n         */\n        apply: function () {\n            if (this.validate()) {\n                setRewardPointAction(this.pointsUsed, this.isApplied, this.pointsLeft, this.rateForCurrency, this.noticeMessage);\n            }\n        },\n\n        /**\n         * Cancel using coupon\n         */\n        cancel: function () {\n            cancelRewardPointAction(this.isApplied);\n            this.pointsLeft((Number.parseFloat(this.pointsLeft()) + Number.parseFloat(this.pointsUsed())).toFixed(2));\n        },\n\n        /**\n         *\n         * @return {*}\n         */\n        getRewardsCount: function () {\n            return this.pointsLeft();\n        },\n\n        /**\n         *\n         * @return {*}\n         */\n        getPointsRate: function () {\n            return this.pointsRate;\n        },\n\n        /**\n         *\n         * @return {*}\n         */\n        getCurrentCurrency: function () {\n            return this.currentCurrencyCode;\n        },\n\n        /**\n         *\n         * @return {*}\n         */\n        getRateForCurrency: function () {\n            return this.rateForCurrency;\n        },\n\n        /**\n         * @return {*}\n         */\n        getMinimumPointsValue: function () {\n            return Number.parseFloat(this.minimumPointsValue);\n        },\n\n        /**\n         * @return {Boolean}\n         */\n        canApply: function () {\n            return !(this.disableElem() || this.isApplied());\n        },\n\n        /**\n         * Coupon form validation\n         *\n         * @returns {Boolean}\n         */\n        validate: function () {\n            var form = '#discount-reward-form',\n                valueValid = (this.pointsLeft() - this.pointsUsed() >= 0) && this.pointsUsed() > 0;\n\n            if ($(form).validation() && $(form).validation('isValid') && valueValid) {\n                return true;\n            }\n\n            messageList.addErrorMessage({\n                message: $t('Points \"' + this.pointsUsed() +'\" not valid.')\n            });\n\n            return false;\n        },\n\n        initTooltip: function () {\n            var tooltipTrigger = this.isTouchDevice() ? 'click' : 'hover';\n\n            if (!this.isRewardsTooltipEnabled) {\n                return;\n            }\n\n            $.async(this.selectors.tooltipElement, function () {\n                $(this.selectors.tooltipElement).tooltipster({\n                    position: 'right',\n                    contentAsHtml: true,\n                    interactive: true,\n                    trigger: tooltipTrigger\n                });\n            }.bind(this));\n        },\n\n        isTouchDevice: function () {\n            return ('ontouchstart' in window)\n                || (navigator.maxTouchPoints > 0)\n                || (navigator.msMaxTouchPoints > 0);\n        }\n    });\n});\n","Amasty_Rewards/js/view/checkout/payment/reward-messages.js":"define([\n    'Magento_Ui/js/view/messages',\n    'Amasty_Rewards/js/model/payment/reward-messages'\n], function (Component, messageContainer) {\n    'use strict';\n\n    return Component.extend({\n        /** @inheritdoc */\n        initialize: function (config) {\n            return this._super(config, messageContainer);\n        }\n    });\n});","Amasty_Rewards/js/model/resource-url-manager.js":"define([\n        'Magento_Customer/js/model/customer',\n        'Magento_Checkout/js/model/url-builder',\n        'mageUtils',\n        'mage/url',\n        'mage/translate'\n    ], function (customer, urlBuilder, utils, url, $t) {\n        'use strict';\n\n        return {\n\n            /**\n             * @param {String} points\n             * @return {*}\n             */\n            getRewardsUrl: function (points) {\n                var params = {},\n                    url = {\n                        'customer': '/carts/mine/points/' + encodeURIComponent(points)\n                    };\n\n                return this.getUrl(url, params);\n            },\n\n            /**\n             * @return {String}\n             */\n            getCheckoutMethod: function () {\n                return 'customer';\n            },\n\n            /**\n             * Get url for service.\n             *\n             * @param {*} url\n             * @param {*} urlParams\n             * @return {String|*}\n             */\n            getUrl: function (url, urlParams) {\n                var finalUrl;\n\n                if (utils.isEmpty(url)) {\n                    return $t('Provided service call does not exist.');\n                }\n\n                if (!utils.isEmpty(url['default'])) {\n                    finalUrl = url['default'];\n                } else {\n                    finalUrl = url[this.getCheckoutMethod()];\n                }\n\n                return urlBuilder.createUrl(finalUrl, urlParams);\n            }\n        };\n    }\n);\n","Amasty_Rewards/js/model/totals/highlight.js":"define([\n    'uiComponent',\n    'Magento_Checkout/js/model/totals',\n    'mage/translate',\n], function (Component, totals, $t) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            template: 'Amasty_Rewards/highlight',\n            captionEndText: $t('for completing your purchase!'),\n            captionStartText : $t('You can earn'),\n            frontend_class: '',\n            highlight: []\n        },\n\n        /**\n         * @return {Object}\n         */\n        initObservable: function () {\n            this._super().observe(['highlight']);\n            totals.totals.subscribe(this.getHighlightData.bind(this));\n\n            return this;\n        },\n\n        /**\n         * @param totals {Object}\n         * @return {void}\n         */\n        getHighlightData: function (totals) {\n            let totalsAttributes = totals.extension_attributes;\n\n            if (totalsAttributes && totalsAttributes.amasty_rewards_highlight) {\n                this.highlight(totalsAttributes.amasty_rewards_highlight);\n            } else {\n                this.highlight({'visible': false});\n            }\n        },\n    });\n});\n","Amasty_Rewards/js/model/payment/reward-messages.js":"define([\n    'Magento_Ui/js/model/messages'\n], function (Messages) {\n    'use strict';\n\n    return new Messages();\n});","Amasty_Rewards/js/model/catalog/highlight-product.js":"define([\n    'jquery',\n    'uiComponent',\n    'mage/translate',\n    'mage/storage',\n], function ($, Component, $t, storage) {\n    'use strict';\n    var xhr = null;\n\n    return Component.extend({\n        defaults: {\n            template: 'Amasty_Rewards/highlight',\n            captionEndText: $t('for buying this product!'),\n            captionStartText : $t('You can earn'),\n            productId : 0,\n            refreshUrl: false,\n            loader: false,\n            formSelector: '#product_addtocart_form',\n            frontend_class: '',\n            highlight: {\n                visible: false\n            }\n        },\n\n        initObservable: function () {\n            this._super().observe(['highlight', 'loader']);\n            this.updateData();\n            $(this.formSelector).change(this.updateData.bind(this));\n\n            return this;\n        },\n\n        hide: function () {\n            this.highlight({'visible':false});\n\n            return this;\n        },\n\n        updateData: function () {\n            if (xhr) {\n                xhr.abort();\n            }\n            this.hide().loader(true);\n\n            xhr = storage.post(this.refreshUrl,\n                JSON.stringify({\n                    productId: this.productId,\n                    attributes: $(this.formSelector).serialize()\n                }),\n                false\n            ).done(function (result) {\n                if (result) {\n                    this.highlight(result);\n                }\n            }.bind(this)).always(function () {\n                this.loader(false);\n                xhr = null;\n            }.bind(this));\n        },\n    });\n});\n","Amasty_Rewards/js/model/catalog/highlight-category.js":"define([\n    'jquery',\n    'uiComponent',\n    'mage/translate',\n    'mage/storage',\n], function ($, Component, $t, storage) {\n    'use strict';\n    var xhr = {};\n\n    return Component.extend({\n        defaults: {\n            template: 'Amasty_Rewards/highlight-category',\n            captionEndText: '',\n            captionStartText: $t('Earn'),\n            productId: 0,\n            refreshUrl: false,\n            loader: false,\n            formSelector: false,\n            frontend_class: '',\n            highlight: {\n                visible: false\n            }\n        },\n\n        initObservable: function () {\n            this._super().observe(['highlight', 'loader']);\n\n            if (this.refreshUrl) {\n                this.updateData();\n                $(this.formSelector).change(this.updateData.bind(this));\n            }\n\n            return this;\n        },\n\n        hide: function () {\n            this.highlight({'visible': false});\n\n            return this;\n        },\n\n        updateData: function () {\n            if (xhr.hasOwnProperty(this.productId)) {\n                xhr[this.productId].abort();\n            }\n            this.hide().loader(true);\n\n            xhr[this.productId] = storage.post(this.refreshUrl,\n                JSON.stringify({\n                    productId: this.productId,\n                    attributes: $(this.formSelector).serialize()\n                }),\n                false\n            ).done(function (result) {\n                if (result) {\n                    this.highlight(result);\n                }\n            }.bind(this)).always(function () {\n                this.loader(false);\n                delete xhr[this.productId];\n            }.bind(this));\n        },\n    });\n});\n","Amasty_Rewards/js/model/catalog/guest-highlight-category.js":"define([\n    'jquery',\n    'uiComponent',\n    'mage/translate',\n    'mage/storage',\n], function ($, Component, $t, storage) {\n    'use strict';\n    var xhr = {};\n\n    return Component.extend({\n        defaults: {\n            template: 'Amasty_Rewards/guest-highlight',\n            captionStartText: $t('You can earn'),\n            captionAfterText: '',\n            captionRegistrationText: $t('for registration!'),\n            captionEndText: '',\n            productId: 0,\n            refreshUrl: false,\n            loader: false,\n            formSelector: false,\n            frontend_class: '',\n            highlight: {\n                visible: false\n            }\n        },\n\n        initObservable: function () {\n            this._super().observe([ 'highlight', 'loader' ]);\n\n            if (this.refreshUrl) {\n                this.updateData();\n                $(this.formSelector).change(this.updateData.bind(this));\n            }\n\n            return this;\n        },\n\n        hide: function () {\n            this.highlight({ 'visible': false });\n\n            return this;\n        },\n\n        updateData: function () {\n            if (xhr.hasOwnProperty(this.productId)) {\n                xhr[this.productId].abort();\n            }\n            this.hide().loader(true);\n\n            xhr[this.productId] = storage.post(this.refreshUrl,\n                JSON.stringify({\n                    page: 3,\n                    productId: this.productId,\n                    attributes: $(this.formSelector).serialize()\n                }),\n                false\n            ).done(function (result) {\n                if (result) {\n                    if (result.need_to_change_message === 1) {\n                        this.captionAfterText = $t('for making a purchase! Available for');\n                        this.captionRegistrationText = $t('registered');\n                        this.captionEndText = $t('customers only.');\n                    }\n                    this.highlight(result);\n                }\n            }.bind(this)).always(function () {\n                this.loader(false);\n                delete xhr[this.productId];\n            }.bind(this));\n        }\n    });\n});\n","Amasty_Rewards/js/model/catalog/guest-highlight-product.js":"define([\n    'jquery',\n    'uiComponent',\n    'mage/translate',\n    'mage/storage',\n], function ($, Component, $t, storage) {\n    'use strict';\n    var xhr = null;\n\n    return Component.extend({\n        defaults: {\n            template: 'Amasty_Rewards/guest-highlight',\n            captionStartText: $t('You can earn'),\n            captionAfterText: '',\n            captionRegistrationText: $t('for registration!'),\n            captionEndText: '',\n            productId: 0,\n            refreshUrl: false,\n            loader: false,\n            formSelector: '#product_addtocart_form',\n            frontend_class: '',\n            highlight: {\n                visible: false\n            }\n        },\n\n        initObservable: function () {\n            this._super().observe([ 'highlight', 'loader' ]);\n            this.updateData();\n            $(this.formSelector).change(this.updateData.bind(this));\n\n            return this;\n        },\n\n        hide: function () {\n            this.highlight({ 'visible':false });\n\n            return this;\n        },\n\n        updateData: function () {\n            if (xhr) {\n                xhr.abort();\n            }\n            this.hide().loader(true);\n\n            xhr = storage.post(this.refreshUrl,\n                JSON.stringify({\n                    page: 0,\n                    productId: this.productId,\n                    attributes: $(this.formSelector).serialize()\n                }),\n                false\n            ).done(function (result) {\n                if (result) {\n                    if (result.need_to_change_message === 1) {\n                        this.captionAfterText = $t('for making a purchase! Available for');\n                        this.captionRegistrationText = $t('registered');\n                        this.captionEndText = $t('customers only.');\n                    }\n                    this.highlight(result);\n                }\n            }.bind(this)).always(function () {\n                this.loader(false);\n                xhr = null;\n            }.bind(this));\n        }\n    });\n});\n","Amasty_Rewards/vendor/tooltipster/js/tooltipster.js":"/**\n * tooltipster http://calebjacob.github.io/tooltipster/\n * A rockin' custom tooltip jQuery plugin\n * Developed by Caleb Jacob and Louis Ameline\n * MIT license\n */\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function ($) {\n\n// This file will be UMDified by a build task.\n\nvar defaults = {\n\t\tanimation: 'fade',\n\t\tanimationDuration: 350,\n\t\tcontent: null,\n\t\tcontentAsHTML: false,\n\t\tcontentCloning: false,\n\t\tdebug: true,\n\t\tdelay: 300,\n\t\tdelayTouch: [300, 500],\n\t\tfunctionInit: null,\n\t\tfunctionBefore: null,\n\t\tfunctionReady: null,\n\t\tfunctionAfter: null,\n\t\tfunctionFormat: null,\n\t\tIEmin: 6,\n\t\tinteractive: false,\n\t\tmultiple: false,\n\t\t// will default to document.body, or must be an element positioned at (0, 0)\n\t\t// in the document, typically like the very top views of an app.\n\t\tparent: null,\n\t\tplugins: ['sideTip'],\n\t\trepositionOnScroll: false,\n\t\trestoration: 'none',\n\t\tselfDestruction: true,\n\t\ttheme: [],\n\t\ttimer: 0,\n\t\ttrackerInterval: 500,\n\t\ttrackOrigin: false,\n\t\ttrackTooltip: false,\n\t\ttrigger: 'hover',\n\t\ttriggerClose: {\n\t\t\tclick: false,\n\t\t\tmouseleave: false,\n\t\t\toriginClick: false,\n\t\t\tscroll: false,\n\t\t\ttap: false,\n\t\t\ttouchleave: false\n\t\t},\n\t\ttriggerOpen: {\n\t\t\tclick: false,\n\t\t\tmouseenter: false,\n\t\t\ttap: false,\n\t\t\ttouchstart: false\n\t\t},\n\t\tupdateAnimation: 'rotate',\n\t\tzIndex: 9999999,\n        styles: {\n            backgroundColor: '',\n            textColor: ''\n        }\n\t},\n\t// we'll avoid using the 'window' global as a good practice but npm's\n\t// jquery@<2.1.0 package actually requires a 'window' global, so not sure\n\t// it's useful at all\n\twin = (typeof window != 'undefined') ? window : null,\n\t// env will be proxied by the core for plugins to have access its properties\n\tenv = {\n\t\t// detect if this device can trigger touch events. Better have a false\n\t\t// positive (unused listeners, that's ok) than a false negative.\n\t\t// https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js\n\t\t// http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript\n\t\thasTouchCapability: !!(\n\t\t\twin\n\t\t\t&&\t(\t'ontouchstart' in win\n\t\t\t\t||\t(win.DocumentTouch && win.document instanceof win.DocumentTouch)\n\t\t\t\t||\twin.navigator.maxTouchPoints\n\t\t\t)\n\t\t),\n\t\thasTransitions: transitionSupport(),\n\t\tIE: false,\n\t\t// don't set manually, it will be updated by a build task after the manifest\n\t\tsemVer: '4.2.8',\n\t\twindow: win\n\t},\n\tcore = function() {\n\n\t\t// core variables\n\n\t\t// the core emitters\n\t\tthis.__$emitterPrivate = $({});\n\t\tthis.__$emitterPublic = $({});\n\t\tthis.__instancesLatestArr = [];\n\t\t// collects plugin constructors\n\t\tthis.__plugins = {};\n\t\t// proxy env variables for plugins who might use them\n\t\tthis._env = env;\n\t};\n\n// core methods\ncore.prototype = {\n\n\t/**\n\t * A function to proxy the public methods of an object onto another\n\t *\n\t * @param {object} constructor The constructor to bridge\n\t * @param {object} obj The object that will get new methods (an instance or the core)\n\t * @param {string} pluginName A plugin name for the console log message\n\t * @return {core}\n\t * @private\n\t */\n\t__bridge: function(constructor, obj, pluginName) {\n\n\t\t// if it's not already bridged\n\t\tif (!obj[pluginName]) {\n\n\t\t\tvar fn = function() {};\n\t\t\tfn.prototype = constructor;\n\n\t\t\tvar pluginInstance = new fn();\n\n\t\t\t// the _init method has to exist in instance constructors but might be missing\n\t\t\t// in core constructors\n\t\t\tif (pluginInstance.__init) {\n\t\t\t\tpluginInstance.__init(obj);\n\t\t\t}\n\n\t\t\t$.each(constructor, function(methodName, fn) {\n\n\t\t\t\t// don't proxy \"private\" methods, only \"protected\" and public ones\n\t\t\t\tif (methodName.indexOf('__') != 0) {\n\n\t\t\t\t\t// if the method does not exist yet\n\t\t\t\t\tif (!obj[methodName]) {\n\n\t\t\t\t\t\tobj[methodName] = function() {\n\t\t\t\t\t\t\treturn pluginInstance[methodName].apply(pluginInstance, Array.prototype.slice.apply(arguments));\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// remember to which plugin this method corresponds (several plugins may\n\t\t\t\t\t\t// have methods of the same name, we need to be sure)\n\t\t\t\t\t\tobj[methodName].bridged = pluginInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if (defaults.debug) {\n\n\t\t\t\t\t\tconsole.log('The '+ methodName +' method of the '+ pluginName\n\t\t\t\t\t\t\t+' plugin conflicts with another plugin or native methods');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tobj[pluginName] = pluginInstance;\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * For mockup in Node env if need be, for testing purposes\n\t *\n\t * @return {core}\n\t * @private\n\t */\n\t__setWindow: function(window) {\n\t\tenv.window = window;\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns a ruler, a tool to help measure the size of a tooltip under\n\t * various settings. Meant for plugins\n\t *\n\t * @see Ruler\n\t * @return {object} A Ruler instance\n\t * @protected\n\t */\n\t_getRuler: function($tooltip) {\n\t\treturn new Ruler($tooltip);\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @return {core}\n\t * @protected\n\t */\n\t_off: function() {\n\t\tthis.__$emitterPrivate.off.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @return {core}\n\t * @protected\n\t */\n\t_on: function() {\n\t\tthis.__$emitterPrivate.on.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @return {core}\n\t * @protected\n\t */\n\t_one: function() {\n\t\tthis.__$emitterPrivate.one.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns (getter) or adds (setter) a plugin\n\t *\n\t * @param {string|object} plugin Provide a string (in the full form\n\t * \"namespace.name\") to use as as getter, an object to use as a setter\n\t * @return {object|core}\n\t * @protected\n\t */\n\t_plugin: function(plugin) {\n\n\t\tvar self = this;\n\n\t\t// getter\n\t\tif (typeof plugin == 'string') {\n\n\t\t\tvar pluginName = plugin,\n\t\t\t\tp = null;\n\n\t\t\t// if the namespace is provided, it's easy to search\n\t\t\tif (pluginName.indexOf('.') > 0) {\n\t\t\t\tp = self.__plugins[pluginName];\n\t\t\t}\n\t\t\t// otherwise, return the first name that matches\n\t\t\telse {\n\t\t\t\t$.each(self.__plugins, function(i, plugin) {\n\n\t\t\t\t\tif (plugin.name.substring(plugin.name.length - pluginName.length - 1) == '.'+ pluginName) {\n\t\t\t\t\t\tp = plugin;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn p;\n\t\t}\n\t\t// setter\n\t\telse {\n\n\t\t\t// force namespaces\n\t\t\tif (plugin.name.indexOf('.') < 0) {\n\t\t\t\tthrow new Error('Plugins must be namespaced');\n\t\t\t}\n\n\t\t\tself.__plugins[plugin.name] = plugin;\n\n\t\t\t// if the plugin has core features\n\t\t\tif (plugin.core) {\n\n\t\t\t\t// bridge non-private methods onto the core to allow new core methods\n\t\t\t\tself.__bridge(plugin.core, self, plugin.name);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t},\n\n\t/**\n\t * Trigger events on the core emitters\n\t *\n\t * @returns {core}\n\t * @protected\n\t */\n\t_trigger: function() {\n\n\t\tvar args = Array.prototype.slice.apply(arguments);\n\n\t\tif (typeof args[0] == 'string') {\n\t\t\targs[0] = { type: args[0] };\n\t\t}\n\n\t\t// note: the order of emitters matters\n\t\tthis.__$emitterPrivate.trigger.apply(this.__$emitterPrivate, args);\n\t\tthis.__$emitterPublic.trigger.apply(this.__$emitterPublic, args);\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns instances of all tooltips in the page or an a given element\n\t *\n\t * @param {string|HTML object collection} selector optional Use this\n\t * parameter to restrict the set of objects that will be inspected\n\t * for the retrieval of instances. By default, all instances in the\n\t * page are returned.\n\t * @return {array} An array of instance objects\n\t * @public\n\t */\n\tinstances: function(selector) {\n\n\t\tvar instances = [],\n\t\t\tsel = selector || '.tooltipstered';\n\n\t\t$(sel).each(function() {\n\n\t\t\tvar $this = $(this),\n\t\t\t\tns = $this.data('tooltipster-ns');\n\n\t\t\tif (ns) {\n\n\t\t\t\t$.each(ns, function(i, namespace) {\n\t\t\t\t\tinstances.push($this.data(namespace));\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\treturn instances;\n\t},\n\n\t/**\n\t * Returns the Tooltipster objects generated by the last initializing call\n\t *\n\t * @return {array} An array of instance objects\n\t * @public\n\t */\n\tinstancesLatest: function() {\n\t\treturn this.__instancesLatestArr;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins (use ::_off() instead)\n\t *\n\t * @return {core}\n\t * @public\n\t */\n\toff: function() {\n\t\tthis.__$emitterPublic.off.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins (use ::_on() instead)\n\t *\n\t * @return {core}\n\t * @public\n\t */\n\ton: function() {\n\t\tthis.__$emitterPublic.on.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins (use ::_one() instead)\n\t *\n\t * @return {core}\n\t * @public\n\t */\n\tone: function() {\n\t\tthis.__$emitterPublic.one.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns all HTML elements which have one or more tooltips\n\t *\n\t * @param {string} selector optional Use this to restrict the results\n\t * to the descendants of an element\n\t * @return {array} An array of HTML elements\n\t * @public\n\t */\n\torigins: function(selector) {\n\n\t\tvar sel = selector ?\n\t\t\tselector +' ' :\n\t\t\t'';\n\n\t\treturn $(sel +'.tooltipstered').toArray();\n\t},\n\n\t/**\n\t * Change default options for all future instances\n\t *\n\t * @param {object} d The options that should be made defaults\n\t * @return {core}\n\t * @public\n\t */\n\tsetDefaults: function(d) {\n\t\t$.extend(defaults, d);\n\t\treturn this;\n\t},\n\n\t/**\n\t * For users to trigger their handlers on the public emitter\n\t *\n\t * @returns {core}\n\t * @public\n\t */\n\ttriggerHandler: function() {\n\t\tthis.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t}\n};\n\n// $.tooltipster will be used to call core methods\n$.tooltipster = new core();\n\n// the Tooltipster instance class (mind the capital T)\n$.Tooltipster = function(element, options) {\n\n\t// list of instance variables\n\n\t// stack of custom callbacks provided as parameters to API methods\n\tthis.__callbacks = {\n\t\tclose: [],\n\t\topen: []\n\t};\n\t// the schedule time of DOM removal\n\tthis.__closingTime;\n\t// this will be the user content shown in the tooltip. A capital \"C\" is used\n\t// because there is also a method called content()\n\tthis.__Content;\n\t// for the size tracker\n\tthis.__contentBcr;\n\t// to disable the tooltip after destruction\n\tthis.__destroyed = false;\n\t// we can't emit directly on the instance because if a method with the same\n\t// name as the event exists, it will be called by jQuery. Se we use a plain\n\t// object as emitter. This emitter is for internal use by plugins,\n\t// if needed.\n\tthis.__$emitterPrivate = $({});\n\t// this emitter is for the user to listen to events without risking to mess\n\t// with our internal listeners\n\tthis.__$emitterPublic = $({});\n\tthis.__enabled = true;\n\t// the reference to the gc interval\n\tthis.__garbageCollector;\n\t// various position and size data recomputed before each repositioning\n\tthis.__Geometry;\n\t// the tooltip position, saved after each repositioning by a plugin\n\tthis.__lastPosition;\n\t// a unique namespace per instance\n\tthis.__namespace = 'tooltipster-'+ Math.round(Math.random()*1000000);\n\tthis.__options;\n\t// will be used to support origins in scrollable areas\n\tthis.__$originParents;\n\tthis.__pointerIsOverOrigin = false;\n\t// to remove themes if needed\n\tthis.__previousThemes = [];\n\t// the state can be either: appearing, stable, disappearing, closed\n\tthis.__state = 'closed';\n\t// timeout references\n\tthis.__timeouts = {\n\t\tclose: [],\n\t\topen: null\n\t};\n\t// store touch events to be able to detect emulated mouse events\n\tthis.__touchEvents = [];\n\t// the reference to the tracker interval\n\tthis.__tracker = null;\n\t// the element to which this tooltip is associated\n\tthis._$origin;\n\t// this will be the tooltip element (jQuery wrapped HTML element).\n\t// It's the job of a plugin to create it and append it to the DOM\n\tthis._$tooltip;\n\n\t// launch\n\tthis.__init(element, options);\n};\n\n$.Tooltipster.prototype = {\n\n\t/**\n\t * @param origin\n\t * @param options\n\t * @private\n\t */\n\t__init: function(origin, options) {\n\n\t\tvar self = this;\n\n\t\tself._$origin = $(origin);\n\t\tself.__options = $.extend(true, {}, defaults, options);\n\n\t\t// some options may need to be reformatted\n\t\tself.__optionsFormat();\n\n\t\t// don't run on old IE if asked no to\n\t\tif (\t!env.IE\n\t\t\t||\tenv.IE >= self.__options.IEmin\n\t\t) {\n\n\t\t\t// note: the content is null (empty) by default and can stay that\n\t\t\t// way if the plugin remains initialized but not fed any content. The\n\t\t\t// tooltip will just not appear.\n\n\t\t\t// let's save the initial value of the title attribute for later\n\t\t\t// restoration if need be.\n\t\t\tvar initialTitle = null;\n\n\t\t\t// it will already have been saved in case of multiple tooltips\n\t\t\tif (self._$origin.data('tooltipster-initialTitle') === undefined) {\n\n\t\t\t\tinitialTitle = self._$origin.attr('title');\n\n\t\t\t\t// we do not want initialTitle to be \"undefined\" because\n\t\t\t\t// of how jQuery's .data() method works\n\t\t\t\tif (initialTitle === undefined) initialTitle = null;\n\n\t\t\t\tself._$origin.data('tooltipster-initialTitle', initialTitle);\n\t\t\t}\n\n\t\t\t// If content is provided in the options, it has precedence over the\n\t\t\t// title attribute.\n\t\t\t// Note: an empty string is considered content, only 'null' represents\n\t\t\t// the absence of content.\n\t\t\t// Also, an existing title=\"\" attribute will result in an empty string\n\t\t\t// content\n\t\t\tif (self.__options.content !== null) {\n\t\t\t\tself.__contentSet(self.__options.content);\n\t\t\t}\n\t\t\telse {\n\n\t\t\t\tvar selector = self._$origin.attr('data-tooltip-content'),\n\t\t\t\t\t$el;\n\n\t\t\t\tif (selector){\n\t\t\t\t\t$el = $(selector);\n\t\t\t\t}\n\n\t\t\t\tif ($el && $el[0]) {\n\t\t\t\t\tself.__contentSet($el.first());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tself.__contentSet(initialTitle);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tself._$origin\n\t\t\t\t// strip the title off of the element to prevent the default tooltips\n\t\t\t\t// from popping up\n\t\t\t\t.removeAttr('title')\n\t\t\t\t// to be able to find all instances on the page later (upon window\n\t\t\t\t// events in particular)\n\t\t\t\t.addClass('tooltipstered');\n\n\t\t\t// set listeners on the origin\n\t\t\tself.__prepareOrigin();\n\n\t\t\t// set the garbage collector\n\t\t\tself.__prepareGC();\n\n\t\t\t// init plugins\n\t\t\t$.each(self.__options.plugins, function(i, pluginName) {\n\t\t\t\tself._plug(pluginName);\n\t\t\t});\n\n\t\t\t// to detect swiping\n\t\t\tif (env.hasTouchCapability) {\n\t\t\t\t$(env.window.document.body).on('touchmove.'+ self.__namespace +'-triggerOpen', function(event) {\n\t\t\t\t\tself._touchRecordEvent(event);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tself\n\t\t\t\t// prepare the tooltip when it gets created. This event must\n\t\t\t\t// be fired by a plugin\n\t\t\t\t._on('created', function() {\n\t\t\t\t\tself.__prepareTooltip();\n\t\t\t\t})\n\t\t\t\t// save position information when it's sent by a plugin\n\t\t\t\t._on('repositioned', function(e) {\n\t\t\t\t\tself.__lastPosition = e.position;\n\t\t\t\t});\n\t\t}\n\t\telse {\n\t\t\tself.__options.disabled = true;\n\t\t}\n\t},\n\n\t/**\n\t * Insert the content into the appropriate HTML element of the tooltip\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__contentInsert: function() {\n\n\t\tvar self = this,\n\t\t\t$el = self._$tooltip.find('.tooltipster-content'),\n\t\t\tformattedContent = self.__Content,\n\t\t\tformat = function(content) {\n\t\t\t\tformattedContent = content;\n\t\t\t};\n\n\t\tself._trigger({\n\t\t\ttype: 'format',\n\t\t\tcontent: self.__Content,\n\t\t\tformat: format\n\t\t});\n\n\t\tif (self.__options.functionFormat) {\n\n\t\t\tformattedContent = self.__options.functionFormat.call(\n\t\t\t\tself,\n\t\t\t\tself,\n\t\t\t\t{ origin: self._$origin[0] },\n\t\t\t\tself.__Content\n\t\t\t);\n\t\t}\n\n\t\tif (typeof formattedContent === 'string' && !self.__options.contentAsHTML) {\n\t\t\t$el.text(formattedContent);\n\t\t}\n\t\telse {\n\t\t\t$el\n\t\t\t\t.empty()\n\t\t\t\t.append(formattedContent);\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Save the content, cloning it beforehand if need be\n\t *\n\t * @param content\n\t * @returns {self}\n\t * @private\n\t */\n\t__contentSet: function(content) {\n\n\t\t// clone if asked. Cloning the object makes sure that each instance has its\n\t\t// own version of the content (in case a same object were provided for several\n\t\t// instances)\n\t\t// reminder: typeof null === object\n\t\tif (content instanceof $ && this.__options.contentCloning) {\n\t\t\tcontent = content.clone(true);\n\t\t}\n\n\t\tthis.__Content = content;\n\n\t\tthis._trigger({\n\t\t\ttype: 'updated',\n\t\t\tcontent: content\n\t\t});\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Error message about a method call made after destruction\n\t *\n\t * @private\n\t */\n\t__destroyError: function() {\n\t\tthrow new Error('This tooltip has been destroyed and cannot execute your method call.');\n\t},\n\n\t/**\n\t * Gather all information about dimensions and available space,\n\t * called before every repositioning\n\t *\n\t * @private\n\t * @returns {object}\n\t */\n\t__geometry: function() {\n\n\t\tvar\tself = this,\n\t\t\t$target = self._$origin,\n\t\t\toriginIsArea = self._$origin.is('area');\n\n\t\t// if this._$origin is a map area, the target we'll need\n\t\t// the dimensions of is actually the image using the map,\n\t\t// not the area itself\n\t\tif (originIsArea) {\n\n\t\t\tvar mapName = self._$origin.parent().attr('name');\n\n\t\t\t$target = $('img[usemap=\"#'+ mapName +'\"]');\n\t\t}\n\n\t\tvar bcr = $target[0].getBoundingClientRect(),\n\t\t\t$document = $(env.window.document),\n\t\t\t$window = $(env.window),\n\t\t\t$parent = $target,\n\t\t\t// some useful properties of important elements\n\t\t\tgeo = {\n\t\t\t\t// available space for the tooltip, see down below\n\t\t\t\tavailable: {\n\t\t\t\t\tdocument: null,\n\t\t\t\t\twindow: null\n\t\t\t\t},\n\t\t\t\tdocument: {\n\t\t\t\t\tsize: {\n\t\t\t\t\t\theight: $document.height(),\n\t\t\t\t\t\twidth: $document.width()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\twindow: {\n\t\t\t\t\tscroll: {\n\t\t\t\t\t\t// the second ones are for IE compatibility\n\t\t\t\t\t\tleft: env.window.scrollX || env.window.document.documentElement.scrollLeft,\n\t\t\t\t\t\ttop: env.window.scrollY || env.window.document.documentElement.scrollTop\n\t\t\t\t\t},\n\t\t\t\t\tsize: {\n\t\t\t\t\t\theight: $window.height(),\n\t\t\t\t\t\twidth: $window.width()\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\torigin: {\n\t\t\t\t\t// the origin has a fixed lineage if itself or one of its\n\t\t\t\t\t// ancestors has a fixed position\n\t\t\t\t\tfixedLineage: false,\n\t\t\t\t\t// relative to the document\n\t\t\t\t\toffset: {},\n\t\t\t\t\tsize: {\n\t\t\t\t\t\theight: bcr.bottom - bcr.top,\n\t\t\t\t\t\twidth: bcr.right - bcr.left\n\t\t\t\t\t},\n\t\t\t\t\tusemapImage: originIsArea ? $target[0] : null,\n\t\t\t\t\t// relative to the window\n\t\t\t\t\twindowOffset: {\n\t\t\t\t\t\tbottom: bcr.bottom,\n\t\t\t\t\t\tleft: bcr.left,\n\t\t\t\t\t\tright: bcr.right,\n\t\t\t\t\t\ttop: bcr.top\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tgeoFixed = false;\n\n\t\t// if the element is a map area, some properties may need\n\t\t// to be recalculated\n\t\tif (originIsArea) {\n\n\t\t\tvar shape = self._$origin.attr('shape'),\n\t\t\t\tcoords = self._$origin.attr('coords');\n\n\t\t\tif (coords) {\n\n\t\t\t\tcoords = coords.split(',');\n\n\t\t\t\t$.map(coords, function(val, i) {\n\t\t\t\t\tcoords[i] = parseInt(val);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// if the image itself is the area, nothing more to do\n\t\t\tif (shape != 'default') {\n\n\t\t\t\tswitch(shape) {\n\n\t\t\t\t\tcase 'circle':\n\n\t\t\t\t\t\tvar circleCenterLeft = coords[0],\n\t\t\t\t\t\t\tcircleCenterTop = coords[1],\n\t\t\t\t\t\t\tcircleRadius = coords[2],\n\t\t\t\t\t\t\tareaTopOffset = circleCenterTop - circleRadius,\n\t\t\t\t\t\t\tareaLeftOffset = circleCenterLeft - circleRadius;\n\n\t\t\t\t\t\tgeo.origin.size.height = circleRadius * 2;\n\t\t\t\t\t\tgeo.origin.size.width = geo.origin.size.height;\n\n\t\t\t\t\t\tgeo.origin.windowOffset.left += areaLeftOffset;\n\t\t\t\t\t\tgeo.origin.windowOffset.top += areaTopOffset;\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'rect':\n\n\t\t\t\t\t\tvar areaLeft = coords[0],\n\t\t\t\t\t\t\tareaTop = coords[1],\n\t\t\t\t\t\t\tareaRight = coords[2],\n\t\t\t\t\t\t\tareaBottom = coords[3];\n\n\t\t\t\t\t\tgeo.origin.size.height = areaBottom - areaTop;\n\t\t\t\t\t\tgeo.origin.size.width = areaRight - areaLeft;\n\n\t\t\t\t\t\tgeo.origin.windowOffset.left += areaLeft;\n\t\t\t\t\t\tgeo.origin.windowOffset.top += areaTop;\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'poly':\n\n\t\t\t\t\t\tvar areaSmallestX = 0,\n\t\t\t\t\t\t\tareaSmallestY = 0,\n\t\t\t\t\t\t\tareaGreatestX = 0,\n\t\t\t\t\t\t\tareaGreatestY = 0,\n\t\t\t\t\t\t\tarrayAlternate = 'even';\n\n\t\t\t\t\t\tfor (var i = 0; i < coords.length; i++) {\n\n\t\t\t\t\t\t\tvar areaNumber = coords[i];\n\n\t\t\t\t\t\t\tif (arrayAlternate == 'even') {\n\n\t\t\t\t\t\t\t\tif (areaNumber > areaGreatestX) {\n\n\t\t\t\t\t\t\t\t\tareaGreatestX = areaNumber;\n\n\t\t\t\t\t\t\t\t\tif (i === 0) {\n\t\t\t\t\t\t\t\t\t\tareaSmallestX = areaGreatestX;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (areaNumber < areaSmallestX) {\n\t\t\t\t\t\t\t\t\tareaSmallestX = areaNumber;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tarrayAlternate = 'odd';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tif (areaNumber > areaGreatestY) {\n\n\t\t\t\t\t\t\t\t\tareaGreatestY = areaNumber;\n\n\t\t\t\t\t\t\t\t\tif (i == 1) {\n\t\t\t\t\t\t\t\t\t\tareaSmallestY = areaGreatestY;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (areaNumber < areaSmallestY) {\n\t\t\t\t\t\t\t\t\tareaSmallestY = areaNumber;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tarrayAlternate = 'even';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgeo.origin.size.height = areaGreatestY - areaSmallestY;\n\t\t\t\t\t\tgeo.origin.size.width = areaGreatestX - areaSmallestX;\n\n\t\t\t\t\t\tgeo.origin.windowOffset.left += areaSmallestX;\n\t\t\t\t\t\tgeo.origin.windowOffset.top += areaSmallestY;\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// user callback through an event\n\t\tvar edit = function(r) {\n\t\t\tgeo.origin.size.height = r.height,\n\t\t\t\tgeo.origin.windowOffset.left = r.left,\n\t\t\t\tgeo.origin.windowOffset.top = r.top,\n\t\t\t\tgeo.origin.size.width = r.width\n\t\t};\n\n\t\tself._trigger({\n\t\t\ttype: 'geometry',\n\t\t\tedit: edit,\n\t\t\tgeometry: {\n\t\t\t\theight: geo.origin.size.height,\n\t\t\t\tleft: geo.origin.windowOffset.left,\n\t\t\t\ttop: geo.origin.windowOffset.top,\n\t\t\t\twidth: geo.origin.size.width\n\t\t\t}\n\t\t});\n\n\t\t// calculate the remaining properties with what we got\n\n\t\tgeo.origin.windowOffset.right = geo.origin.windowOffset.left + geo.origin.size.width;\n\t\tgeo.origin.windowOffset.bottom = geo.origin.windowOffset.top + geo.origin.size.height;\n\n\t\tgeo.origin.offset.left = geo.origin.windowOffset.left + geo.window.scroll.left;\n\t\tgeo.origin.offset.top = geo.origin.windowOffset.top + geo.window.scroll.top;\n\t\tgeo.origin.offset.bottom = geo.origin.offset.top + geo.origin.size.height;\n\t\tgeo.origin.offset.right = geo.origin.offset.left + geo.origin.size.width;\n\n\t\t// the space that is available to display the tooltip relatively to the document\n\t\tgeo.available.document = {\n\t\t\tbottom: {\n\t\t\t\theight: geo.document.size.height - geo.origin.offset.bottom,\n\t\t\t\twidth: geo.document.size.width\n\t\t\t},\n\t\t\tleft: {\n\t\t\t\theight: geo.document.size.height,\n\t\t\t\twidth: geo.origin.offset.left\n\t\t\t},\n\t\t\tright: {\n\t\t\t\theight: geo.document.size.height,\n\t\t\t\twidth: geo.document.size.width - geo.origin.offset.right\n\t\t\t},\n\t\t\ttop: {\n\t\t\t\theight: geo.origin.offset.top,\n\t\t\t\twidth: geo.document.size.width\n\t\t\t}\n\t\t};\n\n\t\t// the space that is available to display the tooltip relatively to the viewport\n\t\t// (the resulting values may be negative if the origin overflows the viewport)\n\t\tgeo.available.window = {\n\t\t\tbottom: {\n\t\t\t\t// the inner max is here to make sure the available height is no bigger\n\t\t\t\t// than the viewport height (when the origin is off screen at the top).\n\t\t\t\t// The outer max just makes sure that the height is not negative (when\n\t\t\t\t// the origin overflows at the bottom).\n\t\t\t\theight: Math.max(geo.window.size.height - Math.max(geo.origin.windowOffset.bottom, 0), 0),\n\t\t\t\twidth: geo.window.size.width\n\t\t\t},\n\t\t\tleft: {\n\t\t\t\theight: geo.window.size.height,\n\t\t\t\twidth: Math.max(geo.origin.windowOffset.left, 0)\n\t\t\t},\n\t\t\tright: {\n\t\t\t\theight: geo.window.size.height,\n\t\t\t\twidth: Math.max(geo.window.size.width - Math.max(geo.origin.windowOffset.right, 0), 0)\n\t\t\t},\n\t\t\ttop: {\n\t\t\t\theight: Math.max(geo.origin.windowOffset.top, 0),\n\t\t\t\twidth: geo.window.size.width\n\t\t\t}\n\t\t};\n\n\t\twhile ($parent[0].tagName.toLowerCase() != 'html') {\n\n\t\t\tif ($parent.css('position') == 'fixed') {\n\t\t\t\tgeo.origin.fixedLineage = true;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$parent = $parent.parent();\n\t\t}\n\n\t\treturn geo;\n\t},\n\n\t/**\n\t * Some options may need to be formated before being used\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__optionsFormat: function() {\n\n\t\tif (typeof this.__options.animationDuration == 'number') {\n\t\t\tthis.__options.animationDuration = [this.__options.animationDuration, this.__options.animationDuration];\n\t\t}\n\n\t\tif (typeof this.__options.delay == 'number') {\n\t\t\tthis.__options.delay = [this.__options.delay, this.__options.delay];\n\t\t}\n\n\t\tif (typeof this.__options.delayTouch == 'number') {\n\t\t\tthis.__options.delayTouch = [this.__options.delayTouch, this.__options.delayTouch];\n\t\t}\n\n\t\tif (typeof this.__options.theme == 'string') {\n\t\t\tthis.__options.theme = [this.__options.theme];\n\t\t}\n\n\t\t// determine the future parent\n\t\tif (this.__options.parent === null) {\n\t\t\tthis.__options.parent = $(env.window.document.body);\n\t\t}\n\t\telse if (typeof this.__options.parent == 'string') {\n\t\t\tthis.__options.parent = $(this.__options.parent);\n\t\t}\n\n\t\tif (this.__options.trigger == 'hover') {\n\n\t\t\tthis.__options.triggerOpen = {\n\t\t\t\tmouseenter: true,\n\t\t\t\ttouchstart: true\n\t\t\t};\n\n\t\t\tthis.__options.triggerClose = {\n\t\t\t\tmouseleave: true,\n\t\t\t\toriginClick: true,\n\t\t\t\ttouchleave: true\n\t\t\t};\n\t\t}\n\t\telse if (this.__options.trigger == 'click') {\n\n\t\t\tthis.__options.triggerOpen = {\n\t\t\t\tclick: true,\n\t\t\t\ttap: true\n\t\t\t};\n\n\t\t\tthis.__options.triggerClose = {\n\t\t\t\tclick: true,\n\t\t\t\ttap: true\n\t\t\t};\n\t\t}\n\n\t\t// for the plugins\n\t\tthis._trigger('options');\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Schedules or cancels the garbage collector task\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__prepareGC: function() {\n\n\t\tvar self = this;\n\n\t\t// in case the selfDestruction option has been changed by a method call\n\t\tif (self.__options.selfDestruction) {\n\n\t\t\t// the GC task\n\t\t\tself.__garbageCollector = setInterval(function() {\n\n\t\t\t\tvar now = new Date().getTime();\n\n\t\t\t\t// forget the old events\n\t\t\t\tself.__touchEvents = $.grep(self.__touchEvents, function(event, i) {\n\t\t\t\t\t// 1 minute\n\t\t\t\t\treturn now - event.time > 60000;\n\t\t\t\t});\n\n\t\t\t\t// auto-destruct if the origin is gone\n\t\t\t\tif (!bodyContains(self._$origin)) {\n\n\t\t\t\t\tself.close(function(){\n\t\t\t\t\t\tself.destroy();\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}, 20000);\n\t\t}\n\t\telse {\n\t\t\tclearInterval(self.__garbageCollector);\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Sets listeners on the origin if the open triggers require them.\n\t * Unlike the listeners set at opening time, these ones\n\t * remain even when the tooltip is closed. It has been made a\n\t * separate method so it can be called when the triggers are\n\t * changed in the options. Closing is handled in _open()\n\t * because of the bindings that may be needed on the tooltip\n\t * itself\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__prepareOrigin: function() {\n\n\t\tvar self = this;\n\n\t\t// in case we're resetting the triggers\n\t\tself._$origin.off('.'+ self.__namespace +'-triggerOpen');\n\n\t\t// if the device is touch capable, even if only mouse triggers\n\t\t// are asked, we need to listen to touch events to know if the mouse\n\t\t// events are actually emulated (so we can ignore them)\n\t\tif (env.hasTouchCapability) {\n\n\t\t\tself._$origin.on(\n\t\t\t\t'touchstart.'+ self.__namespace +'-triggerOpen ' +\n\t\t\t\t'touchend.'+ self.__namespace +'-triggerOpen ' +\n\t\t\t\t'touchcancel.'+ self.__namespace +'-triggerOpen',\n\t\t\t\tfunction(event){\n\t\t\t\t\tself._touchRecordEvent(event);\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\t// mouse click and touch tap work the same way\n\t\tif (\tself.__options.triggerOpen.click\n\t\t\t||\t(self.__options.triggerOpen.tap && env.hasTouchCapability)\n\t\t) {\n\n\t\t\tvar eventNames = '';\n\t\t\tif (self.__options.triggerOpen.click) {\n\t\t\t\teventNames += 'click.'+ self.__namespace +'-triggerOpen ';\n\t\t\t}\n\t\t\tif (self.__options.triggerOpen.tap && env.hasTouchCapability) {\n\t\t\t\teventNames += 'touchend.'+ self.__namespace +'-triggerOpen';\n\t\t\t}\n\n\t\t\tself._$origin.on(eventNames, function(event) {\n\t\t\t\tif (self._touchIsMeaningfulEvent(event)) {\n\t\t\t\t\tself._open(event);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// mouseenter and touch start work the same way\n\t\tif (\tself.__options.triggerOpen.mouseenter\n\t\t\t||\t(self.__options.triggerOpen.touchstart && env.hasTouchCapability)\n\t\t) {\n\n\t\t\tvar eventNames = '';\n\t\t\tif (self.__options.triggerOpen.mouseenter) {\n\t\t\t\teventNames += 'mouseenter.'+ self.__namespace +'-triggerOpen ';\n\t\t\t}\n\t\t\tif (self.__options.triggerOpen.touchstart && env.hasTouchCapability) {\n\t\t\t\teventNames += 'touchstart.'+ self.__namespace +'-triggerOpen';\n\t\t\t}\n\n\t\t\tself._$origin.on(eventNames, function(event) {\n\t\t\t\tif (\tself._touchIsTouchEvent(event)\n\t\t\t\t\t||\t!self._touchIsEmulatedEvent(event)\n\t\t\t\t) {\n\t\t\t\t\tself.__pointerIsOverOrigin = true;\n\t\t\t\t\tself._openShortly(event);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// info for the mouseleave/touchleave close triggers when they use a delay\n\t\tif (\tself.__options.triggerClose.mouseleave\n\t\t\t||\t(self.__options.triggerClose.touchleave && env.hasTouchCapability)\n\t\t) {\n\n\t\t\tvar eventNames = '';\n\t\t\tif (self.__options.triggerClose.mouseleave) {\n\t\t\t\teventNames += 'mouseleave.'+ self.__namespace +'-triggerOpen ';\n\t\t\t}\n\t\t\tif (self.__options.triggerClose.touchleave && env.hasTouchCapability) {\n\t\t\t\teventNames += 'touchend.'+ self.__namespace +'-triggerOpen touchcancel.'+ self.__namespace +'-triggerOpen';\n\t\t\t}\n\n\t\t\tself._$origin.on(eventNames, function(event) {\n\n\t\t\t\tif (self._touchIsMeaningfulEvent(event)) {\n\t\t\t\t\tself.__pointerIsOverOrigin = false;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Do the things that need to be done only once after the tooltip\n\t * HTML element it has been created. It has been made a separate\n\t * method so it can be called when options are changed. Remember\n\t * that the tooltip may actually exist in the DOM before it is\n\t * opened, and present after it has been closed: it's the display\n\t * plugin that takes care of handling it.\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__prepareTooltip: function() {\n\n\t\tvar self = this,\n\t\t\tp = self.__options.interactive ? 'auto' : '';\n\n\t\t// this will be useful to know quickly if the tooltip is in\n\t\t// the DOM or not\n\t\tself._$tooltip\n\t\t\t.attr('id', self.__namespace)\n\t\t\t.css({\n\t\t\t\t// pointer events\n\t\t\t\t'pointer-events': p,\n\t\t\t\tzIndex: self.__options.zIndex\n\t\t\t});\n\n\t\t// themes\n\t\t// remove the old ones and add the new ones\n\t\t$.each(self.__previousThemes, function(i, theme) {\n\t\t\tself._$tooltip.removeClass(theme);\n\t\t});\n\t\t$.each(self.__options.theme, function(i, theme) {\n\t\t\tself._$tooltip.addClass(theme);\n\t\t});\n\n\t\tself.__previousThemes = $.merge([], self.__options.theme);\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Handles the scroll on any of the parents of the origin (when the\n\t * tooltip is open)\n\t *\n\t * @param {object} event\n\t * @returns {self}\n\t * @private\n\t */\n\t__scrollHandler: function(event) {\n\n\t\tvar self = this;\n\n\t\tif (self.__options.triggerClose.scroll) {\n\t\t\tself._close(event);\n\t\t}\n\t\telse {\n\n\t\t\t// if the origin or tooltip have been removed: do nothing, the tracker will\n\t\t\t// take care of it later\n\t\t\tif (bodyContains(self._$origin) && bodyContains(self._$tooltip)) {\n\n\t\t\t\tvar geo = null;\n\n\t\t\t\t// if the scroll happened on the window\n\t\t\t\tif (event.target === env.window.document) {\n\n\t\t\t\t\t// if the origin has a fixed lineage, window scroll will have no\n\t\t\t\t\t// effect on its position nor on the position of the tooltip\n\t\t\t\t\tif (!self.__Geometry.origin.fixedLineage) {\n\n\t\t\t\t\t\t// we don't need to do anything unless repositionOnScroll is true\n\t\t\t\t\t\t// because the tooltip will already have moved with the window\n\t\t\t\t\t\t// (and of course with the origin)\n\t\t\t\t\t\tif (self.__options.repositionOnScroll) {\n\t\t\t\t\t\t\tself.reposition(event);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// if the scroll happened on another parent of the tooltip, it means\n\t\t\t\t// that it's in a scrollable area and now needs to have its position\n\t\t\t\t// adjusted or recomputed, depending ont the repositionOnScroll\n\t\t\t\t// option. Also, if the origin is partly hidden due to a parent that\n\t\t\t\t// hides its overflow, we'll just hide (not close) the tooltip.\n\t\t\t\telse {\n\n\t\t\t\t\tgeo = self.__geometry();\n\n\t\t\t\t\tvar overflows = false;\n\n\t\t\t\t\t// a fixed position origin is not affected by the overflow hiding\n\t\t\t\t\t// of a parent\n\t\t\t\t\tif (self._$origin.css('position') != 'fixed') {\n\n\t\t\t\t\t\tself.__$originParents.each(function(i, el) {\n\n\t\t\t\t\t\t\tvar $el = $(el),\n\t\t\t\t\t\t\t\toverflowX = $el.css('overflow-x'),\n\t\t\t\t\t\t\t\toverflowY = $el.css('overflow-y');\n\n\t\t\t\t\t\t\tif (overflowX != 'visible' || overflowY != 'visible') {\n\n\t\t\t\t\t\t\t\tvar bcr = el.getBoundingClientRect();\n\n\t\t\t\t\t\t\t\tif (overflowX != 'visible') {\n\n\t\t\t\t\t\t\t\t\tif (\tgeo.origin.windowOffset.left < bcr.left\n\t\t\t\t\t\t\t\t\t\t||\tgeo.origin.windowOffset.right > bcr.right\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\toverflows = true;\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (overflowY != 'visible') {\n\n\t\t\t\t\t\t\t\t\tif (\tgeo.origin.windowOffset.top < bcr.top\n\t\t\t\t\t\t\t\t\t\t||\tgeo.origin.windowOffset.bottom > bcr.bottom\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\toverflows = true;\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// no need to go further if fixed, for the same reason as above\n\t\t\t\t\t\t\tif ($el.css('position') == 'fixed') {\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tif (overflows) {\n\t\t\t\t\t\tself._$tooltip.css('visibility', 'hidden');\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\n\t\t\t\t\t\tself._$tooltip.css('visibility', 'visible');\n\n\t\t\t\t\t\t// reposition\n\t\t\t\t\t\tif (self.__options.repositionOnScroll) {\n\t\t\t\t\t\t\tself.reposition(event);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// or just adjust offset\n\t\t\t\t\t\telse {\n\n\t\t\t\t\t\t\t// we have to use offset and not windowOffset because this way,\n\t\t\t\t\t\t\t// only the scroll distance of the scrollable areas are taken into\n\t\t\t\t\t\t\t// account (the scrolltop value of the main window must be\n\t\t\t\t\t\t\t// ignored since the tooltip already moves with it)\n\t\t\t\t\t\t\tvar offsetLeft = geo.origin.offset.left - self.__Geometry.origin.offset.left,\n\t\t\t\t\t\t\t\toffsetTop = geo.origin.offset.top - self.__Geometry.origin.offset.top;\n\n\t\t\t\t\t\t\t// add the offset to the position initially computed by the display plugin\n\t\t\t\t\t\t\tself._$tooltip.css({\n\t\t\t\t\t\t\t\tleft: self.__lastPosition.coord.left + offsetLeft,\n\t\t\t\t\t\t\t\ttop: self.__lastPosition.coord.top + offsetTop\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tself._trigger({\n\t\t\t\t\ttype: 'scroll',\n\t\t\t\t\tevent: event,\n\t\t\t\t\tgeo: geo\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Changes the state of the tooltip\n\t *\n\t * @param {string} state\n\t * @returns {self}\n\t * @private\n\t */\n\t__stateSet: function(state) {\n\n\t\tthis.__state = state;\n\n\t\tthis._trigger({\n\t\t\ttype: 'state',\n\t\t\tstate: state\n\t\t});\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Clear appearance timeouts\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__timeoutsClear: function() {\n\n\t\t// there is only one possible open timeout: the delayed opening\n\t\t// when the mouseenter/touchstart open triggers are used\n\t\tclearTimeout(this.__timeouts.open);\n\t\tthis.__timeouts.open = null;\n\n\t\t// ... but several close timeouts: the delayed closing when the\n\t\t// mouseleave close trigger is used and the timer option\n\t\t$.each(this.__timeouts.close, function(i, timeout) {\n\t\t\tclearTimeout(timeout);\n\t\t});\n\t\tthis.__timeouts.close = [];\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Start the tracker that will make checks at regular intervals\n\t *\n\t * @returns {self}\n\t * @private\n\t */\n\t__trackerStart: function() {\n\n\t\tvar self = this,\n\t\t\t$content = self._$tooltip.find('.tooltipster-content');\n\n\t\t// get the initial content size\n\t\tif (self.__options.trackTooltip) {\n\t\t\tself.__contentBcr = $content[0].getBoundingClientRect();\n\t\t}\n\n\t\tself.__tracker = setInterval(function() {\n\n\t\t\t// if the origin or tooltip elements have been removed.\n\t\t\t// Note: we could destroy the instance now if the origin has\n\t\t\t// been removed but we'll leave that task to our garbage collector\n\t\t\tif (!bodyContains(self._$origin) || !bodyContains(self._$tooltip)) {\n\t\t\t\tself._close();\n\t\t\t}\n\t\t\t// if everything is alright\n\t\t\telse {\n\n\t\t\t\t// compare the former and current positions of the origin to reposition\n\t\t\t\t// the tooltip if need be\n\t\t\t\tif (self.__options.trackOrigin) {\n\n\t\t\t\t\tvar g = self.__geometry(),\n\t\t\t\t\t\tidentical = false;\n\n\t\t\t\t\t// compare size first (a change requires repositioning too)\n\t\t\t\t\tif (areEqual(g.origin.size, self.__Geometry.origin.size)) {\n\n\t\t\t\t\t\t// for elements that have a fixed lineage (see __geometry()), we track the\n\t\t\t\t\t\t// top and left properties (relative to window)\n\t\t\t\t\t\tif (self.__Geometry.origin.fixedLineage) {\n\t\t\t\t\t\t\tif (areEqual(g.origin.windowOffset, self.__Geometry.origin.windowOffset)) {\n\t\t\t\t\t\t\t\tidentical = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// otherwise, track total offset (relative to document)\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tif (areEqual(g.origin.offset, self.__Geometry.origin.offset)) {\n\t\t\t\t\t\t\t\tidentical = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!identical) {\n\n\t\t\t\t\t\t// close the tooltip when using the mouseleave close trigger\n\t\t\t\t\t\t// (see https://github.com/calebjacob/tooltipster/pull/253)\n\t\t\t\t\t\tif (self.__options.triggerClose.mouseleave) {\n\t\t\t\t\t\t\tself._close();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tself.reposition();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (self.__options.trackTooltip) {\n\n\t\t\t\t\tvar currentBcr = $content[0].getBoundingClientRect();\n\n\t\t\t\t\tif (\tcurrentBcr.height !== self.__contentBcr.height\n\t\t\t\t\t\t||\tcurrentBcr.width !== self.__contentBcr.width\n\t\t\t\t\t) {\n\t\t\t\t\t\tself.reposition();\n\t\t\t\t\t\tself.__contentBcr = currentBcr;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}, self.__options.trackerInterval);\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Closes the tooltip (after the closing delay)\n\t *\n\t * @param event\n\t * @param callback\n\t * @param force Set to true to override a potential refusal of the user's function\n\t * @returns {self}\n\t * @protected\n\t */\n\t_close: function(event, callback, force) {\n\n\t\tvar self = this,\n\t\t\tok = true;\n\n\t\tself._trigger({\n\t\t\ttype: 'close',\n\t\t\tevent: event,\n\t\t\tstop: function() {\n\t\t\t\tok = false;\n\t\t\t}\n\t\t});\n\n\t\t// a destroying tooltip (force == true) may not refuse to close\n\t\tif (ok || force) {\n\n\t\t\t// save the method custom callback and cancel any open method custom callbacks\n\t\t\tif (callback) self.__callbacks.close.push(callback);\n\t\t\tself.__callbacks.open = [];\n\n\t\t\t// clear open/close timeouts\n\t\t\tself.__timeoutsClear();\n\n\t\t\tvar finishCallbacks = function() {\n\n\t\t\t\t// trigger any close method custom callbacks and reset them\n\t\t\t\t$.each(self.__callbacks.close, function(i,c) {\n\t\t\t\t\tc.call(self, self, {\n\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\torigin: self._$origin[0]\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tself.__callbacks.close = [];\n\t\t\t};\n\n\t\t\tif (self.__state != 'closed') {\n\n\t\t\t\tvar necessary = true,\n\t\t\t\t\td = new Date(),\n\t\t\t\t\tnow = d.getTime(),\n\t\t\t\t\tnewClosingTime = now + self.__options.animationDuration[1];\n\n\t\t\t\t// the tooltip may already already be disappearing, but if a new\n\t\t\t\t// call to close() is made after the animationDuration was changed\n\t\t\t\t// to 0 (for example), we ought to actually close it sooner than\n\t\t\t\t// previously scheduled. In that case it should be noted that the\n\t\t\t\t// browser will not adapt the animation duration to the new\n\t\t\t\t// animationDuration that was set after the start of the closing\n\t\t\t\t// animation.\n\t\t\t\t// Note: the same thing could be considered at opening, but is not\n\t\t\t\t// really useful since the tooltip is actually opened immediately\n\t\t\t\t// upon a call to _open(). Since it would not make the opening\n\t\t\t\t// animation finish sooner, its sole impact would be to trigger the\n\t\t\t\t// state event and the open callbacks sooner than the actual end of\n\t\t\t\t// the opening animation, which is not great.\n\t\t\t\tif (self.__state == 'disappearing') {\n\n\t\t\t\t\tif (\tnewClosingTime > self.__closingTime\n\t\t\t\t\t\t// in case closing is actually overdue because the script\n\t\t\t\t\t\t// execution was suspended. See #679\n\t\t\t\t\t\t&&\tself.__options.animationDuration[1] > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tnecessary = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (necessary) {\n\n\t\t\t\t\tself.__closingTime = newClosingTime;\n\n\t\t\t\t\tif (self.__state != 'disappearing') {\n\t\t\t\t\t\tself.__stateSet('disappearing');\n\t\t\t\t\t}\n\n\t\t\t\t\tvar finish = function() {\n\n\t\t\t\t\t\t// stop the tracker\n\t\t\t\t\t\tclearInterval(self.__tracker);\n\n\t\t\t\t\t\t// a \"beforeClose\" option has been asked several times but would\n\t\t\t\t\t\t// probably useless since the content element is still accessible\n\t\t\t\t\t\t// via ::content(), and because people can always use listeners\n\t\t\t\t\t\t// inside their content to track what's going on. For the sake of\n\t\t\t\t\t\t// simplicity, this has been denied. Bur for the rare people who\n\t\t\t\t\t\t// really need the option (for old browsers or for the case where\n\t\t\t\t\t\t// detaching the content is actually destructive, for file or\n\t\t\t\t\t\t// password inputs for example), this event will do the work.\n\t\t\t\t\t\tself._trigger({\n\t\t\t\t\t\t\ttype: 'closing',\n\t\t\t\t\t\t\tevent: event\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// unbind listeners which are no longer needed\n\n\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t.off('.'+ self.__namespace +'-triggerClose')\n\t\t\t\t\t\t\t.removeClass('tooltipster-dying');\n\n\t\t\t\t\t\t// orientationchange, scroll and resize listeners\n\t\t\t\t\t\t$(env.window).off('.'+ self.__namespace +'-triggerClose');\n\n\t\t\t\t\t\t// scroll listeners\n\t\t\t\t\t\tself.__$originParents.each(function(i, el) {\n\t\t\t\t\t\t\t$(el).off('scroll.'+ self.__namespace +'-triggerClose');\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// clear the array to prevent memory leaks\n\t\t\t\t\t\tself.__$originParents = null;\n\n\t\t\t\t\t\t$(env.window.document.body).off('.'+ self.__namespace +'-triggerClose');\n\n\t\t\t\t\t\tself._$origin.off('.'+ self.__namespace +'-triggerClose');\n\n\t\t\t\t\t\tself._off('dismissable');\n\n\t\t\t\t\t\t// a plugin that would like to remove the tooltip from the\n\t\t\t\t\t\t// DOM when closed should bind on this\n\t\t\t\t\t\tself.__stateSet('closed');\n\n\t\t\t\t\t\t// trigger event\n\t\t\t\t\t\tself._trigger({\n\t\t\t\t\t\t\ttype: 'after',\n\t\t\t\t\t\t\tevent: event\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// call our constructor custom callback function\n\t\t\t\t\t\tif (self.__options.functionAfter) {\n\t\t\t\t\t\t\tself.__options.functionAfter.call(self, self, {\n\t\t\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\t\t\torigin: self._$origin[0]\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// call our method custom callbacks functions\n\t\t\t\t\t\tfinishCallbacks();\n\t\t\t\t\t};\n\n\t\t\t\t\tif (env.hasTransitions) {\n\n\t\t\t\t\t\tself._$tooltip.css({\n\t\t\t\t\t\t\t'-moz-animation-duration': self.__options.animationDuration[1] + 'ms',\n\t\t\t\t\t\t\t'-ms-animation-duration': self.__options.animationDuration[1] + 'ms',\n\t\t\t\t\t\t\t'-o-animation-duration': self.__options.animationDuration[1] + 'ms',\n\t\t\t\t\t\t\t'-webkit-animation-duration': self.__options.animationDuration[1] + 'ms',\n\t\t\t\t\t\t\t'animation-duration': self.__options.animationDuration[1] + 'ms',\n\t\t\t\t\t\t\t'transition-duration': self.__options.animationDuration[1] + 'ms'\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t// clear both potential open and close tasks\n\t\t\t\t\t\t\t.clearQueue()\n\t\t\t\t\t\t\t.removeClass('tooltipster-show')\n\t\t\t\t\t\t\t// for transitions only\n\t\t\t\t\t\t\t.addClass('tooltipster-dying');\n\n\t\t\t\t\t\tif (self.__options.animationDuration[1] > 0) {\n\t\t\t\t\t\t\tself._$tooltip.delay(self.__options.animationDuration[1]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tself._$tooltip.queue(finish);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\n\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t.stop()\n\t\t\t\t\t\t\t.fadeOut(self.__options.animationDuration[1], finish);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// if the tooltip is already closed, we still need to trigger\n\t\t\t// the method custom callbacks\n\t\t\telse {\n\t\t\t\tfinishCallbacks();\n\t\t\t}\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @returns {self}\n\t * @protected\n\t */\n\t_off: function() {\n\t\tthis.__$emitterPrivate.off.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @returns {self}\n\t * @protected\n\t */\n\t_on: function() {\n\t\tthis.__$emitterPrivate.on.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * For internal use by plugins, if needed\n\t *\n\t * @returns {self}\n\t * @protected\n\t */\n\t_one: function() {\n\t\tthis.__$emitterPrivate.one.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));\n\t\treturn this;\n\t},\n\n\t/**\n\t * Opens the tooltip right away.\n\t *\n\t * @param event\n\t * @param callback Will be called when the opening animation is over\n\t * @returns {self}\n\t * @protected\n\t */\n\t_open: function(event, callback) {\n\n\t\tvar self = this;\n\n\t\t// if the destruction process has not begun and if this was not\n\t\t// triggered by an unwanted emulated click event\n\t\tif (!self.__destroying) {\n\n\t\t\t// check that the origin is still in the DOM\n\t\t\tif (\tbodyContains(self._$origin)\n\t\t\t\t// if the tooltip is enabled\n\t\t\t\t&&\tself.__enabled\n\t\t\t) {\n\n\t\t\t\tvar ok = true;\n\n\t\t\t\t// if the tooltip is not open yet, we need to call functionBefore.\n\t\t\t\t// otherwise we can jst go on\n\t\t\t\tif (self.__state == 'closed') {\n\n\t\t\t\t\t// trigger an event. The event.stop function allows the callback\n\t\t\t\t\t// to prevent the opening of the tooltip\n\t\t\t\t\tself._trigger({\n\t\t\t\t\t\ttype: 'before',\n\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\tstop: function() {\n\t\t\t\t\t\t\tok = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tif (ok && self.__options.functionBefore) {\n\n\t\t\t\t\t\t// call our custom function before continuing\n\t\t\t\t\t\tok = self.__options.functionBefore.call(self, self, {\n\t\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\t\torigin: self._$origin[0]\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (ok !== false) {\n\n\t\t\t\t\t// if there is some content\n\t\t\t\t\tif (self.__Content !== null) {\n\n\t\t\t\t\t\t// save the method callback and cancel close method callbacks\n\t\t\t\t\t\tif (callback) {\n\t\t\t\t\t\t\tself.__callbacks.open.push(callback);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tself.__callbacks.close = [];\n\n\t\t\t\t\t\t// get rid of any appearance timeouts\n\t\t\t\t\t\tself.__timeoutsClear();\n\n\t\t\t\t\t\tvar extraTime,\n\t\t\t\t\t\t\tfinish = function() {\n\n\t\t\t\t\t\t\t\tif (self.__state != 'stable') {\n\t\t\t\t\t\t\t\t\tself.__stateSet('stable');\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// trigger any open method custom callbacks and reset them\n\t\t\t\t\t\t\t\t$.each(self.__callbacks.open, function(i,c) {\n\t\t\t\t\t\t\t\t\tc.call(self, self, {\n\t\t\t\t\t\t\t\t\t\torigin: self._$origin[0],\n\t\t\t\t\t\t\t\t\t\ttooltip: self._$tooltip[0]\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tself.__callbacks.open = [];\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// if the tooltip is already open\n\t\t\t\t\t\tif (self.__state !== 'closed') {\n\n\t\t\t\t\t\t\t// the timer (if any) will start (or restart) right now\n\t\t\t\t\t\t\textraTime = 0;\n\n\t\t\t\t\t\t\t// if it was disappearing, cancel that\n\t\t\t\t\t\t\tif (self.__state === 'disappearing') {\n\n\t\t\t\t\t\t\t\tself.__stateSet('appearing');\n\n\t\t\t\t\t\t\t\tif (env.hasTransitions) {\n\n\t\t\t\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t\t\t\t.clearQueue()\n\t\t\t\t\t\t\t\t\t\t.removeClass('tooltipster-dying')\n\t\t\t\t\t\t\t\t\t\t.addClass('tooltipster-show');\n\n\t\t\t\t\t\t\t\t\tif (self.__options.animationDuration[0] > 0) {\n\t\t\t\t\t\t\t\t\t\tself._$tooltip.delay(self.__options.animationDuration[0]);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tself._$tooltip.queue(finish);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t// in case the tooltip was currently fading out, bring it back\n\t\t\t\t\t\t\t\t\t// to life\n\t\t\t\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t\t\t\t.stop()\n\t\t\t\t\t\t\t\t\t\t.fadeIn(finish);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// if the tooltip is already open, we still need to trigger the method\n\t\t\t\t\t\t\t// custom callback\n\t\t\t\t\t\t\telse if (self.__state == 'stable') {\n\t\t\t\t\t\t\t\tfinish();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// if the tooltip isn't already open, open it\n\t\t\t\t\t\telse {\n\n\t\t\t\t\t\t\t// a plugin must bind on this and store the tooltip in this._$tooltip\n\t\t\t\t\t\t\tself.__stateSet('appearing');\n\n\t\t\t\t\t\t\t// the timer (if any) will start when the tooltip has fully appeared\n\t\t\t\t\t\t\t// after its transition\n\t\t\t\t\t\t\textraTime = self.__options.animationDuration[0];\n\n\t\t\t\t\t\t\t// insert the content inside the tooltip\n\t\t\t\t\t\t\tself.__contentInsert();\n\n\t\t\t\t\t\t\t// reposition the tooltip and attach to the DOM\n\t\t\t\t\t\t\tself.reposition(event, true);\n\n\t\t\t\t\t\t\t// animate in the tooltip. If the display plugin wants no css\n\t\t\t\t\t\t\t// animations, it may override the animation option with a\n\t\t\t\t\t\t\t// dummy value that will produce no effect\n\t\t\t\t\t\t\tif (env.hasTransitions) {\n\n\t\t\t\t\t\t\t\t// note: there seems to be an issue with start animations which\n\t\t\t\t\t\t\t\t// are randomly not played on fast devices in both Chrome and FF,\n\t\t\t\t\t\t\t\t// couldn't find a way to solve it yet. It seems that applying\n\t\t\t\t\t\t\t\t// the classes before appending to the DOM helps a little, but\n\t\t\t\t\t\t\t\t// it messes up some CSS transitions. The issue almost never\n\t\t\t\t\t\t\t\t// happens when delay[0]==0 though\n\t\t\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t\t\t.addClass('tooltipster-'+ self.__options.animation)\n\t\t\t\t\t\t\t\t\t.addClass('tooltipster-initial')\n\t\t\t\t\t\t\t\t\t.css({\n\t\t\t\t\t\t\t\t\t\t'-moz-animation-duration': self.__options.animationDuration[0] + 'ms',\n\t\t\t\t\t\t\t\t\t\t'-ms-animation-duration': self.__options.animationDuration[0] + 'ms',\n\t\t\t\t\t\t\t\t\t\t'-o-animation-duration': self.__options.animationDuration[0] + 'ms',\n\t\t\t\t\t\t\t\t\t\t'-webkit-animation-duration': self.__options.animationDuration[0] + 'ms',\n\t\t\t\t\t\t\t\t\t\t'animation-duration': self.__options.animationDuration[0] + 'ms',\n\t\t\t\t\t\t\t\t\t\t'transition-duration': self.__options.animationDuration[0] + 'ms'\n\t\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tsetTimeout(\n\t\t\t\t\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t\t\t\t\t// a quick hover may have already triggered a mouseleave\n\t\t\t\t\t\t\t\t\t\tif (self.__state != 'closed') {\n\n\t\t\t\t\t\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t\t\t\t\t\t.addClass('tooltipster-show')\n\t\t\t\t\t\t\t\t\t\t\t\t.removeClass('tooltipster-initial');\n\n\t\t\t\t\t\t\t\t\t\t\tif (self.__options.animationDuration[0] > 0) {\n\t\t\t\t\t\t\t\t\t\t\t\tself._$tooltip.delay(self.__options.animationDuration[0]);\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tself._$tooltip.queue(finish);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t0\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\n\t\t\t\t\t\t\t\t// old browsers will have to live with this\n\t\t\t\t\t\t\t\tself._$tooltip\n\t\t\t\t\t\t\t\t\t.css('display', 'none')\n\t\t\t\t\t\t\t\t\t.fadeIn(self.__options.animationDuration[0], finish);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// checks if the origin is removed while the tooltip is open\n\t\t\t\t\t\t\tself.__trackerStart();\n\n\t\t\t\t\t\t\t// NOTE: the listeners below have a '-triggerClose' namespace\n\t\t\t\t\t\t\t// because we'll remove them when the tooltip closes (unlike\n\t\t\t\t\t\t\t// the '-triggerOpen' listeners). So some of them are actually\n\t\t\t\t\t\t\t// not about close triggers, rather about positioning.\n\n\t\t\t\t\t\t\t$(env.window)\n\t\t\t\t\t\t\t\t// reposition on resize\n\t\t\t\t\t\t\t\t.on('resize.'+ self.__namespace +'-triggerClose', function(e) {\n\n\t\t\t\t\t\t\t\t\tvar $ae = $(document.activeElement);\n\n\t\t\t\t\t\t\t\t\t// reposition only if the resize event was not triggered upon the opening\n\t\t\t\t\t\t\t\t\t// of a virtual keyboard due to an input field being focused within the tooltip\n\t\t\t\t\t\t\t\t\t// (otherwise the repositioning would lose the focus)\n\t\t\t\t\t\t\t\t\tif (\t(!$ae.is('input') && !$ae.is('textarea'))\n\t\t\t\t\t\t\t\t\t\t||\t!$.contains(self._$tooltip[0], $ae[0])\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\tself.reposition(e);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t// same as below for parents\n\t\t\t\t\t\t\t\t.on('scroll.'+ self.__namespace +'-triggerClose', function(e) {\n\t\t\t\t\t\t\t\t\tself.__scrollHandler(e);\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tself.__$originParents = self._$origin.parents();\n\n\t\t\t\t\t\t\t// scrolling may require the tooltip to be moved or even\n\t\t\t\t\t\t\t// repositioned in some cases\n\t\t\t\t\t\t\tself.__$originParents.each(function(i, parent) {\n\n\t\t\t\t\t\t\t\t$(parent).on('scroll.'+ self.__namespace +'-triggerClose', function(e) {\n\t\t\t\t\t\t\t\t\tself.__scrollHandler(e);\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (\tself.__options.triggerClose.mouseleave\n\t\t\t\t\t\t\t\t||\t(self.__options.triggerClose.touchleave && env.hasTouchCapability)\n\t\t\t\t\t\t\t) {\n\n\t\t\t\t\t\t\t\t// we use an event to allow users/plugins to control when the mouseleave/touchleave\n\t\t\t\t\t\t\t\t// close triggers will come to action. It allows to have more triggering elements\n\t\t\t\t\t\t\t\t// than just the origin and the tooltip for example, or to cancel/delay the closing,\n\t\t\t\t\t\t\t\t// or to make the tooltip interactive even if it wasn't when it was open, etc.\n\t\t\t\t\t\t\t\tself._on('dismissable', function(event) {\n\n\t\t\t\t\t\t\t\t\tif (event.dismissable) {\n\n\t\t\t\t\t\t\t\t\t\tif (event.delay) {\n\n\t\t\t\t\t\t\t\t\t\t\ttimeout = setTimeout(function() {\n\t\t\t\t\t\t\t\t\t\t\t\t// event.event may be undefined\n\t\t\t\t\t\t\t\t\t\t\t\tself._close(event.event);\n\t\t\t\t\t\t\t\t\t\t\t}, event.delay);\n\n\t\t\t\t\t\t\t\t\t\t\tself.__timeouts.close.push(timeout);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\t\tself._close(event);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t// now set the listeners that will trigger 'dismissable' events\n\t\t\t\t\t\t\t\tvar $elements = self._$origin,\n\t\t\t\t\t\t\t\t\teventNamesIn = '',\n\t\t\t\t\t\t\t\t\teventNamesOut = '',\n\t\t\t\t\t\t\t\t\ttimeout = null;\n\n\t\t\t\t\t\t\t\t// if we have to allow interaction, bind on the tooltip too\n\t\t\t\t\t\t\t\tif (self.__options.interactive) {\n\t\t\t\t\t\t\t\t\t$elements = $elements.add(self._$tooltip);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (self.__options.triggerClose.mouseleave) {\n\t\t\t\t\t\t\t\t\teventNamesIn += 'mouseenter.'+ self.__namespace +'-triggerClose ';\n\t\t\t\t\t\t\t\t\teventNamesOut += 'mouseleave.'+ self.__namespace +'-triggerClose ';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (self.__options.triggerClose.touchleave && env.hasTouchCapability) {\n\t\t\t\t\t\t\t\t\teventNamesIn += 'touchstart.'+ self.__namespace +'-triggerClose';\n\t\t\t\t\t\t\t\t\teventNamesOut += 'touchend.'+ self.__namespace +'-triggerClose touchcancel.'+ self.__namespace +'-triggerClose';\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t$elements\n\t\t\t\t\t\t\t\t\t// close after some time spent outside of the elements\n\t\t\t\t\t\t\t\t\t.on(eventNamesOut, function(event) {\n\n\t\t\t\t\t\t\t\t\t\t// it's ok if the touch gesture ended up to be a swipe,\n\t\t\t\t\t\t\t\t\t\t// it's still a \"touch leave\" situation\n\t\t\t\t\t\t\t\t\t\tif (\tself._touchIsTouchEvent(event)\n\t\t\t\t\t\t\t\t\t\t\t||\t!self._touchIsEmulatedEvent(event)\n\t\t\t\t\t\t\t\t\t\t) {\n\n\t\t\t\t\t\t\t\t\t\t\tvar delay = (event.type == 'mouseleave') ?\n\t\t\t\t\t\t\t\t\t\t\t\tself.__options.delay :\n\t\t\t\t\t\t\t\t\t\t\t\tself.__options.delayTouch;\n\n\t\t\t\t\t\t\t\t\t\t\tself._trigger({\n\t\t\t\t\t\t\t\t\t\t\t\tdelay: delay[1],\n\t\t\t\t\t\t\t\t\t\t\t\tdismissable: true,\n\t\t\t\t\t\t\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'dismissable'\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t// suspend the mouseleave timeout when the pointer comes back\n\t\t\t\t\t\t\t\t\t// over the elements\n\t\t\t\t\t\t\t\t\t.on(eventNamesIn, function(event) {\n\n\t\t\t\t\t\t\t\t\t\t// it's also ok if the touch event is a swipe gesture\n\t\t\t\t\t\t\t\t\t\tif (\tself._touchIsTouchEvent(event)\n\t\t\t\t\t\t\t\t\t\t\t||\t!self._touchIsEmulatedEvent(event)\n\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\tself._trigger({\n\t\t\t\t\t\t\t\t\t\t\t\tdismissable: false,\n\t\t\t\t\t\t\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'dismissable'\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// close the tooltip when the origin gets a mouse click (common behavior of\n\t\t\t\t\t\t\t// native tooltips)\n\t\t\t\t\t\t\tif (self.__options.triggerClose.originClick) {\n\n\t\t\t\t\t\t\t\tself._$origin.on('click.'+ self.__namespace + '-triggerClose', function(event) {\n\n\t\t\t\t\t\t\t\t\t// we could actually let a tap trigger this but this feature just\n\t\t\t\t\t\t\t\t\t// does not make sense on touch devices\n\t\t\t\t\t\t\t\t\tif (\t!self._touchIsTouchEvent(event)\n\t\t\t\t\t\t\t\t\t\t&&\t!self._touchIsEmulatedEvent(event)\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\tself._close(event);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// set the same bindings for click and touch on the body to close the tooltip\n\t\t\t\t\t\t\tif (\tself.__options.triggerClose.click\n\t\t\t\t\t\t\t\t||\t(self.__options.triggerClose.tap && env.hasTouchCapability)\n\t\t\t\t\t\t\t) {\n\n\t\t\t\t\t\t\t\t// don't set right away since the click/tap event which triggered this method\n\t\t\t\t\t\t\t\t// (if it was a click/tap) is going to bubble up to the body, we don't want it\n\t\t\t\t\t\t\t\t// to close the tooltip immediately after it opened\n\t\t\t\t\t\t\t\tsetTimeout(function() {\n\n\t\t\t\t\t\t\t\t\tif (self.__state != 'closed') {\n\n\t\t\t\t\t\t\t\t\t\tvar eventNames = '',\n\t\t\t\t\t\t\t\t\t\t\t$body = $(env.window.document.body);\n\n\t\t\t\t\t\t\t\t\t\tif (self.__options.triggerClose.click) {\n\t\t\t\t\t\t\t\t\t\t\teventNames += 'click.'+ self.__namespace +'-triggerClose ';\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tif (self.__options.triggerClose.tap && env.hasTouchCapability) {\n\t\t\t\t\t\t\t\t\t\t\teventNames += 'touchend.'+ self.__namespace +'-triggerClose';\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t$body.on(eventNames, function(event) {\n\n\t\t\t\t\t\t\t\t\t\t\tif (self._touchIsMeaningfulEvent(event)) {\n\n\t\t\t\t\t\t\t\t\t\t\t\tself._touchRecordEvent(event);\n\n\t\t\t\t\t\t\t\t\t\t\t\tif (!self.__options.interactive || !$.contains(self._$tooltip[0], event.target)) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tself._close(event);\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t\t\t// needed to detect and ignore swiping\n\t\t\t\t\t\t\t\t\t\tif (self.__options.triggerClose.tap && env.hasTouchCapability) {\n\n\t\t\t\t\t\t\t\t\t\t\t$body.on('touchstart.'+ self.__namespace +'-triggerClose', function(event) {\n\t\t\t\t\t\t\t\t\t\t\t\tself._touchRecordEvent(event);\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}, 0);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tself._trigger('ready');\n\n\t\t\t\t\t\t\t// call our custom callback\n\t\t\t\t\t\t\tif (self.__options.functionReady) {\n\t\t\t\t\t\t\t\tself.__options.functionReady.call(self, self, {\n\t\t\t\t\t\t\t\t\torigin: self._$origin[0],\n\t\t\t\t\t\t\t\t\ttooltip: self._$tooltip[0]\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// if we have a timer set, let the countdown begin\n\t\t\t\t\t\tif (self.__options.timer > 0) {\n\n\t\t\t\t\t\t\tvar timeout = setTimeout(function() {\n\t\t\t\t\t\t\t\tself._close();\n\t\t\t\t\t\t\t}, self.__options.timer + extraTime);\n\n\t\t\t\t\t\t\tself.__timeouts.close.push(timeout);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * When using the mouseenter/touchstart open triggers, this function will\n\t * schedule the opening of the tooltip after the delay, if there is one\n\t *\n\t * @param event\n\t * @returns {self}\n\t * @protected\n \t */\n\t_openShortly: function(event) {\n\n\t\tvar self = this,\n\t\t\tok = true;\n\n\t\tif (self.__state != 'stable' && self.__state != 'appearing') {\n\n\t\t\t// if a timeout is not already running\n\t\t\tif (!self.__timeouts.open) {\n\n\t\t\t\tself._trigger({\n\t\t\t\t\ttype: 'start',\n\t\t\t\t\tevent: event,\n\t\t\t\t\tstop: function() {\n\t\t\t\t\t\tok = false;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (ok) {\n\n\t\t\t\t\tvar delay = (event.type.indexOf('touch') == 0) ?\n\t\t\t\t\t\tself.__options.delayTouch :\n\t\t\t\t\t\tself.__options.delay;\n\n\t\t\t\t\tif (delay[0]) {\n\n\t\t\t\t\t\tself.__timeouts.open = setTimeout(function() {\n\n\t\t\t\t\t\t\tself.__timeouts.open = null;\n\n\t\t\t\t\t\t\t// open only if the pointer (mouse or touch) is still over the origin.\n\t\t\t\t\t\t\t// The check on the \"meaningful event\" can only be made here, after some\n\t\t\t\t\t\t\t// time has passed (to know if the touch was a swipe or not)\n\t\t\t\t\t\t\tif (self.__pointerIsOverOrigin && self._touchIsMeaningfulEvent(event)) {\n\n\t\t\t\t\t\t\t\t// signal that we go on\n\t\t\t\t\t\t\t\tself._trigger('startend');\n\n\t\t\t\t\t\t\t\tself._open(event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t// signal that we cancel\n\t\t\t\t\t\t\t\tself._trigger('startcancel');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, delay[0]);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// signal that we go on\n\t\t\t\t\t\tself._trigger('startend');\n\n\t\t\t\t\t\tself._open(event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Meant for plugins to get their options\n\t *\n\t * @param {string} pluginName The name of the plugin that asks for its options\n\t * @param {object} defaultOptions The default options of the plugin\n\t * @returns {object} The options\n\t * @protected\n\t */\n\t_optionsExtract: function(pluginName, defaultOptions) {\n\n\t\tvar self = this,\n\t\t\toptions = $.extend(true, {}, defaultOptions);\n\n\t\t// if the plugin options were isolated in a property named after the\n\t\t// plugin, use them (prevents conflicts with other plugins)\n\t\tvar pluginOptions = self.__options[pluginName];\n\n\t\t// if not, try to get them as regular options\n\t\tif (!pluginOptions){\n\n\t\t\tpluginOptions = {};\n\n\t\t\t$.each(defaultOptions, function(optionName, value) {\n\n\t\t\t\tvar o = self.__options[optionName];\n\n\t\t\t\tif (o !== undefined) {\n\t\t\t\t\tpluginOptions[optionName] = o;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// let's merge the default options and the ones that were provided. We'd want\n\t\t// to do a deep copy but not let jQuery merge arrays, so we'll do a shallow\n\t\t// extend on two levels, that will be enough if options are not more than 1\n\t\t// level deep\n\t\t$.each(options, function(optionName, value) {\n\n\t\t\tif (pluginOptions[optionName] !== undefined) {\n\n\t\t\t\tif ((\t\ttypeof value == 'object'\n\t\t\t\t\t\t&&\t!(value instanceof Array)\n\t\t\t\t\t\t&&\tvalue != null\n\t\t\t\t\t)\n\t\t\t\t\t&&\n\t\t\t\t\t(\t\ttypeof pluginOptions[optionName] == 'object'\n\t\t\t\t\t\t&&\t!(pluginOptions[optionName] instanceof Array)\n\t\t\t\t\t\t&&\tpluginOptions[optionName] != null\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\t$.extend(options[optionName], pluginOptions[optionName]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\toptions[optionName] = pluginOptions[optionName];\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn options;\n\t},\n\n\t/**\n\t * Used at instantiation of the plugin, or afterwards by plugins that activate themselves\n\t * on existing instances\n\t *\n\t * @param {object} pluginName\n\t * @returns {self}\n\t * @protected\n\t */\n\t_plug: function(pluginName) {\n\n\t\tvar plugin = $.tooltipster._plugin(pluginName);\n\n\t\tif (plugin) {\n\n\t\t\t// if there is a constructor for instances\n\t\t\tif (plugin.instance) {\n\n\t\t\t\t// proxy non-private methods on the instance to allow new instance methods\n\t\t\t\t$.tooltipster.__bridge(plugin.instance, this, plugin.name);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthrow new Error('The \"'+ pluginName +'\" plugin is not defined');\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * This will return true if the event is a mouse event which was\n\t * emulated by the browser after a touch event. This allows us to\n\t * really dissociate mouse and touch triggers.\n\t *\n\t * There is a margin of error if a real mouse event is fired right\n\t * after (within the delay shown below) a touch event on the same\n\t * element, but hopefully it should not happen often.\n\t *\n\t * @returns {boolean}\n\t * @protected\n\t */\n\t_touchIsEmulatedEvent: function(event) {\n\n\t\tvar isEmulated = false,\n\t\t\tnow = new Date().getTime();\n\n\t\tfor (var i = this.__touchEvents.length - 1; i >= 0; i--) {\n\n\t\t\tvar e = this.__touchEvents[i];\n\n\t\t\t// delay, in milliseconds. It's supposed to be 300ms in\n\t\t\t// most browsers (350ms on iOS) to allow a double tap but\n\t\t\t// can be less (check out FastClick for more info)\n\t\t\tif (now - e.time < 500) {\n\n\t\t\t\tif (e.target === event.target) {\n\t\t\t\t\tisEmulated = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn isEmulated;\n\t},\n\n\t/**\n\t * Returns false if the event was an emulated mouse event or\n\t * a touch event involved in a swipe gesture.\n\t *\n\t * @param {object} event\n\t * @returns {boolean}\n\t * @protected\n\t */\n\t_touchIsMeaningfulEvent: function(event) {\n\t\treturn (\n\t\t\t\t(this._touchIsTouchEvent(event) && !this._touchSwiped(event.target))\n\t\t\t||\t(!this._touchIsTouchEvent(event) && !this._touchIsEmulatedEvent(event))\n\t\t);\n\t},\n\n\t/**\n\t * Checks if an event is a touch event\n\t *\n\t * @param {object} event\n\t * @returns {boolean}\n\t * @protected\n\t */\n\t_touchIsTouchEvent: function(event){\n\t\treturn event.type.indexOf('touch') == 0;\n\t},\n\n\t/**\n\t * Store touch events for a while to detect swiping and emulated mouse events\n\t *\n\t * @param {object} event\n\t * @returns {self}\n\t * @protected\n\t */\n\t_touchRecordEvent: function(event) {\n\n\t\tif (this._touchIsTouchEvent(event)) {\n\t\t\tevent.time = new Date().getTime();\n\t\t\tthis.__touchEvents.push(event);\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns true if a swipe happened after the last touchstart event fired on\n\t * event.target.\n\t *\n\t * We need to differentiate a swipe from a tap before we let the event open\n\t * or close the tooltip. A swipe is when a touchmove (scroll) event happens\n\t * on the body between the touchstart and the touchend events of an element.\n\t *\n\t * @param {object} target The HTML element that may have triggered the swipe\n\t * @returns {boolean}\n\t * @protected\n\t */\n\t_touchSwiped: function(target) {\n\n\t\tvar swiped = false;\n\n\t\tfor (var i = this.__touchEvents.length - 1; i >= 0; i--) {\n\n\t\t\tvar e = this.__touchEvents[i];\n\n\t\t\tif (e.type == 'touchmove') {\n\t\t\t\tswiped = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (\n\t\t\t\te.type == 'touchstart'\n\t\t\t\t&&\ttarget === e.target\n\t\t\t) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn swiped;\n\t},\n\n\t/**\n\t * Triggers an event on the instance emitters\n\t *\n\t * @returns {self}\n\t * @protected\n\t */\n\t_trigger: function() {\n\n\t\tvar args = Array.prototype.slice.apply(arguments);\n\n\t\tif (typeof args[0] == 'string') {\n\t\t\targs[0] = { type: args[0] };\n\t\t}\n\n\t\t// add properties to the event\n\t\targs[0].instance = this;\n\t\targs[0].origin = this._$origin ? this._$origin[0] : null;\n\t\targs[0].tooltip = this._$tooltip ? this._$tooltip[0] : null;\n\n\t\t// note: the order of emitters matters\n\t\tthis.__$emitterPrivate.trigger.apply(this.__$emitterPrivate, args);\n\t\t$.tooltipster._trigger.apply($.tooltipster, args);\n\t\tthis.__$emitterPublic.trigger.apply(this.__$emitterPublic, args);\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Deactivate a plugin on this instance\n\t *\n\t * @returns {self}\n\t * @protected\n\t */\n\t_unplug: function(pluginName) {\n\n\t\tvar self = this;\n\n\t\t// if the plugin has been activated on this instance\n\t\tif (self[pluginName]) {\n\n\t\t\tvar plugin = $.tooltipster._plugin(pluginName);\n\n\t\t\t// if there is a constructor for instances\n\t\t\tif (plugin.instance) {\n\n\t\t\t\t// unbridge\n\t\t\t\t$.each(plugin.instance, function(methodName, fn) {\n\n\t\t\t\t\t// if the method exists (privates methods do not) and comes indeed from\n\t\t\t\t\t// this plugin (may be missing or come from a conflicting plugin).\n\t\t\t\t\tif (\tself[methodName]\n\t\t\t\t\t\t&&\tself[methodName].bridged === self[pluginName]\n\t\t\t\t\t) {\n\t\t\t\t\t\tdelete self[methodName];\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// destroy the plugin\n\t\t\tif (self[pluginName].__destroy) {\n\t\t\t\tself[pluginName].__destroy();\n\t\t\t}\n\n\t\t\t// remove the reference to the plugin instance\n\t\t\tdelete self[pluginName];\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * @see self::_close\n\t * @returns {self}\n\t * @public\n\t */\n\tclose: function(callback) {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis._close(null, callback);\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Sets or gets the content of the tooltip\n\t *\n\t * @returns {mixed|self}\n\t * @public\n\t */\n\tcontent: function(content) {\n\n\t\tvar self = this;\n\n\t\t// getter method\n\t\tif (content === undefined) {\n\t\t\treturn self.__Content;\n\t\t}\n\t\t// setter method\n\t\telse {\n\n\t\t\tif (!self.__destroyed) {\n\n\t\t\t\t// change the content\n\t\t\t\tself.__contentSet(content);\n\n\t\t\t\tif (self.__Content !== null) {\n\n\t\t\t\t\t// update the tooltip if it is open\n\t\t\t\t\tif (self.__state !== 'closed') {\n\n\t\t\t\t\t\t// reset the content in the tooltip\n\t\t\t\t\t\tself.__contentInsert();\n\n\t\t\t\t\t\t// reposition and resize the tooltip\n\t\t\t\t\t\tself.reposition();\n\n\t\t\t\t\t\t// if we want to play a little animation showing the content changed\n\t\t\t\t\t\tif (self.__options.updateAnimation) {\n\n\t\t\t\t\t\t\tif (env.hasTransitions) {\n\n\t\t\t\t\t\t\t\t// keep the reference in the local scope\n\t\t\t\t\t\t\t\tvar animation = self.__options.updateAnimation;\n\n\t\t\t\t\t\t\t\tself._$tooltip.addClass('tooltipster-update-'+ animation);\n\n\t\t\t\t\t\t\t\t// remove the class after a while. The actual duration of the\n\t\t\t\t\t\t\t\t// update animation may be shorter, it's set in the CSS rules\n\t\t\t\t\t\t\t\tsetTimeout(function() {\n\n\t\t\t\t\t\t\t\t\tif (self.__state != 'closed') {\n\n\t\t\t\t\t\t\t\t\t\tself._$tooltip.removeClass('tooltipster-update-'+ animation);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}, 1000);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tself._$tooltip.fadeTo(200, 0.5, function() {\n\t\t\t\t\t\t\t\t\tif (self.__state != 'closed') {\n\t\t\t\t\t\t\t\t\t\tself._$tooltip.fadeTo(200, 1);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tself._close();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tself.__destroyError();\n\t\t\t}\n\n\t\t\treturn self;\n\t\t}\n\t},\n\n\t/**\n\t * Destroys the tooltip\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\tdestroy: function() {\n\n\t\tvar self = this;\n\n\t\tif (!self.__destroyed) {\n\n\t\t\tif(self.__state != 'closed'){\n\n\t\t\t\t// no closing delay\n\t\t\t\tself.option('animationDuration', 0)\n\t\t\t\t\t// force closing\n\t\t\t\t\t._close(null, null, true);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// there might be an open timeout still running\n\t\t\t\tself.__timeoutsClear();\n\t\t\t}\n\n\t\t\t// send event\n\t\t\tself._trigger('destroy');\n\n\t\t\tself.__destroyed = true;\n\n\t\t\tself._$origin\n\t\t\t\t.removeData(self.__namespace)\n\t\t\t\t// remove the open trigger listeners\n\t\t\t\t.off('.'+ self.__namespace +'-triggerOpen');\n\n\t\t\t// remove the touch listener\n\t\t\t$(env.window.document.body).off('.' + self.__namespace +'-triggerOpen');\n\n\t\t\tvar ns = self._$origin.data('tooltipster-ns');\n\n\t\t\t// if the origin has been removed from DOM, its data may\n\t\t\t// well have been destroyed in the process and there would\n\t\t\t// be nothing to clean up or restore\n\t\t\tif (ns) {\n\n\t\t\t\t// if there are no more tooltips on this element\n\t\t\t\tif (ns.length === 1) {\n\n\t\t\t\t\t// optional restoration of a title attribute\n\t\t\t\t\tvar title = null;\n\t\t\t\t\tif (self.__options.restoration == 'previous') {\n\t\t\t\t\t\ttitle = self._$origin.data('tooltipster-initialTitle');\n\t\t\t\t\t}\n\t\t\t\t\telse if (self.__options.restoration == 'current') {\n\n\t\t\t\t\t\t// old school technique to stringify when outerHTML is not supported\n\t\t\t\t\t\ttitle = (typeof self.__Content == 'string') ?\n\t\t\t\t\t\t\tself.__Content :\n\t\t\t\t\t\t\t$('<div></div>').append(self.__Content).html();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (title) {\n\t\t\t\t\t\tself._$origin.attr('title', title);\n\t\t\t\t\t}\n\n\t\t\t\t\t// final cleaning\n\n\t\t\t\t\tself._$origin.removeClass('tooltipstered');\n\n\t\t\t\t\tself._$origin\n\t\t\t\t\t\t.removeData('tooltipster-ns')\n\t\t\t\t\t\t.removeData('tooltipster-initialTitle');\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// remove the instance namespace from the list of namespaces of\n\t\t\t\t\t// tooltips present on the element\n\t\t\t\t\tns = $.grep(ns, function(el, i) {\n\t\t\t\t\t\treturn el !== self.__namespace;\n\t\t\t\t\t});\n\t\t\t\t\tself._$origin.data('tooltipster-ns', ns);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// last event\n\t\t\tself._trigger('destroyed');\n\n\t\t\t// unbind private and public event listeners\n\t\t\tself._off();\n\t\t\tself.off();\n\n\t\t\t// remove external references, just in case\n\t\t\tself.__Content = null;\n\t\t\tself.__$emitterPrivate = null;\n\t\t\tself.__$emitterPublic = null;\n\t\t\tself.__options.parent = null;\n\t\t\tself._$origin = null;\n\t\t\tself._$tooltip = null;\n\n\t\t\t// make sure the object is no longer referenced in there to prevent\n\t\t\t// memory leaks\n\t\t\t$.tooltipster.__instancesLatestArr = $.grep($.tooltipster.__instancesLatestArr, function(el, i) {\n\t\t\t\treturn self !== el;\n\t\t\t});\n\n\t\t\tclearInterval(self.__garbageCollector);\n\t\t}\n\t\telse {\n\t\t\tself.__destroyError();\n\t\t}\n\n\t\t// we return the scope rather than true so that the call to\n\t\t// .tooltipster('destroy') actually returns the matched elements\n\t\t// and applies to all of them\n\t\treturn self;\n\t},\n\n\t/**\n\t * Disables the tooltip\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\tdisable: function() {\n\n\t\tif (!this.__destroyed) {\n\n\t\t\t// close first, in case the tooltip would not disappear on\n\t\t\t// its own (no close trigger)\n\t\t\tthis._close();\n\t\t\tthis.__enabled = false;\n\n\t\t\treturn this;\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns the HTML element of the origin\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\telementOrigin: function() {\n\n\t\tif (!this.__destroyed) {\n\t\t\treturn this._$origin[0];\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\t},\n\n\t/**\n\t * Returns the HTML element of the tooltip\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\telementTooltip: function() {\n\t\treturn this._$tooltip ? this._$tooltip[0] : null;\n\t},\n\n\t/**\n\t * Enables the tooltip\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\tenable: function() {\n\t\tthis.__enabled = true;\n\t\treturn this;\n\t},\n\n\t/**\n\t * Alias, deprecated in 4.0.0\n\t *\n\t * @param {function} callback\n\t * @returns {self}\n\t * @public\n\t */\n\thide: function(callback) {\n\t\treturn this.close(callback);\n\t},\n\n\t/**\n\t * Returns the instance\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\tinstance: function() {\n\t\treturn this;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins (use ::_off() instead)\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\toff: function() {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis.__$emitterPublic.off.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins (use ::_on() instead)\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\ton: function() {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis.__$emitterPublic.on.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\tone: function() {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis.__$emitterPublic.one.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * @see self::_open\n\t * @returns {self}\n\t * @public\n\t */\n\topen: function(callback) {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis._open(null, callback);\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Get or set options. For internal use and advanced users only.\n\t *\n\t * @param {string} o Option name\n\t * @param {mixed} val optional A new value for the option\n\t * @return {mixed|self} If val is omitted, the value of the option\n\t * is returned, otherwise the instance itself is returned\n\t * @public\n\t */\n\toption: function(o, val) {\n\n\t\t// getter\n\t\tif (val === undefined) {\n\t\t\treturn this.__options[o];\n\t\t}\n\t\t// setter\n\t\telse {\n\n\t\t\tif (!this.__destroyed) {\n\n\t\t\t\t// change value\n\t\t\t\tthis.__options[o] = val;\n\n\t\t\t\t// format\n\t\t\t\tthis.__optionsFormat();\n\n\t\t\t\t// re-prepare the triggers if needed\n\t\t\t\tif ($.inArray(o, ['trigger', 'triggerClose', 'triggerOpen']) >= 0) {\n\t\t\t\t\tthis.__prepareOrigin();\n\t\t\t\t}\n\n\t\t\t\tif (o === 'selfDestruction') {\n\t\t\t\t\tthis.__prepareGC();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.__destroyError();\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\t},\n\n\t/**\n\t * This method is in charge of setting the position and size properties of the tooltip.\n\t * All the hard work is delegated to the display plugin.\n\t * Note: The tooltip may be detached from the DOM at the moment the method is called\n\t * but must be attached by the end of the method call.\n\t *\n\t * @param {object} event For internal use only. Defined if an event such as\n\t * window resizing triggered the repositioning\n\t * @param {boolean} tooltipIsDetached For internal use only. Set this to true if you\n\t * know that the tooltip not being in the DOM is not an issue (typically when the\n\t * tooltip element has just been created but has not been added to the DOM yet).\n\t * @returns {self}\n\t * @public\n\t */\n\treposition: function(event, tooltipIsDetached) {\n\n\t\tvar self = this;\n\n\t\tif (!self.__destroyed) {\n\n\t\t\t// if the tooltip is still open and the origin is still in the DOM\n\t\t\tif (self.__state != 'closed' && bodyContains(self._$origin)) {\n\n\t\t\t\t// if the tooltip has not been removed from DOM manually (or if it\n\t\t\t\t// has been detached on purpose)\n\t\t\t\tif (tooltipIsDetached || bodyContains(self._$tooltip)) {\n\n\t\t\t\t\tif (!tooltipIsDetached) {\n\t\t\t\t\t\t// detach in case the tooltip overflows the window and adds\n\t\t\t\t\t\t// scrollbars to it, so __geometry can be accurate\n\t\t\t\t\t\tself._$tooltip.detach();\n\t\t\t\t\t}\n\n\t\t\t\t\t// refresh the geometry object before passing it as a helper\n\t\t\t\t\tself.__Geometry = self.__geometry();\n\n\t\t\t\t\t// let a plugin fo the rest\n\t\t\t\t\tself._trigger({\n\t\t\t\t\t\ttype: 'reposition',\n\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\thelper: {\n\t\t\t\t\t\t\tgeo: self.__Geometry\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tself.__destroyError();\n\t\t}\n\n\t\treturn self;\n\t},\n\n\t/**\n\t * Alias, deprecated in 4.0.0\n\t *\n\t * @param callback\n\t * @returns {self}\n\t * @public\n\t */\n\tshow: function(callback) {\n\t\treturn this.open(callback);\n\t},\n\n\t/**\n\t * Returns some properties about the instance\n\t *\n\t * @returns {object}\n\t * @public\n\t */\n\tstatus: function() {\n\n\t\treturn {\n\t\t\tdestroyed: this.__destroyed,\n\t\t\tenabled: this.__enabled,\n\t\t\topen: this.__state !== 'closed',\n\t\t\tstate: this.__state\n\t\t};\n\t},\n\n\t/**\n\t * For public use only, not to be used by plugins\n\t *\n\t * @returns {self}\n\t * @public\n\t */\n\ttriggerHandler: function() {\n\n\t\tif (!this.__destroyed) {\n\t\t\tthis.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));\n\t\t}\n\t\telse {\n\t\t\tthis.__destroyError();\n\t\t}\n\n\t\treturn this;\n\t}\n};\n\n$.fn.tooltipster = function() {\n\n\t// for using in closures\n\tvar args = Array.prototype.slice.apply(arguments),\n\t\t// common mistake: an HTML element can't be in several tooltips at the same time\n\t\tcontentCloningWarning = 'You are using a single HTML element as content for several tooltips. You probably want to set the contentCloning option to TRUE.';\n\n\t// this happens with $(sel).tooltipster(...) when $(sel) does not match anything\n\tif (this.length === 0) {\n\n\t\t// still chainable\n\t\treturn this;\n\t}\n\t// this happens when calling $(sel).tooltipster('methodName or options')\n\t// where $(sel) matches one or more elements\n\telse {\n\n\t\t// method calls\n\t\tif (typeof args[0] === 'string') {\n\n\t\t\tvar v = '#*$~&';\n\n\t\t\tthis.each(function() {\n\n\t\t\t\t// retrieve the namepaces of the tooltip(s) that exist on that element.\n\t\t\t\t// We will interact with the first tooltip only.\n\t\t\t\tvar ns = $(this).data('tooltipster-ns'),\n\t\t\t\t\t// self represents the instance of the first tooltipster plugin\n\t\t\t\t\t// associated to the current HTML object of the loop\n\t\t\t\t\tself = ns ? $(this).data(ns[0]) : null;\n\n\t\t\t\t// if the current element holds a tooltipster instance\n\t\t\t\tif (self) {\n\n\t\t\t\t\tif (typeof self[args[0]] === 'function') {\n\n\t\t\t\t\t\tif (\tthis.length > 1\n\t\t\t\t\t\t\t&&\targs[0] == 'content'\n\t\t\t\t\t\t\t&&\t(\targs[1] instanceof $\n\t\t\t\t\t\t\t\t|| (typeof args[1] == 'object' && args[1] != null && args[1].tagName)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t&&\t!self.__options.contentCloning\n\t\t\t\t\t\t\t&&\tself.__options.debug\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tconsole.log(contentCloningWarning);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// note : args[1] and args[2] may not be defined\n\t\t\t\t\t\tvar resp = self[args[0]](args[1], args[2]);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthrow new Error('Unknown method \"'+ args[0] +'\"');\n\t\t\t\t\t}\n\n\t\t\t\t\t// if the function returned anything other than the instance\n\t\t\t\t\t// itself (which implies chaining, except for the `instance` method)\n\t\t\t\t\tif (resp !== self || args[0] === 'instance') {\n\n\t\t\t\t\t\tv = resp;\n\n\t\t\t\t\t\t// return false to stop .each iteration on the first element\n\t\t\t\t\t\t// matched by the selector\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new Error('You called Tooltipster\\'s \"'+ args[0] +'\" method on an uninitialized element');\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn (v !== '#*$~&') ? v : this;\n\t\t}\n\t\t// first argument is undefined or an object: the tooltip is initializing\n\t\telse {\n\n\t\t\t// reset the array of last initialized objects\n\t\t\t$.tooltipster.__instancesLatestArr = [];\n\n\t\t\t// is there a defined value for the multiple option in the options object ?\n\t\t\tvar\tmultipleIsSet = args[0] && args[0].multiple !== undefined,\n\t\t\t\t// if the multiple option is set to true, or if it's not defined but\n\t\t\t\t// set to true in the defaults\n\t\t\t\tmultiple = (multipleIsSet && args[0].multiple) || (!multipleIsSet && defaults.multiple),\n\t\t\t\t// same for content\n\t\t\t\tcontentIsSet = args[0] && args[0].content !== undefined,\n\t\t\t\tcontent = (contentIsSet && args[0].content) || (!contentIsSet && defaults.content),\n\t\t\t\t// same for contentCloning\n\t\t\t\tcontentCloningIsSet = args[0] && args[0].contentCloning !== undefined,\n\t\t\t\tcontentCloning =\n\t\t\t\t\t\t(contentCloningIsSet && args[0].contentCloning)\n\t\t\t\t\t||\t(!contentCloningIsSet && defaults.contentCloning),\n\t\t\t\t// same for debug\n\t\t\t\tdebugIsSet = args[0] && args[0].debug !== undefined,\n\t\t\t\tdebug = (debugIsSet && args[0].debug) || (!debugIsSet && defaults.debug);\n\n\t\t\tif (\tthis.length > 1\n\t\t\t\t&&\t(\tcontent instanceof $\n\t\t\t\t\t|| (typeof content == 'object' && content != null && content.tagName)\n\t\t\t\t)\n\t\t\t\t&&\t!contentCloning\n\t\t\t\t&&\tdebug\n\t\t\t) {\n\t\t\t\tconsole.log(contentCloningWarning);\n\t\t\t}\n\n\t\t\t// create a tooltipster instance for each element if it doesn't\n\t\t\t// already have one or if the multiple option is set, and attach the\n\t\t\t// object to it\n\t\t\tthis.each(function() {\n\n\t\t\t\tvar go = false,\n\t\t\t\t\t$this = $(this),\n\t\t\t\t\tns = $this.data('tooltipster-ns'),\n\t\t\t\t\tobj = null;\n\n\t\t\t\tif (!ns) {\n\t\t\t\t\tgo = true;\n\t\t\t\t}\n\t\t\t\telse if (multiple) {\n\t\t\t\t\tgo = true;\n\t\t\t\t}\n\t\t\t\telse if (debug) {\n\t\t\t\t\tconsole.log('Tooltipster: one or more tooltips are already attached to the element below. Ignoring.');\n\t\t\t\t\tconsole.log(this);\n\t\t\t\t}\n\n\t\t\t\tif (go) {\n\t\t\t\t\tobj = new $.Tooltipster(this, args[0]);\n\n\t\t\t\t\t// save the reference of the new instance\n\t\t\t\t\tif (!ns) ns = [];\n\t\t\t\t\tns.push(obj.__namespace);\n\t\t\t\t\t$this.data('tooltipster-ns', ns);\n\n\t\t\t\t\t// save the instance itself\n\t\t\t\t\t$this.data(obj.__namespace, obj);\n\n\t\t\t\t\t// call our constructor custom function.\n\t\t\t\t\t// we do this here and not in ::init() because we wanted\n\t\t\t\t\t// the object to be saved in $this.data before triggering\n\t\t\t\t\t// it\n\t\t\t\t\tif (obj.__options.functionInit) {\n\t\t\t\t\t\tobj.__options.functionInit.call(obj, obj, {\n\t\t\t\t\t\t\torigin: this\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t// and now the event, for the plugins and core emitter\n\t\t\t\t\tobj._trigger('init');\n\t\t\t\t}\n\n\t\t\t\t$.tooltipster.__instancesLatestArr.push(obj);\n\t\t\t});\n\n\t\t\treturn this;\n\t\t}\n\t}\n};\n\n// Utilities\n\n/**\n * A class to check if a tooltip can fit in given dimensions\n *\n * @param {object} $tooltip The jQuery wrapped tooltip element, or a clone of it\n */\nfunction Ruler($tooltip) {\n\n\t// list of instance variables\n\n\tthis.$container;\n\tthis.constraints = null;\n\tthis.__$tooltip;\n\n\tthis.__init($tooltip);\n}\n\nRuler.prototype = {\n\n\t/**\n\t * Move the tooltip into an invisible div that does not allow overflow to make\n\t * size tests. Note: the tooltip may or may not be attached to the DOM at the\n\t * moment this method is called, it does not matter.\n\t *\n\t * @param {object} $tooltip The object to test. May be just a clone of the\n\t * actual tooltip.\n\t * @private\n\t */\n\t__init: function($tooltip) {\n\n\t\tthis.__$tooltip = $tooltip;\n\n\t\tthis.__$tooltip\n\t\t\t.css({\n\t\t\t\t// for some reason we have to specify top and left 0\n\t\t\t\tleft: 0,\n\t\t\t\t// any overflow will be ignored while measuring\n\t\t\t\toverflow: 'hidden',\n\t\t\t\t// positions at (0,0) without the div using 100% of the available width\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: 0\n\t\t\t})\n\t\t\t// overflow must be auto during the test. We re-set this in case\n\t\t\t// it were modified by the user\n\t\t\t.find('.tooltipster-content')\n\t\t\t\t.css('overflow', 'auto');\n\n\t\tthis.$container = $('<div class=\"tooltipster-ruler\"></div>')\n\t\t\t.append(this.__$tooltip)\n\t\t\t.appendTo(env.window.document.body);\n\t},\n\n\t/**\n\t * Force the browser to redraw (re-render) the tooltip immediately. This is required\n\t * when you changed some CSS properties and need to make something with it\n\t * immediately, without waiting for the browser to redraw at the end of instructions.\n\t *\n\t * @see http://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes\n\t * @private\n\t */\n\t__forceRedraw: function() {\n\n\t\t// note: this would work but for Webkit only\n\t\t//this.__$tooltip.close();\n\t\t//this.__$tooltip[0].offsetHeight;\n\t\t//this.__$tooltip.open();\n\n\t\t// works in FF too\n\t\tvar $p = this.__$tooltip.parent();\n\t\tthis.__$tooltip.detach();\n\t\tthis.__$tooltip.appendTo($p);\n\t},\n\n\t/**\n\t * Set maximum dimensions for the tooltip. A call to ::measure afterwards\n\t * will tell us if the content overflows or if it's ok\n\t *\n\t * @param {int} width\n\t * @param {int} height\n\t * @return {Ruler}\n\t * @public\n\t */\n\tconstrain: function(width, height) {\n\n\t\tthis.constraints = {\n\t\t\twidth: width,\n\t\t\theight: height\n\t\t};\n\n\t\tthis.__$tooltip.css({\n\t\t\t// we disable display:flex, otherwise the content would overflow without\n\t\t\t// creating horizontal scrolling (which we need to detect).\n\t\t\tdisplay: 'block',\n\t\t\t// reset any previous height\n\t\t\theight: '',\n\t\t\t// we'll check if horizontal scrolling occurs\n\t\t\toverflow: 'auto',\n\t\t\t// we'll set the width and see what height is generated and if there\n\t\t\t// is horizontal overflow\n\t\t\twidth: width\n\t\t});\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Reset the tooltip content overflow and remove the test container\n\t *\n\t * @returns {Ruler}\n\t * @public\n\t */\n\tdestroy: function() {\n\n\t\t// in case the element was not a clone\n\t\tthis.__$tooltip\n\t\t\t.detach()\n\t\t\t.find('.tooltipster-content')\n\t\t\t\t.css({\n\t\t\t\t\t// reset to CSS value\n\t\t\t\t\tdisplay: '',\n\t\t\t\t\toverflow: ''\n\t\t\t\t});\n\n\t\tthis.$container.remove();\n\t},\n\n\t/**\n\t * Removes any constraints\n\t *\n\t * @returns {Ruler}\n\t * @public\n\t */\n\tfree: function() {\n\n\t\tthis.constraints = null;\n\n\t\t// reset to natural size\n\t\tthis.__$tooltip.css({\n\t\t\tdisplay: '',\n\t\t\theight: '',\n\t\t\toverflow: 'visible',\n\t\t\twidth: ''\n\t\t});\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Returns the size of the tooltip. When constraints are applied, also returns\n\t * whether the tooltip fits in the provided dimensions.\n\t * The idea is to see if the new height is small enough and if the content does\n\t * not overflow horizontally.\n\t *\n\t * @param {int} width\n\t * @param {int} height\n\t * @returns {object} An object with a bool `fits` property and a `size` property\n\t * @public\n\t */\n\tmeasure: function() {\n\n\t\tthis.__forceRedraw();\n\n\t\tvar tooltipBcr = this.__$tooltip[0].getBoundingClientRect(),\n\t\t\tresult = { size: {\n\t\t\t\t// bcr.width/height are not defined in IE8- but in this\n\t\t\t\t// case, bcr.right/bottom will have the same value\n\t\t\t\t// except in iOS 8+ where tooltipBcr.bottom/right are wrong\n\t\t\t\t// after scrolling for reasons yet to be determined.\n\t\t\t\t// tooltipBcr.top/left might not be 0, see issue #514\n\t\t\t\theight: tooltipBcr.height || (tooltipBcr.bottom - tooltipBcr.top),\n\t\t\t\twidth: tooltipBcr.width || (tooltipBcr.right - tooltipBcr.left)\n\t\t\t}};\n\n\t\tif (this.constraints) {\n\n\t\t\t// note: we used to use offsetWidth instead of boundingRectClient but\n\t\t\t// it returned rounded values, causing issues with sub-pixel layouts.\n\n\t\t\t// note2: noticed that the bcrWidth of text content of a div was once\n\t\t\t// greater than the bcrWidth of its container by 1px, causing the final\n\t\t\t// tooltip box to be too small for its content. However, evaluating\n\t\t\t// their widths one against the other (below) surprisingly returned\n\t\t\t// equality. Happened only once in Chrome 48, was not able to reproduce\n\t\t\t// => just having fun with float position values...\n\n\t\t\tvar $content = this.__$tooltip.find('.tooltipster-content'),\n\t\t\t\theight = this.__$tooltip.outerHeight(),\n\t\t\t\tcontentBcr = $content[0].getBoundingClientRect(),\n\t\t\t\tfits = {\n\t\t\t\t\theight: height <= this.constraints.height,\n\t\t\t\t\twidth: (\n\t\t\t\t\t\t// this condition accounts for min-width property that\n\t\t\t\t\t\t// may apply\n\t\t\t\t\t\ttooltipBcr.width <= this.constraints.width\n\t\t\t\t\t\t\t// the -1 is here because scrollWidth actually returns\n\t\t\t\t\t\t\t// a rounded value, and may be greater than bcr.width if\n\t\t\t\t\t\t\t// it was rounded up. This may cause an issue for contents\n\t\t\t\t\t\t\t// which actually really overflow  by 1px or so, but that\n\t\t\t\t\t\t\t// should be rare. Not sure how to solve this efficiently.\n\t\t\t\t\t\t\t// See http://blogs.msdn.com/b/ie/archive/2012/02/17/sub-pixel-rendering-and-the-css-object-model.aspx\n\t\t\t\t\t\t&&\tcontentBcr.width >= $content[0].scrollWidth - 1\n\t\t\t\t\t)\n\t\t\t\t};\n\n\t\t\tresult.fits = fits.height && fits.width;\n\t\t}\n\n\t\t// old versions of IE get the width wrong for some reason and it causes\n\t\t// the text to be broken to a new line, so we round it up. If the width\n\t\t// is the width of the screen though, we can assume it is accurate.\n\t\tif (\tenv.IE\n\t\t\t&&\tenv.IE <= 11\n\t\t\t&&\tresult.size.width !== env.window.document.documentElement.clientWidth\n\t\t) {\n\t\t\tresult.size.width = Math.ceil(result.size.width) + 1;\n\t\t}\n\n\t\treturn result;\n\t}\n};\n\n// quick & dirty compare function, not bijective nor multidimensional\nfunction areEqual(a,b) {\n\tvar same = true;\n\t$.each(a, function(i, _) {\n\t\tif (b[i] === undefined || a[i] !== b[i]) {\n\t\t\tsame = false;\n\t\t\treturn false;\n\t\t}\n\t});\n\treturn same;\n}\n\n/**\n * A fast function to check if an element is still in the DOM. It\n * tries to use an id as ids are indexed by the browser, or falls\n * back to jQuery's `contains` method. May fail if two elements\n * have the same id, but so be it\n *\n * @param {object} $obj A jQuery-wrapped HTML element\n * @return {boolean}\n */\nfunction bodyContains($obj) {\n\tvar id = $obj.attr('id'),\n\t\tel = id ? env.window.document.getElementById(id) : null;\n\t// must also check that the element with the id is the one we want\n\treturn el ? el === $obj[0] : $.contains(env.window.document.body, $obj[0]);\n}\n\n// detect IE versions for dirty fixes\nvar uA = navigator.userAgent.toLowerCase();\nif (uA.indexOf('msie') != -1) env.IE = parseInt(uA.split('msie')[1]);\nelse if (uA.toLowerCase().indexOf('trident') !== -1 && uA.indexOf(' rv:11') !== -1) env.IE = 11;\nelse if (uA.toLowerCase().indexOf('edge/') != -1) env.IE = parseInt(uA.toLowerCase().split('edge/')[1]);\n\n// detecting support for CSS transitions\nfunction transitionSupport() {\n\n\t// env.window is not defined yet when this is called\n\tif (!win) return false;\n\n\tvar b = win.document.body || win.document.documentElement,\n\t\ts = b.style,\n\t\tp = 'transition',\n\t\tv = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'];\n\n\tif (typeof s[p] == 'string') { return true; }\n\n\tp = p.charAt(0).toUpperCase() + p.substr(1);\n\tfor (var i=0; i<v.length; i++) {\n\t\tif (typeof s[v[i] + p] == 'string') { return true; }\n\t}\n\treturn false;\n}\n\n// we'll return jQuery for plugins not to have to declare it as a dependency,\n// but it's done by a build task since it should be included only once at the\n// end when we concatenate the main file with a plugin\n// sideTip is Tooltipster's default plugin.\n// This file will be UMDified by a build task.\n\nvar pluginName = 'tooltipster.sideTip';\n\n$.tooltipster._plugin({\n\tname: pluginName,\n\tinstance: {\n\t\t/**\n\t\t * Defaults are provided as a function for an easy override by inheritance\n\t\t *\n\t\t * @return {object} An object with the defaults options\n\t\t * @private\n\t\t */\n\t\t__defaults: function() {\n\n\t\t\treturn {\n\t\t\t\t// if the tooltip should display an arrow that points to the origin\n\t\t\t\tarrow: true,\n\t\t\t\t// the distance in pixels between the tooltip and the origin\n\t\t\t\tdistance: 6,\n\t\t\t\t// allows to easily change the position of the tooltip\n\t\t\t\tfunctionPosition: null,\n\t\t\t\tmaxWidth: null,\n\t\t\t\t// used to accomodate the arrow of tooltip if there is one.\n\t\t\t\t// First to make sure that the arrow target is not too close\n\t\t\t\t// to the edge of the tooltip, so the arrow does not overflow\n\t\t\t\t// the tooltip. Secondly when we reposition the tooltip to\n\t\t\t\t// make sure that it's positioned in such a way that the arrow is\n\t\t\t\t// still pointing at the target (and not a few pixels beyond it).\n\t\t\t\t// It should be equal to or greater than half the width of\n\t\t\t\t// the arrow (by width we mean the size of the side which touches\n\t\t\t\t// the side of the tooltip).\n\t\t\t\tminIntersection: 16,\n\t\t\t\tminWidth: 0,\n\t\t\t\t// deprecated in 4.0.0. Listed for _optionsExtract to pick it up\n\t\t\t\tposition: null,\n\t\t\t\tside: 'top',\n\t\t\t\t// set to false to position the tooltip relatively to the document rather\n\t\t\t\t// than the window when we open it\n\t\t\t\tviewportAware: true,\n                defaultStyles: {\n                    backgroundColor: '#fff',\n                    textColor: '#000'\n                }\n\t\t\t};\n\t\t},\n\n\t\t/**\n\t\t * Run once: at instantiation of the plugin\n\t\t *\n\t\t * @param {object} instance The tooltipster object that instantiated this plugin\n\t\t * @private\n\t\t */\n\t\t__init: function(instance) {\n\n\t\t\tvar self = this;\n\n\t\t\t// list of instance variables\n\n\t\t\tself.__instance = instance;\n\t\t\tself.__namespace = 'tooltipster-sideTip-'+ Math.round(Math.random()*1000000);\n\t\t\tself.__previousState = 'closed';\n\t\t\tself.__options;\n\n\t\t\t// initial formatting\n\t\t\tself.__optionsFormat();\n\n\t\t\tself.__instance._on('state.'+ self.__namespace, function(event) {\n\n\t\t\t\tif (event.state == 'closed') {\n\t\t\t\t\tself.__close();\n\t\t\t\t}\n\t\t\t\telse if (event.state == 'appearing' && self.__previousState == 'closed') {\n\t\t\t\t\tself.__create();\n\t\t\t\t}\n\n\t\t\t\tself.__previousState = event.state;\n\t\t\t});\n\n\t\t\t// reformat every time the options are changed\n\t\t\tself.__instance._on('options.'+ self.__namespace, function() {\n\t\t\t\tself.__optionsFormat();\n\t\t\t});\n\n\t\t\tself.__instance._on('reposition.'+ self.__namespace, function(e) {\n\t\t\t\tself.__reposition(e.event, e.helper);\n\t\t\t});\n\t\t},\n\n\t\t/**\n\t\t * Called when the tooltip has closed\n\t\t *\n\t\t * @private\n\t\t */\n\t\t__close: function() {\n\n\t\t\t// detach our content object first, so the next jQuery's remove()\n\t\t\t// call does not unbind its event handlers\n\t\t\tif (this.__instance.content() instanceof $) {\n\t\t\t\tthis.__instance.content().detach();\n\t\t\t}\n\n\t\t\t// remove the tooltip from the DOM\n\t\t\tthis.__instance._$tooltip.remove();\n\t\t\tthis.__instance._$tooltip = null;\n\t\t},\n\n\t\t/**\n\t\t * Creates the HTML element of the tooltip.\n\t\t *\n\t\t * @private\n\t\t */\n\t\t__create: function() {\n\t\t    var self = this,\n                styles = this.__instance.__options.styles;\n\n\t\t\t// note: we wrap with a .tooltipster-box div to be able to set a margin on it\n\t\t\t// (.tooltipster-base must not have one)\n\t\t\tvar $html = $(\n\t\t\t\t'<div class=\"tooltipster-base tooltipster-sidetip\">' +\n\t\t\t\t\t'<div class=\"tooltipster-box\">' +\n\t\t\t\t\t\t'<div class=\"tooltipster-content\"></div>' +\n\t\t\t\t\t'</div>' +\n\t\t\t\t\t'<div class=\"tooltipster-arrow\">' +\n\t\t\t\t\t\t'<div class=\"tooltipster-arrow-uncropped\">' +\n\t\t\t\t\t\t\t'<div class=\"tooltipster-arrow-border\"></div>' +\n\t\t\t\t\t\t\t'<div class=\"tooltipster-arrow-background\"></div>' +\n\t\t\t\t\t\t'</div>' +\n\t\t\t\t\t'</div>' +\n\t\t\t\t'</div>'\n\t\t\t);\n\n            $html\n                .find('.tooltipster-box')\n                .css({\n                    'color': styles.textColor ? styles.textColor : self.__options.defaultStyles.textColor,\n                    'backgroundColor': styles.backgroundColor\n                        ? styles.backgroundColor\n                        : self.__options.defaultStyles.backgroundColor\n                });\n\n            $html\n                .find('.tooltipster-arrow-border')\n                .css({\n                    'backgroundColor': styles.backgroundColor\n                        ? styles.backgroundColor\n                        : self.__options.defaultStyles.backgroundColor\n                });\n\n\t\t\t// hide arrow if asked\n\t\t\tif (!this.__options.arrow) {\n\t\t\t\t$html\n\t\t\t\t\t.find('.tooltipster-box')\n\t\t\t\t\t\t.css('margin', 0)\n\t\t\t\t\t\t.end()\n\t\t\t\t\t.find('.tooltipster-arrow')\n\t\t\t\t\t\t.hide();\n\t\t\t}\n\n\t\t\t// apply min/max width if asked\n\t\t\tif (this.__options.minWidth) {\n\t\t\t\t$html.css('min-width', this.__options.minWidth + 'px');\n\t\t\t}\n\t\t\tif (this.__options.maxWidth) {\n\t\t\t\t$html.css('max-width', this.__options.maxWidth + 'px');\n\t\t\t}\n\n\t\t\tthis.__instance._$tooltip = $html;\n\n\t\t\t// tell the instance that the tooltip element has been created\n\t\t\tthis.__instance._trigger('created');\n\t\t},\n\n\t\t/**\n\t\t * Used when the plugin is to be unplugged\n\t\t *\n\t\t * @private\n\t\t */\n\t\t__destroy: function() {\n\t\t\tthis.__instance._off('.'+ self.__namespace);\n\t\t},\n\n\t\t/**\n\t\t * (Re)compute this.__options from the options declared to the instance\n\t\t *\n\t\t * @private\n\t\t */\n\t\t__optionsFormat: function() {\n\n\t\t\tvar self = this;\n\n\t\t\t// get the options\n\t\t\tself.__options = self.__instance._optionsExtract(pluginName, self.__defaults());\n\n\t\t\t// for backward compatibility, deprecated in v4.0.0\n\t\t\tif (self.__options.position) {\n\t\t\t\tself.__options.side = self.__options.position;\n\t\t\t}\n\n\t\t\t// options formatting\n\n\t\t\t// format distance as a four-cell array if it ain't one yet and then make\n\t\t\t// it an object with top/bottom/left/right properties\n\t\t\tif (typeof self.__options.distance != 'object') {\n\t\t\t\tself.__options.distance = [self.__options.distance];\n\t\t\t}\n\t\t\tif (self.__options.distance.length < 4) {\n\t\t\t\tif (self.__options.distance[1] === undefined) self.__options.distance[1] = self.__options.distance[0];\n\t\t\t\tif (self.__options.distance[2] === undefined) self.__options.distance[2] = self.__options.distance[0];\n\t\t\t\tif (self.__options.distance[3] === undefined) self.__options.distance[3] = self.__options.distance[1];\n\t\t\t}\n\n\t\t\tself.__options.distance = {\n\t\t\t\ttop: self.__options.distance[0],\n\t\t\t\tright: self.__options.distance[1],\n\t\t\t\tbottom: self.__options.distance[2],\n\t\t\t\tleft: self.__options.distance[3]\n\t\t\t};\n\n\t\t\t// let's transform:\n\t\t\t// 'top' into ['top', 'bottom', 'right', 'left']\n\t\t\t// 'right' into ['right', 'left', 'top', 'bottom']\n\t\t\t// 'bottom' into ['bottom', 'top', 'right', 'left']\n\t\t\t// 'left' into ['left', 'right', 'top', 'bottom']\n\t\t\tif (typeof self.__options.side == 'string') {\n\n\t\t\t\tvar opposites = {\n\t\t\t\t\t'top': 'bottom',\n\t\t\t\t\t'right': 'left',\n\t\t\t\t\t'bottom': 'top',\n\t\t\t\t\t'left': 'right'\n\t\t\t\t};\n\n\t\t\t\tself.__options.side = [self.__options.side, opposites[self.__options.side]];\n\n\t\t\t\tif (self.__options.side[0] == 'left' || self.__options.side[0] == 'right') {\n\t\t\t\t\tself.__options.side.push('top', 'bottom');\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tself.__options.side.push('right', 'left');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// misc\n\t\t\t// disable the arrow in IE6 unless the arrow option was explicitly set to true\n\t\t\tif (\t$.tooltipster._env.IE === 6\n\t\t\t\t&&\tself.__options.arrow !== true\n\t\t\t) {\n\t\t\t\tself.__options.arrow = false;\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * This method must compute and set the positioning properties of the\n\t\t * tooltip (left, top, width, height, etc.). It must also make sure the\n\t\t * tooltip is eventually appended to its parent (since the element may be\n\t\t * detached from the DOM at the moment the method is called).\n\t\t *\n\t\t * We'll evaluate positioning scenarios to find which side can contain the\n\t\t * tooltip in the best way. We'll consider things relatively to the window\n\t\t * (unless the user asks not to), then to the document (if need be, or if the\n\t\t * user explicitly requires the tests to run on the document). For each\n\t\t * scenario, measures are taken, allowing us to know how well the tooltip\n\t\t * is going to fit. After that, a sorting function will let us know what\n\t\t * the best scenario is (we also allow the user to choose his favorite\n\t\t * scenario by using an event).\n\t\t *\n\t\t * @param {object} helper An object that contains variables that plugin\n\t\t * creators may find useful (see below)\n\t\t * @param {object} helper.geo An object with many layout properties\n\t\t * about objects of interest (window, document, origin). This should help\n\t\t * plugin users compute the optimal position of the tooltip\n\t\t * @private\n\t\t */\n\t\t__reposition: function(event, helper) {\n\n\t\t\tvar self = this,\n\t\t\t\tfinalResult,\n\t\t\t\t// to know where to put the tooltip, we need to know on which point\n\t\t\t\t// of the x or y axis we should center it. That coordinate is the target\n\t\t\t\ttargets = self.__targetFind(helper),\n\t\t\t\ttestResults = [];\n\n\t\t\t// make sure the tooltip is detached while we make tests on a clone\n\t\t\tself.__instance._$tooltip.detach();\n\n\t\t\t// we could actually provide the original element to the Ruler and\n\t\t\t// not a clone, but it just feels right to keep it out of the\n\t\t\t// machinery.\n\t\t\tvar $clone = self.__instance._$tooltip.clone(),\n\t\t\t\t// start position tests session\n\t\t\t\truler = $.tooltipster._getRuler($clone),\n\t\t\t\tsatisfied = false,\n\t\t\t\tanimation = self.__instance.option('animation');\n\n\t\t\t// an animation class could contain properties that distort the size\n\t\t\tif (animation) {\n\t\t\t\t$clone.removeClass('tooltipster-'+ animation);\n\t\t\t}\n\n\t\t\t// start evaluating scenarios\n\t\t\t$.each(['window', 'document'], function(i, container) {\n\n\t\t\t\tvar takeTest = null;\n\n\t\t\t\t// let the user decide to keep on testing or not\n\t\t\t\tself.__instance._trigger({\n\t\t\t\t\tcontainer: container,\n\t\t\t\t\thelper: helper,\n\t\t\t\t\tsatisfied: satisfied,\n\t\t\t\t\ttakeTest: function(bool) {\n\t\t\t\t\t\ttakeTest = bool;\n\t\t\t\t\t},\n\t\t\t\t\tresults: testResults,\n\t\t\t\t\ttype: 'positionTest'\n\t\t\t\t});\n\n\t\t\t\tif (\ttakeTest == true\n\t\t\t\t\t||\t(\ttakeTest != false\n\t\t\t\t\t\t&&\tsatisfied == false\n\t\t\t\t\t\t\t// skip the window scenarios if asked. If they are reintegrated by\n\t\t\t\t\t\t\t// the callback of the positionTest event, they will have to be\n\t\t\t\t\t\t\t// excluded using the callback of positionTested\n\t\t\t\t\t\t&&\t(container != 'window' || self.__options.viewportAware)\n\t\t\t\t\t)\n\t\t\t\t) {\n\n\t\t\t\t\t// for each allowed side\n\t\t\t\t\tfor (var i=0; i < self.__options.side.length; i++) {\n\n\t\t\t\t\t\tvar distance = {\n\t\t\t\t\t\t\t\thorizontal: 0,\n\t\t\t\t\t\t\t\tvertical: 0\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tside = self.__options.side[i];\n\n\t\t\t\t\t\tif (side == 'top' || side == 'bottom') {\n\t\t\t\t\t\t\tdistance.vertical = self.__options.distance[side];\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tdistance.horizontal = self.__options.distance[side];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// this may have an effect on the size of the tooltip if there are css\n\t\t\t\t\t\t// rules for the arrow or something else\n\t\t\t\t\t\tself.__sideChange($clone, side);\n\n\t\t\t\t\t\t$.each(['natural', 'constrained'], function(i, mode) {\n\n\t\t\t\t\t\t\ttakeTest = null;\n\n\t\t\t\t\t\t\t// emit an event on the instance\n\t\t\t\t\t\t\tself.__instance._trigger({\n\t\t\t\t\t\t\t\tcontainer: container,\n\t\t\t\t\t\t\t\tevent: event,\n\t\t\t\t\t\t\t\thelper: helper,\n\t\t\t\t\t\t\t\tmode: mode,\n\t\t\t\t\t\t\t\tresults: testResults,\n\t\t\t\t\t\t\t\tsatisfied: satisfied,\n\t\t\t\t\t\t\t\tside: side,\n\t\t\t\t\t\t\t\ttakeTest: function(bool) {\n\t\t\t\t\t\t\t\t\ttakeTest = bool;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\ttype: 'positionTest'\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (\ttakeTest == true\n\t\t\t\t\t\t\t\t||\t(\ttakeTest != false\n\t\t\t\t\t\t\t\t\t&&\tsatisfied == false\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t) {\n\n\t\t\t\t\t\t\t\tvar testResult = {\n\t\t\t\t\t\t\t\t\tcontainer: container,\n\t\t\t\t\t\t\t\t\t// we let the distance as an object here, it can make things a little easier\n\t\t\t\t\t\t\t\t\t// during the user's calculations at positionTest/positionTested\n\t\t\t\t\t\t\t\t\tdistance: distance,\n\t\t\t\t\t\t\t\t\t// whether the tooltip can fit in the size of the viewport (does not mean\n\t\t\t\t\t\t\t\t\t// that we'll be able to make it initially entirely visible, see 'whole')\n\t\t\t\t\t\t\t\t\tfits: null,\n\t\t\t\t\t\t\t\t\tmode: mode,\n\t\t\t\t\t\t\t\t\touterSize: null,\n\t\t\t\t\t\t\t\t\tside: side,\n\t\t\t\t\t\t\t\t\tsize: null,\n\t\t\t\t\t\t\t\t\ttarget: targets[side],\n\t\t\t\t\t\t\t\t\t// check if the origin has enough surface on screen for the tooltip to\n\t\t\t\t\t\t\t\t\t// aim at it without overflowing the viewport (this is due to the thickness\n\t\t\t\t\t\t\t\t\t// of the arrow represented by the minIntersection length).\n\t\t\t\t\t\t\t\t\t// If not, the tooltip will have to be partly or entirely off screen in\n\t\t\t\t\t\t\t\t\t// order to stay docked to the origin. This value will stay null when the\n\t\t\t\t\t\t\t\t\t// container is the document, as it is not relevant\n\t\t\t\t\t\t\t\t\twhole: null\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t// get the size of the tooltip with or without size constraints\n\t\t\t\t\t\t\t\tvar rulerConfigured = (mode == 'natural') ?\n\t\t\t\t\t\t\t\t\t\truler.free() :\n\t\t\t\t\t\t\t\t\t\truler.constrain(\n\t\t\t\t\t\t\t\t\t\t\thelper.geo.available[container][side].width - distance.horizontal,\n\t\t\t\t\t\t\t\t\t\t\thelper.geo.available[container][side].height - distance.vertical\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\trulerResults = rulerConfigured.measure();\n\n\t\t\t\t\t\t\t\ttestResult.size = rulerResults.size;\n\t\t\t\t\t\t\t\ttestResult.outerSize = {\n\t\t\t\t\t\t\t\t\theight: rulerResults.size.height + distance.vertical,\n\t\t\t\t\t\t\t\t\twidth: rulerResults.size.width + distance.horizontal\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tif (mode == 'natural') {\n\n\t\t\t\t\t\t\t\t\tif(\t\thelper.geo.available[container][side].width >= testResult.outerSize.width\n\t\t\t\t\t\t\t\t\t\t&&\thelper.geo.available[container][side].height >= testResult.outerSize.height\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\ttestResult.fits = true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\ttestResult.fits = false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\ttestResult.fits = rulerResults.fits;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (container == 'window') {\n\n\t\t\t\t\t\t\t\t\tif (!testResult.fits) {\n\t\t\t\t\t\t\t\t\t\ttestResult.whole = false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tif (side == 'top' || side == 'bottom') {\n\n\t\t\t\t\t\t\t\t\t\t\ttestResult.whole = (\n\t\t\t\t\t\t\t\t\t\t\t\t\thelper.geo.origin.windowOffset.right >= self.__options.minIntersection\n\t\t\t\t\t\t\t\t\t\t\t\t&&\thelper.geo.window.size.width - helper.geo.origin.windowOffset.left >= self.__options.minIntersection\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\t\ttestResult.whole = (\n\t\t\t\t\t\t\t\t\t\t\t\t\thelper.geo.origin.windowOffset.bottom >= self.__options.minIntersection\n\t\t\t\t\t\t\t\t\t\t\t\t&&\thelper.geo.window.size.height - helper.geo.origin.windowOffset.top >= self.__options.minIntersection\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ttestResults.push(testResult);\n\n\t\t\t\t\t\t\t\t// we don't need to compute more positions if we have one fully on screen\n\t\t\t\t\t\t\t\tif (testResult.whole) {\n\t\t\t\t\t\t\t\t\tsatisfied = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t// don't run the constrained test unless the natural width was greater\n\t\t\t\t\t\t\t\t\t// than the available width, otherwise it's pointless as we know it\n\t\t\t\t\t\t\t\t\t// wouldn't fit either\n\t\t\t\t\t\t\t\t\tif (\ttestResult.mode == 'natural'\n\t\t\t\t\t\t\t\t\t\t&&\t(\ttestResult.fits\n\t\t\t\t\t\t\t\t\t\t\t||\ttestResult.size.width <= helper.geo.available[container][side].width\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// the user may eliminate the unwanted scenarios from testResults, but he's\n\t\t\t// not supposed to alter them at this point. functionPosition and the\n\t\t\t// position event serve that purpose.\n\t\t\tself.__instance._trigger({\n\t\t\t\tedit: function(r) {\n\t\t\t\t\ttestResults = r;\n\t\t\t\t},\n\t\t\t\tevent: event,\n\t\t\t\thelper: helper,\n\t\t\t\tresults: testResults,\n\t\t\t\ttype: 'positionTested'\n\t\t\t});\n\n\t\t\t/**\n\t\t\t * Sort the scenarios to find the favorite one.\n\t\t\t *\n\t\t\t * The favorite scenario is when we can fully display the tooltip on screen,\n\t\t\t * even if it means that the middle of the tooltip is no longer centered on\n\t\t\t * the middle of the origin (when the origin is near the edge of the screen\n\t\t\t * or even partly off screen). We want the tooltip on the preferred side,\n\t\t\t * even if it means that we have to use a constrained size rather than a\n\t\t\t * natural one (as long as it fits). When the origin is off screen at the top\n\t\t\t * the tooltip will be positioned at the bottom (if allowed), if the origin\n\t\t\t * is off screen on the right, it will be positioned on the left, etc.\n\t\t\t * If there are no scenarios where the tooltip can fit on screen, or if the\n\t\t\t * user does not want the tooltip to fit on screen (viewportAware == false),\n\t\t\t * we fall back to the scenarios relative to the document.\n\t\t\t *\n\t\t\t * When the tooltip is bigger than the viewport in either dimension, we stop\n\t\t\t * looking at the window scenarios and consider the document scenarios only,\n\t\t\t * with the same logic to find on which side it would fit best.\n\t\t\t *\n\t\t\t * If the tooltip cannot fit the document on any side, we force it at the\n\t\t\t * bottom, so at least the user can scroll to see it.\n \t\t\t */\n\t\t\ttestResults.sort(function(a, b) {\n\n\t\t\t\t// best if it's whole (the tooltip fits and adapts to the viewport)\n\t\t\t\tif (a.whole && !b.whole) {\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\telse if (!a.whole && b.whole) {\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\telse if (a.whole && b.whole) {\n\n\t\t\t\t\tvar ai = self.__options.side.indexOf(a.side),\n\t\t\t\t\t\tbi = self.__options.side.indexOf(b.side);\n\n\t\t\t\t\t// use the user's sides fallback array\n\t\t\t\t\tif (ai < bi) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (ai > bi) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// will be used if the user forced the tests to continue\n\t\t\t\t\t\treturn a.mode == 'natural' ? -1 : 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\n\t\t\t\t\t// better if it fits\n\t\t\t\t\tif (a.fits && !b.fits) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!a.fits && b.fits) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\telse if (a.fits && b.fits) {\n\n\t\t\t\t\t\tvar ai = self.__options.side.indexOf(a.side),\n\t\t\t\t\t\t\tbi = self.__options.side.indexOf(b.side);\n\n\t\t\t\t\t\t// use the user's sides fallback array\n\t\t\t\t\t\tif (ai < bi) {\n\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (ai > bi) {\n\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// will be used if the user forced the tests to continue\n\t\t\t\t\t\t\treturn a.mode == 'natural' ? -1 : 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\n\t\t\t\t\t\t// if everything failed, this will give a preference to the case where\n\t\t\t\t\t\t// the tooltip overflows the document at the bottom\n\t\t\t\t\t\tif (\ta.container == 'document'\n\t\t\t\t\t\t\t&&\ta.side == 'bottom'\n\t\t\t\t\t\t\t&&\ta.mode == 'natural'\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tfinalResult = testResults[0];\n\n\n\t\t\t// now let's find the coordinates of the tooltip relatively to the window\n\t\t\tfinalResult.coord = {};\n\n\t\t\tswitch (finalResult.side) {\n\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'right':\n\t\t\t\t\tfinalResult.coord.top = Math.floor(finalResult.target - finalResult.size.height / 2);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'bottom':\n\t\t\t\tcase 'top':\n\t\t\t\t\tfinalResult.coord.left = Math.floor(finalResult.target - finalResult.size.width / 2);\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tswitch (finalResult.side) {\n\n\t\t\t\tcase 'left':\n\t\t\t\t\tfinalResult.coord.left = helper.geo.origin.windowOffset.left - finalResult.outerSize.width;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'right':\n\t\t\t\t\tfinalResult.coord.left = helper.geo.origin.windowOffset.right + finalResult.distance.horizontal;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'top':\n\t\t\t\t\tfinalResult.coord.top = helper.geo.origin.windowOffset.top - finalResult.outerSize.height;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'bottom':\n\t\t\t\t\tfinalResult.coord.top = helper.geo.origin.windowOffset.bottom + finalResult.distance.vertical;\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// if the tooltip can potentially be contained within the viewport dimensions\n\t\t\t// and that we are asked to make it fit on screen\n\t\t\tif (finalResult.container == 'window') {\n\n\t\t\t\t// if the tooltip overflows the viewport, we'll move it accordingly (then it will\n\t\t\t\t// not be centered on the middle of the origin anymore). We only move horizontally\n\t\t\t\t// for top and bottom tooltips and vice versa.\n\t\t\t\tif (finalResult.side == 'top' || finalResult.side == 'bottom') {\n\n\t\t\t\t\t// if there is an overflow on the left\n\t\t\t\t\tif (finalResult.coord.left < 0) {\n\n\t\t\t\t\t\t// prevent the overflow unless the origin itself gets off screen (minus the\n\t\t\t\t\t\t// margin needed to keep the arrow pointing at the target)\n\t\t\t\t\t\tif (helper.geo.origin.windowOffset.right - this.__options.minIntersection >= 0) {\n\t\t\t\t\t\t\tfinalResult.coord.left = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tfinalResult.coord.left = helper.geo.origin.windowOffset.right - this.__options.minIntersection - 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// or an overflow on the right\n\t\t\t\t\telse if (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) {\n\n\t\t\t\t\t\tif (helper.geo.origin.windowOffset.left + this.__options.minIntersection <= helper.geo.window.size.width) {\n\t\t\t\t\t\t\tfinalResult.coord.left = helper.geo.window.size.width - finalResult.size.width;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tfinalResult.coord.left = helper.geo.origin.windowOffset.left + this.__options.minIntersection + 1 - finalResult.size.width;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\n\t\t\t\t\t// overflow at the top\n\t\t\t\t\tif (finalResult.coord.top < 0) {\n\n\t\t\t\t\t\tif (helper.geo.origin.windowOffset.bottom - this.__options.minIntersection >= 0) {\n\t\t\t\t\t\t\tfinalResult.coord.top = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tfinalResult.coord.top = helper.geo.origin.windowOffset.bottom - this.__options.minIntersection - 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// or at the bottom\n\t\t\t\t\telse if (finalResult.coord.top > helper.geo.window.size.height - finalResult.size.height) {\n\n\t\t\t\t\t\tif (helper.geo.origin.windowOffset.top + this.__options.minIntersection <= helper.geo.window.size.height) {\n\t\t\t\t\t\t\tfinalResult.coord.top = helper.geo.window.size.height - finalResult.size.height;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tfinalResult.coord.top = helper.geo.origin.windowOffset.top + this.__options.minIntersection + 1 - finalResult.size.height;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\n\t\t\t\t// there might be overflow here too but it's easier to handle. If there has\n\t\t\t\t// to be an overflow, we'll make sure it's on the right side of the screen\n\t\t\t\t// (because the browser will extend the document size if there is an overflow\n\t\t\t\t// on the right, but not on the left). The sort function above has already\n\t\t\t\t// made sure that a bottom document overflow is preferred to a top overflow,\n\t\t\t\t// so we don't have to care about it.\n\n\t\t\t\t// if there is an overflow on the right\n\t\t\t\tif (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) {\n\n\t\t\t\t\t// this may actually create on overflow on the left but we'll fix it in a sec\n\t\t\t\t\tfinalResult.coord.left = helper.geo.window.size.width - finalResult.size.width;\n\t\t\t\t}\n\n\t\t\t\t// if there is an overflow on the left\n\t\t\t\tif (finalResult.coord.left < 0) {\n\n\t\t\t\t\t// don't care if it overflows the right after that, we made our best\n\t\t\t\t\tfinalResult.coord.left = 0;\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\t// submit the positioning proposal to the user function which may choose to change\n\t\t\t// the side, size and/or the coordinates\n\n\t\t\t// first, set the rules that corresponds to the proposed side: it may change\n\t\t\t// the size of the tooltip, and the custom functionPosition may want to detect the\n\t\t\t// size of something before making a decision. So let's make things easier for the\n\t\t\t// implementor\n\t\t\tself.__sideChange($clone, finalResult.side);\n\n\t\t\t// add some variables to the helper\n\t\t\thelper.tooltipClone = $clone[0];\n\t\t\thelper.tooltipParent = self.__instance.option('parent').parent[0];\n\t\t\t// move informative values to the helper\n\t\t\thelper.mode = finalResult.mode;\n\t\t\thelper.whole = finalResult.whole;\n\t\t\t// add some variables to the helper for the functionPosition callback (these\n\t\t\t// will also be added to the event fired by self.__instance._trigger but that's\n\t\t\t// ok, we're just being consistent)\n\t\t\thelper.origin = self.__instance._$origin[0];\n\t\t\thelper.tooltip = self.__instance._$tooltip[0];\n\n\t\t\t// leave only the actionable values in there for functionPosition\n\t\t\tdelete finalResult.container;\n\t\t\tdelete finalResult.fits;\n\t\t\tdelete finalResult.mode;\n\t\t\tdelete finalResult.outerSize;\n\t\t\tdelete finalResult.whole;\n\n\t\t\t// keep only the distance on the relevant side, for clarity\n\t\t\tfinalResult.distance = finalResult.distance.horizontal || finalResult.distance.vertical;\n\n\t\t\t// beginners may not be comfortable with the concept of editing the object\n\t\t\t//  passed by reference, so we provide an edit function and pass a clone\n\t\t\tvar finalResultClone = $.extend(true, {}, finalResult);\n\n\t\t\t// emit an event on the instance\n\t\t\tself.__instance._trigger({\n\t\t\t\tedit: function(result) {\n\t\t\t\t\tfinalResult = result;\n\t\t\t\t},\n\t\t\t\tevent: event,\n\t\t\t\thelper: helper,\n\t\t\t\tposition: finalResultClone,\n\t\t\t\ttype: 'position'\n\t\t\t});\n\n\t\t\tif (self.__options.functionPosition) {\n\n\t\t\t\tvar result = self.__options.functionPosition.call(self, self.__instance, helper, finalResultClone);\n\n\t\t\t\tif (result) finalResult = result;\n\t\t\t}\n\n\t\t\t// end the positioning tests session (the user might have had a\n\t\t\t// use for it during the position event, now it's over)\n\t\t\truler.destroy();\n\n\t\t\t// compute the position of the target relatively to the tooltip root\n\t\t\t// element so we can place the arrow and make the needed adjustments\n\t\t\tvar arrowCoord,\n\t\t\t\tmaxVal;\n\n\t\t\tif (finalResult.side == 'top' || finalResult.side == 'bottom') {\n\n\t\t\t\tarrowCoord = {\n\t\t\t\t\tprop: 'left',\n\t\t\t\t\tval: finalResult.target - finalResult.coord.left\n\t\t\t\t};\n\t\t\t\tmaxVal = finalResult.size.width - this.__options.minIntersection;\n\t\t\t}\n\t\t\telse {\n\n\t\t\t\tarrowCoord = {\n\t\t\t\t\tprop: 'top',\n\t\t\t\t\tval: finalResult.target - finalResult.coord.top\n\t\t\t\t};\n\t\t\t\tmaxVal = finalResult.size.height - this.__options.minIntersection;\n\t\t\t}\n\n\t\t\t// cannot lie beyond the boundaries of the tooltip, minus the\n\t\t\t// arrow margin\n\t\t\tif (arrowCoord.val < this.__options.minIntersection) {\n\t\t\t\tarrowCoord.val = this.__options.minIntersection;\n\t\t\t}\n\t\t\telse if (arrowCoord.val > maxVal) {\n\t\t\t\tarrowCoord.val = maxVal;\n\t\t\t}\n\n\t\t\tvar originParentOffset;\n\n\t\t\t// let's convert the window-relative coordinates into coordinates relative to the\n\t\t\t// future positioned parent that the tooltip will be appended to\n\t\t\tif (helper.geo.origin.fixedLineage) {\n\n\t\t\t\t// same as windowOffset when the position is fixed\n\t\t\t\toriginParentOffset = helper.geo.origin.windowOffset;\n\t\t\t}\n\t\t\telse {\n\n\t\t\t\t// this assumes that the parent of the tooltip is located at\n\t\t\t\t// (0, 0) in the document, typically like when the parent is\n\t\t\t\t// <body>.\n\t\t\t\t// If we ever allow other types of parent, .tooltipster-ruler\n\t\t\t\t// will have to be appended to the parent to inherit css style\n\t\t\t\t// values that affect the display of the text and such.\n\t\t\t\toriginParentOffset = {\n\t\t\t\t\tleft: helper.geo.origin.windowOffset.left + helper.geo.window.scroll.left,\n\t\t\t\t\ttop: helper.geo.origin.windowOffset.top + helper.geo.window.scroll.top\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tfinalResult.coord = {\n\t\t\t\tleft: originParentOffset.left + (finalResult.coord.left - helper.geo.origin.windowOffset.left),\n\t\t\t\ttop: originParentOffset.top + (finalResult.coord.top - helper.geo.origin.windowOffset.top)\n\t\t\t};\n\n\t\t\t// set position values on the original tooltip element\n\n\t\t\tself.__sideChange(self.__instance._$tooltip, finalResult.side);\n\n\t\t\tif (helper.geo.origin.fixedLineage) {\n\t\t\t\tself.__instance._$tooltip\n\t\t\t\t\t.css('position', 'fixed');\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// CSS default\n\t\t\t\tself.__instance._$tooltip\n\t\t\t\t\t.css('position', '');\n\t\t\t}\n\n\t\t\tself.__instance._$tooltip\n\t\t\t\t.css({\n\t\t\t\t\tleft: finalResult.coord.left,\n\t\t\t\t\ttop: finalResult.coord.top,\n\t\t\t\t\t// we need to set a size even if the tooltip is in its natural size\n\t\t\t\t\t// because when the tooltip is positioned beyond the width of the body\n\t\t\t\t\t// (which is by default the width of the window; it will happen when\n\t\t\t\t\t// you scroll the window horizontally to get to the origin), its text\n\t\t\t\t\t// content will otherwise break lines at each word to keep up with the\n\t\t\t\t\t// body overflow strategy.\n\t\t\t\t\theight: finalResult.size.height,\n\t\t\t\t\twidth: finalResult.size.width\n\t\t\t\t})\n\t\t\t\t.find('.tooltipster-arrow')\n\t\t\t\t\t.css({\n\t\t\t\t\t\t'left': '',\n\t\t\t\t\t\t'top': ''\n\t\t\t\t\t})\n\t\t\t\t\t.css(arrowCoord.prop, arrowCoord.val);\n\n\t\t\t// append the tooltip HTML element to its parent\n\t\t\tself.__instance._$tooltip.appendTo(self.__instance.option('parent'));\n\n\t\t\tself.__instance._trigger({\n\t\t\t\ttype: 'repositioned',\n\t\t\t\tevent: event,\n\t\t\t\tposition: finalResult\n\t\t\t});\n\t\t},\n\n\t\t/**\n\t\t * Make whatever modifications are needed when the side is changed. This has\n\t\t * been made an independant method for easy inheritance in custom plugins based\n\t\t * on this default plugin.\n\t\t *\n\t\t * @param {object} $obj\n\t\t * @param {string} side\n\t\t * @private\n\t\t */\n\t\t__sideChange: function($obj, side) {\n\n\t\t\t$obj\n\t\t\t\t.removeClass('tooltipster-bottom')\n\t\t\t\t.removeClass('tooltipster-left')\n\t\t\t\t.removeClass('tooltipster-right')\n\t\t\t\t.removeClass('tooltipster-top')\n\t\t\t\t.addClass('tooltipster-'+ side);\n\t\t},\n\n\t\t/**\n\t\t * Returns the target that the tooltip should aim at for a given side.\n\t\t * The calculated value is a distance from the edge of the window\n\t\t * (left edge for top/bottom sides, top edge for left/right side). The\n\t\t * tooltip will be centered on that position and the arrow will be\n\t\t * positioned there (as much as possible).\n\t\t *\n\t\t * @param {object} helper\n\t\t * @return {integer}\n\t\t * @private\n\t\t */\n\t\t__targetFind: function(helper) {\n\n\t\t\tvar target = {},\n\t\t\t\trects = this.__instance._$origin[0].getClientRects();\n\n\t\t\t// these lines fix a Chrome bug (issue #491)\n\t\t\tif (rects.length > 1) {\n\t\t\t\tvar opacity = this.__instance._$origin.css('opacity');\n\t\t\t\tif(opacity == 1) {\n\t\t\t\t\tthis.__instance._$origin.css('opacity', 0.99);\n\t\t\t\t\trects = this.__instance._$origin[0].getClientRects();\n\t\t\t\t\tthis.__instance._$origin.css('opacity', 1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// by default, the target will be the middle of the origin\n\t\t\tif (rects.length < 2) {\n\n\t\t\t\ttarget.top = Math.floor(helper.geo.origin.windowOffset.left + (helper.geo.origin.size.width / 2));\n\t\t\t\ttarget.bottom = target.top;\n\n\t\t\t\ttarget.left = Math.floor(helper.geo.origin.windowOffset.top + (helper.geo.origin.size.height / 2));\n\t\t\t\ttarget.right = target.left;\n\t\t\t}\n\t\t\t// if multiple client rects exist, the element may be text split\n\t\t\t// up into multiple lines and the middle of the origin may not be\n\t\t\t// best option anymore. We need to choose the best target client rect\n\t\t\telse {\n\n\t\t\t\t// top: the first\n\t\t\t\tvar targetRect = rects[0];\n\t\t\t\ttarget.top = Math.floor(targetRect.left + (targetRect.right - targetRect.left) / 2);\n\n\t\t\t\t// right: the middle line, rounded down in case there is an even\n\t\t\t\t// number of lines (looks more centered => check out the\n\t\t\t\t// demo with 4 split lines)\n\t\t\t\tif (rects.length > 2) {\n\t\t\t\t\ttargetRect = rects[Math.ceil(rects.length / 2) - 1];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttargetRect = rects[0];\n\t\t\t\t}\n\t\t\t\ttarget.right = Math.floor(targetRect.top + (targetRect.bottom - targetRect.top) / 2);\n\n\t\t\t\t// bottom: the last\n\t\t\t\ttargetRect = rects[rects.length - 1];\n\t\t\t\ttarget.bottom = Math.floor(targetRect.left + (targetRect.right - targetRect.left) / 2);\n\n\t\t\t\t// left: the middle line, rounded up\n\t\t\t\tif (rects.length > 2) {\n\t\t\t\t\ttargetRect = rects[Math.ceil((rects.length + 1) / 2) - 1];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttargetRect = rects[rects.length - 1];\n\t\t\t\t}\n\n\t\t\t\ttarget.left = Math.floor(targetRect.top + (targetRect.bottom - targetRect.top) / 2);\n\t\t\t}\n\n\t\t\treturn target;\n\t\t}\n\t}\n});\n\n/* a build task will add \"return $;\" here */\nreturn $;\n\n}));\n","Amasty_Rewards/vendor/tooltipster/js/tooltipster.min.js":"!function(t,i){\"function\"==typeof define&&define.amd?define([\"jquery\"],function(t){return i(t)}):\"object\"==typeof exports?module.exports=i(require(\"jquery\")):i(jQuery)}(0,function(t){var i={animation:\"fade\",animationDuration:350,content:null,contentAsHTML:!1,contentCloning:!1,debug:!0,delay:300,delayTouch:[300,500],functionInit:null,functionBefore:null,functionReady:null,functionAfter:null,functionFormat:null,IEmin:6,interactive:!1,multiple:!1,parent:null,plugins:[\"sideTip\"],repositionOnScroll:!1,restoration:\"none\",selfDestruction:!0,theme:[],timer:0,trackerInterval:500,trackOrigin:!1,trackTooltip:!1,trigger:\"hover\",triggerClose:{click:!1,mouseleave:!1,originClick:!1,scroll:!1,tap:!1,touchleave:!1},triggerOpen:{click:!1,mouseenter:!1,tap:!1,touchstart:!1},updateAnimation:\"rotate\",zIndex:9999999,styles:{backgroundColor:\"\",textColor:\"\"}},o=\"undefined\"!=typeof window?window:null,e={hasTouchCapability:!(!o||!(\"ontouchstart\"in o||o.DocumentTouch&&o.document instanceof o.DocumentTouch||o.navigator.maxTouchPoints)),hasTransitions:function(){if(!o)return!1;var t=(o.document.body||o.document.documentElement).style,i=\"transition\",e=[\"Moz\",\"Webkit\",\"Khtml\",\"O\",\"ms\"];if(\"string\"==typeof t[i])return!0;i=i.charAt(0).toUpperCase()+i.substr(1);for(var n=0;n<e.length;n++)if(\"string\"==typeof t[e[n]+i])return!0;return!1}(),IE:!1,semVer:\"4.2.8\",window:o},n=function(){this.__$emitterPrivate=t({}),this.__$emitterPublic=t({}),this.__instancesLatestArr=[],this.__plugins={},this._env=e};function s(t){this.$container,this.constraints=null,this.__$tooltip,this.__init(t)}function r(i,o){var e=!0;return t.each(i,function(t,n){if(void 0===o[t]||i[t]!==o[t])return e=!1,!1}),e}function _(i){var o=i.attr(\"id\"),n=o?e.window.document.getElementById(o):null;return n?n===i[0]:t.contains(e.window.document.body,i[0])}n.prototype={__bridge:function(o,e,n){if(!e[n]){var s=function(){};s.prototype=o;var r=new s;r.__init&&r.__init(e),t.each(o,function(t,o){0!=t.indexOf(\"__\")&&(e[t]?i.debug&&console.log(\"The \"+t+\" method of the \"+n+\" plugin conflicts with another plugin or native methods\"):(e[t]=function(){return r[t].apply(r,Array.prototype.slice.apply(arguments))},e[t].bridged=r))}),e[n]=r}return this},__setWindow:function(t){return e.window=t,this},_getRuler:function(t){return new s(t)},_off:function(){return this.__$emitterPrivate.off.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_on:function(){return this.__$emitterPrivate.on.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_one:function(){return this.__$emitterPrivate.one.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_plugin:function(i){if(\"string\"==typeof i){var o=i,e=null;return o.indexOf(\".\")>0?e=this.__plugins[o]:t.each(this.__plugins,function(t,i){if(i.name.substring(i.name.length-o.length-1)==\".\"+o)return e=i,!1}),e}if(i.name.indexOf(\".\")<0)throw new Error(\"Plugins must be namespaced\");return this.__plugins[i.name]=i,i.core&&this.__bridge(i.core,this,i.name),this},_trigger:function(){var t=Array.prototype.slice.apply(arguments);return\"string\"==typeof t[0]&&(t[0]={type:t[0]}),this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate,t),this.__$emitterPublic.trigger.apply(this.__$emitterPublic,t),this},instances:function(i){var o=[];return t(i||\".tooltipstered\").each(function(){var i=t(this),e=i.data(\"tooltipster-ns\");e&&t.each(e,function(t,e){o.push(i.data(e))})}),o},instancesLatest:function(){return this.__instancesLatestArr},off:function(){return this.__$emitterPublic.off.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},on:function(){return this.__$emitterPublic.on.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},one:function(){return this.__$emitterPublic.one.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},origins:function(i){return t((i?i+\" \":\"\")+\".tooltipstered\").toArray()},setDefaults:function(o){return t.extend(i,o),this},triggerHandler:function(){return this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this}},t.tooltipster=new n,t.Tooltipster=function(i,o){this.__callbacks={close:[],open:[]},this.__closingTime,this.__Content,this.__contentBcr,this.__destroyed=!1,this.__$emitterPrivate=t({}),this.__$emitterPublic=t({}),this.__enabled=!0,this.__garbageCollector,this.__Geometry,this.__lastPosition,this.__namespace=\"tooltipster-\"+Math.round(1e6*Math.random()),this.__options,this.__$originParents,this.__pointerIsOverOrigin=!1,this.__previousThemes=[],this.__state=\"closed\",this.__timeouts={close:[],open:null},this.__touchEvents=[],this.__tracker=null,this._$origin,this._$tooltip,this.__init(i,o)},t.Tooltipster.prototype={__init:function(o,n){var s=this;if(s._$origin=t(o),s.__options=t.extend(!0,{},i,n),s.__optionsFormat(),!e.IE||e.IE>=s.__options.IEmin){var r=null;if(void 0===s._$origin.data(\"tooltipster-initialTitle\")&&(void 0===(r=s._$origin.attr(\"title\"))&&(r=null),s._$origin.data(\"tooltipster-initialTitle\",r)),null!==s.__options.content)s.__contentSet(s.__options.content);else{var _,a=s._$origin.attr(\"data-tooltip-content\");a&&(_=t(a)),_&&_[0]?s.__contentSet(_.first()):s.__contentSet(r)}s._$origin.removeAttr(\"title\").addClass(\"tooltipstered\"),s.__prepareOrigin(),s.__prepareGC(),t.each(s.__options.plugins,function(t,i){s._plug(i)}),e.hasTouchCapability&&t(e.window.document.body).on(\"touchmove.\"+s.__namespace+\"-triggerOpen\",function(t){s._touchRecordEvent(t)}),s._on(\"created\",function(){s.__prepareTooltip()})._on(\"repositioned\",function(t){s.__lastPosition=t.position})}else s.__options.disabled=!0},__contentInsert:function(){var t=this._$tooltip.find(\".tooltipster-content\"),i=this.__Content;return this._trigger({type:\"format\",content:this.__Content,format:function(t){i=t}}),this.__options.functionFormat&&(i=this.__options.functionFormat.call(this,this,{origin:this._$origin[0]},this.__Content)),\"string\"!=typeof i||this.__options.contentAsHTML?t.empty().append(i):t.text(i),this},__contentSet:function(i){return i instanceof t&&this.__options.contentCloning&&(i=i.clone(!0)),this.__Content=i,this._trigger({type:\"updated\",content:i}),this},__destroyError:function(){throw new Error(\"This tooltip has been destroyed and cannot execute your method call.\")},__geometry:function(){var i=this._$origin,o=this._$origin.is(\"area\");if(o){var n=this._$origin.parent().attr(\"name\");i=t('img[usemap=\"#'+n+'\"]')}var s=i[0].getBoundingClientRect(),r=t(e.window.document),_=t(e.window),a=i,l={available:{document:null,window:null},document:{size:{height:r.height(),width:r.width()}},window:{scroll:{left:e.window.scrollX||e.window.document.documentElement.scrollLeft,top:e.window.scrollY||e.window.document.documentElement.scrollTop},size:{height:_.height(),width:_.width()}},origin:{fixedLineage:!1,offset:{},size:{height:s.bottom-s.top,width:s.right-s.left},usemapImage:o?i[0]:null,windowOffset:{bottom:s.bottom,left:s.left,right:s.right,top:s.top}}};if(o){var p=this._$origin.attr(\"shape\"),c=this._$origin.attr(\"coords\");if(c&&(c=c.split(\",\"),t.map(c,function(t,i){c[i]=parseInt(t)})),\"default\"!=p)switch(p){case\"circle\":var h=c[0],d=c[1],u=c[2],g=d-u,f=h-u;l.origin.size.height=2*u,l.origin.size.width=l.origin.size.height,l.origin.windowOffset.left+=f,l.origin.windowOffset.top+=g;break;case\"rect\":var m=c[0],w=c[1],v=c[2],y=c[3];l.origin.size.height=y-w,l.origin.size.width=v-m,l.origin.windowOffset.left+=m,l.origin.windowOffset.top+=w;break;case\"poly\":for(var b=0,$=0,C=0,O=0,T=\"even\",z=0;z<c.length;z++){var E=c[z];\"even\"==T?(E>C&&(C=E,0===z&&(b=C)),E<b&&(b=E),T=\"odd\"):(E>O&&(O=E,1==z&&($=O)),E<$&&($=E),T=\"even\")}l.origin.size.height=O-$,l.origin.size.width=C-b,l.origin.windowOffset.left+=b,l.origin.windowOffset.top+=$}}for(this._trigger({type:\"geometry\",edit:function(t){l.origin.size.height=t.height,l.origin.windowOffset.left=t.left,l.origin.windowOffset.top=t.top,l.origin.size.width=t.width},geometry:{height:l.origin.size.height,left:l.origin.windowOffset.left,top:l.origin.windowOffset.top,width:l.origin.size.width}}),l.origin.windowOffset.right=l.origin.windowOffset.left+l.origin.size.width,l.origin.windowOffset.bottom=l.origin.windowOffset.top+l.origin.size.height,l.origin.offset.left=l.origin.windowOffset.left+l.window.scroll.left,l.origin.offset.top=l.origin.windowOffset.top+l.window.scroll.top,l.origin.offset.bottom=l.origin.offset.top+l.origin.size.height,l.origin.offset.right=l.origin.offset.left+l.origin.size.width,l.available.document={bottom:{height:l.document.size.height-l.origin.offset.bottom,width:l.document.size.width},left:{height:l.document.size.height,width:l.origin.offset.left},right:{height:l.document.size.height,width:l.document.size.width-l.origin.offset.right},top:{height:l.origin.offset.top,width:l.document.size.width}},l.available.window={bottom:{height:Math.max(l.window.size.height-Math.max(l.origin.windowOffset.bottom,0),0),width:l.window.size.width},left:{height:l.window.size.height,width:Math.max(l.origin.windowOffset.left,0)},right:{height:l.window.size.height,width:Math.max(l.window.size.width-Math.max(l.origin.windowOffset.right,0),0)},top:{height:Math.max(l.origin.windowOffset.top,0),width:l.window.size.width}};\"html\"!=a[0].tagName.toLowerCase();){if(\"fixed\"==a.css(\"position\")){l.origin.fixedLineage=!0;break}a=a.parent()}return l},__optionsFormat:function(){return\"number\"==typeof this.__options.animationDuration&&(this.__options.animationDuration=[this.__options.animationDuration,this.__options.animationDuration]),\"number\"==typeof this.__options.delay&&(this.__options.delay=[this.__options.delay,this.__options.delay]),\"number\"==typeof this.__options.delayTouch&&(this.__options.delayTouch=[this.__options.delayTouch,this.__options.delayTouch]),\"string\"==typeof this.__options.theme&&(this.__options.theme=[this.__options.theme]),null===this.__options.parent?this.__options.parent=t(e.window.document.body):\"string\"==typeof this.__options.parent&&(this.__options.parent=t(this.__options.parent)),\"hover\"==this.__options.trigger?(this.__options.triggerOpen={mouseenter:!0,touchstart:!0},this.__options.triggerClose={mouseleave:!0,originClick:!0,touchleave:!0}):\"click\"==this.__options.trigger&&(this.__options.triggerOpen={click:!0,tap:!0},this.__options.triggerClose={click:!0,tap:!0}),this._trigger(\"options\"),this},__prepareGC:function(){var i=this;return i.__options.selfDestruction?i.__garbageCollector=setInterval(function(){var o=(new Date).getTime();i.__touchEvents=t.grep(i.__touchEvents,function(t,i){return o-t.time>6e4}),_(i._$origin)||i.close(function(){i.destroy()})},2e4):clearInterval(i.__garbageCollector),i},__prepareOrigin:function(){var t=this;if(t._$origin.off(\".\"+t.__namespace+\"-triggerOpen\"),e.hasTouchCapability&&t._$origin.on(\"touchstart.\"+t.__namespace+\"-triggerOpen touchend.\"+t.__namespace+\"-triggerOpen touchcancel.\"+t.__namespace+\"-triggerOpen\",function(i){t._touchRecordEvent(i)}),t.__options.triggerOpen.click||t.__options.triggerOpen.tap&&e.hasTouchCapability){var i=\"\";t.__options.triggerOpen.click&&(i+=\"click.\"+t.__namespace+\"-triggerOpen \"),t.__options.triggerOpen.tap&&e.hasTouchCapability&&(i+=\"touchend.\"+t.__namespace+\"-triggerOpen\"),t._$origin.on(i,function(i){t._touchIsMeaningfulEvent(i)&&t._open(i)})}if(t.__options.triggerOpen.mouseenter||t.__options.triggerOpen.touchstart&&e.hasTouchCapability){i=\"\";t.__options.triggerOpen.mouseenter&&(i+=\"mouseenter.\"+t.__namespace+\"-triggerOpen \"),t.__options.triggerOpen.touchstart&&e.hasTouchCapability&&(i+=\"touchstart.\"+t.__namespace+\"-triggerOpen\"),t._$origin.on(i,function(i){!t._touchIsTouchEvent(i)&&t._touchIsEmulatedEvent(i)||(t.__pointerIsOverOrigin=!0,t._openShortly(i))})}if(t.__options.triggerClose.mouseleave||t.__options.triggerClose.touchleave&&e.hasTouchCapability){i=\"\";t.__options.triggerClose.mouseleave&&(i+=\"mouseleave.\"+t.__namespace+\"-triggerOpen \"),t.__options.triggerClose.touchleave&&e.hasTouchCapability&&(i+=\"touchend.\"+t.__namespace+\"-triggerOpen touchcancel.\"+t.__namespace+\"-triggerOpen\"),t._$origin.on(i,function(i){t._touchIsMeaningfulEvent(i)&&(t.__pointerIsOverOrigin=!1)})}return t},__prepareTooltip:function(){var i=this,o=i.__options.interactive?\"auto\":\"\";return i._$tooltip.attr(\"id\",i.__namespace).css({\"pointer-events\":o,zIndex:i.__options.zIndex}),t.each(i.__previousThemes,function(t,o){i._$tooltip.removeClass(o)}),t.each(i.__options.theme,function(t,o){i._$tooltip.addClass(o)}),i.__previousThemes=t.merge([],i.__options.theme),i},__scrollHandler:function(i){if(this.__options.triggerClose.scroll)this._close(i);else if(_(this._$origin)&&_(this._$tooltip)){var o=null;if(i.target===e.window.document)this.__Geometry.origin.fixedLineage||this.__options.repositionOnScroll&&this.reposition(i);else{o=this.__geometry();var n=!1;if(\"fixed\"!=this._$origin.css(\"position\")&&this.__$originParents.each(function(i,e){var s=t(e),r=s.css(\"overflow-x\"),_=s.css(\"overflow-y\");if(\"visible\"!=r||\"visible\"!=_){var a=e.getBoundingClientRect();if(\"visible\"!=r&&(o.origin.windowOffset.left<a.left||o.origin.windowOffset.right>a.right))return n=!0,!1;if(\"visible\"!=_&&(o.origin.windowOffset.top<a.top||o.origin.windowOffset.bottom>a.bottom))return n=!0,!1}if(\"fixed\"==s.css(\"position\"))return!1}),n)this._$tooltip.css(\"visibility\",\"hidden\");else if(this._$tooltip.css(\"visibility\",\"visible\"),this.__options.repositionOnScroll)this.reposition(i);else{var s=o.origin.offset.left-this.__Geometry.origin.offset.left,r=o.origin.offset.top-this.__Geometry.origin.offset.top;this._$tooltip.css({left:this.__lastPosition.coord.left+s,top:this.__lastPosition.coord.top+r})}}this._trigger({type:\"scroll\",event:i,geo:o})}return this},__stateSet:function(t){return this.__state=t,this._trigger({type:\"state\",state:t}),this},__timeoutsClear:function(){return clearTimeout(this.__timeouts.open),this.__timeouts.open=null,t.each(this.__timeouts.close,function(t,i){clearTimeout(i)}),this.__timeouts.close=[],this},__trackerStart:function(){var t=this,i=t._$tooltip.find(\".tooltipster-content\");return t.__options.trackTooltip&&(t.__contentBcr=i[0].getBoundingClientRect()),t.__tracker=setInterval(function(){if(_(t._$origin)&&_(t._$tooltip)){if(t.__options.trackOrigin){var o=t.__geometry(),e=!1;r(o.origin.size,t.__Geometry.origin.size)&&(t.__Geometry.origin.fixedLineage?r(o.origin.windowOffset,t.__Geometry.origin.windowOffset)&&(e=!0):r(o.origin.offset,t.__Geometry.origin.offset)&&(e=!0)),e||(t.__options.triggerClose.mouseleave?t._close():t.reposition())}if(t.__options.trackTooltip){var n=i[0].getBoundingClientRect();n.height===t.__contentBcr.height&&n.width===t.__contentBcr.width||(t.reposition(),t.__contentBcr=n)}}else t._close()},t.__options.trackerInterval),t},_close:function(i,o,n){var s=this,r=!0;if(s._trigger({type:\"close\",event:i,stop:function(){r=!1}}),r||n){o&&s.__callbacks.close.push(o),s.__callbacks.open=[],s.__timeoutsClear();var _=function(){t.each(s.__callbacks.close,function(t,o){o.call(s,s,{event:i,origin:s._$origin[0]})}),s.__callbacks.close=[]};if(\"closed\"!=s.__state){var a=!0,l=(new Date).getTime()+s.__options.animationDuration[1];if(\"disappearing\"==s.__state&&l>s.__closingTime&&s.__options.animationDuration[1]>0&&(a=!1),a){s.__closingTime=l,\"disappearing\"!=s.__state&&s.__stateSet(\"disappearing\");var p=function(){clearInterval(s.__tracker),s._trigger({type:\"closing\",event:i}),s._$tooltip.off(\".\"+s.__namespace+\"-triggerClose\").removeClass(\"tooltipster-dying\"),t(e.window).off(\".\"+s.__namespace+\"-triggerClose\"),s.__$originParents.each(function(i,o){t(o).off(\"scroll.\"+s.__namespace+\"-triggerClose\")}),s.__$originParents=null,t(e.window.document.body).off(\".\"+s.__namespace+\"-triggerClose\"),s._$origin.off(\".\"+s.__namespace+\"-triggerClose\"),s._off(\"dismissable\"),s.__stateSet(\"closed\"),s._trigger({type:\"after\",event:i}),s.__options.functionAfter&&s.__options.functionAfter.call(s,s,{event:i,origin:s._$origin[0]}),_()};e.hasTransitions?(s._$tooltip.css({\"-moz-animation-duration\":s.__options.animationDuration[1]+\"ms\",\"-ms-animation-duration\":s.__options.animationDuration[1]+\"ms\",\"-o-animation-duration\":s.__options.animationDuration[1]+\"ms\",\"-webkit-animation-duration\":s.__options.animationDuration[1]+\"ms\",\"animation-duration\":s.__options.animationDuration[1]+\"ms\",\"transition-duration\":s.__options.animationDuration[1]+\"ms\"}),s._$tooltip.clearQueue().removeClass(\"tooltipster-show\").addClass(\"tooltipster-dying\"),s.__options.animationDuration[1]>0&&s._$tooltip.delay(s.__options.animationDuration[1]),s._$tooltip.queue(p)):s._$tooltip.stop().fadeOut(s.__options.animationDuration[1],p)}}else _()}return s},_off:function(){return this.__$emitterPrivate.off.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_on:function(){return this.__$emitterPrivate.on.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_one:function(){return this.__$emitterPrivate.one.apply(this.__$emitterPrivate,Array.prototype.slice.apply(arguments)),this},_open:function(i,o){var n=this;if(!n.__destroying&&_(n._$origin)&&n.__enabled){var s=!0;if(\"closed\"==n.__state&&(n._trigger({type:\"before\",event:i,stop:function(){s=!1}}),s&&n.__options.functionBefore&&(s=n.__options.functionBefore.call(n,n,{event:i,origin:n._$origin[0]}))),!1!==s&&null!==n.__Content){o&&n.__callbacks.open.push(o),n.__callbacks.close=[],n.__timeoutsClear();var r,a=function(){\"stable\"!=n.__state&&n.__stateSet(\"stable\"),t.each(n.__callbacks.open,function(t,i){i.call(n,n,{origin:n._$origin[0],tooltip:n._$tooltip[0]})}),n.__callbacks.open=[]};if(\"closed\"!==n.__state)r=0,\"disappearing\"===n.__state?(n.__stateSet(\"appearing\"),e.hasTransitions?(n._$tooltip.clearQueue().removeClass(\"tooltipster-dying\").addClass(\"tooltipster-show\"),n.__options.animationDuration[0]>0&&n._$tooltip.delay(n.__options.animationDuration[0]),n._$tooltip.queue(a)):n._$tooltip.stop().fadeIn(a)):\"stable\"==n.__state&&a();else{if(n.__stateSet(\"appearing\"),r=n.__options.animationDuration[0],n.__contentInsert(),n.reposition(i,!0),e.hasTransitions?(n._$tooltip.addClass(\"tooltipster-\"+n.__options.animation).addClass(\"tooltipster-initial\").css({\"-moz-animation-duration\":n.__options.animationDuration[0]+\"ms\",\"-ms-animation-duration\":n.__options.animationDuration[0]+\"ms\",\"-o-animation-duration\":n.__options.animationDuration[0]+\"ms\",\"-webkit-animation-duration\":n.__options.animationDuration[0]+\"ms\",\"animation-duration\":n.__options.animationDuration[0]+\"ms\",\"transition-duration\":n.__options.animationDuration[0]+\"ms\"}),setTimeout(function(){\"closed\"!=n.__state&&(n._$tooltip.addClass(\"tooltipster-show\").removeClass(\"tooltipster-initial\"),n.__options.animationDuration[0]>0&&n._$tooltip.delay(n.__options.animationDuration[0]),n._$tooltip.queue(a))},0)):n._$tooltip.css(\"display\",\"none\").fadeIn(n.__options.animationDuration[0],a),n.__trackerStart(),t(e.window).on(\"resize.\"+n.__namespace+\"-triggerClose\",function(i){var o=t(document.activeElement);(o.is(\"input\")||o.is(\"textarea\"))&&t.contains(n._$tooltip[0],o[0])||n.reposition(i)}).on(\"scroll.\"+n.__namespace+\"-triggerClose\",function(t){n.__scrollHandler(t)}),n.__$originParents=n._$origin.parents(),n.__$originParents.each(function(i,o){t(o).on(\"scroll.\"+n.__namespace+\"-triggerClose\",function(t){n.__scrollHandler(t)})}),n.__options.triggerClose.mouseleave||n.__options.triggerClose.touchleave&&e.hasTouchCapability){n._on(\"dismissable\",function(t){t.dismissable?t.delay?(h=setTimeout(function(){n._close(t.event)},t.delay),n.__timeouts.close.push(h)):n._close(t):clearTimeout(h)});var l=n._$origin,p=\"\",c=\"\",h=null;n.__options.interactive&&(l=l.add(n._$tooltip)),n.__options.triggerClose.mouseleave&&(p+=\"mouseenter.\"+n.__namespace+\"-triggerClose \",c+=\"mouseleave.\"+n.__namespace+\"-triggerClose \"),n.__options.triggerClose.touchleave&&e.hasTouchCapability&&(p+=\"touchstart.\"+n.__namespace+\"-triggerClose\",c+=\"touchend.\"+n.__namespace+\"-triggerClose touchcancel.\"+n.__namespace+\"-triggerClose\"),l.on(c,function(t){if(n._touchIsTouchEvent(t)||!n._touchIsEmulatedEvent(t)){var i=\"mouseleave\"==t.type?n.__options.delay:n.__options.delayTouch;n._trigger({delay:i[1],dismissable:!0,event:t,type:\"dismissable\"})}}).on(p,function(t){!n._touchIsTouchEvent(t)&&n._touchIsEmulatedEvent(t)||n._trigger({dismissable:!1,event:t,type:\"dismissable\"})})}n.__options.triggerClose.originClick&&n._$origin.on(\"click.\"+n.__namespace+\"-triggerClose\",function(t){n._touchIsTouchEvent(t)||n._touchIsEmulatedEvent(t)||n._close(t)}),(n.__options.triggerClose.click||n.__options.triggerClose.tap&&e.hasTouchCapability)&&setTimeout(function(){if(\"closed\"!=n.__state){var i=\"\",o=t(e.window.document.body);n.__options.triggerClose.click&&(i+=\"click.\"+n.__namespace+\"-triggerClose \"),n.__options.triggerClose.tap&&e.hasTouchCapability&&(i+=\"touchend.\"+n.__namespace+\"-triggerClose\"),o.on(i,function(i){n._touchIsMeaningfulEvent(i)&&(n._touchRecordEvent(i),n.__options.interactive&&t.contains(n._$tooltip[0],i.target)||n._close(i))}),n.__options.triggerClose.tap&&e.hasTouchCapability&&o.on(\"touchstart.\"+n.__namespace+\"-triggerClose\",function(t){n._touchRecordEvent(t)})}},0),n._trigger(\"ready\"),n.__options.functionReady&&n.__options.functionReady.call(n,n,{origin:n._$origin[0],tooltip:n._$tooltip[0]})}if(n.__options.timer>0){h=setTimeout(function(){n._close()},n.__options.timer+r);n.__timeouts.close.push(h)}}}return n},_openShortly:function(t){var i=this,o=!0;if(\"stable\"!=i.__state&&\"appearing\"!=i.__state&&!i.__timeouts.open&&(i._trigger({type:\"start\",event:t,stop:function(){o=!1}}),o)){var e=0==t.type.indexOf(\"touch\")?i.__options.delayTouch:i.__options.delay;e[0]?i.__timeouts.open=setTimeout(function(){i.__timeouts.open=null,i.__pointerIsOverOrigin&&i._touchIsMeaningfulEvent(t)?(i._trigger(\"startend\"),i._open(t)):i._trigger(\"startcancel\")},e[0]):(i._trigger(\"startend\"),i._open(t))}return i},_optionsExtract:function(i,o){var e=this,n=t.extend(!0,{},o),s=e.__options[i];return s||(s={},t.each(o,function(t,i){var o=e.__options[t];void 0!==o&&(s[t]=o)})),t.each(n,function(i,o){void 0!==s[i]&&(\"object\"!=typeof o||o instanceof Array||null==o||\"object\"!=typeof s[i]||s[i]instanceof Array||null==s[i]?n[i]=s[i]:t.extend(n[i],s[i]))}),n},_plug:function(i){var o=t.tooltipster._plugin(i);if(!o)throw new Error('The \"'+i+'\" plugin is not defined');return o.instance&&t.tooltipster.__bridge(o.instance,this,o.name),this},_touchIsEmulatedEvent:function(t){for(var i=!1,o=(new Date).getTime(),e=this.__touchEvents.length-1;e>=0;e--){var n=this.__touchEvents[e];if(!(o-n.time<500))break;n.target===t.target&&(i=!0)}return i},_touchIsMeaningfulEvent:function(t){return this._touchIsTouchEvent(t)&&!this._touchSwiped(t.target)||!this._touchIsTouchEvent(t)&&!this._touchIsEmulatedEvent(t)},_touchIsTouchEvent:function(t){return 0==t.type.indexOf(\"touch\")},_touchRecordEvent:function(t){return this._touchIsTouchEvent(t)&&(t.time=(new Date).getTime(),this.__touchEvents.push(t)),this},_touchSwiped:function(t){for(var i=!1,o=this.__touchEvents.length-1;o>=0;o--){var e=this.__touchEvents[o];if(\"touchmove\"==e.type){i=!0;break}if(\"touchstart\"==e.type&&t===e.target)break}return i},_trigger:function(){var i=Array.prototype.slice.apply(arguments);return\"string\"==typeof i[0]&&(i[0]={type:i[0]}),i[0].instance=this,i[0].origin=this._$origin?this._$origin[0]:null,i[0].tooltip=this._$tooltip?this._$tooltip[0]:null,this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate,i),t.tooltipster._trigger.apply(t.tooltipster,i),this.__$emitterPublic.trigger.apply(this.__$emitterPublic,i),this},_unplug:function(i){var o=this;if(o[i]){var e=t.tooltipster._plugin(i);e.instance&&t.each(e.instance,function(t,e){o[t]&&o[t].bridged===o[i]&&delete o[t]}),o[i].__destroy&&o[i].__destroy(),delete o[i]}return o},close:function(t){return this.__destroyed?this.__destroyError():this._close(null,t),this},content:function(t){var i=this;if(void 0===t)return i.__Content;if(i.__destroyed)i.__destroyError();else if(i.__contentSet(t),null!==i.__Content){if(\"closed\"!==i.__state&&(i.__contentInsert(),i.reposition(),i.__options.updateAnimation))if(e.hasTransitions){var o=i.__options.updateAnimation;i._$tooltip.addClass(\"tooltipster-update-\"+o),setTimeout(function(){\"closed\"!=i.__state&&i._$tooltip.removeClass(\"tooltipster-update-\"+o)},1e3)}else i._$tooltip.fadeTo(200,.5,function(){\"closed\"!=i.__state&&i._$tooltip.fadeTo(200,1)})}else i._close();return i},destroy:function(){var i=this;if(i.__destroyed)i.__destroyError();else{\"closed\"!=i.__state?i.option(\"animationDuration\",0)._close(null,null,!0):i.__timeoutsClear(),i._trigger(\"destroy\"),i.__destroyed=!0,i._$origin.removeData(i.__namespace).off(\".\"+i.__namespace+\"-triggerOpen\"),t(e.window.document.body).off(\".\"+i.__namespace+\"-triggerOpen\");var o=i._$origin.data(\"tooltipster-ns\");if(o)if(1===o.length){var n=null;\"previous\"==i.__options.restoration?n=i._$origin.data(\"tooltipster-initialTitle\"):\"current\"==i.__options.restoration&&(n=\"string\"==typeof i.__Content?i.__Content:t(\"<div></div>\").append(i.__Content).html()),n&&i._$origin.attr(\"title\",n),i._$origin.removeClass(\"tooltipstered\"),i._$origin.removeData(\"tooltipster-ns\").removeData(\"tooltipster-initialTitle\")}else o=t.grep(o,function(t,o){return t!==i.__namespace}),i._$origin.data(\"tooltipster-ns\",o);i._trigger(\"destroyed\"),i._off(),i.off(),i.__Content=null,i.__$emitterPrivate=null,i.__$emitterPublic=null,i.__options.parent=null,i._$origin=null,i._$tooltip=null,t.tooltipster.__instancesLatestArr=t.grep(t.tooltipster.__instancesLatestArr,function(t,o){return i!==t}),clearInterval(i.__garbageCollector)}return i},disable:function(){return this.__destroyed?(this.__destroyError(),this):(this._close(),this.__enabled=!1,this)},elementOrigin:function(){if(!this.__destroyed)return this._$origin[0];this.__destroyError()},elementTooltip:function(){return this._$tooltip?this._$tooltip[0]:null},enable:function(){return this.__enabled=!0,this},hide:function(t){return this.close(t)},instance:function(){return this},off:function(){return this.__destroyed||this.__$emitterPublic.off.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},on:function(){return this.__destroyed?this.__destroyError():this.__$emitterPublic.on.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},one:function(){return this.__destroyed?this.__destroyError():this.__$emitterPublic.one.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this},open:function(t){return this.__destroyed?this.__destroyError():this._open(null,t),this},option:function(i,o){return void 0===o?this.__options[i]:(this.__destroyed?this.__destroyError():(this.__options[i]=o,this.__optionsFormat(),t.inArray(i,[\"trigger\",\"triggerClose\",\"triggerOpen\"])>=0&&this.__prepareOrigin(),\"selfDestruction\"===i&&this.__prepareGC()),this)},reposition:function(t,i){return this.__destroyed?this.__destroyError():\"closed\"!=this.__state&&_(this._$origin)&&(i||_(this._$tooltip))&&(i||this._$tooltip.detach(),this.__Geometry=this.__geometry(),this._trigger({type:\"reposition\",event:t,helper:{geo:this.__Geometry}})),this},show:function(t){return this.open(t)},status:function(){return{destroyed:this.__destroyed,enabled:this.__enabled,open:\"closed\"!==this.__state,state:this.__state}},triggerHandler:function(){return this.__destroyed?this.__destroyError():this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic,Array.prototype.slice.apply(arguments)),this}},t.fn.tooltipster=function(){var o=Array.prototype.slice.apply(arguments),e=\"You are using a single HTML element as content for several tooltips. You probably want to set the contentCloning option to TRUE.\";if(0===this.length)return this;if(\"string\"==typeof o[0]){var n=\"#*$~&\";return this.each(function(){var i=t(this).data(\"tooltipster-ns\"),s=i?t(this).data(i[0]):null;if(!s)throw new Error(\"You called Tooltipster's \\\"\"+o[0]+'\" method on an uninitialized element');if(\"function\"!=typeof s[o[0]])throw new Error('Unknown method \"'+o[0]+'\"');this.length>1&&\"content\"==o[0]&&(o[1]instanceof t||\"object\"==typeof o[1]&&null!=o[1]&&o[1].tagName)&&!s.__options.contentCloning&&s.__options.debug&&console.log(e);var r=s[o[0]](o[1],o[2]);if(r!==s||\"instance\"===o[0])return n=r,!1}),\"#*$~&\"!==n?n:this}t.tooltipster.__instancesLatestArr=[];var s=o[0]&&void 0!==o[0].multiple,r=s&&o[0].multiple||!s&&i.multiple,_=o[0]&&void 0!==o[0].content,a=_&&o[0].content||!_&&i.content,l=o[0]&&void 0!==o[0].contentCloning,p=l&&o[0].contentCloning||!l&&i.contentCloning,c=o[0]&&void 0!==o[0].debug,h=c&&o[0].debug||!c&&i.debug;return this.length>1&&(a instanceof t||\"object\"==typeof a&&null!=a&&a.tagName)&&!p&&h&&console.log(e),this.each(function(){var i=!1,e=t(this),n=e.data(\"tooltipster-ns\"),s=null;n?r?i=!0:h&&(console.log(\"Tooltipster: one or more tooltips are already attached to the element below. Ignoring.\"),console.log(this)):i=!0,i&&(s=new t.Tooltipster(this,o[0]),n||(n=[]),n.push(s.__namespace),e.data(\"tooltipster-ns\",n),e.data(s.__namespace,s),s.__options.functionInit&&s.__options.functionInit.call(s,s,{origin:this}),s._trigger(\"init\")),t.tooltipster.__instancesLatestArr.push(s)}),this},s.prototype={__init:function(i){this.__$tooltip=i,this.__$tooltip.css({left:0,overflow:\"hidden\",position:\"absolute\",top:0}).find(\".tooltipster-content\").css(\"overflow\",\"auto\"),this.$container=t('<div class=\"tooltipster-ruler\"></div>').append(this.__$tooltip).appendTo(e.window.document.body)},__forceRedraw:function(){var t=this.__$tooltip.parent();this.__$tooltip.detach(),this.__$tooltip.appendTo(t)},constrain:function(t,i){return this.constraints={width:t,height:i},this.__$tooltip.css({display:\"block\",height:\"\",overflow:\"auto\",width:t}),this},destroy:function(){this.__$tooltip.detach().find(\".tooltipster-content\").css({display:\"\",overflow:\"\"}),this.$container.remove()},free:function(){return this.constraints=null,this.__$tooltip.css({display:\"\",height:\"\",overflow:\"visible\",width:\"\"}),this},measure:function(){this.__forceRedraw();var t=this.__$tooltip[0].getBoundingClientRect(),i={size:{height:t.height||t.bottom-t.top,width:t.width||t.right-t.left}};if(this.constraints){var o=this.__$tooltip.find(\".tooltipster-content\"),n=this.__$tooltip.outerHeight(),s=o[0].getBoundingClientRect(),r={height:n<=this.constraints.height,width:t.width<=this.constraints.width&&s.width>=o[0].scrollWidth-1};i.fits=r.height&&r.width}return e.IE&&e.IE<=11&&i.size.width!==e.window.document.documentElement.clientWidth&&(i.size.width=Math.ceil(i.size.width)+1),i}};var a=navigator.userAgent.toLowerCase();-1!=a.indexOf(\"msie\")?e.IE=parseInt(a.split(\"msie\")[1]):-1!==a.toLowerCase().indexOf(\"trident\")&&-1!==a.indexOf(\" rv:11\")?e.IE=11:-1!=a.toLowerCase().indexOf(\"edge/\")&&(e.IE=parseInt(a.toLowerCase().split(\"edge/\")[1]));return t.tooltipster._plugin({name:\"tooltipster.sideTip\",instance:{__defaults:function(){return{arrow:!0,distance:6,functionPosition:null,maxWidth:null,minIntersection:16,minWidth:0,position:null,side:\"top\",viewportAware:!0,defaultStyles:{backgroundColor:\"#fff\",textColor:\"#000\"}}},__init:function(t){var i=this;i.__instance=t,i.__namespace=\"tooltipster-sideTip-\"+Math.round(1e6*Math.random()),i.__previousState=\"closed\",i.__options,i.__optionsFormat(),i.__instance._on(\"state.\"+i.__namespace,function(t){\"closed\"==t.state?i.__close():\"appearing\"==t.state&&\"closed\"==i.__previousState&&i.__create(),i.__previousState=t.state}),i.__instance._on(\"options.\"+i.__namespace,function(){i.__optionsFormat()}),i.__instance._on(\"reposition.\"+i.__namespace,function(t){i.__reposition(t.event,t.helper)})},__close:function(){this.__instance.content()instanceof t&&this.__instance.content().detach(),this.__instance._$tooltip.remove(),this.__instance._$tooltip=null},__create:function(){var i=this.__instance.__options.styles,o=t('<div class=\"tooltipster-base tooltipster-sidetip\"><div class=\"tooltipster-box\"><div class=\"tooltipster-content\"></div></div><div class=\"tooltipster-arrow\"><div class=\"tooltipster-arrow-uncropped\"><div class=\"tooltipster-arrow-border\"></div><div class=\"tooltipster-arrow-background\"></div></div></div></div>');o.find(\".tooltipster-box\").css({color:i.textColor?i.textColor:this.__options.defaultStyles.textColor,backgroundColor:i.backgroundColor?i.backgroundColor:this.__options.defaultStyles.backgroundColor}),o.find(\".tooltipster-arrow-border\").css({backgroundColor:i.backgroundColor?i.backgroundColor:this.__options.defaultStyles.backgroundColor}),this.__options.arrow||o.find(\".tooltipster-box\").css(\"margin\",0).end().find(\".tooltipster-arrow\").hide(),this.__options.minWidth&&o.css(\"min-width\",this.__options.minWidth+\"px\"),this.__options.maxWidth&&o.css(\"max-width\",this.__options.maxWidth+\"px\"),this.__instance._$tooltip=o,this.__instance._trigger(\"created\")},__destroy:function(){this.__instance._off(\".\"+self.__namespace)},__optionsFormat:function(){if(this.__options=this.__instance._optionsExtract(\"tooltipster.sideTip\",this.__defaults()),this.__options.position&&(this.__options.side=this.__options.position),\"object\"!=typeof this.__options.distance&&(this.__options.distance=[this.__options.distance]),this.__options.distance.length<4&&(void 0===this.__options.distance[1]&&(this.__options.distance[1]=this.__options.distance[0]),void 0===this.__options.distance[2]&&(this.__options.distance[2]=this.__options.distance[0]),void 0===this.__options.distance[3]&&(this.__options.distance[3]=this.__options.distance[1])),this.__options.distance={top:this.__options.distance[0],right:this.__options.distance[1],bottom:this.__options.distance[2],left:this.__options.distance[3]},\"string\"==typeof this.__options.side){this.__options.side=[this.__options.side,{top:\"bottom\",right:\"left\",bottom:\"top\",left:\"right\"}[this.__options.side]],\"left\"==this.__options.side[0]||\"right\"==this.__options.side[0]?this.__options.side.push(\"top\",\"bottom\"):this.__options.side.push(\"right\",\"left\")}6===t.tooltipster._env.IE&&!0!==this.__options.arrow&&(this.__options.arrow=!1)},__reposition:function(i,o){var e,n=this,s=n.__targetFind(o),r=[];n.__instance._$tooltip.detach();var _=n.__instance._$tooltip.clone(),a=t.tooltipster._getRuler(_),l=!1,p=n.__instance.option(\"animation\");switch(p&&_.removeClass(\"tooltipster-\"+p),t.each([\"window\",\"document\"],function(e,p){var c=null;if(n.__instance._trigger({container:p,helper:o,satisfied:l,takeTest:function(t){c=t},results:r,type:\"positionTest\"}),1==c||0!=c&&0==l&&(\"window\"!=p||n.__options.viewportAware))for(e=0;e<n.__options.side.length;e++){var h={horizontal:0,vertical:0},d=n.__options.side[e];\"top\"==d||\"bottom\"==d?h.vertical=n.__options.distance[d]:h.horizontal=n.__options.distance[d],n.__sideChange(_,d),t.each([\"natural\",\"constrained\"],function(t,e){if(c=null,n.__instance._trigger({container:p,event:i,helper:o,mode:e,results:r,satisfied:l,side:d,takeTest:function(t){c=t},type:\"positionTest\"}),1==c||0!=c&&0==l){var _={container:p,distance:h,fits:null,mode:e,outerSize:null,side:d,size:null,target:s[d],whole:null},u=(\"natural\"==e?a.free():a.constrain(o.geo.available[p][d].width-h.horizontal,o.geo.available[p][d].height-h.vertical)).measure();if(_.size=u.size,_.outerSize={height:u.size.height+h.vertical,width:u.size.width+h.horizontal},\"natural\"==e?o.geo.available[p][d].width>=_.outerSize.width&&o.geo.available[p][d].height>=_.outerSize.height?_.fits=!0:_.fits=!1:_.fits=u.fits,\"window\"==p&&(_.fits?_.whole=\"top\"==d||\"bottom\"==d?o.geo.origin.windowOffset.right>=n.__options.minIntersection&&o.geo.window.size.width-o.geo.origin.windowOffset.left>=n.__options.minIntersection:o.geo.origin.windowOffset.bottom>=n.__options.minIntersection&&o.geo.window.size.height-o.geo.origin.windowOffset.top>=n.__options.minIntersection:_.whole=!1),r.push(_),_.whole)l=!0;else if(\"natural\"==_.mode&&(_.fits||_.size.width<=o.geo.available[p][d].width))return!1}})}}),n.__instance._trigger({edit:function(t){r=t},event:i,helper:o,results:r,type:\"positionTested\"}),r.sort(function(t,i){return t.whole&&!i.whole?-1:!t.whole&&i.whole?1:t.whole&&i.whole?(o=n.__options.side.indexOf(t.side))<(e=n.__options.side.indexOf(i.side))?-1:o>e?1:\"natural\"==t.mode?-1:1:t.fits&&!i.fits?-1:!t.fits&&i.fits?1:t.fits&&i.fits?(o=n.__options.side.indexOf(t.side))<(e=n.__options.side.indexOf(i.side))?-1:o>e?1:\"natural\"==t.mode?-1:1:\"document\"==t.container&&\"bottom\"==t.side&&\"natural\"==t.mode?-1:1;var o,e}),(e=r[0]).coord={},e.side){case\"left\":case\"right\":e.coord.top=Math.floor(e.target-e.size.height/2);break;case\"bottom\":case\"top\":e.coord.left=Math.floor(e.target-e.size.width/2)}switch(e.side){case\"left\":e.coord.left=o.geo.origin.windowOffset.left-e.outerSize.width;break;case\"right\":e.coord.left=o.geo.origin.windowOffset.right+e.distance.horizontal;break;case\"top\":e.coord.top=o.geo.origin.windowOffset.top-e.outerSize.height;break;case\"bottom\":e.coord.top=o.geo.origin.windowOffset.bottom+e.distance.vertical}\"window\"==e.container?\"top\"==e.side||\"bottom\"==e.side?e.coord.left<0?o.geo.origin.windowOffset.right-this.__options.minIntersection>=0?e.coord.left=0:e.coord.left=o.geo.origin.windowOffset.right-this.__options.minIntersection-1:e.coord.left>o.geo.window.size.width-e.size.width&&(o.geo.origin.windowOffset.left+this.__options.minIntersection<=o.geo.window.size.width?e.coord.left=o.geo.window.size.width-e.size.width:e.coord.left=o.geo.origin.windowOffset.left+this.__options.minIntersection+1-e.size.width):e.coord.top<0?o.geo.origin.windowOffset.bottom-this.__options.minIntersection>=0?e.coord.top=0:e.coord.top=o.geo.origin.windowOffset.bottom-this.__options.minIntersection-1:e.coord.top>o.geo.window.size.height-e.size.height&&(o.geo.origin.windowOffset.top+this.__options.minIntersection<=o.geo.window.size.height?e.coord.top=o.geo.window.size.height-e.size.height:e.coord.top=o.geo.origin.windowOffset.top+this.__options.minIntersection+1-e.size.height):(e.coord.left>o.geo.window.size.width-e.size.width&&(e.coord.left=o.geo.window.size.width-e.size.width),e.coord.left<0&&(e.coord.left=0)),n.__sideChange(_,e.side),o.tooltipClone=_[0],o.tooltipParent=n.__instance.option(\"parent\").parent[0],o.mode=e.mode,o.whole=e.whole,o.origin=n.__instance._$origin[0],o.tooltip=n.__instance._$tooltip[0],delete e.container,delete e.fits,delete e.mode,delete e.outerSize,delete e.whole,e.distance=e.distance.horizontal||e.distance.vertical;var c,h,d,u=t.extend(!0,{},e);if(n.__instance._trigger({edit:function(t){e=t},event:i,helper:o,position:u,type:\"position\"}),n.__options.functionPosition){var g=n.__options.functionPosition.call(n,n.__instance,o,u);g&&(e=g)}a.destroy(),\"top\"==e.side||\"bottom\"==e.side?(c={prop:\"left\",val:e.target-e.coord.left},h=e.size.width-this.__options.minIntersection):(c={prop:\"top\",val:e.target-e.coord.top},h=e.size.height-this.__options.minIntersection),c.val<this.__options.minIntersection?c.val=this.__options.minIntersection:c.val>h&&(c.val=h),d=o.geo.origin.fixedLineage?o.geo.origin.windowOffset:{left:o.geo.origin.windowOffset.left+o.geo.window.scroll.left,top:o.geo.origin.windowOffset.top+o.geo.window.scroll.top},e.coord={left:d.left+(e.coord.left-o.geo.origin.windowOffset.left),top:d.top+(e.coord.top-o.geo.origin.windowOffset.top)},n.__sideChange(n.__instance._$tooltip,e.side),o.geo.origin.fixedLineage?n.__instance._$tooltip.css(\"position\",\"fixed\"):n.__instance._$tooltip.css(\"position\",\"\"),n.__instance._$tooltip.css({left:e.coord.left,top:e.coord.top,height:e.size.height,width:e.size.width}).find(\".tooltipster-arrow\").css({left:\"\",top:\"\"}).css(c.prop,c.val),n.__instance._$tooltip.appendTo(n.__instance.option(\"parent\")),n.__instance._trigger({type:\"repositioned\",event:i,position:e})},__sideChange:function(t,i){t.removeClass(\"tooltipster-bottom\").removeClass(\"tooltipster-left\").removeClass(\"tooltipster-right\").removeClass(\"tooltipster-top\").addClass(\"tooltipster-\"+i)},__targetFind:function(t){var i={},o=this.__instance._$origin[0].getClientRects();o.length>1&&(1==this.__instance._$origin.css(\"opacity\")&&(this.__instance._$origin.css(\"opacity\",.99),o=this.__instance._$origin[0].getClientRects(),this.__instance._$origin.css(\"opacity\",1)));if(o.length<2)i.top=Math.floor(t.geo.origin.windowOffset.left+t.geo.origin.size.width/2),i.bottom=i.top,i.left=Math.floor(t.geo.origin.windowOffset.top+t.geo.origin.size.height/2),i.right=i.left;else{var e=o[0];i.top=Math.floor(e.left+(e.right-e.left)/2),e=o.length>2?o[Math.ceil(o.length/2)-1]:o[0],i.right=Math.floor(e.top+(e.bottom-e.top)/2),e=o[o.length-1],i.bottom=Math.floor(e.left+(e.right-e.left)/2),e=o.length>2?o[Math.ceil((o.length+1)/2)-1]:o[o.length-1],i.left=Math.floor(e.top+(e.bottom-e.top)/2)}return i}}}),t});\n","Magento_ConfigurableProduct/js/catalog-add-to-cart-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'jquery',\n    'Magento_ConfigurableProduct/js/product/view/product-info-resolver'\n], function (_, $, productInfoResolver) {\n    'use strict';\n\n    return function (widget) {\n\n        $.widget('mage.catalogAddToCart', widget, {\n            /**\n             * @param {jQuery} form\n             */\n            ajaxSubmit: function (form) {\n                var isConfigurable = !!_.find(form.serializeArray(), function (item) {\n                    return item.name.indexOf('super_attribute') !== -1;\n                });\n\n                if (isConfigurable) {\n                    this.options.productInfoResolver = productInfoResolver;\n                }\n\n                return this._super(form);\n            }\n        });\n\n        return $.mage.catalogAddToCart;\n    };\n});\n","Magento_ConfigurableProduct/js/configurable-customer-data.js":"require([\n    'jquery',\n    'Magento_ConfigurableProduct/js/options-updater'\n], function ($, Updater) {\n    'use strict';\n\n    var selectors = {\n            formSelector: '#product_addtocart_form'\n        },\n        configurableWidgetName = 'mageConfigurable',\n        widgetInitEvent = 'configurable.initialized',\n\n    /**\n    * Sets all configurable attribute's selected values\n    */\n    updateConfigurableOptions = function () {\n        var configurableWidget = $(selectors.formSelector).data(configurableWidgetName);\n\n        if (!configurableWidget) {\n            return;\n        }\n        configurableWidget.options.values = this.productOptions || {};\n        configurableWidget._configureForValues();\n    },\n    updater = new Updater(widgetInitEvent, updateConfigurableOptions);\n\n    updater.listen();\n});\n","Magento_ConfigurableProduct/js/options-updater.js":"define([\n    'jquery',\n    'underscore',\n    'Magento_Customer/js/customer-data',\n    'domReady!'\n], function ($, _, customerData) {\n    'use strict';\n\n    var selectors = {\n        formSelector: '#product_addtocart_form',\n        productIdSelector: '#product_addtocart_form [name=\"product\"]',\n        itemIdSelector: '#product_addtocart_form [name=\"item\"]'\n    },\n    cartData = customerData.get('cart'),\n    productId = $(selectors.productIdSelector).val(),\n    itemId = $(selectors.itemIdSelector).val(),\n\n    /**\n    * set productOptions according to cart data from customer-data\n    *\n    * @param {Object} data - cart data from customer-data\n    * @returns {Boolean} - whether the new options differ from previous\n    */\n    setProductOptions = function (data) {\n        var changedProductOptions;\n\n        if (!(data && data.items && data.items.length && productId)) {\n            return false;\n        }\n        changedProductOptions = _.find(data.items, function (item) {\n            if (item['item_id'] === itemId) {\n                return item['product_id'] === productId;\n            }\n        });\n        changedProductOptions = changedProductOptions && changedProductOptions.options &&\n            changedProductOptions.options.reduce(function (obj, val) {\n                obj[val['option_id']] = val['option_value'];\n\n                return obj;\n            }, {});\n\n        if (JSON.stringify(this.productOptions || {}) === JSON.stringify(changedProductOptions || {})) {\n            return false;\n        }\n\n        this.productOptions = changedProductOptions;\n\n        return true;\n    },\n\n    /**\n    * Listens to update of cart data or options initialization and update selected option according to customer data\n    *\n    */\n    listen = function () {\n        cartData.subscribe(function (updateCartData) {\n            if (this.setProductOptions(updateCartData)) {\n                this.updateOptions();\n            }\n        }.bind(this));\n        $(selectors.formSelector).on(this.eventName, function () {\n            this.setProductOptions(cartData());\n            this.updateOptions();\n        }.bind(this));\n    },\n\n    /**\n    * Updater constructor function\n    *\n    */\n    Updater = function (eventName, updateOptionsCallback) {\n        if (this instanceof Updater) {\n            this.eventName = eventName;\n            this.updateOptions = updateOptionsCallback;\n            this.productOptions = {};\n        }\n    };\n\n    Updater.prototype.setProductOptions = setProductOptions;\n    Updater.prototype.listen = listen;\n\n    return Updater;\n});\n","Magento_ConfigurableProduct/js/configurable.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'mage/template',\n    'mage/translate',\n    'priceUtils',\n    'priceBox',\n    'jquery-ui-modules/widget',\n    'jquery/jquery.parsequery',\n    'fotoramaVideoEvents'\n], function ($, _, mageTemplate, $t, priceUtils) {\n    'use strict';\n\n    $.widget('mage.configurable', {\n        options: {\n            superSelector: '.super-attribute-select',\n            selectSimpleProduct: '[name=\"selected_configurable_option\"]',\n\n            /**\n             * @deprecated Not used anymore\n             * @see selectorProductPrice\n             */\n            priceHolderSelector: '.price-box',\n            spConfig: {},\n            state: {},\n            priceFormat: {},\n            optionTemplate: '<%- data.label %>' +\n            '<% if (typeof data.finalPrice.value !== \"undefined\") { %>' +\n            ' <%- data.finalPrice.formatted %>' +\n            '<% } %>',\n            mediaGallerySelector: '[data-gallery-role=gallery-placeholder]',\n            mediaGalleryInitial: null,\n            slyOldPriceSelector: '.sly-old-price',\n            normalPriceLabelSelector: '.product-info-main .normal-price .price-label',\n\n            /**\n             * Defines the mechanism of how images of a gallery should be\n             * updated when user switches between configurations of a product.\n             *\n             * As for now value of this option can be either 'replace' or 'prepend'.\n             *\n             * @type {String}\n             */\n            gallerySwitchStrategy: 'replace',\n            tierPriceTemplateSelector: '#tier-prices-template',\n            tierPriceBlockSelector: '[data-role=\"tier-price-block\"]',\n            tierPriceTemplate: '',\n            selectorProduct: '.product-info-main',\n            selectorProductPrice: '[data-role=priceBox]',\n            qtyInfo: '#qty'\n        },\n\n        /**\n         * Creates widget\n         * @private\n         */\n        _create: function () {\n            // Initial setting of various option values\n            this._initializeOptions();\n\n            // Override defaults with URL query parameters and/or inputs values\n            this._overrideDefaults();\n\n            // Change events to check select reloads\n            this._setupChangeEvents();\n\n            // Fill state\n            this._fillState();\n\n            // Setup child and prev/next settings\n            this._setChildSettings();\n\n            // Setup/configure values to inputs\n            this._configureForValues();\n\n            $(this.element).trigger('configurable.initialized');\n            $(this.options.qtyInfo).on('input', this._reloadPrice.bind(this));\n        },\n\n        /**\n         * Initialize tax configuration, initial settings, and options values.\n         * @private\n         */\n        _initializeOptions: function () {\n            var options = this.options,\n                gallery = $(options.mediaGallerySelector),\n                priceBoxOptions = this._getPriceBoxElement().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                this.element.parents(this.options.selectorProduct).find(options.superSelector);\n\n            options.values = options.spConfig.defaultValues || {};\n            options.parentImage = $('[data-role=base-image-container] img').attr('src');\n\n            this.inputSimpleProduct = this.element.find(options.selectSimpleProduct);\n\n            gallery.data('gallery') ?\n                this._onGalleryLoaded(gallery) :\n                gallery.on('gallery:loaded', this._onGalleryLoaded.bind(this, gallery));\n\n        },\n\n        /**\n         * Override default options values settings with either URL query parameters or\n         * initialized inputs values.\n         * @private\n         */\n        _overrideDefaults: function () {\n            var hashIndex = window.location.href.indexOf('#');\n\n            if (hashIndex !== -1) {\n                this._parseQueryParams(window.location.href.substr(hashIndex + 1));\n            }\n\n            if (this.options.spConfig.inputsInitialized) {\n                this._setValuesByAttribute();\n            }\n\n            this._setInitialOptionsLabels();\n        },\n\n        /**\n         * Parse query parameters from a query string and set options values based on the\n         * key value pairs of the parameters.\n         * @param {*} queryString - URL query string containing query parameters.\n         * @private\n         */\n        _parseQueryParams: function (queryString) {\n            var queryParams = $.parseQuery({\n                query: queryString\n            });\n\n            $.each(queryParams, $.proxy(function (key, value) {\n                if (this.options.spConfig.attributes[key] !== undefined &&\n                    _.find(this.options.spConfig.attributes[key].options, function (element) {\n                        return element.id === value;\n                    })) {\n                    this.options.values[key] = value;\n                }\n            }, this));\n        },\n\n        /**\n         * Override default options values with values based on each element's attribute\n         * identifier.\n         * @private\n         */\n        _setValuesByAttribute: function () {\n            this.options.values = {};\n            $.each(this.options.settings, $.proxy(function (index, element) {\n                var attributeId;\n\n                if (element.value) {\n                    attributeId = element.id.replace(/[a-z]*/, '');\n\n                    if (this.options.spConfig.attributes[attributeId] !== undefined &&\n                        _.find(this.options.spConfig.attributes[attributeId].options, function (optionElement) {\n                            return optionElement.id === element.value;\n                        })) {\n                        this.options.values[attributeId] = element.value;\n                    }\n                }\n            }, this));\n        },\n\n        /**\n         * Set additional field with initial label to be used when switching between options with different prices.\n         * @private\n         */\n        _setInitialOptionsLabels: function () {\n            $.each(this.options.spConfig.attributes, $.proxy(function (index, element) {\n                $.each(element.options, $.proxy(function (optIndex, optElement) {\n                    this.options.spConfig.attributes[index].options[optIndex].initialLabel = optElement.label;\n                }, this));\n            }, this));\n        },\n\n        /**\n         * Set up .on('change') events for each option element to configure the option.\n         * @private\n         */\n        _setupChangeEvents: function () {\n            $.each(this.options.settings, $.proxy(function (index, element) {\n                $(element).on('change', this, this._configure);\n            }, this));\n        },\n\n        /**\n         * Iterate through the option settings and set each option's element configuration,\n         * attribute identifier. Set the state based on the attribute identifier.\n         * @private\n         */\n        _fillState: function () {\n            $.each(this.options.settings, $.proxy(function (index, element) {\n                var attributeId = element.id.replace(/[a-z]*/, '');\n\n                if (attributeId && this.options.spConfig.attributes[attributeId]) {\n                    element.config = this.options.spConfig.attributes[attributeId];\n                    element.attributeId = attributeId;\n                    this.options.state[attributeId] = false;\n                }\n            }, this));\n        },\n\n        /**\n         * Set each option's child settings, and next/prev option setting. Fill (initialize)\n         * an option's list of selections as needed or disable an option's setting.\n         * @private\n         */\n        _setChildSettings: function () {\n            var childSettings = [],\n                settings = this.options.settings,\n                index = settings.length,\n                option;\n\n            while (index--) {\n                option = settings[index];\n\n                if (index) {\n                    option.disabled = true;\n                } else {\n                    this._fillSelect(option);\n                }\n\n                _.extend(option, {\n                    childSettings: childSettings.slice(),\n                    prevSetting: settings[index - 1],\n                    nextSetting: settings[index + 1]\n                });\n\n                childSettings.push(option);\n            }\n        },\n\n        /**\n         * Setup for all configurable option settings. Set the value of the option and configure\n         * the option, which sets its state, and initializes the option's choices, etc.\n         * @private\n         */\n        _configureForValues: function () {\n            if (this.options.values) {\n                this.options.settings.each($.proxy(function (index, element) {\n                    var attributeId = element.attributeId;\n\n                    element.value = this.options.values[attributeId] || '';\n                    this._configureElement(element);\n                }, this));\n            }\n        },\n\n        /**\n         * Event handler for configuring an option.\n         * @private\n         * @param {Object} event - Event triggered to configure an option.\n         */\n        _configure: function (event) {\n            event.data._configureElement(this);\n        },\n\n        /**\n         * Configure an option, initializing it's state and enabling related options, which\n         * populates the related option's selection and resets child option selections.\n         * @private\n         * @param {*} element - The element associated with a configurable option.\n         */\n        _configureElement: function (element) {\n            this.simpleProduct = this._getSimpleProductId(element);\n\n            if (element.value && element.config) {\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            if (element.config) {\n                this._displayRegularPriceBlock(this.simpleProduct);\n                this._displayTierPriceBlock(this.simpleProduct);\n                this._displayNormalPriceLabel();\n            }\n            this._changeProductImage();\n        },\n\n        /**\n         * Change displayed product image according to chosen options of configurable product\n         *\n         * @private\n         */\n        _changeProductImage: function () {\n            var images,\n                initialImages = this.options.mediaGalleryInitial,\n                gallery = $(this.options.mediaGallerySelector).data('gallery');\n\n            if (_.isUndefined(gallery)) {\n                $(this.options.mediaGallerySelector).on('gallery:loaded', function () {\n                    this._changeProductImage();\n                }.bind(this));\n\n                return;\n            }\n\n            images = this.options.spConfig.images[this.simpleProduct];\n\n            if (images) {\n                images = this._sortImages(images);\n\n                if (this.options.gallerySwitchStrategy === 'prepend') {\n                    images = images.concat(initialImages);\n                }\n\n                images = $.extend(true, [], images);\n                images = this._setImageIndex(images);\n\n                gallery.updateData(images);\n                this._addFotoramaVideoEvents(false);\n            } else {\n                gallery.updateData(initialImages);\n                this._addFotoramaVideoEvents(true);\n            }\n        },\n\n        /**\n         * Add video events\n         *\n         * @param {Boolean} isInitial\n         * @private\n         */\n        _addFotoramaVideoEvents: function (isInitial) {\n            if (_.isUndefined($.mage.AddFotoramaVideoEvents)) {\n                return;\n            }\n\n            if (isInitial) {\n                $(this.options.mediaGallerySelector).AddFotoramaVideoEvents();\n\n                return;\n            }\n\n            $(this.options.mediaGallerySelector).AddFotoramaVideoEvents({\n                selectedOption: this.simpleProduct,\n                dataMergeStrategy: this.options.gallerySwitchStrategy\n            });\n        },\n\n        /**\n         * Sorting images array\n         *\n         * @private\n         */\n        _sortImages: function (images) {\n            return _.sortBy(images, function (image) {\n                return parseInt(image.position, 10);\n            });\n        },\n\n        /**\n         * Set correct indexes for image set.\n         *\n         * @param {Array} images\n         * @private\n         */\n        _setImageIndex: function (images) {\n            var length = images.length,\n                i;\n\n            for (i = 0; length > i; i++) {\n                images[i].i = i + 1;\n            }\n\n            return images;\n        },\n\n        /**\n         * For a given option element, reset all of its selectable options. Clear any selected\n         * index, disable the option choice, and reset the option's state if necessary.\n         * @private\n         * @param {*} element - The element associated with a configurable option.\n         */\n        _resetChildren: function (element) {\n            if (element.childSettings) {\n                _.each(element.childSettings, function (set) {\n                    set.selectedIndex = 0;\n                    set.disabled = true;\n                });\n\n                if (element.config) {\n                    this.options.state[element.config.id] = false;\n                }\n            }\n        },\n\n        /**\n         * Populates an option's selectable choices.\n         * @private\n         * @param {*} element - Element associated with a configurable option.\n         */\n        _fillSelect: function (element) {\n            var attributeId = element.id.replace(/[a-z]*/, ''),\n                options = this._getAttributeOptions(attributeId),\n                prevConfig,\n                index = 1,\n                allowedProducts,\n                allowedProductsByOption,\n                allowedProductsAll,\n                i,\n                j,\n                finalPrice = parseFloat(this.options.spConfig.prices.finalPrice.amount),\n                optionFinalPrice,\n                optionPriceDiff,\n                optionPrices = this.options.spConfig.optionPrices,\n                allowedOptions = [],\n                indexKey,\n                allowedProductMinPrice,\n                allowedProductsAllMinPrice,\n                canDisplayOutOfStockProducts = false,\n                filteredSalableProducts;\n\n            this._clearSelect(element);\n            if (element.options) {\n                element.options[0] = new Option('', '');\n                element.options[0].innerHTML = this.options.spConfig.chooseText;\n            }\n            prevConfig = false;\n\n            if (element.prevSetting) {\n                prevConfig = element.prevSetting.options[element.prevSetting.selectedIndex];\n            }\n\n            if (options) {\n                for (indexKey in this.options.spConfig.index) {\n                    /* eslint-disable max-depth */\n                    if (this.options.spConfig.index.hasOwnProperty(indexKey)) {\n                        allowedOptions = allowedOptions.concat(_.values(this.options.spConfig.index[indexKey]));\n                    }\n                }\n\n                if (prevConfig) {\n                    allowedProductsByOption = {};\n                    allowedProductsAll = [];\n\n                    for (i = 0; i < options.length; i++) {\n                        /* eslint-disable max-depth */\n                        for (j = 0; j < options[i].products.length; j++) {\n                            // prevConfig.config can be undefined\n                            if (prevConfig.config &&\n                                prevConfig.config.allowedProducts &&\n                                prevConfig.config.allowedProducts.indexOf(options[i].products[j]) > -1) {\n                                if (!allowedProductsByOption[i]) {\n                                    allowedProductsByOption[i] = [];\n                                }\n                                allowedProductsByOption[i].push(options[i].products[j]);\n                                allowedProductsAll.push(options[i].products[j]);\n                            }\n                        }\n                    }\n\n                    if (typeof allowedProductsAll[0] !== 'undefined' &&\n                        typeof optionPrices[allowedProductsAll[0]] !== 'undefined') {\n                        allowedProductsAllMinPrice = this._getAllowedProductWithMinPrice(allowedProductsAll);\n                        finalPrice = parseFloat(optionPrices[allowedProductsAllMinPrice].finalPrice.amount);\n                    }\n                }\n\n                for (i = 0; i < options.length; i++) {\n                    if (prevConfig && typeof allowedProductsByOption[i] === 'undefined') {\n                        continue; //jscs:ignore disallowKeywords\n                    }\n\n                    allowedProducts = prevConfig ? allowedProductsByOption[i] : options[i].products.slice(0);\n                    optionPriceDiff = 0;\n\n                    if (typeof allowedProducts[0] !== 'undefined' &&\n                        typeof optionPrices[allowedProducts[0]] !== 'undefined') {\n                        allowedProductMinPrice = this._getAllowedProductWithMinPrice(allowedProducts);\n                        optionFinalPrice = parseFloat(optionPrices[allowedProductMinPrice].finalPrice.amount);\n                        optionPriceDiff = optionFinalPrice - finalPrice;\n                        options[i].label = options[i].initialLabel;\n\n                        if (optionPriceDiff !== 0) {\n                            options[i].label += ' ' + priceUtils.formatPriceLocale(\n                                optionPriceDiff,\n                                this.options.priceFormat,\n                                true\n                            );\n                        }\n                    }\n\n                    if (allowedProducts.length > 0 || _.include(allowedOptions, options[i].id)) {\n                        options[i].allowedProducts = allowedProducts;\n                        element.options[index] = new Option(this._getOptionLabel(options[i]), options[i].id);\n\n                        if (this.options.spConfig.canDisplayShowOutOfStockStatus) {\n                            filteredSalableProducts = $(this.options.spConfig.salable[attributeId][options[i].id]).\n                            filter(options[i].allowedProducts);\n                            canDisplayOutOfStockProducts = filteredSalableProducts.length === 0;\n                        }\n\n                        if (typeof options[i].price !== 'undefined') {\n                            element.options[index].setAttribute('price', options[i].price);\n                        }\n\n                        if (allowedProducts.length === 0 || canDisplayOutOfStockProducts) {\n                            element.options[index].disabled = true;\n                        }\n\n                        element.options[index].config = options[i];\n                        index++;\n                    }\n\n                    /* eslint-enable max-depth */\n                }\n            }\n        },\n\n        /**\n         * Generate the label associated with a configurable option. This includes the option's\n         * label or value and the option's price.\n         * @private\n         * @param {*} option - A single choice among a group of choices for a configurable option.\n         * @return {String} The option label with option value and price (e.g. Black +1.99)\n         */\n        _getOptionLabel: function (option) {\n            return option.label;\n        },\n\n        /**\n         * Removes an option's selections.\n         * @private\n         * @param {*} element - The element associated with a configurable option.\n         */\n        _clearSelect: function (element) {\n            var i;\n\n            if (element.options) {\n                for (i = element.options.length - 1; i >= 0; i--) {\n                    element.remove(i);\n                }\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._getPriceBoxElement().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                selected,\n                config,\n                priceValue;\n\n            _.each(elements, function (element) {\n                if (element.options) {\n                    selected = element.options[element.selectedIndex];\n                    config = selected && selected.config;\n                    priceValue = this._calculatePrice({});\n\n                    if (config && config.allowedProducts.length === 1) {\n                        priceValue = this._calculatePrice(config);\n                    } else if (element.value) {\n                        allowedProduct = this._getAllowedProductWithMinPrice(config.allowedProducts);\n                        priceValue = this._calculatePrice({\n                            'allowedProducts': [\n                                allowedProduct\n                            ]\n                        });\n                    }\n\n                    if (!_.isEmpty(priceValue)) {\n                        prices.prices = priceValue;\n                    }\n                }\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._getPriceBoxElement().priceBox('option').prices,\n                newPrices = this.options.spConfig.optionPrices[_.first(config.allowedProducts)] || {};\n\n            _.each(displayPrices, function (price, code) {\n                displayPrices[code].amount = newPrices[code] ? newPrices[code].amount - displayPrices[code].amount : 0;\n            });\n\n            return displayPrices;\n        },\n\n        /**\n         * Returns Simple product Id\n         *  depending on current selected option.\n         *\n         * @private\n         * @param {HTMLElement} element\n         * @returns {String|undefined}\n         */\n        _getSimpleProductId: function (element) {\n            // TODO: Rewrite algorithm. It should return ID of\n            //        simple product based on selected options.\n            var allOptions,\n                value,\n                config;\n\n            if (element.config) {\n                allOptions = element.config.options;\n                value = element.value;\n\n                config = _.filter(allOptions, function (option) {\n                    return option.id === value;\n                });\n                config = _.first(config);\n\n                return _.isEmpty(config) ?\n                    undefined :\n                    _.first(config.allowedProducts);\n            }\n        },\n\n        /**\n         * Show or hide regular price block\n         *\n         * @param {*} optionId\n         * @private\n         */\n        _displayRegularPriceBlock: function (optionId) {\n            var shouldBeShown = true,\n                $priceBox = this._getPriceBoxElement();\n\n            _.each(this.options.settings, function (element) {\n                if (element.value === '') {\n                    shouldBeShown = false;\n                }\n            });\n\n            if (shouldBeShown &&\n                this.options.spConfig.optionPrices[optionId].oldPrice.amount !==\n                this.options.spConfig.optionPrices[optionId].finalPrice.amount\n            ) {\n                $(this.options.slyOldPriceSelector).show();\n            } else {\n                $(this.options.slyOldPriceSelector).hide();\n            }\n\n            $(document).trigger('updateMsrpPriceBlock',\n                [\n                    optionId,\n                    this.options.spConfig.optionPrices,\n                    $priceBox\n                ]\n            );\n        },\n\n        /**\n         * Show or hide normal price label\n         *\n         * @private\n         */\n        _displayNormalPriceLabel: function () {\n            var shouldBeShown = false;\n\n            _.each(this.options.settings, function (element) {\n                if (element.value === '') {\n                    shouldBeShown = true;\n                }\n            });\n\n            if (shouldBeShown) {\n                $(this.options.normalPriceLabelSelector).show();\n            } else {\n                $(this.options.normalPriceLabelSelector).hide();\n            }\n        },\n\n        /**\n         * Callback which fired after gallery gets initialized.\n         *\n         * @param {HTMLElement} element - DOM element associated with gallery.\n         */\n        _onGalleryLoaded: function (element) {\n            var galleryObject = element.data('gallery');\n\n            this.options.mediaGalleryInitial = galleryObject.returnCurrentImages();\n        },\n\n        /**\n         * Show or hide tier price block\n         *\n         * @param {*} optionId\n         * @private\n         */\n        _displayTierPriceBlock: function (optionId) {\n            var tierPrices = typeof optionId != 'undefined' && this.options.spConfig.optionPrices[optionId].tierPrices;\n\n            if (_.isArray(tierPrices) && tierPrices.length > 0) {\n\n                if (this.options.tierPriceTemplate) {\n                    $(this.options.tierPriceBlockSelector).html(\n                        mageTemplate(this.options.tierPriceTemplate, {\n                            'tierPrices': tierPrices,\n                            '$t': $t,\n                            'currencyFormat': this.options.spConfig.currencyFormat,\n                            'priceUtils': priceUtils\n                        })\n                    ).show();\n                }\n            } else {\n                $(this.options.tierPriceBlockSelector).hide();\n            }\n        },\n\n        /**\n         * Returns the price container element\n         *\n         * @returns {*}\n         * @private\n         */\n        _getPriceBoxElement: function () {\n            return this.element\n                .parents(this.options.selectorProduct)\n                .find(this.options.selectorProductPrice);\n        }\n    });\n\n    return $.mage.configurable;\n});\n","Magento_ConfigurableProduct/js/catalog-add-to-cart.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\nrequire([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    /**\n     * Add selected configurable attributes to redirect url\n     *\n     * @see Magento_Catalog/js/catalog-add-to-cart\n     */\n    $('body').on('catalogCategoryAddToCartRedirect', function (event, data) {\n        $(data.form).find('select[name*=\"super\"]').each(function (index, item) {\n            data.redirectParameters.push(item.config.id + '=' + $(item).val());\n        });\n    });\n});\n","Magento_ConfigurableProduct/js/product/view/product-info-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'Magento_Catalog/js/product/view/product-info'\n], function (_, productInfo) {\n    'use strict';\n\n    /**\n     * Returns info about configurable products in form.\n     *\n     * @param {jQuery} $form\n     * @return {Array}\n     */\n    return function ($form) {\n        var optionValues = [],\n            product = _.findWhere($form.serializeArray(), {\n                name: 'product'\n            }),\n            productId;\n\n        if (!_.isUndefined(product)) {\n            productId = product.value;\n            _.each($form.serializeArray(), function (item) {\n                if (item.name.indexOf('super_attribute') !== -1) {\n                    optionValues.push(item.value);\n                }\n            });\n            optionValues.sort();\n            productInfo().push(\n                {\n                    'id': productId,\n                    'optionValues': optionValues\n                }\n            );\n        }\n\n        return _.uniq(productInfo(), function (item) {\n            var optionValuesStr = item.optionValues ? item.optionValues.join() : '';\n\n            return item.id + optionValuesStr;\n        });\n    };\n});\n\n","Magento_ReCaptchaCheckoutSalesRule/js/checkout-sales-rule.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/* global grecaptcha */\ndefine(\n    [\n        'Magento_ReCaptchaWebapiUi/js/webapiReCaptcha',\n        'Magento_ReCaptchaWebapiUi/js/webapiReCaptchaRegistry',\n        'jquery',\n        'Magento_SalesRule/js/action/set-coupon-code',\n        'Magento_SalesRule/js/action/cancel-coupon',\n        'Magento_Checkout/js/model/quote',\n        'ko'\n    ], function (Component, recaptchaRegistry, $, setCouponCodeAction, cancelCouponAction, quote, ko) {\n        'use strict';\n\n        var totals = quote.getTotals(),\n            couponCode = ko.observable(null),\n            isApplied;\n\n        if (totals()) {\n            couponCode(totals()['coupon_code']);\n        }\n        //Captcha can only be required for adding a coupon so we need to know if one was added already.\n        isApplied = ko.observable(couponCode() != null);\n\n        return Component.extend({\n\n            /**\n             * Initialize parent form.\n             *\n             * @param {Object} parentForm\n             * @param {String} widgetId\n             */\n            initParentForm: function (parentForm, widgetId) {\n                var self = this,\n                    xRecaptchaValue,\n                    captchaId = this.getReCaptchaId();\n\n                this._super();\n\n                if (couponCode() != null) {\n                    if (isApplied) {\n                        self.validateReCaptcha(true);\n                        $('#' + captchaId).hide();\n                    }\n                }\n\n                if (recaptchaRegistry.triggers.hasOwnProperty('recaptcha-checkout-coupon-apply')) {\n                    recaptchaRegistry.addListener('recaptcha-checkout-coupon-apply', function (token) {\n                        //Add reCaptcha value to coupon request\n                        xRecaptchaValue = token;\n                    });\n                }\n\n                setCouponCodeAction.registerDataModifier(function (headers) {\n                    headers['X-ReCaptcha'] = xRecaptchaValue;\n                });\n\n                if (self.getIsInvisibleRecaptcha()) {\n                    grecaptcha.execute(widgetId);\n                    self.validateReCaptcha(true);\n                }\n                //Refresh reCaptcha after failed request.\n                setCouponCodeAction.registerFailCallback(function () {\n                    if (self.getIsInvisibleRecaptcha()) {\n                        grecaptcha.execute(widgetId);\n                        self.validateReCaptcha(true);\n                    } else {\n                        self.validateReCaptcha(false);\n                        grecaptcha.reset(widgetId);\n                        $('#' + captchaId).show();\n                    }\n                });\n                //Hide captcha when a coupon has been applied.\n                setCouponCodeAction.registerSuccessCallback(function () {\n                    self.validateReCaptcha(true);\n                    $('#' + captchaId).hide();\n                });\n                //Show captcha again if it was canceled.\n                cancelCouponAction.registerSuccessCallback(function () {\n                    self.validateReCaptcha(false);\n                    grecaptcha.reset(widgetId);\n                    $('#' + captchaId).show();\n                });\n            }\n        });\n    });\n","Magento_Bundle/js/price-bundle.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'mage/template',\n    'priceUtils',\n    'jquery/jquery.parsequery',\n    'priceBox'\n], function ($, _, mageTemplate, utils) {\n    'use strict';\n\n    var globalOptions = {\n        optionConfig: null,\n        productBundleSelector: 'input.bundle.option, select.bundle.option, textarea.bundle.option',\n        qtyFieldSelector: 'input.qty',\n        priceBoxSelector: '.price-box',\n        optionHandlers: {},\n        optionTemplate: '<%- data.label %>' +\n            '<% if (data.finalPrice.value) { %>' +\n            ' +<%- data.finalPrice.formatted %>' +\n            '<% } %>',\n        controlContainer: 'dd', // should be eliminated\n        priceFormat: {},\n        isFixedPrice: false,\n        optionTierPricesBlocksSelector: '#option-tier-prices-{1} [data-role=\"selection-tier-prices\"]',\n        isOptionsInitialized: false\n    };\n\n    $.widget('mage.priceBundle', {\n        options: globalOptions,\n\n        /**\n         * @private\n         */\n        _init: function initPriceBundle() {\n            var form = this.element,\n                options = $(this.options.productBundleSelector, form),\n                qty = $(this.options.qtyFieldSelector, form);\n\n            // Override defaults with URL query parameters and/or inputs values\n            this._overrideDefaults();\n\n            options.trigger('change');\n            qty.trigger('change');\n        },\n\n        /**\n         * @private\n         */\n        _create: function createPriceBundle() {\n            var form = this.element,\n                options = $(this.options.productBundleSelector, form),\n                priceBox = $(this.options.priceBoxSelector, form),\n                qty = $(this.options.qtyFieldSelector, form);\n\n            this._updatePriceBox();\n            priceBox.on('price-box-initialized', this._updatePriceBox.bind(this));\n            options.on('change', this._onBundleOptionChanged.bind(this));\n            qty.on('change', this._onQtyFieldChanged.bind(this));\n        },\n\n        /**\n         * 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\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                selectedValues = [],\n                form = this.element,\n                options = $(this.options.productBundleSelector, form),\n                qtys = $(this.options.qtyFieldSelector, form);\n\n            $.each(queryParams, $.proxy(function (key, value) {\n                qtys.each(function (index, qty) {\n                    if (qty.name === key) {\n                        $(qty).val(value);\n                    }\n                });\n                options.each(function (index, option) {\n                    let optionType = $(option).prop('type');\n\n                    if (option.name === key ||\n                        optionType === 'select-multiple'\n                        && key.indexOf(option.name.substr(0, option.name.length - 2)) !== false\n                    ) {\n\n                        switch (optionType) {\n                            case 'radio':\n                                $(option).val() === value ? $(option).prop('checked', true) : '';\n                                break;\n                            case 'checkbox':\n                                $(option).prop('checked', true);\n                                break;\n                            case 'hidden':\n                            case 'select-one':\n                                $(option).val(value);\n                                break;\n                            case 'select-multiple':\n                                selectedValues.push(value);\n                                break;\n                        }\n                        if (optionType === 'select-multiple' && selectedValues.length) {\n                            $(option).val(selectedValues);\n                        }\n                    }\n                });\n            }, this));\n        },\n\n        /**\n         * Update price box config with bundle option prices\n         * @private\n         */\n        _updatePriceBox: function () {\n            var form = this.element,\n                options = $(this.options.productBundleSelector, form),\n                priceBox = $(this.options.priceBoxSelector, form);\n\n            if (!this.options.isOptionsInitialized) {\n                if (priceBox.data('magePriceBox') &&\n                    priceBox.priceBox('option') &&\n                    priceBox.priceBox('option').priceConfig\n                ) {\n                    if (priceBox.priceBox('option').priceConfig.optionTemplate) { //eslint-disable-line max-depth\n                        this._setOption('optionTemplate', priceBox.priceBox('option').priceConfig.optionTemplate);\n                    }\n                    this._setOption('priceFormat', priceBox.priceBox('option').priceConfig.priceFormat);\n                    priceBox.priceBox('setDefault', this.options.optionConfig.prices);\n                    this.options.isOptionsInitialized = true;\n                }\n                this._applyOptionNodeFix(options);\n            }\n\n            return this;\n        },\n\n        /**\n         * Handle change on bundle option inputs\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _onBundleOptionChanged: function onBundleOptionChanged(event) {\n            var changes,\n                bundleOption = $(event.target),\n                priceBox = $(this.options.priceBoxSelector, this.element),\n                handler = this.options.optionHandlers[bundleOption.data('role')];\n\n            bundleOption.data('optionContainer', bundleOption.closest(this.options.controlContainer));\n            bundleOption.data('qtyField', bundleOption.data('optionContainer').find(this.options.qtyFieldSelector));\n\n            if (handler && handler instanceof Function) {\n                changes = handler(bundleOption, this.options.optionConfig, this);\n            } else {\n                changes = defaultGetOptionValue(bundleOption, this.options.optionConfig);//eslint-disable-line\n            }\n\n            // eslint-disable-next-line no-use-before-define\n            if (isValidQty(bundleOption)) {\n                if (changes) {\n                    priceBox.trigger('updatePrice', changes);\n                }\n\n                this._displayTierPriceBlock(bundleOption);\n                this.updateProductSummary();\n            }\n        },\n\n        /**\n         * Handle change on qty inputs near bundle option\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _onQtyFieldChanged: function onQtyFieldChanged(event) {\n            var field = $(event.target),\n                optionInstance,\n                optionConfig;\n\n            if (field.data('optionId') && field.data('optionValueId')) {\n                optionInstance = field.data('option');\n                optionConfig = this.options.optionConfig\n                    .options[field.data('optionId')]\n                    .selections[field.data('optionValueId')];\n                optionConfig.qty = field.val();\n\n                // eslint-disable-next-line no-use-before-define\n                if (isValidQty(optionInstance)) {\n                    optionInstance.trigger('change');\n                }\n            }\n        },\n\n        /**\n         * Helper to fix backend behavior:\n         *  - if default qty large than 1 then backend multiply price in config\n         *\n         * @deprecated\n         * @private\n         */\n        _applyQtyFix: function applyQtyFix() {\n            var config = this.options.optionConfig;\n\n            if (config.isFixedPrice) {\n                _.each(config.options, function (option) {\n                    _.each(option.selections, function (item) {\n                        if (item.qty && item.qty !== 1) {\n                            _.each(item.prices, function (price) {\n                                price.amount /= item.qty;\n                            });\n                        }\n                    });\n                });\n            }\n        },\n\n        /**\n         * Helper to fix issue with option nodes:\n         *  - you can't place any html in option ->\n         *    so you can't style it via CSS\n         * @param {jQuery} options\n         * @private\n         */\n        _applyOptionNodeFix: function applyOptionNodeFix(options) {\n            var config = this.options,\n                format = config.priceFormat,\n                template = config.optionTemplate;\n\n            template = mageTemplate(template);\n            options.filter('select').each(function (index, element) {\n                var $element = $(element),\n                    optionId = utils.findOptionId($element),\n                    optionConfig = config.optionConfig && config.optionConfig.options[optionId].selections,\n                    value;\n\n                $element.find('option').each(function (idx, option) {\n                    var $option,\n                        optionValue,\n                        toTemplate,\n                        prices;\n\n                    $option = $(option);\n                    optionValue = $option.val();\n\n                    if (!optionValue && optionValue !== 0) {\n                        return;\n                    }\n\n                    toTemplate = {\n                        data: {\n                            label: optionConfig[optionValue] && optionConfig[optionValue].name\n                        }\n                    };\n                    prices = optionConfig[optionValue].prices;\n\n                    _.each(prices, function (price, type) {\n                        value = +price.amount;\n                        value += _.reduce(price.adjustments, function (sum, x) {//eslint-disable-line\n                            return sum + x;\n                        }, 0);\n                        toTemplate.data[type] = {\n                            value: value,\n                            formatted: utils.formatPriceLocale(value, format)\n                        };\n                    });\n\n                    $option.html(template(toTemplate));\n                });\n            });\n        },\n\n        /**\n         * Custom behavior on getting options:\n         * now widget able to deep merge accepted configuration with instance options.\n         * @param  {Object}  options\n         * @return {$.Widget}\n         */\n        _setOptions: function setOptions(options) {\n            $.extend(true, this.options, options);\n\n            this._super(options);\n\n            return this;\n        },\n\n        /**\n         * Show or hide option tier prices block\n         *\n         * @param {Object} optionElement\n         * @private\n         */\n        _displayTierPriceBlock: function (optionElement) {\n            var optionType = optionElement.prop('type'),\n                optionId,\n                optionValue,\n                optionTierPricesElements;\n\n            if (optionType === 'select-one') {\n                optionId = utils.findOptionId(optionElement[0]);\n                optionValue = optionElement.val() || null;\n                optionTierPricesElements = $(this.options.optionTierPricesBlocksSelector.replace('{1}', optionId));\n\n                _.each(optionTierPricesElements, function (tierPriceElement) {\n                    var selectionId = $(tierPriceElement).data('selection-id') + '';\n\n                    if (selectionId === optionValue) {\n                        $(tierPriceElement).show();\n                    } else {\n                        $(tierPriceElement).hide();\n                    }\n                });\n            }\n        },\n\n        /**\n         * Handler to update productSummary box\n         */\n        updateProductSummary: function updateProductSummary() {\n            this.element.trigger('updateProductSummary', {\n                config: this.options.optionConfig\n            });\n        }\n    });\n\n    return $.mage.priceBundle;\n\n    /**\n     * Converts option value to priceBox object\n     *\n     * @param   {jQuery} element\n     * @param   {Object} config\n     * @returns {Object|null} - priceBox object with additional prices\n     */\n    function defaultGetOptionValue(element, config) {\n        var changes = {},\n            optionHash,\n            tempChanges,\n            qtyField,\n            optionId = utils.findOptionId(element[0]),\n            optionValue = element.val() || null,\n            optionName = element.prop('name'),\n            optionType = element.prop('type'),\n            optionConfig = config.options[optionId].selections,\n            optionQty = 0,\n            canQtyCustomize = false,\n            selectedIds = config.selected;\n\n        switch (optionType) {\n            case 'radio':\n            case 'select-one':\n\n                if (optionType === 'radio' && !element.is(':checked')) {\n                    return null;\n                }\n\n                qtyField = element.data('qtyField');\n                qtyField.data('option', element);\n\n                if (optionValue) {\n                    optionQty = optionConfig[optionValue].qty || 0;\n                    canQtyCustomize = optionConfig[optionValue].customQty === '1';\n                    toggleQtyField(qtyField, optionQty, optionId, optionValue, canQtyCustomize);//eslint-disable-line\n                    tempChanges = utils.deepClone(optionConfig[optionValue].prices);\n                    tempChanges = applyTierPrice(//eslint-disable-line\n                        tempChanges,\n                        optionQty,\n                        optionConfig[optionValue]\n                    );\n                    tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n                } else {\n                    tempChanges = {};\n                    toggleQtyField(qtyField, '0', optionId, optionValue, false);//eslint-disable-line\n                }\n                optionHash = 'bundle-option-' + optionName;\n                changes[optionHash] = tempChanges;\n                selectedIds[optionId] = [optionValue];\n                break;\n\n            case 'select-multiple':\n                optionValue = _.compact(optionValue);\n\n                _.each(optionConfig, function (row, optionValueCode) {\n                    optionHash = 'bundle-option-' + optionName + '##' + optionValueCode;\n                    optionQty = row.qty || 0;\n                    tempChanges = utils.deepClone(row.prices);\n                    tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig);//eslint-disable-line\n                    tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n                    changes[optionHash] = _.contains(optionValue, optionValueCode) ? tempChanges : {};\n                });\n\n                selectedIds[optionId] = optionValue || [];\n                break;\n\n            case 'checkbox':\n                optionHash = 'bundle-option-' + optionName + '##' + optionValue;\n                optionQty = optionConfig[optionValue].qty || 0;\n                tempChanges = utils.deepClone(optionConfig[optionValue].prices);\n                tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig);//eslint-disable-line\n                tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n                changes[optionHash] = element.is(':checked') ? tempChanges : {};\n\n                selectedIds[optionId] = selectedIds[optionId] || [];\n\n                if (!_.contains(selectedIds[optionId], optionValue) && element.is(':checked')) {\n                    selectedIds[optionId].push(optionValue);\n                } else if (!element.is(':checked')) {\n                    selectedIds[optionId] = _.without(selectedIds[optionId], optionValue);\n                }\n                break;\n\n            case 'hidden':\n                optionHash = 'bundle-option-' + optionName + '##' + optionValue;\n                optionQty = optionConfig[optionValue].qty || 0;\n                canQtyCustomize = optionConfig[optionValue].customQty === '1';\n                qtyField = element.data('qtyField');\n                qtyField.data('option', element);\n                toggleQtyField(qtyField, optionQty, optionId, optionValue, canQtyCustomize);//eslint-disable-line\n                tempChanges = utils.deepClone(optionConfig[optionValue].prices);\n                tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig);//eslint-disable-line\n                tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n\n                optionHash = 'bundle-option-' + optionName;\n                changes[optionHash] = tempChanges;\n                selectedIds[optionId] = [optionValue];\n                break;\n        }\n\n        return changes;\n    }\n\n    /**\n     * Check the quantity field if negative value occurs.\n     *\n     * @param {Object} bundleOption\n     */\n    function isValidQty(bundleOption) {\n        var isValid = true,\n            qtyElem = bundleOption.data('qtyField'),\n            bundleOptionType = bundleOption.prop('type');\n\n        if (['radio', 'select-one'].includes(bundleOptionType) && qtyElem.val() < 0) {\n            isValid = false;\n        }\n\n        return isValid;\n    }\n\n    /**\n     * Helper to toggle qty field\n     * @param {jQuery} element\n     * @param {String|Number} value\n     * @param {String|Number} optionId\n     * @param {String|Number} optionValueId\n     * @param {Boolean} canEdit\n     */\n    function toggleQtyField(element, value, optionId, optionValueId, canEdit) {\n        element\n            .val(value)\n            .data('optionId', optionId)\n            .data('optionValueId', optionValueId)\n            .attr('disabled', !canEdit);\n\n        if (canEdit) {\n            element.removeClass('qty-disabled');\n        } else {\n            element.addClass('qty-disabled');\n        }\n    }\n\n    /**\n     * Helper to multiply on qty\n     *\n     * @param   {Object} prices\n     * @param   {Number} qty\n     * @returns {Object}\n     */\n    function applyQty(prices, qty) {\n        _.each(prices, function (everyPrice) {\n            everyPrice.amount *= qty;\n            _.each(everyPrice.adjustments, function (el, index) {\n                everyPrice.adjustments[index] *= qty;\n            });\n        });\n\n        return prices;\n    }\n\n    /**\n     * Helper to limit price with tier price\n     *\n     * @param {Object} oneItemPrice\n     * @param {Number} qty\n     * @param {Object} optionConfig\n     * @returns {Object}\n     */\n    function applyTierPrice(oneItemPrice, qty, optionConfig) {\n        var tiers = optionConfig.tierPrice,\n            magicKey = _.keys(oneItemPrice)[0],\n            tiersFirstKey = _.keys(optionConfig)[0],\n            lowest = false;\n\n        if (!tiers) {//tiers is undefined when options has only one option\n            tiers = optionConfig[tiersFirstKey].tierPrice;\n        }\n\n        tiers.sort(function (a, b) {//sorting based on \"price_qty\"\n            return a['price_qty'] - b['price_qty'];\n        });\n\n        _.each(tiers, function (tier, index) {\n            if (tier['price_qty'] > qty) {\n                return;\n            }\n\n            if (tier.prices[magicKey].amount < oneItemPrice[magicKey].amount) {\n                lowest = index;\n            }\n        });\n\n        if (lowest !== false) {\n            oneItemPrice = utils.deepClone(tiers[lowest].prices);\n        }\n\n        return oneItemPrice;\n    }\n});\n","Magento_Bundle/js/product-summary.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'mage/template',\n    'jquery-ui-modules/widget',\n    'Magento_Bundle/js/price-bundle'\n], function ($, mageTemplate) {\n    'use strict';\n\n    /**\n     * Widget product Summary:\n     * Handles rendering of Bundle options and displays them in the Summary box\n     */\n    $.widget('mage.productSummary', {\n        options: {\n            mainContainer:          '#product_addtocart_form',\n            templates: {\n                summaryBlock:       '[data-template=\"bundle-summary\"]',\n                optionBlock:        '[data-template=\"bundle-option\"]'\n            },\n            optionSelector:         '[data-container=\"options\"]',\n            summaryContainer:       '[data-container=\"product-summary\"]',\n            bundleSummaryContainer: '.bundle-summary'\n        },\n        cache: {},\n\n        /**\n         * Method attaches event observer to the product form\n         * @private\n         */\n        _create: function () {\n            this.element\n                .closest(this.options.mainContainer)\n                .on('updateProductSummary', $.proxy(this._renderSummaryBox, this))\n                .priceBundle({})\n            ;\n        },\n\n        /**\n         * Method extracts data from the event and renders Summary box\n         * using jQuery template mechanism\n         * @param {Event} event\n         * @param {Object} data\n         * @private\n         */\n        _renderSummaryBox: function (event, data) {\n            this.cache.currentElement = data.config;\n            this.cache.currentElementCount = 0;\n\n            // Clear Summary box\n            this.element.html('');\n            this.cache.currentElement.positions.forEach(function (optionId) {\n                this._renderOption(optionId, this.cache.currentElement.selected[optionId]);\n            }, this);\n            this.element\n                .parents(this.options.bundleSummaryContainer)\n                .toggleClass('empty', !this.cache.currentElementCount); // Zero elements equal '.empty' container\n        },\n\n        /**\n         * @param {String} key\n         * @param {String} row\n         * @private\n         */\n        _renderOption: function (key, row) {\n            var template;\n\n            if (row && row.length > 0 && row[0] !== null) {\n                template = this.element\n                    .closest(this.options.summaryContainer)\n                    .find(this.options.templates.summaryBlock)\n                    .html();\n                template = mageTemplate(template.trim(), {\n                    data: {\n                        _label_: this.cache.currentElement.options[key].title\n                    }\n                });\n\n                this.cache.currentKey = key;\n                this.cache.summaryContainer = $(template);\n                this.element.append(this.cache.summaryContainer);\n\n                $.each(row, this._renderOptionRow.bind(this));\n                this.cache.currentElementCount += row.length;\n\n                //Reset Cache\n                this.cache.currentKey = null;\n            }\n        },\n\n        /**\n         * @param {String} key\n         * @param {String} optionIndex\n         * @private\n         */\n        _renderOptionRow: function (key, optionIndex) {\n            var template;\n\n            template = this.element\n                .closest(this.options.summaryContainer)\n                .find(this.options.templates.optionBlock)\n                .html();\n            template = mageTemplate(template.trim(), {\n                data: {\n                    _quantity_: this.cache.currentElement.options[this.cache.currentKey].selections[optionIndex].qty,\n                    _label_: this.cache.currentElement.options[this.cache.currentKey].selections[optionIndex].name\n                }\n            });\n            this.cache.summaryContainer\n                .find(this.options.optionSelector)\n                .append(template);\n        }\n    });\n\n    return $.mage.productSummary;\n});\n","Magento_Bundle/js/slide.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.slide', {\n        options: {\n            slideSpeed: 1500,\n            slideSelector: '#bundle-slide',\n            slideBackSelector: '.bundle-slide-back',\n            bundleProductSelector: '#bundleProduct',\n            bundleOptionsContainer: '#options-container',\n            productViewContainer: '#productView',\n            slidedown: true\n\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            if (this.options.slidedown === true) {\n                $(this.options.slideSelector).on('click', $.proxy(this._show, this));\n                $(this.options.slideBackSelector).on('click', $.proxy(this._hide, this));\n                this.options.autostart && this._show();\n            } else {\n                $(this.options.slideSelector).on('click', $.proxy(this._slide, this));\n                $(this.options.slideBackSelector).on('click', $.proxy(this._slideBack, this));\n                this.options.autostart && this._slide();\n            }\n        },\n\n        /**\n         * slide bundleOptionsContainer over to the main view area\n         * @private\n         */\n        _slide: function () {\n            $(this.options.bundleProductSelector).css('top', '0px');\n            $(this.options.bundleOptionsContainer).show();\n            this.element.css('height', $(this.options.productViewContainer).height() + 'px');\n            $(this.options.bundleProductSelector).css('left', '0px').animate(\n                {\n                    'left': '-' + this.element.width() + 'px'\n                },\n                this.options.slideSpeed,\n                $.proxy(function () {\n                    this.element.css('height', 'auto');\n                    $(this.options.productViewContainer).hide();\n                }, this)\n            );\n        },\n\n        /**\n         * slideback productViewContainer to main view area\n         * @private\n         */\n        _slideBack: function () {\n            $(this.options.bundleProductSelector).css('top', '0px');\n            $(this.options.productViewContainer).show();\n            this.element.css('height', $(this.options.bundleOptionsContainer).height() + 'px');\n            $(this.options.bundleProductSelector).animate(\n                {\n                    'left': '0px'\n                },\n                this.options.slideSpeed,\n                $.proxy(function () {\n                    $(this.options.bundleOptionsContainer).hide();\n                    this.element.css('height', 'auto');\n                }, this)\n            );\n        },\n\n        /**\n         * @private\n         */\n        _show: function () {\n            $(this.options.bundleOptionsContainer).slideDown(800);\n            $('html, body').animate({\n                scrollTop: $(this.options.bundleOptionsContainer).offset().top\n            }, 600);\n            $('#product-options-wrapper > fieldset').trigger('focus');\n        },\n\n        /**\n         * @private\n         */\n        _hide: function () {\n            $('html, body').animate({\n                scrollTop: 0\n            }, 600);\n            $(this.options.bundleOptionsContainer).slideUp(800);\n        }\n    });\n\n    return $.mage.slide;\n});\n","Magento_Newsletter/js/subscription-status-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/url'\n], function ($, urlBuilder) {\n    'use strict';\n\n    return function (email, deferred) {\n        return $.getJSON(\n            urlBuilder.build('newsletter/ajax/status'),\n            {\n                email: email\n            }\n        ).done(function (response) {\n            if (response.errors) {\n                deferred.reject();\n            } else {\n                deferred.resolve(response.subscribed);\n            }\n        }).fail(function () {\n            deferred.reject();\n        });\n    };\n});\n","Magento_Newsletter/js/newsletter-sign-up.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'uiElement',\n    'mage/url',\n    'subscriptionStatusResolver',\n    'mage/validation'\n], function ($, Component, urlBuilder, subscriptionStatusResolver) {\n    'use strict';\n\n    return Component.extend({\n\n        defaults: {\n            signUpElement: '',\n            submitButton: '',\n            element: null\n        },\n\n        /** @inheritdoc */\n        initialize: function (config, element) {\n            this._super();\n            this.element = element;\n            $(element).on('change', $.proxy(this.updateSignUpStatus, this));\n            this.updateSignUpStatus();\n        },\n\n        /**\n         * Send status request and update subscription element according to result.\n         */\n        updateSignUpStatus: function () {\n            var element = $(this.element),\n                email = element.val(),\n                self = this,\n                newsletterSubscription;\n\n            if ($(self.signUpElement).is(':checked')) {\n                return;\n            }\n\n            if (!email || !$.validator.methods['validate-email'].call(this, email, element)) {\n                return;\n            }\n\n            newsletterSubscription = $.Deferred();\n\n            $(self.submitButton).prop('disabled', true);\n\n            subscriptionStatusResolver(email, newsletterSubscription);\n\n            $.when(newsletterSubscription).done(function (isSubscribed) {\n                if (isSubscribed) {\n                    $(self.signUpElement).prop('checked', true);\n                }\n            }).always(function () {\n                $(self.submitButton).prop('disabled', false);\n            });\n        }\n    });\n});\n","Magento_Ui/js/block-loader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'jquery',\n    'Magento_Ui/js/lib/knockout/template/loader',\n    'mage/template'\n], function (ko, $, templateLoader, template) {\n    'use strict';\n\n    var blockLoaderTemplatePath = 'ui/block-loader',\n        blockContentLoadingClass = '_block-content-loading',\n        blockLoader,\n        blockLoaderClass,\n        blockLoaderElement = $.Deferred(),\n        loaderImageHref = $.Deferred();\n\n    templateLoader.loadTemplate(blockLoaderTemplatePath).done(function (blockLoaderTemplate) {\n        loaderImageHref.done(function (loaderHref) {\n            blockLoader = template(blockLoaderTemplate.trim(), {\n                loaderImageHref: loaderHref\n            });\n            blockLoader = $(blockLoader);\n            blockLoaderClass = '.' + blockLoader.attr('class');\n            blockLoaderElement.resolve();\n        });\n    });\n\n    /**\n     * Helper function to check if blockContentLoading class should be applied.\n     * @param {Object} element\n     * @returns {Boolean}\n     */\n    function isLoadingClassRequired(element) {\n        var position = element.css('position');\n\n        if (position === 'absolute' || position === 'fixed') {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Add loader to block.\n     * @param {Object} element\n     */\n    function addBlockLoader(element) {\n        element.find(':focus').trigger('blur');\n        element.find('input:disabled, select:disabled').addClass('_disabled');\n        element.find('input, select').prop('disabled', true);\n\n        if (isLoadingClassRequired(element)) {\n            element.addClass(blockContentLoadingClass);\n        }\n        element.append(blockLoader.clone());\n    }\n\n    /**\n     * Remove loader from block.\n     * @param {Object} element\n     */\n    function removeBlockLoader(element) {\n        if (!element.has(blockLoaderClass).length) {\n            return;\n        }\n        element.find(blockLoaderClass).remove();\n        element.find('input:not(\"._disabled\"), select:not(\"._disabled\")').prop('disabled', false);\n        element.find('input:disabled, select:disabled').removeClass('_disabled');\n        element.removeClass(blockContentLoadingClass);\n    }\n\n    return function (loaderHref) {\n        loaderImageHref.resolve(loaderHref);\n        ko.bindingHandlers.blockLoader = {\n            /**\n             * Process loader for block\n             * @param {String} element\n             * @param {Boolean} displayBlockLoader\n             */\n            update: function (element, displayBlockLoader) {\n                element = $(element);\n\n                if (ko.unwrap(displayBlockLoader())) {\n                    blockLoaderElement.done(addBlockLoader(element));\n                } else {\n                    blockLoaderElement.done(removeBlockLoader(element));\n                }\n            }\n        };\n    };\n});\n","Magento_Ui/js/form/button-adapter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'uiClass',\n    'jquery',\n    'underscore',\n    'uiRegistry'\n], function (Class, $, _, registry) {\n    'use strict';\n\n    return Class.extend({\n\n        /**\n         * Initialize actions and adapter.\n         *\n         * @param {Object} config\n         * @param {Element} elem\n         * @returns {Object}\n         */\n        initialize: function (config, elem) {\n            return this._super()\n                .initActions()\n                .initAdapter(elem);\n        },\n\n        /**\n         * Creates callback from declared actions.\n         *\n         * @returns {Object}\n         */\n        initActions: function () {\n            var callbacks = [];\n\n            _.each(this.actions, function (action) {\n                callbacks.push({\n                    action: registry.async(action.targetName),\n                    args: _.union([action.actionName], action.params)\n                });\n            });\n\n            /**\n             * Callback function.\n             */\n            this.callback = function () {\n                _.each(callbacks, function (callback) {\n                    callback.action.apply(callback.action, callback.args);\n                });\n            };\n\n            return this;\n        },\n\n        /**\n         * Attach callback handler on button.\n         *\n         * @param {Element} elem\n         */\n        initAdapter: function (elem) {\n            $(elem).on('click', this.callback);\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/switcher.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiRegistry',\n    'uiClass'\n], function (_, registry, Class) {\n    'use strict';\n\n    return Class.extend({\n        defaults: {\n            rules: []\n        },\n\n        /**\n         * Initializes instance of a DataSwitcher.\n         *\n         * @returns {DataSwitcher} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initRules();\n\n            return this;\n        },\n\n        /**\n         *\n         * @returns {DataSwitcher} Chainable.\n         */\n        initRules: function () {\n            this.rules.forEach(this.initRule, this);\n\n            return this;\n        },\n\n        /**\n         *\n         * @param {Object} rule - Rule definition.\n         * @returns {DataSwitcher} Chainable.\n         */\n        initRule: function (rule) {\n            var handler = this.onValueChange.bind(this, rule);\n\n            if (!rule.target) {\n                rule.target = this.target;\n            }\n\n            if (!rule.property) {\n                rule.property = this.property;\n            }\n\n            registry.get(rule.target, function (target) {\n                this.applyRule(rule, target.get(rule.property));\n                target.on(rule.property, handler);\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         *\n         * @param {Object} rule - Rule definition.\n         * @returns {DataSwitcher} Chainable.\n         */\n        addRule: function (rule) {\n            this.rules.push(rule);\n            this.initRule(rule);\n\n            return this;\n        },\n\n        /**\n         *\n         * @param {Object} rule - Rule object.\n         * @param {*} value - Current value associated with a rule.\n         */\n        applyRule: function (rule, value) {\n            var actions = rule.actions;\n\n            //TODO Refactor this logic in scope of MAGETWO-48585\n            /* eslint-disable eqeqeq */\n            if (rule.value != value) {\n                return;\n            } else if (rule.strict) {\n                return;\n            }\n\n            /* eslint-enable eqeqeq */\n            actions.forEach(this.applyAction, this);\n        },\n\n        /**\n         *\n         * @param {Object} action - Action object.\n         */\n        applyAction: function (action) {\n            registry.get(action.target, function (target) {\n                var callback = target[action.callback];\n\n                callback.apply(target, action.params || []);\n            });\n        },\n\n        /**\n         *\n         * @param {Object} rule - Rules object.\n         * @param {*} value - Current value associated with a rule.\n         */\n        onValueChange: function (rule, value) {\n            this.applyRule(rule, value);\n        }\n    });\n});\n","Magento_Ui/js/form/form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'Magento_Ui/js/lib/spinner',\n    'rjsResolver',\n    './adapter',\n    'uiCollection',\n    'mageUtils',\n    'jquery',\n    'Magento_Ui/js/core/app',\n    'mage/validation'\n], function (_, loader, resolver, adapter, Collection, utils, $, app) {\n    'use strict';\n\n    /**\n     * Format params\n     *\n     * @param {Object} params\n     * @returns {Array}\n     */\n    function prepareParams(params) {\n        var result = '?';\n\n        _.each(params, function (value, key) {\n            result += key + '=' + value + '&';\n        });\n\n        return result.slice(0, -1);\n    }\n\n    /**\n     * Collect form data.\n     *\n     * @param {Array} items\n     * @returns {Object}\n     */\n    function collectData(items) {\n        var result = {},\n            name;\n\n        items = Array.prototype.slice.call(items);\n\n        items.forEach(function (item) {\n            switch (item.type) {\n                case 'checkbox':\n                    result[item.name] = +!!item.checked;\n                    break;\n\n                case 'radio':\n                    if (item.checked) {\n                        result[item.name] = item.value;\n                    }\n                    break;\n\n                case 'select-multiple':\n                    name = item.name.substring(0, item.name.length - 2); //remove [] from the name ending\n                    result[name] = _.pluck(item.selectedOptions, 'value');\n                    break;\n\n                default:\n                    result[item.name] = item.value;\n            }\n        });\n\n        return result;\n    }\n\n    /**\n     * Makes ajax request\n     *\n     * @param {Object} params\n     * @param {Object} data\n     * @param {String} url\n     * @returns {*}\n     */\n    function makeRequest(params, data, url) {\n        var save = $.Deferred();\n\n        data = utils.serialize(data);\n        data['form_key'] = window.FORM_KEY;\n\n        if (!url) {\n            save.resolve();\n        }\n\n        $('body').trigger('processStart');\n\n        $.ajax({\n            url: url + prepareParams(params),\n            data: data,\n            dataType: 'json',\n\n            /**\n             * Success callback.\n             * @param {Object} resp\n             * @returns {Boolean}\n             */\n            success: function (resp) {\n                if (resp.ajaxExpired) {\n                    window.location.href = resp.ajaxRedirect;\n                }\n\n                if (!resp.error) {\n                    save.resolve(resp);\n\n                    return true;\n                }\n\n                $('body').notification('clear');\n                $.each(resp.messages, function (key, message) {\n                    $('body').notification('add', {\n                        error: resp.error,\n                        message: message,\n\n                        /**\n                         * Inserts message on page\n                         * @param {String} msg\n                         */\n                        insertMethod: function (msg) {\n                            $('.page-main-actions').after(msg);\n                        }\n                    });\n                });\n            },\n\n            /**\n             * Complete callback.\n             */\n            complete: function () {\n                $('body').trigger('processStop');\n            }\n        });\n\n        return save.promise();\n    }\n\n    /**\n     * Check if fields is valid.\n     *\n     * @param {Array}items\n     * @returns {Boolean}\n     */\n    function isValidFields(items) {\n        var result = true;\n\n        _.each(items, function (item) {\n            if (!$.validator.validateSingleElement(item)) {\n                result = false;\n            }\n        });\n\n        return result;\n    }\n\n    return Collection.extend({\n        defaults: {\n            additionalFields: [],\n            additionalInvalid: false,\n            selectorPrefix: '.page-content',\n            messagesClass: 'messages',\n            errorClass: '.admin__field._error',\n            eventPrefix: '.${ $.index }',\n            ajaxSave: false,\n            ajaxSaveType: 'default',\n            imports: {\n                reloadUrl: '${ $.provider}:reloadUrl'\n            },\n            listens: {\n                selectorPrefix: 'destroyAdapter initAdapter',\n                '${ $.name }.${ $.reloadItem }': 'params.set reload'\n            },\n            exports: {\n                selectorPrefix: '${ $.provider }:client.selectorPrefix',\n                messagesClass: '${ $.provider }:client.messagesClass'\n            }\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super()\n                .initAdapter();\n\n            resolver(this.hideLoader, this);\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            return this._super()\n                .observe([\n                    'responseData',\n                    'responseStatus'\n                ]);\n        },\n\n        /** @inheritdoc */\n        initConfig: function () {\n            this._super();\n\n            this.selector = '[data-form-part=' + this.namespace + ']';\n\n            return this;\n        },\n\n        /**\n         * Initialize adapter handlers.\n         *\n         * @returns {Object}\n         */\n        initAdapter: function () {\n            adapter.on({\n                'reset': this.reset.bind(this),\n                'save': this.save.bind(this, true, {}),\n                'saveAndContinue': this.save.bind(this, false, {})\n            }, this.selectorPrefix, this.eventPrefix);\n\n            return this;\n        },\n\n        /**\n         * Destroy adapter handlers.\n         *\n         * @returns {Object}\n         */\n        destroyAdapter: function () {\n            adapter.off([\n                'reset',\n                'save',\n                'saveAndContinue'\n            ], this.eventPrefix);\n\n            return this;\n        },\n\n        /**\n         * Hide loader.\n         *\n         * @returns {Object}\n         */\n        hideLoader: function () {\n            loader.get(this.name).hide();\n\n            return this;\n        },\n\n        /**\n         * Validate and save form.\n         *\n         * @param {String} redirect\n         * @param {Object} data\n         */\n        save: function (redirect, data) {\n            this.validate();\n\n            if (!this.additionalInvalid && !this.source.get('params.invalid')) {\n                this.setAdditionalData(data)\n                    .submit(redirect);\n            } else {\n                this.focusInvalid();\n            }\n        },\n\n        /**\n         * Tries to set focus on first invalid form field.\n         *\n         * @returns {Object}\n         */\n        focusInvalid: function () {\n            var invalidField = _.find(this.delegate('checkInvalid'));\n\n            if (!_.isUndefined(invalidField) && _.isFunction(invalidField.focused)) {\n                invalidField.focused(true);\n            }\n\n            return this;\n        },\n\n        /**\n         * Set additional data to source before form submit and after validation.\n         *\n         * @param {Object} data\n         * @returns {Object}\n         */\n        setAdditionalData: function (data) {\n            _.each(data, function (value, name) {\n                this.source.set('data.' + name, value);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Submits form\n         *\n         * @param {String} redirect\n         */\n        submit: function (redirect) {\n            var additional = collectData(this.additionalFields),\n                source = this.source;\n\n            _.each(additional, function (value, name) {\n                source.set('data.' + name, value);\n            });\n\n            source.save({\n                redirect: redirect,\n                ajaxSave: this.ajaxSave,\n                ajaxSaveType: this.ajaxSaveType,\n                response: {\n                    data: this.responseData,\n                    status: this.responseStatus\n                },\n                attributes: {\n                    id: this.namespace\n                }\n            });\n        },\n\n        /**\n         * Validates each element and returns true, if all elements are valid.\n         */\n        validate: function () {\n            this.additionalFields = document.querySelectorAll(this.selector);\n            this.source.set('params.invalid', false);\n            this.source.trigger('data.validate');\n            this.set('additionalInvalid', !isValidFields(this.additionalFields));\n        },\n\n        /**\n         * Trigger reset form data.\n         */\n        reset: function () {\n            this.source.trigger('data.reset');\n            $('[data-bind*=datepicker]').val('');\n        },\n\n        /**\n         * Trigger overload form data.\n         */\n        overload: function () {\n            this.source.trigger('data.overload');\n        },\n\n        /**\n         * Updates data from server.\n         */\n        reload: function () {\n            makeRequest(this.params, this.data, this.reloadUrl).then(function (data) {\n                app(data, true);\n            });\n        }\n    });\n});\n","Magento_Ui/js/form/client.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'mageUtils',\n    'uiClass'\n], function ($, _, utils, Class) {\n    'use strict';\n\n    /**\n     * Before save validate request.\n     *\n     * @param {Object} data\n     * @param {String} url\n     * @param {String} selectorPrefix\n     * @param {String} messagesClass\n     * @returns {*}\n     */\n    function beforeSave(data, url, selectorPrefix, messagesClass) {\n        var save = $.Deferred();\n\n        data = utils.serialize(utils.filterFormData(data));\n        data['form_key'] = window.FORM_KEY;\n\n        if (!url || url === 'undefined') {\n            return save.resolve();\n        }\n\n        $('body').trigger('processStart');\n\n        $.ajax({\n            url: url,\n            data: data,\n\n            /**\n             * Success callback.\n             * @param {Object} resp\n             * @returns {Boolean}\n             */\n            success: function (resp) {\n                if (!resp.error) {\n                    save.resolve();\n\n                    return true;\n                }\n\n                $('body').notification('clear');\n                $.each(resp.messages || [resp.message] || [], function (key, message) {\n                    $('body').notification('add', {\n                        error: resp.error,\n                        message: message,\n\n                        /**\n                         * Insert method.\n                         *\n                         * @param {String} msg\n                         */\n                        insertMethod: function (msg) {\n                            var $wrapper = $('<div></div>').addClass(messagesClass).html(msg);\n\n                            $('.page-main-actions', selectorPrefix).after($wrapper);\n                            $('html, body').animate({\n                                scrollTop: $('.page-main-actions', selectorPrefix).offset().top\n                            });\n                        }\n                    });\n                });\n            },\n\n            /**\n             * Complete callback.\n             */\n            complete: function () {\n                $('body').trigger('processStop');\n            }\n        });\n\n        return save.promise();\n    }\n\n    return Class.extend({\n\n        /**\n         * Assembles data and submits it using 'utils.submit' method\n         */\n        save: function (data, options) {\n            var url = this.urls.beforeSave,\n                save = this._save.bind(this, data, options);\n\n            beforeSave(data, url, this.selectorPrefix, this.messagesClass).then(save);\n\n            return this;\n        },\n\n        /**\n         * Save data.\n         *\n         * @param {Object} data\n         * @param {Object} options\n         * @returns {Object}\n         * @private\n         */\n        _save: function (data, options) {\n            var url = this.urls.save;\n\n            $('body').trigger('processStart');\n            options = options || {};\n\n            if (!options.redirect) {\n                url += 'back/edit';\n            }\n\n            if (options.ajaxSave) {\n                utils.ajaxSubmit({\n                    url: url,\n                    data: data\n                }, options);\n\n                $('body').trigger('processStop');\n\n                return this;\n            }\n\n            utils.submit({\n                url: url,\n                data: data\n            }, options.attributes);\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/adapter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'Magento_Ui/js/form/adapter/buttons'\n], function ($, _, buttons) {\n    'use strict';\n\n    var selectorPrefix = '',\n        eventPrefix;\n\n    /**\n     * Initialize listener.\n     *\n     * @param {Function} callback\n     * @param {String} action\n     */\n    function initListener(callback, action) {\n        var selector    = selectorPrefix ? selectorPrefix + ' ' + buttons[action] : buttons[action],\n            elem        = $(selector)[0];\n\n        if (!elem) {\n            return;\n        }\n\n        if (elem.onclick) {\n            elem.onclick = null;\n        }\n\n        $(elem).on('click' + eventPrefix, callback);\n    }\n\n    /**\n     * Destroy listener.\n     *\n     * @param {String} action\n     */\n    function destroyListener(action) {\n        var selector    = selectorPrefix ? selectorPrefix + ' ' + buttons[action] : buttons[action],\n            elem        = $(selector)[0];\n\n        if (!elem) {\n            return;\n        }\n\n        if (elem.onclick) {\n            elem.onclick = null;\n        }\n\n        $(elem).off('click' + eventPrefix);\n    }\n\n    return {\n\n        /**\n         * Attaches events handlers.\n         *\n         * @param {Object} handlers\n         * @param {String} selectorPref\n         * @param {String} eventPref\n         */\n        on: function (handlers, selectorPref, eventPref) {\n            selectorPrefix = selectorPrefix || selectorPref;\n            eventPrefix = eventPref;\n            _.each(handlers, initListener);\n            selectorPrefix = '';\n        },\n\n        /**\n         * Removes events handlers.\n         *\n         * @param {Object} handlers\n         * @param {String} eventPref\n         */\n        off: function (handlers, eventPref) {\n            eventPrefix = eventPref;\n            _.each(handlers, destroyListener);\n        }\n    };\n});\n","Magento_Ui/js/form/provider.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiElement',\n    './client',\n    'mageUtils'\n], function (_, Element, Client, utils) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            clientConfig: {\n                urls: {\n                    save: '${ $.submit_url }',\n                    beforeSave: '${ $.validate_url }'\n                }\n            },\n            ignoreTmpls: {\n                data: true\n            }\n        },\n\n        /**\n         * Initializes provider component.\n         *\n         * @returns {Provider} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initClient();\n\n            return this;\n        },\n\n        /**\n         * Initializes client component.\n         *\n         * @returns {Provider} Chainable.\n         */\n        initClient: function () {\n            this.client = new Client(this.clientConfig);\n\n            return this;\n        },\n\n        /**\n         * Saves currently available data.\n         *\n         * @param {Object} [options] - Addtitional request options.\n         * @returns {Provider} Chainable.\n         */\n        save: function (options) {\n            var data = this.get('data');\n\n            this.client.save(data, options);\n\n            return this;\n        },\n\n        /**\n         * Update data that stored in provider.\n         *\n         * @param {Boolean} isProvider\n         * @param {Object} newData\n         * @param {Object} oldData\n         *\n         * @returns {Provider}\n         */\n        updateConfig: function (isProvider, newData, oldData) {\n            if (isProvider === true) {\n                this.setData(oldData, newData, this);\n            }\n\n            return this;\n        },\n\n        /**\n         *  Set data to provider based on current data.\n         *\n         * @param {Object} oldData\n         * @param {Object} newData\n         * @param {Provider} current\n         * @param {String} parentPath\n         */\n        setData: function (oldData, newData, current, parentPath) {\n            _.each(newData, function (val, key) {\n                if (_.isObject(val) || _.isArray(val)) {\n                    this.setData(oldData[key], val, current[key], utils.fullPath(parentPath, key));\n                } else if (val != oldData[key] && oldData[key] == current[key]) {//eslint-disable-line eqeqeq\n                    this.set(utils.fullPath(parentPath, key), val);\n                }\n            }, this);\n        }\n    });\n});\n","Magento_Ui/js/form/adapter/buttons.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine(function () {\n    'use strict';\n\n    return {\n        'reset': '#reset',\n        'save': '#save',\n        'saveAndContinue': '#save_and_continue'\n    };\n});\n","Magento_Ui/js/form/components/fieldset.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/lib/collapsible',\n    'underscore'\n], function (Collapsible, _) {\n    'use strict';\n\n    return Collapsible.extend({\n        defaults: {\n            template: 'ui/form/fieldset',\n            collapsible: false,\n            changed: false,\n            loading: false,\n            error: false,\n            opened: false,\n            level: 0,\n            visible: true,\n            initializeFieldsetDataByDefault: false, /* Data in some fieldsets should be initialized before open */\n            disabled: false,\n            listens: {\n                'opened': 'onVisibilityChange'\n            },\n            additionalClasses: {}\n        },\n\n        /**\n         * Extends instance with defaults. Invokes parent initialize method.\n         * Calls initListeners and pushParams methods.\n         */\n        initialize: function () {\n            _.bindAll(this, 'onChildrenUpdate', 'onChildrenError', 'onContentLoading');\n\n            return this._super()\n                ._setClasses();\n        },\n\n        /**\n         * Initializes components' configuration.\n         *\n         * @returns {Fieldset} Chainable.\n         */\n        initConfig: function () {\n            this._super();\n            this._wasOpened = this.opened || !this.collapsible;\n\n            return this;\n        },\n\n        /**\n         * Calls initObservable of parent class.\n         * Defines observable properties of instance.\n         *\n         * @returns {Object} Reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe('changed loading error visible');\n\n            return this;\n        },\n\n        /**\n         * Calls parent's initElement method.\n         * Assigns callbacks on various events of incoming element.\n         *\n         * @param  {Object} elem\n         * @return {Object} - reference to instance\n         */\n        initElement: function (elem) {\n            elem.initContainer(this);\n\n            elem.on({\n                'update': this.onChildrenUpdate,\n                'loading': this.onContentLoading,\n                'error': this.onChildrenError\n            });\n\n            if (this.disabled) {\n                try {\n                    elem.disabled(true);\n                }\n                catch (e) {\n\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Is being invoked on children update.\n         * Sets changed property to one incoming.\n         *\n         * @param  {Boolean} hasChanged\n         */\n        onChildrenUpdate: function (hasChanged) {\n            if (!hasChanged) {\n                hasChanged = _.some(this.delegate('hasChanged'));\n            }\n\n            this.bubble('update', hasChanged);\n            this.changed(hasChanged);\n        },\n\n        /**\n         * Extends 'additionalClasses' object.\n         *\n         * @returns {Group} Chainable.\n         */\n        _setClasses: function () {\n            var additional = this.additionalClasses,\n                classes;\n\n            if (_.isString(additional)) {\n                additional = this.additionalClasses.split(' ');\n                classes = this.additionalClasses = {};\n\n                additional.forEach(function (name) {\n                    classes[name] = true;\n                }, this);\n            }\n\n            _.extend(this.additionalClasses, {\n                'admin__collapsible-block-wrapper': this.collapsible,\n                _show: this.opened,\n                _hide: !this.opened,\n                _disabled: this.disabled\n            });\n\n            return this;\n        },\n\n        /**\n         * Handler of the \"opened\" property changes.\n         *\n         * @param {Boolean} isOpened\n         */\n        onVisibilityChange: function (isOpened) {\n            if (!this._wasOpened) {\n                this._wasOpened = isOpened;\n            }\n        },\n\n        /**\n         * Is being invoked on children validation error.\n         * Sets error property to one incoming.\n         *\n         * @param {String} message - error message.\n         */\n        onChildrenError: function (message) {\n            var hasErrors = false;\n\n            if (!message) {\n                hasErrors = this._isChildrenHasErrors(hasErrors, this);\n            }\n\n            this.error(hasErrors || message);\n\n            if (hasErrors || message) {\n                this.open();\n            }\n        },\n\n        /**\n         * Returns errors of children if exist\n         *\n         * @param {Boolean} hasErrors\n         * @param {*} container\n         * @return {Boolean}\n         * @private\n         */\n        _isChildrenHasErrors: function (hasErrors, container) {\n            var self = this;\n\n            if (hasErrors === false && container.hasOwnProperty('elems')) {\n                hasErrors = container.elems.some('error');\n\n                if (hasErrors === false && container.hasOwnProperty('_elems')) {\n                    container._elems.forEach(function (child) {\n\n                        if (hasErrors === false) {\n                            hasErrors = self._isChildrenHasErrors(hasErrors, child);\n                        }\n                    });\n                }\n            }\n\n            return hasErrors;\n        },\n\n        /**\n         * Callback that sets loading property to true.\n         */\n        onContentLoading: function (isLoading) {\n            this.loading(isLoading);\n        }\n    });\n});\n","Magento_Ui/js/form/components/button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'uiElement',\n    'uiRegistry',\n    'uiLayout',\n    'mageUtils',\n    'underscore'\n], function (Element, registry, layout, utils, _) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            buttonClasses: {},\n            additionalClasses: {},\n            displayArea: 'outsideGroup',\n            displayAsLink: false,\n            elementTmpl: 'ui/form/element/button',\n            template: 'ui/form/components/button/simple',\n            visible: true,\n            disabled: false,\n            title: '',\n            buttonTextId: '',\n            ariLabelledby: ''\n        },\n\n        /**\n         * Initializes component.\n         *\n         * @returns {Object} Chainable.\n         */\n        initialize: function () {\n            return this._super()\n                ._setClasses()\n                ._setButtonClasses();\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            return this._super()\n                .observe([\n                    'visible',\n                    'disabled',\n                    'title',\n                    'childError'\n                ]);\n        },\n\n        /**\n         * Performs configured actions\n         */\n        action: function () {\n            this.actions.forEach(this.applyAction, this);\n        },\n\n        /**\n         * Apply action on target component,\n         * but previously create this component from template if it is not existed\n         *\n         * @param {Object} action - action configuration\n         */\n        applyAction: function (action) {\n            var targetName = action.targetName,\n                params = utils.copy(action.params) || [],\n                actionName = action.actionName,\n                target;\n\n            if (!registry.has(targetName)) {\n                this.getFromTemplate(targetName);\n            }\n            target = registry.async(targetName);\n\n            if (target && typeof target === 'function' && actionName) {\n                params.unshift(actionName);\n                target.apply(target, params);\n            }\n        },\n\n        /**\n         * Create target component from template\n         *\n         * @param {Object} targetName - name of component,\n         * that supposed to be a template and need to be initialized\n         */\n        getFromTemplate: function (targetName) {\n            var parentName = targetName.split('.'),\n                index = parentName.pop(),\n                child;\n\n            parentName = parentName.join('.');\n            child = utils.template({\n                parent: parentName,\n                name: index,\n                nodeTemplate: targetName\n            });\n            layout([child]);\n        },\n\n        /**\n         * Extends 'additionalClasses' object.\n         *\n         * @returns {Object} Chainable.\n         */\n        _setClasses: function () {\n            if (typeof this.additionalClasses === 'string') {\n                if (this.additionalClasses === '') {\n                    this.additionalClasses = {};\n\n                    return this;\n                }\n\n                this.additionalClasses = this.additionalClasses\n                    .trim()\n                    .split(' ')\n                    .reduce(function (classes, name) {\n                        classes[name] = true;\n\n                        return classes;\n                    }, {}\n                );\n            }\n\n            return this;\n        },\n\n        /**\n         * Extends 'buttonClasses' object.\n         *\n         * @returns {Object} Chainable.\n         */\n        _setButtonClasses: function () {\n            var additional = this.buttonClasses;\n\n            if (_.isString(additional)) {\n                this.buttonClasses = {};\n\n                if (additional.trim().length) {\n                    additional = additional.trim().split(' ');\n\n                    additional.forEach(function (name) {\n                        if (name.length) {\n                            this.buttonClasses[name] = true;\n                        }\n                    }, this);\n                }\n            }\n\n            _.extend(this.buttonClasses, {\n                'action-basic': !this.displayAsLink,\n                'action-additional': this.displayAsLink\n            });\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/components/tab.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'uiCollection'\n], function (Collection) {\n    'use strict';\n\n    return Collection.extend({\n        defaults: {\n            uniqueProp:     'active',\n            active:         false,\n            wasActivated:   false\n        },\n\n        /**\n         * Extends instance with defaults. Invokes parent initialize method.\n         * Calls initListeners and pushParams methods.\n         */\n        initialize: function () {\n            this._super()\n                .setUnique();\n        },\n\n        /**\n         * Calls initObservable of parent class.\n         * Defines observable properties of instance.\n         * @return {Object} - reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe('active wasActivated');\n\n            return this;\n        },\n\n        /**\n         * Sets active property to true, then invokes pushParams method.\n         */\n        activate: function () {\n            this.active(true);\n            this.wasActivated(true);\n\n            this.setUnique();\n\n            return true;\n        }\n    });\n});\n","Magento_Ui/js/form/components/html.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'uiComponent'\n], function ($, _, Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            content:        '',\n            showSpinner:    false,\n            loading:        false,\n            visible:        true,\n            template:       'ui/content/content',\n            additionalClasses: {},\n            ignoreTmpls: {\n                content: true\n            }\n        },\n\n        /**\n         * Extends instance with default config, calls 'initialize' method of\n         *     parent, calls 'initAjaxConfig'\n         */\n        initialize: function () {\n            _.bindAll(this, 'onContainerToggle', 'onDataLoaded');\n\n            this._super()\n                ._setClasses()\n                .initAjaxConfig();\n\n            return this;\n        },\n\n        /**\n         * Calls 'initObservable' method of parent, initializes observable\n         * properties of instance\n         *\n         * @return {Object} - reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe('content loading visible');\n\n            return this;\n        },\n\n        /**\n         * Extends 'additionalClasses' object.\n         *\n         * @returns {Group} Chainable.\n         */\n        _setClasses: function () {\n            var additional = this.additionalClasses,\n                classes;\n\n            if (_.isString(additional)) {\n                additional = this.additionalClasses.split(' ');\n                classes = this.additionalClasses = {};\n\n                additional.forEach(function (name) {\n                    classes[name] = true;\n                }, this);\n            }\n\n            _.extend(this.additionalClasses, {\n                'admin__scope-old': !!additional\n            });\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        initContainer: function (parent) {\n            this._super();\n\n            parent.on('active', this.onContainerToggle);\n\n            return this;\n        },\n\n        /**\n         * Initializes default ajax config on instance\n         *\n         * @return {Object} - reference to instance\n         */\n        initAjaxConfig: function () {\n            this.ajaxConfig = {\n                url: this.url,\n                data: {\n                    FORM_KEY: window.FORM_KEY\n                },\n                success:    this.onDataLoaded\n            };\n\n            return this;\n        },\n\n        /**\n         * Calls 'loadData' if both 'active' variable and 'shouldLoad'\n         * property are truthy\n         *\n         * @param  {Boolean} active\n         */\n        onContainerToggle: function (active) {\n            if (active && this.shouldLoad()) {\n                this.loadData();\n            }\n        },\n\n        /**\n         * Defines if instance has 'content' property defined.\n         *\n         * @return {Boolean} [description]\n         */\n        hasData: function () {\n            return !!this.content();\n        },\n\n        /**\n         * Defines if instance should load external data\n         *\n         * @return {Boolean}\n         */\n        shouldLoad: function () {\n            return this.url && !this.hasData() && !this.loading();\n        },\n\n        /**\n         * Sets loading property to true, makes ajax call\n         *\n         * @return {Object} - reference to instance\n         */\n        loadData: function () {\n            this.loading(true);\n\n            $.ajax(this.ajaxConfig);\n\n            return this;\n        },\n\n        /**\n         * Ajax's request success handler. Calls 'updateContent' passing 'data'\n         * to it, then sets 'loading' property to false.\n         *\n         * @param  {String} data\n         */\n        onDataLoaded: function (data) {\n            this.updateContent(data)\n                .loading(false);\n        },\n\n        /**\n         * Sets incoming data 'content' property's value\n         *\n         * @param  {String} content\n         * @return {Object} - reference to instance\n         */\n        updateContent: function (content) {\n            this.content(content);\n\n            return this;\n        },\n\n        /**\n         * Content getter\n         *\n         * @returns {String}\n         */\n        getContentUnsanitizedHtml: function () {\n            return this.content();\n        }\n    });\n});\n","Magento_Ui/js/form/components/multiline.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    './group'\n], function (Group) {\n    'use strict';\n\n    return Group.extend({\n        defaults: {\n            links: {\n                value: '${ $.provider }:${ $.dataScope }'\n            }\n        },\n\n        /**\n         * Initialize Multiline component.\n         *\n         * @returns {Object}\n         */\n        initialize: function () {\n            return this._super()\n                ._prepareValue();\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        initObservable: function () {\n            this._super()\n                .observe('value');\n\n            return this;\n        },\n\n        /**\n         * Prepare value for Multiline options.\n         *\n         * @returns {Object} Chainable.\n         * @private\n         */\n        _prepareValue: function () {\n            var value = this.value();\n\n            if (typeof value === 'string') {\n                this.value(value.split('\\n'));\n            }\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/components/collection.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    'uiRegistry',\n    'uiComponent',\n    'uiLayout',\n    'Magento_Ui/js/modal/confirm'\n], function (_, utils, registry, Component, layout, confirm) {\n    'use strict';\n\n    var childTemplate = {\n        parent: '${ $.$data.name }',\n        name: '${ $.$data.childIndex }',\n        dataScope: '${ $.name }',\n        nodeTemplate: '${ $.$data.name }.${ $.$data.itemTemplate }'\n    };\n\n    return Component.extend({\n        defaults: {\n            lastIndex: 0,\n            template: 'ui/form/components/collection'\n        },\n\n        /**\n         * Extends instance with default config, calls initialize of parent\n         * class, calls initChildren method.\n         */\n        initialize: function () {\n            this._super()\n                .initChildren();\n\n            return this;\n        },\n\n        /**\n         * Activates the incoming child and triggers the update event.\n         *\n         * @param {Object} elem - Incoming child.\n         */\n        initElement: function (elem) {\n            this._super();\n\n            elem.activate();\n\n            this.bubble('update');\n\n            return this;\n        },\n\n        /**\n         * Loops over corresponding data in data storage,\n         * creates child for each and pushes it's identifier to initialItems array.\n         *\n         * @returns {Collection} Chainable.\n         */\n        initChildren: function () {\n            var children = this.source.get(this.dataScope),\n                initial = this.initialItems = [];\n\n            _.each(children, function (item, index) {\n                initial.push(index);\n                this.addChild(index);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Creates new item of collection, based on incoming 'index'.\n         * If not passed creates one with 'new_' prefix.\n         *\n         * @param {String|Object} [index] - Index of a child.\n         * @returns {Collection} Chainable.\n         */\n        addChild: function (index) {\n            this.childIndex = !_.isString(index) ?\n                'new_' + this.lastIndex++ :\n                index;\n\n            layout([utils.template(childTemplate, this)]);\n\n            return this;\n        },\n\n        /**\n         * Returns true if current set of items differ from initial one,\n         * or if some child has been changed.\n         *\n         * @returns {Boolean}\n         */\n        hasChanged: function () {\n            var initial = this.initialItems,\n                current = this.elems.pluck('index'),\n                changed = !utils.equalArrays(initial, current);\n\n            return changed || this.elems.some(function (elem) {\n                return _.some(elem.delegate('hasChanged'));\n            });\n        },\n\n        /**\n         * Initiates validation of its' children components.\n         *\n         * @returns {Array} An array of validation results.\n         */\n        validate: function () {\n            var elems;\n\n            this.allValid = true;\n\n            elems = this.elems.sortBy(function (elem) {\n                return !elem.active();\n            });\n\n            elems = elems.map(this._validate, this);\n\n            return _.flatten(elems);\n        },\n\n        /**\n         * Iterator function for components validation.\n         * Activates first invalid child component.\n         *\n         * @param {Object} elem - Element to run validation on.\n         * @returns {Array} An array of validation results.\n         */\n        _validate: function (elem) {\n            var result = elem.delegate('validate'),\n                invalid;\n\n            invalid = _.some(result, function (item) {\n                return !item.valid;\n            });\n\n            if (this.allValid && invalid) {\n                this.allValid = false;\n\n                elem.activate();\n            }\n\n            return result;\n        },\n\n        /**\n         * Creates function that removes element\n         * from collection using '_removeChild' method.\n         * @param  {Object} elem - Element that should be removed.\n         * @deprecated Not used anymore\n         */\n        removeAddress: function (elem) {\n            var self = this;\n\n            confirm({\n                content: this.removeMessage,\n                actions: {\n                    /** @inheritdoc */\n                    confirm: function () {\n                        self._removeAddress(elem);\n                    }\n                }\n            });\n        },\n\n        /**\n         * Removes element from both collection and data storage,\n         * activates first element if removed one was active,\n         * triggers 'update' event.\n         *\n         * @param {Object} elem - Element to remove.\n         */\n        _removeAddress: function (elem) {\n            var isActive = elem.active(),\n                first;\n\n            elem.destroy();\n\n            first = this.elems.first();\n\n            if (first && isActive) {\n                first.activate();\n            }\n\n            this.bubble('update');\n        }\n    });\n});\n","Magento_Ui/js/form/components/area.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    './tab'\n], function (_, Tab) {\n    'use strict';\n\n    return Tab.extend({\n        defaults: {\n            uniqueNs:   'params.activeArea',\n            template:   'ui/area',\n            changed:    false,\n            loading:    false\n        },\n\n        /**\n         * Extends instance with defaults. Invokes parent initialize method.\n         * Calls initListeners and pushParams methods.\n         */\n        initialize: function () {\n            _.bindAll(this, 'onChildrenUpdate', 'onContentLoading');\n\n            return this._super();\n        },\n\n        /**\n         * Calls initObservable of parent class.\n         * Defines observable properties of instance.\n         * @return {Object} - reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe('changed loading');\n\n            return this;\n        },\n\n        /**\n         * Calls parent's initElement method.\n         * Assigns callbacks on various events of incoming element.\n         * @param  {Object} elem\n         * @return {Object} - reference to instance\n         */\n        initElement: function (elem) {\n            this._super();\n\n            elem.on({\n                'update':   this.onChildrenUpdate,\n                'loading':  this.onContentLoading\n            });\n\n            return this;\n        },\n\n        /**\n         * Is being invoked on children update.\n         * Sets changed property to one incoming.\n         * Invokes setActive method if settings\n         * contain makeVisible property set to true.\n         *\n         * @param  {Boolean} hasChanged\n         */\n        onChildrenUpdate: function (hasChanged) {\n            if (!hasChanged) {\n                hasChanged = _.some(this.delegate('hasChanged'));\n            }\n\n            this.changed(hasChanged);\n        },\n\n        /**\n         * Callback that sets loading property to true.\n         */\n        onContentLoading: function (isLoading) {\n            this.loading(isLoading);\n        }\n    });\n});\n","Magento_Ui/js/form/components/insert-form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    './insert',\n    'mageUtils',\n    'jquery'\n], function (Insert, utils, $) {\n    'use strict';\n\n    /**\n     * Get page actions element.\n     *\n     * @param {String} elem\n     * @param {String} actionsClass\n     * @returns {String}\n     */\n    function getPageActions(elem, actionsClass) {\n        var el = document.createElement('div');\n\n        el.innerHTML = elem;\n\n        return el.getElementsByClassName(actionsClass)[0];\n    }\n\n    /**\n     * Return element without page actions toolbar\n     *\n     * @param {String} elem\n     * @param {String} actionsClass\n     * @returns {String}\n     */\n    function removePageActions(elem, actionsClass) {\n        var el = document.createElement('div'),\n            actions;\n\n        el.innerHTML = elem;\n        actions = el.getElementsByClassName(actionsClass)[0];\n\n        if (actions) {\n            el.removeChild(actions);\n        }\n\n        return el.innerHTML;\n    }\n\n    return Insert.extend({\n        defaults: {\n            externalFormName: '${ $.ns }.${ $.ns }',\n            pageActionsClass: 'page-actions',\n            actionsContainerClass: 'page-main-actions',\n            exports: {\n                prefix: '${ $.externalFormName }:selectorPrefix'\n            },\n            imports: {\n                toolbarSection: '${ $.toolbarContainer }:toolbarSection',\n                prefix: '${ $.toolbarContainer }:rootSelector',\n                messagesClass: '${ $.externalFormName }:messagesClass'\n            },\n            settings: {\n                ajax: {\n                    ajaxSave: true,\n                    exports: {\n                        ajaxSave: '${ $.externalFormName }:ajaxSave'\n                    },\n                    imports: {\n                        responseStatus: '${ $.externalFormName }:responseStatus',\n                        responseData: '${ $.externalFormName }:responseData'\n                    }\n                }\n            },\n            modules: {\n                externalForm: '${ $.externalFormName }'\n            }\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            return this._super()\n                .observe('responseStatus');\n        },\n\n        /** @inheritdoc */\n        initConfig: function (config) {\n            var defaults = this.constructor.defaults;\n\n            utils.extend(defaults, defaults.settings[config.formSubmitType] || {});\n\n            return this._super();\n        },\n\n        /** @inheritdoc*/\n        destroyInserted: function () {\n            if (this.isRendered && this.externalForm()) {\n                this.externalForm().delegate('destroy');\n                this.removeActions();\n                this.responseStatus(undefined);\n                this.responseData = {};\n            }\n\n            return this._super();\n        },\n\n        /** @inheritdoc */\n        onRender: function (data) {\n            var actions = getPageActions(data, this.pageActionsClass);\n\n            if (!data.length) {\n                return this;\n            }\n            data = removePageActions(data, this.pageActionsClass);\n            this.renderActions(actions);\n            this._super(data);\n        },\n\n        /**\n         * Insert actions in toolbar.\n         *\n         * @param {String} actions\n         */\n        renderActions: function (actions) {\n            var $container = $('<div></div>');\n\n            $container\n                .addClass(this.actionsContainerClass)\n                .append(actions);\n\n            this.formHeader = $container;\n\n            $(this.toolbarSection).append(this.formHeader);\n        },\n\n        /**\n         * Remove actions toolbar.\n         */\n        removeActions: function () {\n            $(this.formHeader).siblings('.' + this.messagesClass).remove();\n            $(this.formHeader).remove();\n            this.formHeader = $();\n        },\n\n        /**\n         * Reset external form data.\n         */\n        resetForm: function () {\n            if (this.externalSource()) {\n                this.externalSource().trigger('data.reset');\n                this.responseStatus(undefined);\n            }\n        }\n    });\n});\n","Magento_Ui/js/form/components/tab_group.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'Magento_Ui/js/lib/collapsible'\n], function (_, Collapsible) {\n    'use strict';\n\n    return Collapsible.extend({\n        defaults: {\n            listens: {\n                '${ $.provider }:data.validate': 'onValidate'\n            },\n            collapsible: false,\n            opened: true\n        },\n\n        /**\n         * Invokes initElement method of parent class, calls 'initActivation' method\n         * passing element to it.\n         * @param {Object} elem\n         * @returns {Object} - reference to instance\n         */\n        initElement: function (elem) {\n            this._super()\n                .initActivation(elem);\n\n            return this;\n        },\n\n        /**\n         * Activates element if one is first or if one has 'active' propert\n         * set to true.\n         *\n         * @param  {Object} elem\n         * @returns {Object} - reference to instance\n         */\n        initActivation: function (elem) {\n            var elems   = this.elems(),\n                isFirst = !elems.indexOf(elem);\n\n            if (isFirst || elem.active()) {\n                elem.activate();\n            }\n\n            return this;\n        },\n\n        /**\n         * Delegates 'validate' method on element, then reads 'invalid' property\n         * of params storage, and if defined, activates element, sets\n         * 'allValid' property of instance to false and sets invalid's\n         * 'focused' property to true.\n         *\n         * @param {Object} elem\n         */\n        validate: function (elem) {\n            var result  = elem.delegate('validate'),\n                invalid;\n\n            invalid = _.find(result, function (item) {\n                return typeof item !== 'undefined' && !item.valid;\n            });\n\n            if (invalid) {\n                elem.activate();\n                invalid.target.focused(true);\n            }\n\n            return invalid;\n        },\n\n        /**\n         * Sets 'allValid' property of instance to true, then calls 'validate' method\n         * of instance for each element.\n         */\n        onValidate: function () {\n            this.elems.sortBy(function (elem) {\n                return !elem.active();\n            }).some(this.validate, this);\n        }\n    });\n});\n","Magento_Ui/js/form/components/group.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiCollection'\n], function (_, Collection) {\n    'use strict';\n\n    return Collection.extend({\n        defaults: {\n            visible: true,\n            label: '',\n            showLabel: true,\n            required: false,\n            template: 'ui/group/group',\n            fieldTemplate: 'ui/form/field',\n            breakLine: true,\n            validateWholeGroup: false,\n            additionalClasses: {}\n        },\n\n        /**\n         * Extends this with defaults and config.\n         * Then calls initObservable, iniListenes and extractData methods.\n         */\n        initialize: function () {\n            this._super()\n                ._setClasses();\n\n            return this;\n        },\n\n        /**\n         * Calls initObservable of parent class.\n         * Defines observable properties of instance.\n         *\n         * @return {Object} - reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe('visible')\n                .observe({\n                    required: !!+this.required\n                });\n\n            return this;\n        },\n\n        /**\n         * Extends 'additionalClasses' object.\n         *\n         * @returns {Group} Chainable.\n         */\n        _setClasses: function () {\n            var additional = this.additionalClasses,\n                classes;\n\n            if (_.isString(additional)) {\n                additional = this.additionalClasses.split(' ');\n                classes = this.additionalClasses = {};\n\n                additional.forEach(function (name) {\n                    classes[name] = true;\n                }, this);\n            }\n\n            _.extend(this.additionalClasses, {\n                'admin__control-grouped': !this.breakLine,\n                'admin__control-fields': this.breakLine,\n                required:   this.required,\n                _error:     this.error,\n                _disabled:  this.disabled\n            });\n\n            return this;\n        },\n\n        /**\n         * Defines if group has only one element.\n         * @return {Boolean}\n         */\n        isSingle: function () {\n            return this.elems.getLength() === 1;\n        },\n\n        /**\n         * Defines if group has multiple elements.\n         * @return {Boolean}\n         */\n        isMultiple: function () {\n            return this.elems.getLength() > 1;\n        },\n\n        /**\n         * Returns an array of child components previews.\n         *\n         * @returns {Array}\n         */\n        getPreview: function () {\n            return this.elems.map('getPreview');\n        }\n    });\n});\n","Magento_Ui/js/form/components/collection/item.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    '../tab'\n], function (_, utils, Tab) {\n    'use strict';\n\n    var previewConfig = {\n        separator: ' ',\n        prefix: ''\n    };\n\n    /**\n     * Parses incoming data and returns result merged with default preview config\n     *\n     * @param  {Object|String} data\n     * @return {Object}\n     */\n    function parsePreview(data) {\n        if (typeof data == 'string') {\n            data = {\n                items: data\n            };\n        }\n\n        data.items = utils.stringToArray(data.items);\n\n        return _.defaults(data, previewConfig);\n    }\n\n    return Tab.extend({\n        defaults: {\n            label: '',\n            uniqueNs: 'activeCollectionItem',\n            previewTpl: 'ui/form/components/collection/preview'\n        },\n\n        /**\n         * Extends instance with default config, calls initializes of parent class\n         */\n        initialize: function () {\n            _.bindAll(this, 'buildPreview', 'hasPreview');\n\n            return this._super();\n        },\n\n        /**\n         * Calls initProperties of parent class, initializes properties\n         * of instance.\n         *\n         * @return {Object} - reference to instance\n         */\n        initConfig: function () {\n            this._super();\n\n            this.displayed = [];\n\n            return this;\n        },\n\n        /**\n         * Calls initObservable of parent class, initializes observable\n         * properties of instance.\n         *\n         * @return {Object} - reference to instance\n         */\n        initObservable: function () {\n            this._super()\n                .observe({\n                    noPreview: true,\n                    indexed: {}\n                });\n\n            return this;\n        },\n\n        /**\n         * Is being called when child element has been initialized,\n         *     calls initElement of parent class, binds to element's update event,\n         *     calls insertToArea and insertToIndexed methods passing element to it\n         *\n         * @param  {Object} elem\n         */\n        initElement: function (elem) {\n            this._super()\n                .insertToIndexed(elem);\n\n            return this;\n        },\n\n        /**\n         * Adds element to observable indexed object of instance\n         *\n         * @param  {Object} elem\n         * @return {Object} - reference to instance\n         */\n        insertToIndexed: function (elem) {\n            var indexed = this.indexed();\n\n            indexed[elem.index] = elem;\n\n            this.indexed(indexed);\n\n            return this;\n        },\n\n        /**\n         * Destroys current instance along with all of its' children.\n         * Overrides base method to clear data when this method is called.\n         */\n        destroy: function () {\n            this._super();\n            this._clearData();\n        },\n\n        /**\n         * Clears all data associated with component.\n         * @private\n         *\n         * @returns {Item} Chainable.\n         */\n        _clearData: function () {\n            this.source.remove(this.dataScope);\n\n            return this;\n        },\n\n        /**\n         * Formats incoming previews array via parsePreview function.\n         *\n         * @param  {Array} previews\n         * @return {Array} - formatted previews\n         */\n        formatPreviews: function (previews) {\n            return previews.map(parsePreview);\n        },\n\n        /**\n         * Creates string view of previews\n         *\n         * @param  {Object} data\n         * @return {Strict} - formatted preview string\n         */\n        buildPreview: function (data) {\n            var preview = this.getPreview(data.items),\n                prefix = data.prefix;\n\n            return prefix + preview.join(data.separator);\n        },\n\n        /**\n         * Defines if instance has preview for incoming data\n         *\n         * @param  {Object}  data\n         * @return {Boolean}\n         */\n        hasPreview: function (data) {\n            return !!this.getPreview(data.items).length;\n        },\n\n        /**\n         * Creates an array of previews for elements specified in incoming\n         * items array, calls updatePreview afterwards.\n         *\n         * @param  {Array} items - An array of element's indexes.\n         * @returns {Array} An array of previews.\n         */\n        getPreview: function (items) {\n            var elems = this.indexed(),\n                displayed = this.displayed,\n                preview;\n\n            items = items.map(function (index) {\n                var elem = elems[index];\n\n                preview = elem && elem.visible() ? elem.getPreview() : '';\n\n                preview = Array.isArray(preview) ?\n                    _.compact(preview).join(', ') :\n                    preview;\n\n                utils.toggle(displayed, index, !!preview);\n\n                return preview;\n            });\n\n            this.noPreview(!displayed.length);\n\n            return _.compact(items);\n        }\n    });\n});\n","Magento_Ui/js/form/element/multiselect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    './select'\n], function (_, utils, Select) {\n    'use strict';\n\n    return Select.extend({\n        defaults: {\n            size: 5,\n            elementTmpl: 'ui/form/element/multiselect',\n            listens: {\n                value: 'setDifferedFromDefault setPrepareToSendData'\n            }\n        },\n\n        /**\n         * @inheritdoc\n         */\n        setInitialValue: function () {\n            this._super();\n\n            this.initialValue = utils.copy(this.initialValue);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        normalizeData: function (value) {\n            if (utils.isEmpty(value)) {\n                value = [];\n            }\n\n            return _.isString(value) ? value.split(',') : value;\n        },\n\n        /**\n         * Sets the prepared data to dataSource\n         * by path, where key is component link to dataSource with\n         * suffix \"-prepared-for-send\"\n         *\n         * @param {Array} data - current component value\n         */\n        setPrepareToSendData: function (data) {\n            if (_.isUndefined(data) || !data.length) {\n                data = '';\n            }\n\n            this.source.set(this.dataScope + '-prepared-for-send', data);\n        },\n\n        /**\n         * @inheritdoc\n         */\n        getInitialValue: function () {\n            var values = [\n                    this.normalizeData(this.source.get(this.dataScope)),\n                    this.normalizeData(this.default)\n                ],\n                value;\n\n            values.some(function (v) {\n                return _.isArray(v) && (value = utils.copy(v)) && !_.isEmpty(v);\n            });\n\n            return value;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        hasChanged: function () {\n            var value = this.value(),\n                initial = this.initialValue;\n\n            return !utils.equalArrays(value, initial);\n        },\n\n        /**\n         * @inheritdoc\n         */\n        reset: function () {\n            this.value(utils.copy(this.initialValue));\n            this.error(false);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        clear: function () {\n            this.value([]);\n            this.error(false);\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/form/element/url-input.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'uiLayout',\n    'mage/translate',\n    'Magento_Ui/js/form/element/abstract'\n], function (_, layout, $t, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            linkedElement: {},\n            settingTemplate: 'ui/form/element/urlInput/setting',\n            typeSelectorTemplate: 'ui/form/element/urlInput/typeSelector',\n            options: [],\n            linkedElementInstances: {},\n            //checkbox\n            isDisplayAdditionalSettings: true,\n            settingValue: false,\n            settingLabel: $t('Open in new tab'),\n            tracks: {\n                linkedElement: true\n            },\n            baseLinkSetting: {\n                namePrefix: '${$.name}.',\n                dataScopePrefix: '${$.dataScope}.',\n                provider: '${$.provider}'\n            },\n            urlTypes: {},\n            listens: {\n                settingValue: 'checked',\n                disabled: 'hideLinkedElement',\n                linkType: 'createChildUrlInputComponent'\n            },\n            links: {\n                linkType: '${$.provider}:${$.dataScope}.type',\n                settingValue: '${$.provider}:${$.dataScope}.setting'\n            }\n        },\n\n        /** @inheritdoc */\n        initConfig: function (config) {\n            var processedLinkTypes = {},\n                baseLinkType = this.constructor.defaults.baseLinkSetting;\n\n            _.each(config.urlTypes, function (linkSettingsArray, linkName) {\n                //add link name by link type\n                linkSettingsArray.name = baseLinkType.namePrefix + linkName;\n                linkSettingsArray.dataScope = baseLinkType.dataScopePrefix + linkName;\n                linkSettingsArray.type = linkName;\n                linkSettingsArray.disabled = config.disabled;\n                linkSettingsArray.visible = config.visible;\n                processedLinkTypes[linkName] = {};\n                _.extend(processedLinkTypes[linkName], baseLinkType, linkSettingsArray);\n            });\n            _.extend(this.constructor.defaults.urlTypes, processedLinkTypes);\n\n            this._super();\n        },\n\n        /**\n         * Initializes observable properties of instance\n         *\n         * @returns {Abstract} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe('componentTemplate options value linkType settingValue checked isDisplayAdditionalSettings')\n                .setOptions();\n\n            return this;\n        },\n\n        /**\n         * Set options to select based on link types configuration\n         *\n         * @return {Object}\n         */\n        setOptions: function () {\n            var result = [];\n\n            _.each(this.urlTypes, function (option, key) {\n                result.push({\n                    value: key,\n                    label: option.label,\n                    sortOrder: option.sortOrder || 0\n                });\n            });\n\n            //sort options by sortOrder\n            result.sort(function (a, b) {\n                return a.sortOrder > b.sortOrder ? 1 : -1;\n            });\n\n            this.options(result);\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        setPreview: function (visible) {\n            this.linkedElement().visible(visible);\n        },\n\n        /**\n         * Initializes observable properties of instance\n         *\n         * @param {Boolean} disabled\n         */\n        hideLinkedElement: function (disabled) {\n            this.linkedElement().disabled(disabled);\n        },\n\n        /** @inheritdoc */\n        destroy: function () {\n            _.each(this.linkedElementInstances, function (value) {\n                value().destroy();\n            });\n            this._super();\n        },\n\n        /**\n         * Create child component by value\n         *\n         * @param {String} value\n         * @return void\n         */\n        createChildUrlInputComponent: function (value) {\n            var elementConfig;\n\n            if (!_.isEmpty(value) && _.isUndefined(this.linkedElementInstances[value])) {\n                elementConfig = this.urlTypes[value];\n                layout([elementConfig]);\n                this.linkedElementInstances[value] = this.requestModule(elementConfig.name);\n            }\n            this.linkedElement = this.linkedElementInstances[value];\n\n        },\n\n        /**\n         * Returns linked element to display related field in template\n         * @return String\n         */\n        getLinkedElementName: function () {\n            return this.linkedElement;\n        },\n\n        /**\n         * Add ability to choose check box by clicking on label\n         */\n        checkboxClick: function () {\n            if (!this.disabled()) {\n                this.settingValue(!this.settingValue());\n            }\n        }\n    });\n});\n","Magento_Ui/js/form/element/media.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'mageUtils',\n    './abstract'\n], function (utils, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            links: {\n                value: ''\n            }\n        },\n\n        /**\n         * Initializes file component.\n         *\n         * @returns {Media} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initFormId();\n\n            return this;\n        },\n\n        /**\n         * Defines form ID with which file input will be associated.\n         *\n         * @returns {Media} Chainable.\n         */\n        initFormId: function () {\n            var namespace;\n\n            if (this.formId) {\n                return this;\n            }\n\n            namespace   = this.name.split('.');\n            this.formId = namespace[0];\n\n            return this;\n        }\n    });\n});\n"}
}});