Spamworldpro Mini Shell
Spamworldpro


Server : Apache
System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64
User : corals ( 1002)
PHP Version : 7.4.33
Disable Function : exec,passthru,shell_exec,system
Directory :  /home/corals/cartforge.co/pub/static/adminhtml/Magento/backend/en_US/js/bundle/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/corals/cartforge.co/pub/static/adminhtml/Magento/backend/en_US/js/bundle/bundle5.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","knockoutjs/knockout-fast-foreach.js":"/*!\n  Knockout Fast Foreach v0.4.1 (2015-07-17T14:06:15.974Z)\n  By: Brian M Hunt (C) 2015\n  License: MIT\n\n  Adds `fastForEach` to `ko.bindingHandlers`.\n*/\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    define(['knockout'], factory);\n  } else if (typeof exports === 'object') {\n    module.exports = factory(require('knockout'));\n  } else {\n    root.KnockoutFastForeach = factory(root.ko);\n  }\n}(this, function (ko) {\n  \"use strict\";\n// index.js\n// --------\n// Fast For Each\n//\n// Employing sound techniques to make a faster Knockout foreach binding.\n// --------\n\n//      Utilities\n\n// from https://github.com/jonschlinkert/is-plain-object\nfunction isPlainObject(o) {\n  return !!o && typeof o === 'object' && o.constructor === Object;\n}\n\n// From knockout/src/virtualElements.js\nvar commentNodesHaveTextProperty = document && document.createComment(\"test\").text === \"<!--test-->\";\nvar startCommentRegex = commentNodesHaveTextProperty ? /^<!--\\s*ko(?:\\s+([\\s\\S]+))?\\s*-->$/ : /^\\s*ko(?:\\s+([\\s\\S]+))?\\s*$/;\nvar supportsDocumentFragment = document && typeof document.createDocumentFragment === \"function\";\nfunction isVirtualNode(node) {\n  return (node.nodeType === 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);\n}\n\n\n// Get a copy of the (possibly virtual) child nodes of the given element,\n// put them into a container, then empty the given node.\nfunction makeTemplateNode(sourceNode) {\n  var container = document.createElement(\"div\");\n  var parentNode;\n  if (sourceNode.content) {\n    // For e.g. <template> tags\n    parentNode = sourceNode.content;\n  } else if (sourceNode.tagName === 'SCRIPT') {\n    parentNode = document.createElement(\"div\");\n    parentNode.innerHTML = sourceNode.text;\n  } else {\n    // Anything else e.g. <div>\n    parentNode = sourceNode;\n  }\n  ko.utils.arrayForEach(ko.virtualElements.childNodes(parentNode), function (child) {\n    // FIXME - This cloneNode could be expensive; we may prefer to iterate over the\n    // parentNode children in reverse (so as not to foul the indexes as childNodes are\n    // removed from parentNode when inserted into the container)\n    if (child) {\n      container.insertBefore(child.cloneNode(true), null);\n    }\n  });\n  return container;\n}\n\nfunction insertAllAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode) {\n  var frag, len, i;\n  // poor man's node and array check, should be enough for this\n  if (typeof nodeOrNodeArrayToInsert.nodeType !== \"undefined\" && typeof nodeOrNodeArrayToInsert.length === \"undefined\") {\n    throw new Error(\"Expected a single node or a node array\");\n  }\n\n  if (typeof nodeOrNodeArrayToInsert.nodeType !== \"undefined\") {\n    ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode);\n    return;\n  }\n\n  if (nodeOrNodeArrayToInsert.length === 1) {\n    ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert[0], insertAfterNode);\n    return;\n  }\n\n  if (supportsDocumentFragment) {\n    frag = document.createDocumentFragment();\n\n    for (i = 0, len = nodeOrNodeArrayToInsert.length; i !== len; ++i) {\n      frag.appendChild(nodeOrNodeArrayToInsert[i]);\n    }\n    ko.virtualElements.insertAfter(containerNode, frag, insertAfterNode);\n  } else {\n    // Nodes are inserted in reverse order - pushed down immediately after\n    // the last node for the previous item or as the first node of element.\n    for (i = nodeOrNodeArrayToInsert.length - 1; i >= 0; --i) {\n      var child = nodeOrNodeArrayToInsert[i];\n      if (!child) {\n        return;\n      }\n      ko.virtualElements.insertAfter(containerNode, child, insertAfterNode);\n    }\n  }\n}\n\n// Mimic a KO change item 'add'\nfunction valueToChangeAddItem(value, index) {\n  return {\n    status: 'added',\n    value: value,\n    index: index\n  };\n}\n\nfunction isAdditionAdjacentToLast(changeIndex, arrayChanges) {\n  return changeIndex > 0 &&\n    changeIndex < arrayChanges.length &&\n    arrayChanges[changeIndex].status === \"added\" &&\n    arrayChanges[changeIndex - 1].status === \"added\" &&\n    arrayChanges[changeIndex - 1].index === arrayChanges[changeIndex].index - 1;\n}\n\nfunction FastForEach(spec) {\n  this.element = spec.element;\n  this.container = isVirtualNode(this.element) ?\n                   this.element.parentNode : this.element;\n  this.$context = spec.$context;\n  this.data = spec.data;\n  this.as = spec.as;\n  this.noContext = spec.noContext;\n  this.templateNode = makeTemplateNode(\n    spec.name ? document.getElementById(spec.name).cloneNode(true) : spec.element\n  );\n  this.afterQueueFlush = spec.afterQueueFlush;\n  this.beforeQueueFlush = spec.beforeQueueFlush;\n  this.changeQueue = [];\n  this.lastNodesList = [];\n  this.indexesToDelete = [];\n  this.rendering_queued = false;\n\n  // Remove existing content.\n  ko.virtualElements.emptyNode(this.element);\n\n  // Prime content\n  var primeData = ko.unwrap(this.data);\n  if (primeData.map) {\n    this.onArrayChange(primeData.map(valueToChangeAddItem));\n  }\n\n  // Watch for changes\n  if (ko.isObservable(this.data)) {\n    if (!this.data.indexOf) {\n      // Make sure the observable is trackable.\n      this.data = this.data.extend({trackArrayChanges: true});\n    }\n    this.changeSubs = this.data.subscribe(this.onArrayChange, this, 'arrayChange');\n  }\n}\n\n\nFastForEach.animateFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame ||\n  window.mozRequestAnimationFrame || window.msRequestAnimationFrame ||\n  function(cb) { return window.setTimeout(cb, 1000 / 60); };\n\n\nFastForEach.prototype.dispose = function () {\n  if (this.changeSubs) {\n    this.changeSubs.dispose();\n  }\n};\n\n\n// If the array changes we register the change.\nFastForEach.prototype.onArrayChange = function (changeSet) {\n  var self = this;\n  var changeMap = {\n    added: [],\n    deleted: []\n  };\n  for (var i = 0, len = changeSet.length; i < len; i++) {\n    // the change is appended to a last change info object when both are 'added' and have indexes next to each other\n    // here I presume that ko is sending changes in monotonic order (in index variable) which happens to be true, tested with push and splice with multiple pushed values\n    if (isAdditionAdjacentToLast(i, changeSet)) {\n      var batchValues = changeMap.added[changeMap.added.length - 1].values;\n      if (!batchValues) {\n        // transform the last addition into a batch addition object\n        var lastAddition = changeMap.added.pop();\n        var batchAddition = {\n          isBatch: true,\n          status: 'added',\n          index: lastAddition.index,\n          values: [lastAddition.value]\n        };\n        batchValues = batchAddition.values;\n        changeMap.added.push(batchAddition);\n      }\n      batchValues.push(changeSet[i].value);\n    } else {\n      changeMap[changeSet[i].status].push(changeSet[i]);\n    }\n  }\n  if (changeMap.deleted.length > 0) {\n    this.changeQueue.push.apply(this.changeQueue, changeMap.deleted);\n    this.changeQueue.push({status: 'clearDeletedIndexes'});\n  }\n  this.changeQueue.push.apply(this.changeQueue, changeMap.added);\n  // Once a change is registered, the ticking count-down starts for the processQueue.\n  if (this.changeQueue.length > 0 && !this.rendering_queued) {\n    this.rendering_queued = true;\n    FastForEach.animateFrame.call(window, function () { self.processQueue(); });\n  }\n};\n\n\n// Reflect all the changes in the queue in the DOM, then wipe the queue.\nFastForEach.prototype.processQueue = function () {\n  var self = this;\n\n  // Callback so folks can do things before the queue flush.\n  if (typeof this.beforeQueueFlush === 'function') {\n    this.beforeQueueFlush(this.changeQueue);\n  }\n\n  ko.utils.arrayForEach(this.changeQueue, function (changeItem) {\n    // console.log(self.data(), \"CI\", JSON.stringify(changeItem, null, 2), JSON.stringify($(self.element).text()))\n    self[changeItem.status](changeItem);\n    // console.log(\"  ==> \", JSON.stringify($(self.element).text()))\n  });\n  this.rendering_queued = false;\n  // Callback so folks can do things.\n  if (typeof this.afterQueueFlush === 'function') {\n    this.afterQueueFlush(this.changeQueue);\n  }\n  this.changeQueue = [];\n};\n\n\n// Process a changeItem with {status: 'added', ...}\nFastForEach.prototype.added = function (changeItem) {\n  var index = changeItem.index;\n  var valuesToAdd = changeItem.isBatch ? changeItem.values : [changeItem.value];\n  var referenceElement = this.lastNodesList[index - 1] || null;\n  // gather all childnodes for a possible batch insertion\n  var allChildNodes = [];\n\n  for (var i = 0, len = valuesToAdd.length; i < len; ++i) {\n    var templateClone = this.templateNode.cloneNode(true);\n    var childContext;\n\n    if (this.noContext) {\n      childContext = this.$context.extend({\n        '$item': valuesToAdd[i]\n      });\n    } else {\n      childContext = this.$context.createChildContext(valuesToAdd[i], this.as || null);\n    }\n\n    // apply bindings first, and then process child nodes, because bindings can add childnodes\n    ko.applyBindingsToDescendants(childContext, templateClone);\n\n    var childNodes = ko.virtualElements.childNodes(templateClone);\n    // Note discussion at https://github.com/angular/angular.js/issues/7851\n    allChildNodes.push.apply(allChildNodes, Array.prototype.slice.call(childNodes));\n    this.lastNodesList.splice(index + i, 0, childNodes[childNodes.length - 1]);\n  }\n\n  insertAllAfter(this.element, allChildNodes, referenceElement);\n};\n\n\n// Process a changeItem with {status: 'deleted', ...}\nFastForEach.prototype.deleted = function (changeItem) {\n  var index = changeItem.index;\n  var ptr = this.lastNodesList[index],\n      // We use this.element because that will be the last previous node\n      // for virtual element lists.\n      lastNode = this.lastNodesList[index - 1] || this.element;\n  do {\n    ptr = ptr.previousSibling;\n    ko.removeNode((ptr && ptr.nextSibling) || ko.virtualElements.firstChild(this.element));\n  } while (ptr && ptr !== lastNode);\n  // The \"last node\" in the DOM from which we begin our delets of the next adjacent node is\n  // now the sibling that preceded the first node of this item.\n  this.lastNodesList[index] = this.lastNodesList[index - 1];\n  this.indexesToDelete.push(index);\n};\n\n\n// We batch our deletion of item indexes in our parallel array.\n// See brianmhunt/knockout-fast-foreach#6/#8\nFastForEach.prototype.clearDeletedIndexes = function () {\n  // We iterate in reverse on the presumption (following the unit tests) that KO's diff engine\n  // processes diffs (esp. deletes) monotonically ascending i.e. from index 0 -> N.\n  for (var i = this.indexesToDelete.length - 1; i >= 0; --i) {\n    this.lastNodesList.splice(this.indexesToDelete[i], 1);\n  }\n  this.indexesToDelete = [];\n};\n\n\nko.bindingHandlers.fastForEach = {\n  // Valid valueAccessors:\n  //    []\n  //    ko.observable([])\n  //    ko.observableArray([])\n  //    ko.computed\n  //    {data: array, name: string, as: string}\n  init: function init(element, valueAccessor, bindings, vm, context) {\n    var value = valueAccessor(),\n        ffe;\n    if (isPlainObject(value)) {\n      value.element = value.element || element;\n      value.$context = context;\n      ffe = new FastForEach(value);\n    } else {\n      ffe = new FastForEach({\n        element: element,\n        data: ko.unwrap(context.$rawData) === value ? context.$rawData : value,\n        $context: context\n      });\n    }\n    ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n      ffe.dispose();\n    });\n    return {controlsDescendantBindings: true};\n  },\n\n  // Export for testing, debugging, and overloading.\n  FastForEach: FastForEach\n};\n\nko.virtualElements.allowedBindings.fastForEach = true;\n}));","knockoutjs/knockout-repeat.js":"// REPEAT binding for Knockout http://knockoutjs.com/\n// (c) Michael Best\n// License: MIT (http://www.opensource.org/licenses/mit-license.php)\n// Version 2.1.0\n\n(function(factory) {\n    if (typeof define === 'function' && define.amd) {\n        // [1] AMD anonymous module\n        define(['knockout'], factory);\n    } else if (typeof exports === 'object') {\n        // [2] commonJS\n        factory(require('knockout'));\n    } else {\n        // [3] No module loader (plain <script> tag) - put directly in global namespace\n        factory(window.ko);\n    }\n})(function(ko) {\n\nif (!ko.virtualElements)\n    throw Error('Repeat requires at least Knockout 2.1');\n\nvar ko_bindingFlags = ko.bindingFlags || {};\nvar ko_unwrap = ko.utils.unwrapObservable;\n\nvar koProtoName = '__ko_proto__';\n\nif (ko.version >= \"3.0.0\") {\n    // In Knockout 3.0.0, use the node preprocessor to replace a node with a repeat binding with a virtual element\n    var provider = ko.bindingProvider.instance, previousPreprocessFn = provider.preprocessNode;\n    provider.preprocessNode = function(node) {\n        var newNodes, nodeBinding;\n        if (!previousPreprocessFn || !(newNodes = previousPreprocessFn.call(this, node))) {\n            if (node.nodeType === 1 && (nodeBinding = node.getAttribute('data-bind'))) {\n                if (/^\\s*repeat\\s*:/.test(nodeBinding)) {\n                    var leadingComment = node.ownerDocument.createComment('ko ' + nodeBinding),\n                        trailingComment = node.ownerDocument.createComment('/ko');\n                    node.parentNode.insertBefore(leadingComment, node);\n                    node.parentNode.insertBefore(trailingComment, node.nextSibling);\n                    node.removeAttribute('data-bind');\n                    newNodes = [leadingComment, node, trailingComment];\n                }\n            }\n        }\n        return newNodes;\n    };\n}\n\nko.virtualElements.allowedBindings.repeat = true;\nko.bindingHandlers.repeat = {\n    flags: ko_bindingFlags.contentBind | ko_bindingFlags.canUseVirtual,\n    init: function(element, valueAccessor, allBindingsAccessor, xxx, bindingContext) {\n\n        // Read and set fixed options--these options cannot be changed\n        var repeatParam = ko_unwrap(valueAccessor());\n        if (repeatParam && typeof repeatParam == 'object' && !('length' in repeatParam)) {\n            var repeatIndex = repeatParam.index,\n                repeatData = repeatParam.item,\n                repeatStep = repeatParam.step,\n                repeatReversed = repeatParam.reverse,\n                repeatBind = repeatParam.bind,\n                repeatInit = repeatParam.init,\n                repeatUpdate = repeatParam.update;\n        }\n        // Set default values for options that need it\n        repeatIndex = repeatIndex || '$index';\n        repeatData = repeatData || ko.bindingHandlers.repeat.itemName || '$item';\n        repeatStep = repeatStep || 1;\n        repeatReversed = repeatReversed || false;\n\n        var parent = element.parentNode, placeholder;\n        if (element.nodeType == 8) {    // virtual element\n            // Extract the \"children\" and find the single element node\n            var childNodes = ko.utils.arrayFilter(ko.virtualElements.childNodes(element), function(node) { return node.nodeType == 1;});\n            if (childNodes.length !== 1) {\n                throw Error(\"Repeat binding requires a single element to repeat\");\n            }\n            ko.virtualElements.emptyNode(element);\n\n            // The placeholder is the closing comment normally, or the opening comment if reversed\n            placeholder = repeatReversed ? element : element.nextSibling;\n            // The element to repeat is the contained element\n            element = childNodes[0];\n        } else {    // regular element\n            // First clean the element node and remove node's binding\n            var origBindString = element.getAttribute('data-bind');\n            ko.cleanNode(element);\n            element.removeAttribute('data-bind');\n\n            // Original element is no longer needed: delete it and create a placeholder comment\n            placeholder = element.ownerDocument.createComment('ko_repeatplaceholder ' + origBindString);\n            parent.replaceChild(placeholder, element);\n        }\n\n        // extract and remove a data-repeat-bind attribute, if present\n        if (!repeatBind) {\n            repeatBind = element.getAttribute('data-repeat-bind');\n            if (repeatBind) {\n                element.removeAttribute('data-repeat-bind');\n            }\n        }\n\n        // Make a copy of the element node to be copied for each repetition\n        var cleanNode = element.cloneNode(true);\n        if (typeof repeatBind == \"string\") {\n            cleanNode.setAttribute('data-bind', repeatBind);\n            repeatBind = null;\n        }\n\n        // Set up persistent data\n        var lastRepeatCount = 0,\n            notificationObservable = ko.observable(),\n            repeatArray, arrayObservable;\n\n        if (repeatInit) {\n            repeatInit(parent);\n        }\n\n        var subscribable = ko.computed(function() {\n            function makeArrayItemAccessor(index) {\n                var f = function(newValue) {\n                    var item = repeatArray[index];\n                    // Reading the value of the item\n                    if (!arguments.length) {\n                        notificationObservable();   // for dependency tracking\n                        return ko_unwrap(item);\n                    }\n                    // Writing a value to the item\n                    if (ko.isObservable(item)) {\n                        item(newValue);\n                    } else if (arrayObservable && arrayObservable.splice) {\n                        arrayObservable.splice(index, 1, newValue);\n                    } else {\n                        repeatArray[index] = newValue;\n                    }\n                    return this;\n                };\n                // Pretend that our accessor function is an observable\n                f[koProtoName] = ko.observable;\n                return f;\n            }\n\n            function makeBinding(item, index, context) {\n                return repeatArray\n                    ? function() { return repeatBind.call(bindingContext.$data, item, index, context); }\n                    : function() { return repeatBind.call(bindingContext.$data, index, context); }\n            }\n\n            // Read and set up variable options--these options can change and will update the binding\n            var paramObservable = valueAccessor(), repeatParam = ko_unwrap(paramObservable), repeatCount = 0;\n            if (repeatParam && typeof repeatParam == 'object') {\n                if ('length' in repeatParam) {\n                    repeatArray = repeatParam;\n                    repeatCount = repeatArray.length;\n                } else {\n                    if ('foreach' in repeatParam) {\n                        repeatArray = ko_unwrap(paramObservable = repeatParam.foreach);\n                        if (repeatArray && typeof repeatArray == 'object' && 'length' in repeatArray) {\n                            repeatCount = repeatArray.length || 0;\n                        } else {\n                            repeatCount = repeatArray || 0;\n                            repeatArray = null;\n                        }\n                    }\n                    // If a count value is provided (>0), always output that number of items\n                    if ('count' in repeatParam)\n                        repeatCount = ko_unwrap(repeatParam.count) || repeatCount;\n                    // If a limit is provided, don't output more than the limit\n                    if ('limit' in repeatParam)\n                        repeatCount = Math.min(repeatCount, ko_unwrap(repeatParam.limit)) || repeatCount;\n                }\n                arrayObservable = repeatArray && ko.isObservable(paramObservable) ? paramObservable : null;\n            } else {\n                repeatCount = repeatParam || 0;\n            }\n\n            // Remove nodes from end if array is shorter\n            for (; lastRepeatCount > repeatCount; lastRepeatCount-=repeatStep) {\n                ko.removeNode(repeatReversed ? placeholder.nextSibling : placeholder.previousSibling);\n            }\n\n            // Notify existing nodes of change\n            notificationObservable.notifySubscribers();\n\n            // Add nodes to end if array is longer (also initially populates nodes)\n            for (; lastRepeatCount < repeatCount; lastRepeatCount+=repeatStep) {\n                // Clone node and add to document\n                var newNode = cleanNode.cloneNode(true);\n                parent.insertBefore(newNode, repeatReversed ? placeholder.nextSibling : placeholder);\n                newNode.setAttribute('data-repeat-index', lastRepeatCount);\n\n                // Apply bindings to inserted node\n                if (repeatArray && repeatData == '$data') {\n                    var newContext = bindingContext.createChildContext(makeArrayItemAccessor(lastRepeatCount));\n                } else {\n                    var newContext = bindingContext.extend();\n                    if (repeatArray)\n                        newContext[repeatData] = makeArrayItemAccessor(lastRepeatCount);\n                }\n                newContext[repeatIndex] = lastRepeatCount;\n                if (repeatBind) {\n                    var result = ko.applyBindingsToNode(newNode, makeBinding(newContext[repeatData], lastRepeatCount, newContext), newContext, true),\n                        shouldBindDescendants = result && result.shouldBindDescendants;\n                }\n                if (!repeatBind || (result && shouldBindDescendants !== false)) {\n                    ko.applyBindings(newContext, newNode);\n                }\n            }\n            if (repeatUpdate) {\n                repeatUpdate(parent);\n            }\n        }, null, {disposeWhenNodeIsRemoved: placeholder});\n\n        return { controlsDescendantBindings: true, subscribable: subscribable };\n    }\n};\n});","vimeo/vimeo-wrapper.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'vimeo'\n], function (Player) {\n    'use strict';\n\n    window.Vimeo = window.Vimeo || {\n        'Player': Player\n    };\n});\n","vimeo/player.min.js":"/*! @vimeo/player v2.16.4 | (c) 2022 Vimeo | MIT License | https://github.com/vimeo/player.js */\n!function(e,t){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define(t):((e=\"undefined\"!=typeof globalThis?globalThis:e||self).Vimeo=e.Vimeo||{},e.Vimeo.Player=t())}(this,function(){\"use strict\";function r(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,\"value\"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}var e=\"undefined\"!=typeof global&&\"[object global]\"==={}.toString.call(global);function i(e,t){return 0===e.indexOf(t.toLowerCase())?e:\"\".concat(t.toLowerCase()).concat(e.substr(0,1).toUpperCase()).concat(e.substr(1))}function l(e){return/^(https?:)?\\/\\/((player|www)\\.)?vimeo\\.com(?=$|\\/)/.test(e)}function u(e){var t=0<arguments.length&&void 0!==e?e:{},n=t.id,e=t.url,t=n||e;if(!t)throw new Error(\"An id or url must be passed, either in an options object or as a data-vimeo-id or data-vimeo-url attribute.\");if(e=t,!isNaN(parseFloat(e))&&isFinite(e)&&Math.floor(e)==e)return\"https://vimeo.com/\".concat(t);if(l(t))return t.replace(\"http:\",\"https:\");if(n)throw new TypeError(\"\u201c\".concat(n,\"\u201d is not a valid video id.\"));throw new TypeError(\"\u201c\".concat(t,\"\u201d is not a vimeo.com url.\"))}var t=void 0!==Array.prototype.indexOf,Player=\"undefined\"!=typeof window&&void 0!==window.postMessage;if(!(e||t&&Player))throw new Error(\"Sorry, the Vimeo Player API is not available in this browser.\");var n,o,a=\"undefined\"!=typeof globalThis?globalThis:\"undefined\"!=typeof window?window:\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:{};function c(){if(void 0===this)throw new TypeError(\"Constructor WeakMap requires 'new'\");if(o(this,\"_id\",\"_WeakMap_\"+f()+\".\"+f()),0<arguments.length)throw new TypeError(\"WeakMap iterable is not supported\")}function s(e,t){if(!d(e)||!n.call(e,\"_id\"))throw new TypeError(t+\" method called on incompatible receiver \"+typeof e)}function f(){return Math.random().toString().substring(2)}function d(e){return Object(e)===e}(Player=\"undefined\"!=typeof self?self:\"undefined\"!=typeof window?window:a).WeakMap||(n=Object.prototype.hasOwnProperty,Player.WeakMap=((o=function(e,t,n){Object.defineProperty?Object.defineProperty(e,t,{configurable:!0,writable:!0,value:n}):e[t]=n})(c.prototype,\"delete\",function(e){if(s(this,\"delete\"),!d(e))return!1;var t=e[this._id];return!(!t||t[0]!==e)&&(delete e[this._id],!0)}),o(c.prototype,\"get\",function(e){if(s(this,\"get\"),d(e)){var t=e[this._id];return t&&t[0]===e?t[1]:void 0}}),o(c.prototype,\"has\",function(e){if(s(this,\"has\"),!d(e))return!1;var t=e[this._id];return!(!t||t[0]!==e)}),o(c.prototype,\"set\",function(e,t){if(s(this,\"set\"),!d(e))throw new TypeError(\"Invalid value used as weak map key\");var n=e[this._id];return n&&n[0]===e?n[1]=t:o(e,this._id,[e,t]),this}),o(c,\"_polyfill\",!0),c));var h,m=(function(e){var t,n,r;r=function(){var t,n,r,o,i,e=Object.prototype.toString,a=\"undefined\"!=typeof setImmediate?function(e){return setImmediate(e)}:setTimeout;try{Object.defineProperty({},\"x\",{}),t=function(e,t,n,r){return Object.defineProperty(e,t,{value:n,writable:!0,configurable:!1!==r})}}catch(e){t=function(e,t,n){return e[t]=n,e}}function u(e,t){this.fn=e,this.self=t,this.next=void 0}function l(e,t){y.add(e,t),n=n||a(y.drain)}function c(e){var t,n=typeof e;return\"function\"==typeof(t=null!=e&&(\"object\"==n||\"function\"==n)?e.then:t)&&t}function s(){for(var e=0;e<this.chain.length;e++)!function(e,t,n){var r,o;try{!1===t?n.reject(e.msg):(r=!0===t?e.msg:t.call(void 0,e.msg))===n.promise?n.reject(TypeError(\"Promise-chain cycle\")):(o=c(r))?o.call(r,n.resolve,n.reject):n.resolve(r)}catch(e){n.reject(e)}}(this,1===this.state?this.chain[e].success:this.chain[e].failure,this.chain[e]);this.chain.length=0}function f(e){var n,r=this;if(!r.triggered){r.triggered=!0,r.def&&(r=r.def);try{(n=c(e))?l(function(){var t=new m(r);try{n.call(e,function(){f.apply(t,arguments)},function(){d.apply(t,arguments)})}catch(e){d.call(t,e)}}):(r.msg=e,r.state=1,0<r.chain.length&&l(s,r))}catch(e){d.call(new m(r),e)}}}function d(e){var t=this;t.triggered||(t.triggered=!0,(t=t.def?t.def:t).msg=e,t.state=2,0<t.chain.length&&l(s,t))}function h(e,n,r,o){for(var t=0;t<n.length;t++)!function(t){e.resolve(n[t]).then(function(e){r(t,e)},o)}(t)}function m(e){this.def=e,this.triggered=!1}function v(e){this.promise=e,this.state=0,this.triggered=!1,this.chain=[],this.msg=void 0}function p(e){if(\"function\"!=typeof e)throw TypeError(\"Not a function\");if(0!==this.__NPO__)throw TypeError(\"Not a promise\");this.__NPO__=1;var r=new v(this);this.then=function(e,t){var n={success:\"function\"!=typeof e||e,failure:\"function\"==typeof t&&t};return n.promise=new this.constructor(function(e,t){if(\"function\"!=typeof e||\"function\"!=typeof t)throw TypeError(\"Not a function\");n.resolve=e,n.reject=t}),r.chain.push(n),0!==r.state&&l(s,r),n.promise},this.catch=function(e){return this.then(void 0,e)};try{e.call(void 0,function(e){f.call(r,e)},function(e){d.call(r,e)})}catch(e){d.call(r,e)}}var y={add:function(e,t){i=new u(e,t),o?o.next=i:r=i,o=i,i=void 0},drain:function(){var e=r;for(r=o=n=void 0;e;)e.fn.call(e.self),e=e.next}},g=t({},\"constructor\",p,!1);return t(p.prototype=g,\"__NPO__\",0,!1),t(p,\"resolve\",function(n){return n&&\"object\"==typeof n&&1===n.__NPO__?n:new this(function(e,t){if(\"function\"!=typeof e||\"function\"!=typeof t)throw TypeError(\"Not a function\");e(n)})}),t(p,\"reject\",function(n){return new this(function(e,t){if(\"function\"!=typeof e||\"function\"!=typeof t)throw TypeError(\"Not a function\");t(n)})}),t(p,\"all\",function(t){var a=this;return\"[object Array]\"!=e.call(t)?a.reject(TypeError(\"Not an array\")):0===t.length?a.resolve([]):new a(function(n,e){if(\"function\"!=typeof n||\"function\"!=typeof e)throw TypeError(\"Not a function\");var r=t.length,o=Array(r),i=0;h(a,t,function(e,t){o[e]=t,++i===r&&n(o)},e)})}),t(p,\"race\",function(t){var r=this;return\"[object Array]\"!=e.call(t)?r.reject(TypeError(\"Not an array\")):new r(function(n,e){if(\"function\"!=typeof n||\"function\"!=typeof e)throw TypeError(\"Not a function\");h(r,t,function(e,t){n(t)},e)})}),p},(n=a)[t=\"Promise\"]=n[t]||r(),e.exports&&(e.exports=n[t])}(h={exports:{}}),h.exports),v=new WeakMap;function p(e,t,n){var r=v.get(e.element)||{};t in r||(r[t]=[]),r[t].push(n),v.set(e.element,r)}function y(e,t){return(v.get(e.element)||{})[t]||[]}function g(e,t,n){var r=v.get(e.element)||{};if(!r[t])return!0;if(!n)return r[t]=[],v.set(e.element,r),!0;n=r[t].indexOf(n);return-1!==n&&r[t].splice(n,1),v.set(e.element,r),r[t]&&0===r[t].length}var w=[\"autopause\",\"autoplay\",\"background\",\"byline\",\"color\",\"controls\",\"dnt\",\"height\",\"id\",\"interactive_params\",\"keyboard\",\"loop\",\"maxheight\",\"maxwidth\",\"muted\",\"playsinline\",\"portrait\",\"responsive\",\"speed\",\"texttrack\",\"title\",\"transparent\",\"url\",\"width\"];function b(r,e){return w.reduce(function(e,t){var n=r.getAttribute(\"data-vimeo-\".concat(t));return!n&&\"\"!==n||(e[t]=\"\"===n?1:n),e},1<arguments.length&&void 0!==e?e:{})}function k(e,t){var n=e.html;if(!t)throw new TypeError(\"An element must be provided\");if(null!==t.getAttribute(\"data-vimeo-initialized\"))return t.querySelector(\"iframe\");e=document.createElement(\"div\");return e.innerHTML=n,t.appendChild(e.firstChild),t.setAttribute(\"data-vimeo-initialized\",\"true\"),t.querySelector(\"iframe\")}function E(i,e,t){var a=1<arguments.length&&void 0!==e?e:{},u=2<arguments.length?t:void 0;return new Promise(function(t,n){if(!l(i))throw new TypeError(\"\u201c\".concat(i,\"\u201d is not a vimeo.com url.\"));var e,r=\"https://vimeo.com/api/oembed.json?url=\".concat(encodeURIComponent(i));for(e in a)a.hasOwnProperty(e)&&(r+=\"&\".concat(e,\"=\").concat(encodeURIComponent(a[e])));var o=new(\"XDomainRequest\"in window?XDomainRequest:XMLHttpRequest);o.open(\"GET\",r,!0),o.onload=function(){if(404!==o.status)if(403!==o.status)try{var e=JSON.parse(o.responseText);if(403===e.domain_status_code)return k(e,u),void n(new Error(\"\u201c\".concat(i,\"\u201d is not embeddable.\")));t(e)}catch(e){n(e)}else n(new Error(\"\u201c\".concat(i,\"\u201d is not embeddable.\")));else n(new Error(\"\u201c\".concat(i,\"\u201d was not found.\")))},o.onerror=function(){var e=o.status?\" (\".concat(o.status,\")\"):\"\";n(new Error(\"There was an error fetching the embed code from Vimeo\".concat(e,\".\")))},o.send()})}function T(e){function n(e){\"console\"in window&&console.error&&console.error(\"There was an error creating an embed: \".concat(e))}e=0<arguments.length&&void 0!==e?e:document,e=[].slice.call(e.querySelectorAll(\"[data-vimeo-id], [data-vimeo-url]\"));e.forEach(function(t){try{if(null!==t.getAttribute(\"data-vimeo-defer\"))return;var e=b(t);E(u(e),e,t).then(function(e){return k(e,t)}).catch(n)}catch(e){n(e)}})}function P(e){if(\"string\"==typeof e)try{e=JSON.parse(e)}catch(e){return console.warn(e),{}}return e}function _(e,t,n){e.element.contentWindow&&e.element.contentWindow.postMessage&&(t={method:t},void 0!==n&&(t.value=n),8<=(n=parseFloat(navigator.userAgent.toLowerCase().replace(/^.*msie (\\d+).*$/,\"$1\")))&&n<10&&(t=JSON.stringify(t)),e.element.contentWindow.postMessage(t,e.origin))}function M(n,r){var t,e,o,i,a=[];(r=P(r)).event?(\"error\"===r.event&&y(n,r.data.method).forEach(function(e){var t=new Error(r.data.message);t.name=r.data.name,e.reject(t),g(n,r.data.method,e)}),a=y(n,\"event:\".concat(r.event)),t=r.data):r.method&&(e=n,o=r.method,(i=!((i=y(e,o)).length<1)&&(i=i.shift(),g(e,o,i),i))&&(a.push(i),t=r.value)),a.forEach(function(e){try{if(\"function\"==typeof e)return void e.call(n,t);e.resolve(t)}catch(e){}})}var N,F,x,C=new WeakMap,j=new WeakMap,A={},Player=function(){function Player(i){var e,a=this,t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};if(!function(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}(this,Player),window.jQuery&&i instanceof jQuery&&(1<i.length&&window.console&&console.warn&&console.warn(\"A jQuery object with multiple elements was passed, using the first element.\"),i=i[0]),\"undefined\"!=typeof document&&\"string\"==typeof i&&(i=document.getElementById(i)),e=i,!Boolean(e&&1===e.nodeType&&\"nodeName\"in e&&e.ownerDocument&&e.ownerDocument.defaultView))throw new TypeError(\"You must pass either a valid element or a valid id.\");if(\"IFRAME\"===i.nodeName||(r=i.querySelector(\"iframe\"))&&(i=r),\"IFRAME\"===i.nodeName&&!l(i.getAttribute(\"src\")||\"\"))throw new Error(\"The player element passed isn\u2019t a Vimeo embed.\");if(C.has(i))return C.get(i);this._window=i.ownerDocument.defaultView,this.element=i,this.origin=\"*\";var n,r=new m(function(r,o){var e;a._onMessage=function(e){if(l(e.origin)&&a.element.contentWindow===e.source){\"*\"===a.origin&&(a.origin=e.origin);var t=P(e.data);if(t&&\"error\"===t.event&&t.data&&\"ready\"===t.data.method){var n=new Error(t.data.message);return n.name=t.data.name,void o(n)}e=t&&\"ready\"===t.event,n=t&&\"ping\"===t.method;if(e||n)return a.element.setAttribute(\"data-ready\",\"true\"),void r();M(a,t)}},a._window.addEventListener(\"message\",a._onMessage),\"IFRAME\"!==a.element.nodeName&&E(u(e=b(i,t)),e,i).then(function(e){var t,n,r=k(e,i);return a.element=r,a._originalElement=i,t=i,n=r,r=v.get(t),v.set(n,r),v.delete(t),C.set(a.element,a),e}).catch(o)});return j.set(this,r),C.set(this.element,this),\"IFRAME\"===this.element.nodeName&&_(this,\"ping\"),A.isEnabled&&(n=function(){return A.exit()},this.fullscreenchangeHandler=function(){(A.isFullscreen?p:g)(a,\"event:exitFullscreen\",n),a.ready().then(function(){_(a,\"fullscreenchange\",A.isFullscreen)})},A.on(\"fullscreenchange\",this.fullscreenchangeHandler)),this}var e,t,n;return e=Player,(t=[{key:\"callMethod\",value:function(n){var r=this,o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};return new m(function(e,t){return r.ready().then(function(){p(r,n,{resolve:e,reject:t}),_(r,n,o)}).catch(t)})}},{key:\"get\",value:function(n){var r=this;return new m(function(e,t){return n=i(n,\"get\"),r.ready().then(function(){p(r,n,{resolve:e,reject:t}),_(r,n)}).catch(t)})}},{key:\"set\",value:function(n,r){var o=this;return new m(function(e,t){if(n=i(n,\"set\"),null==r)throw new TypeError(\"There must be a value to set.\");return o.ready().then(function(){p(o,n,{resolve:e,reject:t}),_(o,n,r)}).catch(t)})}},{key:\"on\",value:function(e,t){if(!e)throw new TypeError(\"You must pass an event name.\");if(!t)throw new TypeError(\"You must pass a callback function.\");if(\"function\"!=typeof t)throw new TypeError(\"The callback must be a function.\");0===y(this,\"event:\".concat(e)).length&&this.callMethod(\"addEventListener\",e).catch(function(){}),p(this,\"event:\".concat(e),t)}},{key:\"off\",value:function(e,t){if(!e)throw new TypeError(\"You must pass an event name.\");if(t&&\"function\"!=typeof t)throw new TypeError(\"The callback must be a function.\");g(this,\"event:\".concat(e),t)&&this.callMethod(\"removeEventListener\",e).catch(function(e){})}},{key:\"loadVideo\",value:function(e){return this.callMethod(\"loadVideo\",e)}},{key:\"ready\",value:function(){var e=j.get(this)||new m(function(e,t){t(new Error(\"Unknown player. Probably unloaded.\"))});return m.resolve(e)}},{key:\"addCuePoint\",value:function(e){return this.callMethod(\"addCuePoint\",{time:e,data:1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}})}},{key:\"removeCuePoint\",value:function(e){return this.callMethod(\"removeCuePoint\",e)}},{key:\"enableTextTrack\",value:function(e,t){if(!e)throw new TypeError(\"You must pass a language.\");return this.callMethod(\"enableTextTrack\",{language:e,kind:t})}},{key:\"disableTextTrack\",value:function(){return this.callMethod(\"disableTextTrack\")}},{key:\"pause\",value:function(){return this.callMethod(\"pause\")}},{key:\"play\",value:function(){return this.callMethod(\"play\")}},{key:\"requestFullscreen\",value:function(){return A.isEnabled?A.request(this.element):this.callMethod(\"requestFullscreen\")}},{key:\"exitFullscreen\",value:function(){return A.isEnabled?A.exit():this.callMethod(\"exitFullscreen\")}},{key:\"getFullscreen\",value:function(){return A.isEnabled?m.resolve(A.isFullscreen):this.get(\"fullscreen\")}},{key:\"requestPictureInPicture\",value:function(){return this.callMethod(\"requestPictureInPicture\")}},{key:\"exitPictureInPicture\",value:function(){return this.callMethod(\"exitPictureInPicture\")}},{key:\"getPictureInPicture\",value:function(){return this.get(\"pictureInPicture\")}},{key:\"unload\",value:function(){return this.callMethod(\"unload\")}},{key:\"destroy\",value:function(){var n=this;return new m(function(e){var t;j.delete(n),C.delete(n.element),n._originalElement&&(C.delete(n._originalElement),n._originalElement.removeAttribute(\"data-vimeo-initialized\")),n.element&&\"IFRAME\"===n.element.nodeName&&n.element.parentNode&&(n.element.parentNode.parentNode&&n._originalElement&&n._originalElement!==n.element.parentNode?n.element.parentNode.parentNode.removeChild(n.element.parentNode):n.element.parentNode.removeChild(n.element)),n.element&&\"DIV\"===n.element.nodeName&&n.element.parentNode&&(n.element.removeAttribute(\"data-vimeo-initialized\"),(t=n.element.querySelector(\"iframe\"))&&t.parentNode&&(t.parentNode.parentNode&&n._originalElement&&n._originalElement!==t.parentNode?t.parentNode.parentNode.removeChild(t.parentNode):t.parentNode.removeChild(t))),n._window.removeEventListener(\"message\",n._onMessage),A.isEnabled&&A.off(\"fullscreenchange\",n.fullscreenchangeHandler),e()})}},{key:\"getAutopause\",value:function(){return this.get(\"autopause\")}},{key:\"setAutopause\",value:function(e){return this.set(\"autopause\",e)}},{key:\"getBuffered\",value:function(){return this.get(\"buffered\")}},{key:\"getCameraProps\",value:function(){return this.get(\"cameraProps\")}},{key:\"setCameraProps\",value:function(e){return this.set(\"cameraProps\",e)}},{key:\"getChapters\",value:function(){return this.get(\"chapters\")}},{key:\"getCurrentChapter\",value:function(){return this.get(\"currentChapter\")}},{key:\"getColor\",value:function(){return this.get(\"color\")}},{key:\"setColor\",value:function(e){return this.set(\"color\",e)}},{key:\"getCuePoints\",value:function(){return this.get(\"cuePoints\")}},{key:\"getCurrentTime\",value:function(){return this.get(\"currentTime\")}},{key:\"setCurrentTime\",value:function(e){return this.set(\"currentTime\",e)}},{key:\"getDuration\",value:function(){return this.get(\"duration\")}},{key:\"getEnded\",value:function(){return this.get(\"ended\")}},{key:\"getLoop\",value:function(){return this.get(\"loop\")}},{key:\"setLoop\",value:function(e){return this.set(\"loop\",e)}},{key:\"setMuted\",value:function(e){return this.set(\"muted\",e)}},{key:\"getMuted\",value:function(){return this.get(\"muted\")}},{key:\"getPaused\",value:function(){return this.get(\"paused\")}},{key:\"getPlaybackRate\",value:function(){return this.get(\"playbackRate\")}},{key:\"setPlaybackRate\",value:function(e){return this.set(\"playbackRate\",e)}},{key:\"getPlayed\",value:function(){return this.get(\"played\")}},{key:\"getQualities\",value:function(){return this.get(\"qualities\")}},{key:\"getQuality\",value:function(){return this.get(\"quality\")}},{key:\"setQuality\",value:function(e){return this.set(\"quality\",e)}},{key:\"getSeekable\",value:function(){return this.get(\"seekable\")}},{key:\"getSeeking\",value:function(){return this.get(\"seeking\")}},{key:\"getTextTracks\",value:function(){return this.get(\"textTracks\")}},{key:\"getVideoEmbedCode\",value:function(){return this.get(\"videoEmbedCode\")}},{key:\"getVideoId\",value:function(){return this.get(\"videoId\")}},{key:\"getVideoTitle\",value:function(){return this.get(\"videoTitle\")}},{key:\"getVideoWidth\",value:function(){return this.get(\"videoWidth\")}},{key:\"getVideoHeight\",value:function(){return this.get(\"videoHeight\")}},{key:\"getVideoUrl\",value:function(){return this.get(\"videoUrl\")}},{key:\"getVolume\",value:function(){return this.get(\"volume\")}},{key:\"setVolume\",value:function(e){return this.set(\"volume\",e)}}])&&r(e.prototype,t),n&&r(e,n),Player}();return e||(N=function(){for(var e,t=[[\"requestFullscreen\",\"exitFullscreen\",\"fullscreenElement\",\"fullscreenEnabled\",\"fullscreenchange\",\"fullscreenerror\"],[\"webkitRequestFullscreen\",\"webkitExitFullscreen\",\"webkitFullscreenElement\",\"webkitFullscreenEnabled\",\"webkitfullscreenchange\",\"webkitfullscreenerror\"],[\"webkitRequestFullScreen\",\"webkitCancelFullScreen\",\"webkitCurrentFullScreenElement\",\"webkitCancelFullScreen\",\"webkitfullscreenchange\",\"webkitfullscreenerror\"],[\"mozRequestFullScreen\",\"mozCancelFullScreen\",\"mozFullScreenElement\",\"mozFullScreenEnabled\",\"mozfullscreenchange\",\"mozfullscreenerror\"],[\"msRequestFullscreen\",\"msExitFullscreen\",\"msFullscreenElement\",\"msFullscreenEnabled\",\"MSFullscreenChange\",\"MSFullscreenError\"]],n=0,r=t.length,o={};n<r;n++)if((e=t[n])&&e[1]in document){for(n=0;n<e.length;n++)o[t[0][n]]=e[n];return o}return!1}(),F={fullscreenchange:N.fullscreenchange,fullscreenerror:N.fullscreenerror},x={request:function(o){return new Promise(function(e,t){function n(){x.off(\"fullscreenchange\",n),e()}x.on(\"fullscreenchange\",n);var r=(o=o||document.documentElement)[N.requestFullscreen]();r instanceof Promise&&r.then(n).catch(t)})},exit:function(){return new Promise(function(t,e){var n,r;x.isFullscreen?(n=function e(){x.off(\"fullscreenchange\",e),t()},x.on(\"fullscreenchange\",n),(r=document[N.exitFullscreen]())instanceof Promise&&r.then(n).catch(e)):t()})},on:function(e,t){e=F[e];e&&document.addEventListener(e,t)},off:function(e,t){e=F[e];e&&document.removeEventListener(e,t)}},Object.defineProperties(x,{isFullscreen:{get:function(){return Boolean(document[N.fullscreenElement])}},element:{enumerable:!0,get:function(){return document[N.fullscreenElement]}},isEnabled:{enumerable:!0,get:function(){return Boolean(document[N.fullscreenEnabled])}}}),A=x,T(),function(e){var r=0<arguments.length&&void 0!==e?e:document;window.VimeoPlayerResizeEmbeds_||(window.VimeoPlayerResizeEmbeds_=!0,window.addEventListener(\"message\",function(e){if(l(e.origin)&&e.data&&\"spacechange\"===e.data.event)for(var t=r.querySelectorAll(\"iframe\"),n=0;n<t.length;n++)if(t[n].contentWindow===e.source){t[n].parentElement.style.paddingBottom=\"\".concat(e.data.data[0].bottom,\"px\");break}}))}()),Player});\n","Magento_Catalog/js/price-options.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'mage/template',\n    'priceUtils',\n    'priceBox',\n    'jquery-ui-modules/widget'\n], function ($, _, mageTemplate, utils) {\n    'use strict';\n\n    var globalOptions = {\n        productId: null,\n        priceHolderSelector: '.price-box', //data-role=\"priceBox\"\n        optionsSelector: '.product-custom-option',\n        optionConfig: {},\n        optionHandlers: {},\n        optionTemplate: '<%= data.label %>' +\n        '<% if (data.finalPrice.value > 0) { %>' +\n        ' +<%- data.finalPrice.formatted %>' +\n        '<% } else if (data.finalPrice.value < 0) { %>' +\n        ' <%- data.finalPrice.formatted %>' +\n        '<% } %>',\n        controlContainer: 'dd'\n    };\n\n    /**\n     * Custom option preprocessor\n     * @param  {jQuery} element\n     * @param  {Object} optionsConfig - part of config\n     * @return {Object}\n     */\n    function defaultGetOptionValue(element, optionsConfig) {\n        var changes = {},\n            optionValue = element.val(),\n            optionId = utils.findOptionId(element[0]),\n            optionName = element.prop('name'),\n            optionType = element.prop('type'),\n            optionConfig = optionsConfig[optionId],\n            optionHash = optionName;\n\n        switch (optionType) {\n            case 'text':\n            case 'textarea':\n                changes[optionHash] = optionValue ? optionConfig.prices : {};\n                break;\n\n            case 'radio':\n                if (element.is(':checked')) {\n                    changes[optionHash] = optionConfig[optionValue] && optionConfig[optionValue].prices || {};\n                }\n                break;\n\n            case 'select-one':\n                changes[optionHash] = optionConfig[optionValue] && optionConfig[optionValue].prices || {};\n                break;\n\n            case 'select-multiple':\n                _.each(optionConfig, function (row, optionValueCode) {\n                    optionHash = optionName + '##' + optionValueCode;\n                    changes[optionHash] = _.contains(optionValue, optionValueCode) ? row.prices : {};\n                });\n                break;\n\n            case 'checkbox':\n                optionHash = optionName + '##' + optionValue;\n                changes[optionHash] = element.is(':checked') ? optionConfig[optionValue].prices : {};\n                break;\n\n            case 'file':\n                // Checking for 'disable' property equal to checking DOMNode with id*=\"change-\"\n                changes[optionHash] = optionValue || element.prop('disabled') ? optionConfig.prices : {};\n                break;\n        }\n\n        return changes;\n    }\n\n    $.widget('mage.priceOptions', {\n        options: globalOptions,\n\n        /**\n         * @private\n         */\n        _init: function initPriceBundle() {\n            $(this.options.optionsSelector, this.element).trigger('change');\n        },\n\n        /**\n         * Widget creating method.\n         * Triggered once.\n         * @private\n         */\n        _create: function createPriceOptions() {\n            var form = this.element,\n                options = $(this.options.optionsSelector, form),\n                priceBox = $(this.options.priceHolderSelector, $(this.options.optionsSelector).element);\n\n            if (priceBox.data('magePriceBox') &&\n                priceBox.priceBox('option') &&\n                priceBox.priceBox('option').priceConfig\n            ) {\n                if (priceBox.priceBox('option').priceConfig.optionTemplate) {\n                    this._setOption('optionTemplate', priceBox.priceBox('option').priceConfig.optionTemplate);\n                }\n                this._setOption('priceFormat', priceBox.priceBox('option').priceConfig.priceFormat);\n            }\n\n            this._applyOptionNodeFix(options);\n\n            options.on('change', this._onOptionChanged.bind(this));\n        },\n\n        /**\n         * Custom option change-event handler\n         * @param {Event} event\n         * @private\n         */\n        _onOptionChanged: function onOptionChanged(event) {\n            var changes,\n                option = $(event.target),\n                handler = this.options.optionHandlers[option.data('role')];\n\n            option.data('optionContainer', option.closest(this.options.controlContainer));\n\n            if (handler && handler instanceof Function) {\n                changes = handler(option, this.options.optionConfig, this);\n            } else {\n                changes = defaultGetOptionValue(option, this.options.optionConfig);\n            }\n            $(this.options.priceHolderSelector).trigger('updatePrice', changes);\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[optionId];\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] ? optionConfig[optionValue].prices : null;\n\n                    if (prices) {\n                        _.each(prices, function (price, type) {\n                            var value = +price.amount;\n\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.text(template(toTemplate));\n                    }\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         * @private\n         */\n        _setOptions: function setOptions(options) {\n            $.extend(true, this.options, options);\n            this._super(options);\n\n            return this;\n        }\n    });\n\n    return $.mage.priceOptions;\n});\n","Magento_Catalog/js/price-option-date.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'priceUtils',\n    'priceOptions',\n    'jquery-ui-modules/widget'\n], function ($, utils) {\n    'use strict';\n\n    var globalOptions = {\n            fromSelector: 'form',\n            dropdownsSelector: '[data-role=calendar-dropdown]'\n        },\n        optionHandler = {};\n\n    optionHandler.optionHandlers = {};\n\n    /**\n     * Custom handler for Date-with-Dropdowns option type.\n     * @param  {jQuery} siblings\n     * @return {Function} function that return object { optionHash : optionAdditionalPrice }\n     */\n    function onCalendarDropdownChange(siblings) {\n        return function (element, optionConfig) {\n            var changes = {},\n                optionId = utils.findOptionId(element),\n                overhead = optionConfig[optionId].prices,\n                isNeedToUpdate = true,\n                optionHash = 'price-option-calendar-' + optionId;\n\n            siblings.each(function (index, el) {\n                isNeedToUpdate = isNeedToUpdate && !!$(el).val();\n            });\n\n            overhead = isNeedToUpdate ? overhead : {};\n            changes[optionHash] = overhead;\n\n            return changes;\n        };\n    }\n\n    /**\n     * Returns number of days for special month and year\n     * @param  {Number} month\n     * @param  {Number} year\n     * @return {Number}\n     */\n    function getDaysInMonth(month, year) {\n        return new Date(year, month, 0).getDate();\n    }\n\n    /**\n     * Adjusts the number of days in the day option element based on which month or year\n     * is selected (changed). Adjusts the days to 28, 29, 30, or 31 typically.\n     * @param {jQuery} dropdowns\n     */\n    function onDateChange(dropdowns) {\n        var daysNodes,\n            curMonth, curYear, expectedDays,\n            options, needed,\n            month = dropdowns.filter('[data-calendar-role=month]'),\n            year = dropdowns.filter('[data-calendar-role=year]');\n\n        if (month.length && year.length) {\n            daysNodes = dropdowns.filter('[data-calendar-role=day]').find('option');\n\n            curMonth = month.val() || '01';\n            curYear = year.val() || '2000';\n            expectedDays = getDaysInMonth(curMonth, curYear);\n\n            if (daysNodes.length - 1 > expectedDays) { // remove unnecessary option nodes\n                daysNodes.each(function (i, e) {\n                    if (e.value > expectedDays) {\n                        $(e).remove();\n                    }\n                });\n            } else if (daysNodes.length - 1 < expectedDays) { // add missing option nodes\n                options = [];\n                needed = expectedDays - daysNodes.length + 1;\n\n                while (needed--) { //eslint-disable-line max-depth\n                    options.push(\n                        '<option value=\"' + (expectedDays - needed) + '\">' + (expectedDays - needed) + '</option>'\n                    );\n                }\n                $(options.join('')).insertAfter(daysNodes.last());\n            }\n        }\n    }\n\n    $.widget('mage.priceOptionDate', {\n        options: globalOptions,\n\n        /**\n         * Function-initializer of priceOptionDate widget\n         * @private\n         */\n        _create: function initOptionDate() {\n            var field = this.element,\n                form = field.closest(this.options.fromSelector),\n                dropdowns = $(this.options.dropdownsSelector, field),\n                dateOptionId;\n\n            if (dropdowns.length) {\n                dateOptionId = this.options.dropdownsSelector + dropdowns.attr('name');\n\n                optionHandler.optionHandlers[dateOptionId] = onCalendarDropdownChange(dropdowns);\n\n                form.priceOptions(optionHandler);\n\n                dropdowns.data('role', dateOptionId);\n                dropdowns.on('change', onDateChange.bind(this, dropdowns));\n            }\n        }\n    });\n\n    return $.mage.priceOptionDate;\n});\n","Magento_Catalog/js/price-box.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'Magento_Catalog/js/price-utils',\n    'underscore',\n    'mage/template',\n    'jquery-ui-modules/widget'\n], function ($, utils, _, mageTemplate) {\n    'use strict';\n\n    var globalOptions = {\n        productId: null,\n        priceConfig: null,\n        prices: {},\n        priceTemplate: '<span class=\"price\"><%- data.formatted %></span>'\n    };\n\n    $.widget('mage.priceBox', {\n        options: globalOptions,\n        qtyInfo: '#qty',\n\n        /**\n         * Widget initialisation.\n         * Every time when option changed prices also can be changed. So\n         * changed options.prices -> changed cached prices -> recalculation -> redraw price box\n         */\n        _init: function initPriceBox() {\n            var box = this.element;\n\n            box.trigger('updatePrice');\n            this.cache.displayPrices = utils.deepClone(this.options.prices);\n        },\n\n        /**\n         * Widget creating.\n         */\n        _create: function createPriceBox() {\n            var box = this.element;\n\n            this.cache = {};\n            this._setDefaultsFromPriceConfig();\n            this._setDefaultsFromDataSet();\n\n            box.on('reloadPrice', this.reloadPrice.bind(this));\n            box.on('updatePrice', this.onUpdatePrice.bind(this));\n            $(this.qtyInfo).on('input', this.updateProductTierPrice.bind(this));\n            box.trigger('price-box-initialized');\n        },\n\n        /**\n         * Call on event updatePrice. Proxy to updatePrice method.\n         * @param {Event} event\n         * @param {Object} prices\n         */\n        onUpdatePrice: function onUpdatePrice(event, prices) {\n            return this.updatePrice(prices);\n        },\n\n        /**\n         * Updates price via new (or additional values).\n         * It expects object like this:\n         * -----\n         *   \"option-hash\":\n         *      \"price-code\":\n         *         \"amount\": 999.99999,\n         *         ...\n         * -----\n         * Empty option-hash object or empty price-code object treats as zero amount.\n         * @param {Object} newPrices\n         */\n        updatePrice: function updatePrice(newPrices) {\n            var prices = this.cache.displayPrices,\n                additionalPrice = {},\n                pricesCode = [],\n                priceValue, origin, finalPrice;\n\n            this.cache.additionalPriceObject = this.cache.additionalPriceObject || {};\n\n            if (newPrices) {\n                $.extend(this.cache.additionalPriceObject, newPrices);\n            }\n\n            if (!_.isEmpty(additionalPrice)) {\n                pricesCode = _.keys(additionalPrice);\n            } else if (!_.isEmpty(prices)) {\n                pricesCode = _.keys(prices);\n            }\n\n            _.each(this.cache.additionalPriceObject, function (additional) {\n                if (additional && !_.isEmpty(additional)) {\n                    pricesCode = _.keys(additional);\n                }\n                _.each(pricesCode, function (priceCode) {\n                    priceValue = additional[priceCode] || {};\n                    priceValue.amount = +priceValue.amount || 0;\n                    priceValue.adjustments = priceValue.adjustments || {};\n\n                    additionalPrice[priceCode] = additionalPrice[priceCode] || {\n                        'amount': 0,\n                        'adjustments': {}\n                    };\n                    additionalPrice[priceCode].amount =  0 + (additionalPrice[priceCode].amount || 0) +\n                        priceValue.amount;\n                    _.each(priceValue.adjustments, function (adValue, adCode) {\n                        additionalPrice[priceCode].adjustments[adCode] = 0 +\n                            (additionalPrice[priceCode].adjustments[adCode] || 0) + adValue;\n                    });\n                });\n            });\n\n            if (_.isEmpty(additionalPrice)) {\n                this.cache.displayPrices = utils.deepClone(this.options.prices);\n            } else {\n                _.each(additionalPrice, function (option, priceCode) {\n                    origin = this.options.prices[priceCode] || {};\n                    finalPrice = prices[priceCode] || {};\n                    option.amount = option.amount || 0;\n                    origin.amount = origin.amount || 0;\n                    origin.adjustments = origin.adjustments || {};\n                    finalPrice.adjustments = finalPrice.adjustments || {};\n\n                    finalPrice.amount = 0 + origin.amount + option.amount;\n                    _.each(option.adjustments, function (pa, paCode) {\n                        finalPrice.adjustments[paCode] = 0 + (origin.adjustments[paCode] || 0) + pa;\n                    });\n                }, this);\n            }\n\n            this.element.trigger('priceUpdated', this.cache.displayPrices);\n            this.element.trigger('reloadPrice');\n        },\n\n        /*eslint-disable no-extra-parens*/\n        /**\n         * Render price unit block.\n         */\n        reloadPrice: function reDrawPrices() {\n            var priceFormat = (this.options.priceConfig && this.options.priceConfig.priceFormat) || {},\n                priceTemplate = mageTemplate(this.options.priceTemplate);\n\n            _.each(this.cache.displayPrices, function (price, priceCode) {\n                price.final = _.reduce(price.adjustments, function (memo, amount) {\n                    return memo + amount;\n                }, price.amount);\n\n                price.formatted = utils.formatPriceLocale(price.final, priceFormat);\n\n                $('[data-price-type=\"' + priceCode + '\"]', this.element).html(priceTemplate({\n                    data: price\n                }));\n            }, this);\n        },\n\n        /*eslint-enable no-extra-parens*/\n        /**\n         * Overwrites initial (default) prices object.\n         * @param {Object} prices\n         */\n        setDefault: function setDefaultPrices(prices) {\n            this.cache.displayPrices = utils.deepClone(prices);\n            this.options.prices = utils.deepClone(prices);\n        },\n\n        /**\n         * Custom behavior on getting options:\n         * now widget able to deep merge of accepted configuration.\n         * @param  {Object} options\n         * @return {mage.priceBox}\n         */\n        _setOptions: function setOptions(options) {\n            $.extend(true, this.options, options);\n\n            if ('disabled' in options) {\n                this._setOption('disabled', options.disabled);\n            }\n\n            return this;\n        },\n\n        /**\n         * setDefaultsFromDataSet\n         */\n        _setDefaultsFromDataSet: function _setDefaultsFromDataSet() {\n            var box = this.element,\n                priceHolders = $('[data-price-type]', box),\n                prices = this.options.prices;\n\n            this.options.productId = box.data('productId');\n\n            if (_.isEmpty(prices)) {\n                priceHolders.each(function (index, element) {\n                    var type = $(element).data('priceType'),\n                        amount = parseFloat($(element).data('priceAmount'));\n\n                    if (type && !_.isNaN(amount)) {\n                        prices[type] = {\n                            amount: amount\n                        };\n                    }\n                });\n            }\n        },\n\n        /**\n         * setDefaultsFromPriceConfig\n         */\n        _setDefaultsFromPriceConfig: function _setDefaultsFromPriceConfig() {\n            var config = this.options.priceConfig;\n\n            if (config && config.prices) {\n                this.options.prices = config.prices;\n            }\n        },\n\n        /**\n         * Updates product final and base price according to tier prices\n         */\n        updateProductTierPrice: function updateProductTierPrice() {\n            var originalPrice,\n                prices = {'prices': {}};\n\n            if (this.options.prices.finalPrice) {\n                originalPrice = this.options.prices.finalPrice.amount;\n                prices.prices.finalPrice = {'amount': this.getPrice('price') - originalPrice};\n            }\n\n            if (this.options.prices.basePrice) {\n                originalPrice = this.options.prices.basePrice.amount;\n                prices.prices.basePrice = {'amount': this.getPrice('basePrice') - originalPrice};\n            }\n\n            this.updatePrice(prices);\n        },\n\n        /**\n         * Returns price.\n         *\n         * @param {String} priceKey\n         * @returns {Number}\n         */\n        getPrice: function (priceKey) {\n            var productQty = $(this.qtyInfo).val(),\n                result,\n                tierPriceItem,\n                i;\n\n            for (i = 0; i < this.options.priceConfig.tierPrices.length; i++) {\n                tierPriceItem = this.options.priceConfig.tierPrices[i];\n                if (productQty >= tierPriceItem.qty && tierPriceItem[priceKey]) {\n                    result = tierPriceItem[priceKey];\n                }\n            }\n\n            return result;\n        }\n    });\n\n    return $.mage.priceBox;\n});\n","Magento_Catalog/js/price-utils.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore'\n], function ($, _) {\n    'use strict';\n\n    var globalPriceFormat = {\n        requiredPrecision: 2,\n        integerRequired: 1,\n        decimalSymbol: ',',\n        groupSymbol: ',',\n        groupLength: ','\n    };\n\n    /**\n     * Repeats {string} {times} times\n     * @param  {String} string\n     * @param  {Number} times\n     * @return {String}\n     */\n    function stringPad(string, times) {\n        return new Array(times + 1).join(string);\n    }\n\n    /**\n     * Format the price with the compliance to the specified locale\n     *\n     * @param {Number} amount\n     * @param {Object} format\n     * @param  {Boolean} isShowSign\n     */\n    function formatPriceLocale(amount, format, isShowSign)\n    {\n        var s = '',\n            precision, pattern, locale, r;\n\n        format = _.extend(globalPriceFormat, format);\n        precision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision;\n        pattern = format.pattern || '%s';\n        locale = window.LOCALE || 'en-US';\n        if (isShowSign === undefined || isShowSign === true) {\n            s = amount < 0 ? '-' : isShowSign ? '+' : '';\n        } else if (isShowSign === false) {\n            s = '';\n        }\n        pattern = pattern.indexOf('{sign}') < 0 ? s + pattern : pattern.replace('{sign}', s);\n        amount = Number(Math.round(Math.abs(+amount || 0) + 'e+' + precision) + ('e-' + precision));\n        r = amount.toLocaleString(locale, {minimumFractionDigits: precision});\n\n        return pattern.replace('%s', r).replace(/^\\s\\s*/, '').replace(/\\s\\s*$/, '');\n    }\n\n    /**\n     * Formatter for price amount\n     * @param  {Number}  amount\n     * @param  {Object}  format\n     * @param  {Boolean} isShowSign\n     * @return {String}              Formatted value\n     * @deprecated\n     */\n    function formatPrice(amount, format, isShowSign) {\n        var s = '',\n            precision, integerRequired, decimalSymbol, groupSymbol, groupLength, pattern, i, pad, j, re, r, am;\n\n        format = _.extend(globalPriceFormat, format);\n\n        // copied from price-option.js | Could be refactored with varien/js.js\n\n        precision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision;\n        integerRequired = isNaN(format.integerRequired = Math.abs(format.integerRequired)) ? 1 : format.integerRequired;\n        decimalSymbol = format.decimalSymbol === undefined ? ',' : format.decimalSymbol;\n        groupSymbol = format.groupSymbol === undefined ? '.' : format.groupSymbol;\n        groupLength = format.groupLength === undefined ? 3 : format.groupLength;\n        pattern = format.pattern || '%s';\n\n        if (isShowSign === undefined || isShowSign === true) {\n            s = amount < 0 ? '-' : isShowSign ? '+' : '';\n        } else if (isShowSign === false) {\n            s = '';\n        }\n        pattern = pattern.indexOf('{sign}') < 0 ? s + pattern : pattern.replace('{sign}', s);\n\n        // we're avoiding the usage of to fixed, and using round instead with the e representation to address\n        // numbers like 1.005 = 1.01. Using ToFixed to only provide trailing zeroes in case we have a whole number\n        i = parseInt(\n                amount = Number(Math.round(Math.abs(+amount || 0) + 'e+' + precision) + ('e-' + precision)),\n                10\n            ) + '';\n        pad = i.length < integerRequired ? integerRequired - i.length : 0;\n\n        i = stringPad('0', pad) + i;\n\n        j = i.length > groupLength ? i.length % groupLength : 0;\n        re = new RegExp('(\\\\d{' + groupLength + '})(?=\\\\d)', 'g');\n\n        // replace(/-/, 0) is only for fixing Safari bug which appears\n        // when Math.abs(0).toFixed() executed on '0' number.\n        // Result is '0.-0' :(\n\n        am = Number(Math.round(Math.abs(amount - i) + 'e+' + precision) + ('e-' + precision));\n        r = (j ? i.substr(0, j) + groupSymbol : '') +\n            i.substr(j).replace(re, '$1' + groupSymbol) +\n            (precision ? decimalSymbol + am.toFixed(precision).replace(/-/, 0).slice(2) : '');\n\n        return pattern.replace('%s', r).replace(/^\\s\\s*/, '').replace(/\\s\\s*$/, '');\n    }\n\n    /**\n     * Deep clone of Object. Doesn't support functions\n     * @param {Object} obj\n     * @return {Object}\n     */\n    function objectDeepClone(obj) {\n        return JSON.parse(JSON.stringify(obj));\n    }\n\n    /**\n     * Helper to find ID in name attribute\n     * @param   {jQuery} element\n     * @returns {undefined|String}\n     */\n    function findOptionId(element) {\n        var re, id, name;\n\n        if (!element) {\n            return id;\n        }\n        name = $(element).attr('name');\n\n        if (name.indexOf('[') !== -1) {\n            re = /\\[([^\\]]+)?\\]/;\n        } else {\n            re = /_([^\\]]+)?_/; // just to support file-type-option\n        }\n        id = re.exec(name) && re.exec(name)[1];\n\n        if (id) {\n            return id;\n        }\n    }\n\n    return {\n        formatPriceLocale: formatPriceLocale,\n        formatPrice: formatPrice,\n        deepClone: objectDeepClone,\n        strPad: stringPad,\n        findOptionId: findOptionId\n    };\n});\n","Magento_Catalog/js/price-option-file.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery-ui-modules/widget'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.priceOptionFile', {\n        options: {\n            fileName: '',\n            fileNamed: '',\n            fieldNameAction: '',\n            changeFileSelector: '',\n            deleteFileSelector: ''\n        },\n\n        /**\n         * Creates instance of widget\n         * @private\n         */\n        _create: function () {\n            this.fileDeleteFlag = this.fileChangeFlag = false;\n            this.inputField = this.element.find('input[name=' + this.options.fileName + ']')[0];\n            this.inputFieldAction = this.element.find('input[name=' + this.options.fieldNameAction + ']')[0];\n            this.fileNameSpan = this.element.parent('dd').find('.' + this.options.fileNamed);\n\n            $(this.options.changeFileSelector).on('click', $.proxy(function () {\n                this._toggleFileChange();\n            }, this));\n            $(this.options.deleteFileSelector).on('click', $.proxy(function () {\n                this._toggleFileDelete();\n            }, this));\n        },\n\n        /**\n         * Toggles whether the current file is being changed or not. If the file is being deleted\n         * then the option to change the file is disabled.\n         * @private\n         */\n        _toggleFileChange: function () {\n            this.element.toggle();\n            this.fileChangeFlag = !this.fileChangeFlag;\n\n            if (!this.fileDeleteFlag) {\n                $(this.inputFieldAction).attr('value', this.fileChangeFlag ? 'save_new' : 'save_old');\n                this.inputField.disabled = !this.fileChangeFlag;\n            }\n        },\n\n        /**\n         * Toggles whether the file is to be deleted. When the file is being deleted, the name of\n         * the file is decorated with strike-through text and the option to change the file is\n         * disabled.\n         * @private\n         */\n        _toggleFileDelete: function () {\n            this.fileDeleteFlag = $(this.options.deleteFileSelector + ':checked').val();\n            $(this.inputFieldAction).attr('value',\n                this.fileDeleteFlag ? '' : this.fileChangeFlag ? 'save_new' : 'save_old');\n            this.inputField.disabled = this.fileDeleteFlag || !this.fileChangeFlag;\n            this.fileNameSpan.css('text-decoration', this.fileDeleteFlag ? 'line-through' : 'none');\n        }\n    });\n\n    return $.mage.priceOptionFile;\n});\n","Magento_Catalog/js/product-gallery.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    'uiRegistry',\n    'jquery/ui',\n    'baseImage'\n], function ($, _, mageTemplate, registry) {\n    'use strict';\n\n    /**\n     * Formats incoming bytes value to a readable format.\n     *\n     * @param {Number} bytes\n     * @returns {String}\n     */\n    function bytesToSize(bytes) {\n        var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'],\n            i;\n\n        if (bytes === 0) {\n            return '0 Byte';\n        }\n\n        i = window.parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));\n\n        return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];\n    }\n\n    /**\n     * Product gallery widget\n     */\n    $.widget('mage.productGallery', {\n        options: {\n            imageSelector: '[data-role=image]',\n            imageElementSelector: '[data-role=image-element]',\n            template: '[data-template=image]',\n            imageResolutionLabel: '[data-role=resolution]',\n            imgTitleSelector: '[data-role=img-title]',\n            imageSizeLabel: '[data-role=size]',\n            types: null,\n            initialized: false\n        },\n\n        /**\n         * Gallery creation\n         * @protected\n         */\n        _create: function () {\n            this.options.types = this.options.types || this.element.data('types');\n            this.options.images = this.options.images || this.element.data('images');\n            this.options.parentComponent = this.options.parentComponent || this.element.data('parent-component');\n\n            this.imgTmpl = mageTemplate(this.element.find(this.options.template).html().trim());\n\n            this._bind();\n\n            this._isInitializingItems = true;\n            this._initializedItemCount = 0;\n            this._lastInitializedElement = null;\n\n            $.each(this.options.images, $.proxy(function (index, imageData) {\n                this.element.trigger('addItem', imageData);\n            }, this));\n\n            this._updateImagesRoles();\n            this._contentUpdated();\n\n            this._isInitializingItems = false;\n            this.options.initialized = true;\n        },\n\n        /**\n         * Bind handler to elements\n         * @protected\n         */\n        _bind: function () {\n            this._on({\n                updateImageTitle: '_updateImageTitle',\n                updateVisibility: '_updateVisibility',\n                openDialog: '_onOpenDialog',\n                addItem: '_addItem',\n                removeItem: '_removeItem',\n                setImageType: '_setImageType',\n                setPosition: '_setPosition',\n                resort: '_resort',\n\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                'mouseup [data-role=delete-button]': function (event) {\n                    var $imageContainer;\n\n                    event.preventDefault();\n                    $imageContainer = $(event.currentTarget).closest(this.options.imageSelector);\n                    this.element.find('[data-role=dialog]').trigger('close');\n                    this.element.trigger('removeItem', $imageContainer.data('imageData'));\n                },\n\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                'mouseup [data-role=make-base-button]': function (event) {\n                    var $imageContainer,\n                        imageData;\n\n                    event.preventDefault();\n                    event.stopImmediatePropagation();\n                    $imageContainer = $(event.currentTarget).closest(this.options.imageSelector);\n                    imageData = $imageContainer.data('imageData');\n                    this.setBase(imageData);\n                }\n            });\n\n            this.element.sortable({\n                distance: 8,\n                items: this.options.imageSelector,\n                tolerance: 'pointer',\n                cancel: 'input, button, .uploader',\n                update: $.proxy(function () {\n                    this.element.trigger('resort');\n                }, this)\n            });\n        },\n\n        /**\n         * Set image as main\n         * @param {Object} imageData\n         * @private\n         */\n        setBase: function (imageData) {\n            var baseImage = this.options.types.image,\n                sameImages = $.grep(\n                    $.map(this.options.types, function (el) {\n                        return el;\n                    }),\n                    function (el) {\n                        return el.value === baseImage.value;\n                    }\n                ),\n                isImageOpened = this.findElement(imageData).hasClass('active');\n\n            $.each(sameImages, $.proxy(function (index, image) {\n                this.element.trigger('setImageType', {\n                    type: image.code,\n                    imageData: imageData\n                });\n\n                if (isImageOpened) {\n                    this.element.find('.item').addClass('selected');\n                    this.element.find('[data-role=type-selector]').prop({\n                        'checked': true\n                    });\n                }\n            }, this));\n        },\n\n        /**\n         * Find element by fileName\n         * @param {Object} data\n         * @returns {Element}\n         */\n        findElement: function (data) {\n            return this.element.find(this.options.imageSelector).filter(function () {\n                return $(this).data('imageData').file === data.file;\n            }).first();\n        },\n\n        /**\n         * Mark parent fieldset that content was updated\n         */\n        _contentUpdated: function () {\n            if (this.options.initialized && this.options.parentComponent) {\n                registry.async(this.options.parentComponent)(\n                    function (parentComponent) {\n                        parentComponent.bubble('update', true);\n                    }\n                );\n            }\n        },\n\n        /**\n         * Add image\n         * @param {jQuery.Event} event\n         * @param {Object} imageData\n         * @private\n         */\n        _addItem: function (event, imageData) {\n            var element,\n                imgElement,\n                lastElement,\n                count,\n                position;\n\n            if (this._isInitializingItems) {\n                count = this._initializedItemCount++;\n                lastElement = this._lastInitializedElement;\n            } else {\n                count = this.element.find(this.options.imageSelector).length;\n                lastElement = this.element.find(this.options.imageSelector + ':last');\n            }\n\n            position = count + 1;\n\n            if (lastElement && lastElement.length === 1) {\n                position = parseInt(lastElement.data('imageData').position || count, 10) + 1;\n            }\n            imageData = $.extend({\n                'file_id': imageData['value_id'] ? imageData['value_id'] : Math.random().toString(33).substr(2, 18),\n                'disabled': imageData.disabled ? imageData.disabled : 0,\n                'position': position,\n                sizeLabel: bytesToSize(imageData.size)\n            }, imageData);\n\n            element = this.imgTmpl({\n                data: imageData\n            });\n\n            element = $(element).data('imageData', imageData);\n\n            if (count === 0) {\n                element.prependTo(this.element);\n            } else {\n                element.insertAfter(lastElement);\n            }\n\n            this._lastInitializedElement = element;\n\n            if (!this.options.initialized &&\n                this.options.images.length === 0 ||\n                this.options.initialized &&\n                this.element.find(this.options.imageSelector + ':not(.removed)').length === 1\n            ) {\n                this.setBase(imageData);\n            }\n\n            imgElement = element.find(this.options.imageElementSelector);\n\n            imgElement.on('load', this._updateImageDimesions.bind(this, element));\n\n            $.each(this.options.types, $.proxy(function (index, image) {\n                if (imageData.file === image.value) {\n                    this.element.trigger('setImageType', {\n                        type: image.code,\n                        imageData: imageData\n                    });\n                }\n            }, this));\n\n            if (!this._isInitializingItems) {\n                this._updateImagesRoles();\n                this._contentUpdated();\n            }\n        },\n\n        /**\n         * Returns a list of current images.\n         *\n         * @returns {jQueryCollection}\n         */\n        _getImages: function () {\n            return this.element.find(this.options.imageSelector);\n        },\n\n        /**\n         * Returns a list of images roles.\n         *\n         * @return {Object}\n         */\n        _getRoles: function () {\n            return _.mapObject(this.options.types, function (data, key) {\n                var elem = this.element.find('.image-' + key);\n\n                return {\n                    index: key,\n                    value: elem.val(),\n                    elem: elem\n                };\n            }, this);\n        },\n\n        /**\n         * Updates labels with roles information for each image.\n         */\n        _updateImagesRoles: function () {\n            var $images = this._getImages().toArray(),\n                roles = this._getRoles();\n\n            $images.forEach(function (img) {\n                var $img = $(img),\n                    data = $img.data('imageData');\n\n                $img.find('[data-role=roles-labels] li').each(function (index, elem) {\n                    var $elem = $(elem),\n                        roleCode = $elem.data('roleCode'),\n                        role = roles[roleCode];\n\n                    role.value === data.file  ?\n                        $elem.show() :\n                        $elem.hide();\n                });\n\n            });\n        },\n\n        /**\n         * Updates image's dimensions information.\n         *\n         * @param {jQeuryCollection} imgContainer\n         */\n        _updateImageDimesions: function (imgContainer) {\n            var $img = imgContainer.find(this.options.imageElementSelector)[0],\n                $dimens = imgContainer.find('[data-role=image-dimens]');\n\n            $dimens.text($img.naturalWidth + 'x' + $img.naturalHeight + ' px');\n        },\n\n        /**\n         *\n         * @param {jQuery.Event} event\n         * @param {Object} data\n         */\n        _updateImageTitle: function (event, data) {\n            var imageData = data.imageData,\n                $imgContainer = this.findElement(imageData),\n                $title = $imgContainer.find(this.options.imgTitleSelector),\n                value;\n\n            value = imageData['media_type'] === 'external-video' ?\n                imageData['video_title'] :\n                imageData.label;\n\n            $title.text(value);\n\n            this._contentUpdated();\n        },\n\n        /**\n         * Remove Image\n         * @param {jQuery.Event} event\n         * @param {Object} imageData\n         * @private\n         */\n        _removeItem: function (event, imageData) {\n            var $imageContainer = this.findElement(imageData);\n\n            imageData.isRemoved = true;\n            $imageContainer.addClass('removed').hide().find('.is-removed').val(1);\n\n            this._contentUpdated();\n        },\n\n        /**\n         * Set image type\n         * @param {jQuery.Event} event\n         * @param {Obejct} data\n         * @private\n         */\n        _setImageType: function (event, data) {\n            if (data.type === 'image') {\n                this.element.find('.base-image').removeClass('base-image');\n            }\n\n            if (data.imageData) {\n                this.options.types[data.type].value = data.imageData.file;\n\n                if (data.type === 'image') {\n                    this.findElement(data.imageData).addClass('base-image');\n                }\n            } else {\n                this.options.types[data.type].value = 'no_selection';\n            }\n            this.element.find('.image-' + data.type).val(this.options.types[data.type].value || 'no_selection');\n            this._updateImagesRoles();\n            this._contentUpdated();\n        },\n\n        /**\n         * Resort images\n         * @private\n         */\n        _resort: function () {\n            this.element.find('.position').each($.proxy(function (index, element) {\n                var value = $(element).val();\n\n                if (value != index) { //eslint-disable-line eqeqeq\n                    this.element.trigger('moveElement', {\n                        imageData: $(element).closest(this.options.imageSelector).data('imageData'),\n                        position: index\n                    });\n                    $(element).val(index);\n                }\n            }, this));\n\n            this._contentUpdated();\n        },\n\n        /**\n         * Set image position\n         * @param {jQuery.Event} event\n         * @param {Object} data\n         * @private\n         */\n        _setPosition: function (event, data) {\n            var $element = this.findElement(data.imageData),\n                curIndex = this.element.find(this.options.imageSelector).index($element),\n                newPosition = data.position + (curIndex > data.position ? -1 : 0);\n\n            if (data.position != curIndex) { //eslint-disable-line eqeqeq\n                if (data.position === 0) {\n                    this.element.prepend($element);\n                } else {\n                    $element.insertAfter(\n                        this.element.find(this.options.imageSelector).eq(newPosition)\n                    );\n                }\n                this.element.trigger('resort');\n            }\n\n            this._contentUpdated();\n        }\n    });\n\n    // Extension for mage.productGallery - Add advanced settings block\n    $.widget('mage.productGallery', $.mage.productGallery, {\n        options: {\n            dialogTemplate: '[data-role=img-dialog-tmpl]',\n            dialogContainerTmpl: '[data-role=img-dialog-container-tmpl]'\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            var template = this.element.find(this.options.dialogTemplate),\n                containerTmpl = this.element.find(this.options.dialogContainerTmpl);\n\n            this._super();\n            this.modalPopupInit = false;\n\n            if (template.length) {\n                this.dialogTmpl = mageTemplate(template.html().trim());\n            }\n\n            if (containerTmpl.length) {\n                this.dialogContainerTmpl = mageTemplate(containerTmpl.html().trim());\n            } else {\n                this.dialogContainerTmpl = mageTemplate('');\n            }\n\n            this._initDialog();\n        },\n\n        /**\n         * Bind handler to elements\n         * @protected\n         */\n        _bind: function () {\n            var events = {};\n\n            this._super();\n\n            events['click [data-role=close-panel]'] = $.proxy(function () {\n                this.element.find('[data-role=dialog]').trigger('close');\n            }, this);\n\n            /**\n             * @param {jQuery.Event} event\n             */\n            events['click ' + this.options.imageSelector] = function (event) {\n                var imageData, $imageContainer;\n\n                if (!$(event.currentTarget).is('.ui-sortable-helper')) {\n                    $(event.currentTarget).addClass('active');\n                    imageData = $(event.currentTarget).data('imageData');\n                    $imageContainer = this.findElement(imageData);\n\n                    if ($imageContainer.is('.removed')) {\n                        return;\n                    }\n                    this.element.trigger('openDialog', [imageData]);\n                }\n            };\n            this._on(events);\n            this.element.on('sortstart', $.proxy(function () {\n                this.element.find('[data-role=dialog]').trigger('close');\n            }, this));\n        },\n\n        /**\n         * Initializes dialog element.\n         */\n        _initDialog: function () {\n            var $dialog = $(this.dialogContainerTmpl());\n\n            $dialog.modal({\n                'type': 'slide',\n                title: $.mage.__('Image Detail'),\n                buttons: [],\n\n                /** @inheritdoc */\n                opened: function () {\n                    $dialog.trigger('open');\n                },\n\n                /** @inheritdoc */\n                closed: function () {\n                    $dialog.trigger('close');\n                }\n            });\n\n            $dialog.on('open', this.onDialogOpen.bind(this));\n            $dialog.on('close', function () {\n                var $imageContainer = $dialog.data('imageContainer');\n\n                $imageContainer.removeClass('active');\n                $dialog.find('#hide-from-product-page').remove();\n            });\n\n            $dialog.on('change', '[data-role=type-selector]', function () {\n                var parent = $(this).closest('.item'),\n                    selectedClass = 'selected';\n\n                parent.toggleClass(selectedClass, $(this).prop('checked'));\n            });\n\n            $dialog.on('change', '[data-role=type-selector]', $.proxy(this._notifyType, this));\n\n            $dialog.on('change', '[data-role=visibility-trigger]', $.proxy(function (e) {\n                var imageData = $dialog.data('imageData');\n\n                this.element.trigger('updateVisibility', {\n                    disabled: $(e.currentTarget).is(':checked'),\n                    imageData: imageData\n                });\n            }, this));\n\n            $dialog.on('change', '[data-role=\"image-description\"]', function (e) {\n                var target = $(e.target),\n                    targetName = target.attr('name'),\n                    desc = target.val(),\n                    imageData = $dialog.data('imageData');\n\n                this.element.find('input[type=\"hidden\"][name=\"' + targetName + '\"]').val(desc);\n\n                imageData.label = desc;\n                imageData['label_default'] = desc;\n\n                this.element.trigger('updateImageTitle', {\n                    imageData: imageData\n                });\n            }.bind(this));\n\n            this.$dialog = $dialog;\n        },\n\n        /**\n         * @param {Object} imageData\n         * @private\n         */\n        _showDialog: function (imageData) {\n            var $imageContainer = this.findElement(imageData),\n                $template;\n\n            $template = this.dialogTmpl({\n                'data': imageData\n            });\n\n            this.$dialog\n                .html($template)\n                .data('imageData', imageData)\n                .data('imageContainer', $imageContainer)\n                .modal('openModal');\n        },\n\n        /**\n         * Handles dialog open event.\n         *\n         * @param {EventObject} event\n         */\n        onDialogOpen: function (event) {\n            var imageData = this.$dialog.data('imageData'),\n                imageSizeKb = imageData.sizeLabel,\n                image = document.createElement('img'),\n                sizeSpan = this.$dialog.find(this.options.imageSizeLabel)\n                    .find('[data-message]'),\n                resolutionSpan = this.$dialog.find(this.options.imageResolutionLabel)\n                    .find('[data-message]'),\n                sizeText = sizeSpan.attr('data-message').replace('{size}', imageSizeKb),\n                resolutionText;\n\n            image.src = imageData.url;\n\n            resolutionText = resolutionSpan\n                .attr('data-message')\n                .replace('{width}^{height}', image.width + 'x' + image.height);\n\n            sizeSpan.text(sizeText);\n            resolutionSpan.text(resolutionText);\n\n            $(event.target)\n                .find('[data-role=type-selector]')\n                .each($.proxy(function (index, checkbox) {\n                    var $checkbox = $(checkbox),\n                        parent = $checkbox.closest('.item'),\n                        selectedClass = 'selected',\n                        isChecked = this.options.types[$checkbox.val()].value == imageData.file; //eslint-disable-line\n\n                    $checkbox.prop(\n                        'checked',\n                        isChecked\n                    );\n                    parent.toggleClass(selectedClass, isChecked);\n                }, this));\n        },\n\n        /**\n         *\n         * Click by image handler\n         *\n         * @param {jQuery.Event} e\n         * @param {Object} imageData\n         * @private\n         */\n        _onOpenDialog: function (e, imageData) {\n            if (imageData['media_type'] && imageData['media_type'] != 'image') { //eslint-disable-line eqeqeq\n                return;\n            }\n            this._showDialog(imageData);\n        },\n\n        /**\n         * Change visibility\n         *\n         * @param {jQuery.Event} event\n         * * @param {Object} data\n         * @private\n         */\n        _updateVisibility: function (event, data) {\n            var imageData = data.imageData,\n                disabled = +data.disabled,\n                $imageContainer = this.findElement(imageData);\n\n            !!disabled ? //eslint-disable-line no-extra-boolean-cast\n                $imageContainer.addClass('hidden-for-front') :\n                $imageContainer.removeClass('hidden-for-front');\n\n            $imageContainer.find('[name*=\"disabled\"]').val(disabled);\n            imageData.disabled = disabled;\n\n            this._contentUpdated();\n        },\n\n        /**\n         * Set image\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _notifyType: function (event) {\n            var $checkbox = $(event.currentTarget),\n                $imageContainer = $checkbox.closest('[data-role=dialog]').data('imageContainer');\n\n            this.element.trigger('setImageType', {\n                type: $checkbox.val(),\n                imageData: $checkbox.is(':checked') ? $imageContainer.data('imageData') : null\n            });\n\n            this._updateImagesRoles();\n        }\n    });\n\n    return $.mage.productGallery;\n});\n","Magento_Catalog/js/new-category-dialog.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\n/*global FORM_KEY*/\ndefine([\n    'jquery',\n    'jquery/ui',\n    'Magento_Ui/js/modal/modal',\n    'mage/translate',\n    'mage/backend/tree-suggest',\n    'mage/backend/validation'\n], function ($) {\n    'use strict';\n\n    /** Clear parent category. */\n    var clearParentCategory = function () {\n        $('#new_category_parent').find('option').each(function () {\n            $('#new_category_parent-suggest').treeSuggest('removeOption', null, this);\n        });\n    };\n\n    $.widget('mage.newCategoryDialog', {\n        /** @inheritdoc */\n        _create: function () {\n            var widget = this,\n                newCategoryForm;\n\n            $('#new_category_parent').before($('<input>', {\n                id: 'new_category_parent-suggest',\n                placeholder: $.mage.__('start typing to search category')\n            }));\n\n            $('#new_category_parent-suggest').treeSuggest(this.options.suggestOptions)\n                .on('suggestbeforeselect', function (event) {\n                    clearParentCategory();\n                    $(event.target).treeSuggest('close');\n                });\n\n            $.validator.addMethod('validate-parent-category', function () {\n                return $('#new_category_parent').val() || $('#new_category_parent-suggest').val() === '';\n            }, $.mage.__('Choose existing category.'));\n            newCategoryForm = $('#new_category_form');\n            newCategoryForm.mage('validation', {\n                /**\n                 * @param {jQuery} error\n                 * @param {*} element\n                 */\n                errorPlacement: function (error, element) {\n                    error.insertAfter(element.is('#new_category_parent') ?\n                        $('#new_category_parent-suggest').closest('.mage-suggest') :\n                        element);\n                }\n            }).on('highlight.validate', function (e) {\n                var options = $(this).validation('option');\n\n                if ($(e.target).is('#new_category_parent')) {\n                    options.highlight($('#new_category_parent-suggest').get(0),\n                        options.errorClass, options.validClass || '');\n                }\n            });\n            this.element.modal({\n                type: 'slide',\n                modalClass: 'mage-new-category-dialog form-inline',\n                title: $.mage.__('Create Category'),\n\n                /** @inheritdoc */\n                opened: function () {\n                    var enteredName = $('#category_ids-suggest').val();\n\n                    $('#new_category_name').val(enteredName);\n\n                    if (enteredName === '') {\n                        $('#new_category_name').trigger('focus');\n                    }\n                    $('#new_category_messages').html('');\n                },\n\n                /** @inheritdoc */\n                closed: function () {\n                    var validationOptions = newCategoryForm.validation('option');\n\n                    $('#new_category_name, #new_category_parent-suggest').val('');\n                    validationOptions.unhighlight($('#new_category_parent-suggest').get(0),\n                        validationOptions.errorClass, validationOptions.validClass || '');\n                    newCategoryForm.validation('clearError');\n                    $('#category_ids-suggest').trigger('focus');\n                },\n                buttons: [{\n                    text: $.mage.__('Create Category'),\n                    class: 'action-primary',\n\n                    /** @inheritdoc */\n                    click: function (e) {\n                        var thisButton;\n\n                        if (!newCategoryForm.valid()) {\n                            return;\n                        }\n                        thisButton = $(e.currentTarget);\n\n                        thisButton.prop('disabled', true);\n                        $.ajax({\n                            type: 'POST',\n                            url: widget.options.saveCategoryUrl,\n                            data: {\n                                name: $('#new_category_name').val(),\n                                parent: $('#new_category_parent').val(),\n                                'is_active': 1,\n                                'include_in_menu': 1,\n                                'use_config': ['available_sort_by', 'default_sort_by'],\n                                'form_key': FORM_KEY,\n                                'return_session_messages_only': 1\n                            },\n                            dataType: 'json',\n                            context: $('body')\n                        }).done(function (data) {\n                            var $suggest;\n\n                            if (!data.error) {\n                                $suggest = $('#category_ids-suggest');\n\n                                $suggest.trigger('selectItem', {\n                                    id: data.category['entity_id'],\n                                    label: data.category.name\n                                });\n                                $('#new_category_name, #new_category_parent-suggest').val('');\n                                $suggest.val('');\n                                clearParentCategory();\n                                $(widget.element).modal('closeModal');\n                            } else {\n                                $('#new_category_messages').html(data.messages);\n                            }\n                        }).always(\n                            function () {\n                                thisButton.prop('disabled', false);\n                            }\n                        );\n                    }\n                }]\n            });\n        }\n    });\n\n    return $.mage.newCategoryDialog;\n});\n","Magento_Catalog/js/category-tree.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'jquery/ui',\n    'jquery/jstree/jquery.jstree'\n], function ($) {\n    'use strict';\n\n    $.widget('mage.categoryTree', {\n        options: {\n            url: '',\n            data: [],\n            tree: {\n                core: {\n                    themes: {\n                        dots: false\n                    }\n                }\n            }\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            var options = this.options,\n                treeOptions = $.extend(\n                    true,\n                    {},\n                    options.tree,\n                    {\n                        core: {\n                            data: this._convertData(this.options.data).children\n                        }\n                    }\n                );\n\n            this.element.jstree(treeOptions);\n            this.element.on('select_node.jstree', $.proxy(this._selectNode, this));\n        },\n\n        /**\n         * @param {jQuery.Event} event\n         * @param {Object} data\n         * @private\n         */\n        _selectNode: function (event, data) {\n            var node = data.node;\n\n            if (!node.state.disabled) {\n                window.location = window.location + '/' + node.id;\n            } else {\n                event.preventDefault();\n            }\n        },\n\n        /**\n         * @param {Array} nodes\n         * @returns {Array}\n         * @private\n         */\n        _convertDataNodes: function (nodes) {\n            var nodesData = [];\n\n            nodes.children.forEach(function (node) {\n                nodesData.push(this._convertData(node));\n            }, this);\n\n            return nodesData;\n        },\n\n        /**\n         * @param {Object} node\n         * @return {*}\n         * @private\n         */\n        _convertData: function (node) {\n            var self = this,\n                result;\n\n            if (!node) {\n                return result;\n            }\n            // jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n            result = {\n                id: node.id,\n                text: node.name + ' (' + node.product_count + ')',\n                li_attr: {\n                    class: node.cls + (!!node.disabled ? ' disabled' : '') //eslint-disable-line no-extra-boolean-cast\n                },\n                state: {\n                    disabled: node.disabled,\n                    opened:  !!node.children_count && node.expanded\n                }\n            };\n            // jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n            if (node.children) {\n                result.children = [];\n                $.each(node.children, function () {\n                    result.children.push(self._convertData(this));\n                });\n            }\n\n            return result;\n        }\n    });\n\n    return $.mage.categoryTree;\n});\n","Magento_Catalog/js/category-checkbox-tree.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* global Ext, varienWindowOnload, varienElementMethods */\n\ndefine([\n    'jquery',\n    'prototype',\n    'extjs/ext-tree-checkbox',\n    'mage/adminhtml/form'\n], function (jQuery) {\n    'use strict';\n\n    return function (config) {\n        var tree,\n            options = {\n                dataUrl: config.dataUrl,\n                divId: config.divId,\n                rootVisible: config.rootVisible,\n                useAjax: config.useAjax,\n                currentNodeId: config.currentNodeId,\n                jsFormObject: window[config.jsFormObject],\n                name: config.name,\n                checked: config.checked,\n                allowDrop: config.allowDrop,\n                rootId: config.rootId,\n                expanded: config.expanded,\n                categoryId: config.categoryId,\n                treeJson: config.treeJson\n            },\n            data = {},\n            parameters = {},\n            root = {},\n            key = '';\n\n        /**\n         * Fix ext compatibility with prototype 1.6\n         */\n        Ext.lib.Event.getTarget = function (e) {\n            var ee = e.browserEvent || e;\n\n            return ee.target ? Event.element(ee) : null;\n        };\n\n        /**\n         * @param {Object} el\n         * @param {Object} nodeConfig\n         */\n        Ext.tree.TreePanel.Enhanced = function (el, nodeConfig) {\n            Ext.tree.TreePanel.Enhanced.superclass.constructor.call(this, el, nodeConfig);\n        };\n\n        Ext.extend(Ext.tree.TreePanel.Enhanced, Ext.tree.TreePanel, {\n            /**\n             * @param {Object} treeConfig\n             * @param {Boolean} firstLoad\n             */\n            loadTree: function (treeConfig, firstLoad) {\n                parameters = treeConfig.parameters,\n                    data = treeConfig.data,\n                    root = new Ext.tree.TreeNode(parameters);\n\n                if (typeof parameters.rootVisible !== 'undefined') {\n                    this.rootVisible = parameters.rootVisible * 1;\n                }\n\n                this.nodeHash = {};\n                this.setRootNode(root);\n\n                if (firstLoad) {\n                    this.addListener('click', this.categoryClick.createDelegate(this));\n                }\n\n                this.loader.buildCategoryTree(root, data);\n                this.el.dom.innerHTML = '';\n                // render the tree\n                this.render();\n            },\n\n            /**\n             * @param {Object} node\n             */\n            categoryClick: function (node) {\n                node.getUI().check(!node.getUI().checked());\n            }\n        });\n\n        jQuery(function () {\n            var categoryLoader = new Ext.tree.TreeLoader({\n                dataUrl: config.dataUrl\n            });\n\n            /**\n             * @param {Object} response\n             * @param {Object} parent\n             * @param {Function} callback\n             */\n            categoryLoader.processResponse = function (response, parent, callback) {\n                config = JSON.parse(response.responseText);\n\n                this.buildCategoryTree(parent, config);\n\n                if (typeof callback === 'function') {\n                    callback(this, parent);\n                }\n            };\n\n            /**\n             * @param {Object} nodeConfig\n             * @returns {Object}\n             */\n            categoryLoader.createNode = function (nodeConfig) {\n                var node;\n\n                nodeConfig.uiProvider = Ext.tree.CheckboxNodeUI;\n\n                if (nodeConfig.children && !nodeConfig.children.length) {\n                    delete nodeConfig.children;\n                    node = new Ext.tree.AsyncTreeNode(nodeConfig);\n                } else {\n                    node = new Ext.tree.TreeNode(nodeConfig);\n                }\n\n                return node;\n            };\n\n            /**\n             * @param {Object} parent\n             * @param {Object} nodeConfig\n             * @param {Integer} i\n             */\n            categoryLoader.processCategoryTree = function (parent, nodeConfig, i) {\n                var node,\n                    _node = {};\n\n                nodeConfig[i].uiProvider = Ext.tree.CheckboxNodeUI;\n\n                _node = Object.clone(nodeConfig[i]);\n\n                if (_node.children && !_node.children.length) {\n                    delete _node.children;\n                    node = new Ext.tree.AsyncTreeNode(_node);\n                } else {\n                    node = new Ext.tree.TreeNode(nodeConfig[i]);\n                }\n                parent.appendChild(node);\n                node.loader = node.getOwnerTree().loader;\n\n                if (_node.children) {\n                    categoryLoader.buildCategoryTree(node, _node.children);\n                }\n            };\n\n            /**\n             * @param {Object} parent\n             * @param {Object} nodeConfig\n             * @returns {void}\n             */\n            categoryLoader.buildCategoryTree = function (parent, nodeConfig) {\n                var i = 0;\n\n                if (!nodeConfig) {\n                    return null;\n                }\n\n                if (parent && nodeConfig && nodeConfig.length) {\n                    for (i; i < nodeConfig.length; i++) {\n                        categoryLoader.processCategoryTree(parent, nodeConfig, i);\n                    }\n                }\n            };\n\n            /**\n             *\n             * @param {Object} hash\n             * @param {Object} node\n             * @returns {Object}\n             */\n            categoryLoader.buildHashChildren = function (hash, node) {\n                var i = 0,\n                    len;\n\n                if (node.childNodes.length > 0 || node.loaded === false && node.loading === false) {\n                    hash.children = [];\n\n                    for (i, len = node.childNodes.length; i < len; i++) {\n                        hash.children = hash.children ? hash.children : [];\n                        hash.children.push(this.buildHash(node.childNodes[i]));\n                    }\n                }\n\n                return hash;\n            };\n\n            /**\n             * @param {Object} node\n             * @returns {Object}\n             */\n            categoryLoader.buildHash = function (node) {\n                var hash = {};\n\n                hash = this.toArray(node.attributes);\n\n                return categoryLoader.buildHashChildren(hash, node);\n            };\n\n            /**\n             * @param {Object} attributes\n             * @returns {Object}\n             */\n            categoryLoader.toArray = function (attributes) {\n                data = {};\n\n                for (key in attributes) {\n\n                    if (attributes[key]) {\n                        data[key] = attributes[key];\n                    }\n                }\n\n                return data;\n            };\n\n            categoryLoader.on('beforeload', function (treeLoader, node) {\n                treeLoader.baseParams.id = node.attributes.id;\n                treeLoader.baseParams.selected = options.jsFormObject.updateElement.value;\n            });\n\n            categoryLoader.on('load', function () {\n                varienWindowOnload();\n            });\n\n            tree = new Ext.tree.TreePanel.Enhanced(options.divId, {\n                animate: false,\n                loader: categoryLoader,\n                enableDD: false,\n                containerScroll: true,\n                selModel: new Ext.tree.CheckNodeMultiSelectionModel(),\n                rootVisible: options.rootVisible,\n                useAjax: options.useAjax,\n                currentNodeId: options.currentNodeId,\n                addNodeTo: false,\n                rootUIProvider: Ext.tree.CheckboxNodeUI\n            });\n\n            tree.on('check', function (node) {\n                options.jsFormObject.updateElement.value = this.getChecked().join(', ');\n                varienElementMethods.setHasChanges(node.getUI().checkbox);\n            }, tree);\n\n            // set the root node\n            //jscs:disable requireCamelCaseOrUpperCaseIdentifiers\n            parameters = {\n                text: options.name,\n                draggable: false,\n                checked: options.checked,\n                uiProvider: Ext.tree.CheckboxNodeUI,\n                allowDrop: options.allowDrop,\n                id: options.rootId,\n                expanded: options.expanded,\n                category_id: options.categoryId\n            };\n            //jscs:enable requireCamelCaseOrUpperCaseIdentifiers\n\n            tree.loadTree({\n                parameters: parameters, data: options.treeJson\n            }, true);\n        });\n    };\n});\n","Magento_Catalog/js/edit-tree.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\n// jscs:disable jsDoc\n\nrequire([\n    'jquery',\n    'Magento_Ui/js/modal/confirm',\n    'Magento_Ui/js/modal/alert',\n    'loadingPopup',\n    'mage/backend/floating-header'\n], function (jQuery, confirm) {\n    'use strict';\n\n    /**\n     * Delete some category\n     * This routine get categoryId explicitly, so even if currently selected tree node is out of sync\n     * with this form, we surely delete same category in the tree and at backend.\n     *\n     * @deprecated\n     * @see deleteConfirm\n     */\n    function categoryDelete(url) {\n        confirm({\n            content: 'Are you sure you want to delete this category?',\n            actions: {\n                confirm: function () {\n                    location.href = url;\n                }\n            }\n        });\n    }\n\n    function displayLoadingMask() {\n        jQuery('body').loadingPopup();\n    }\n\n    window.categoryDelete = categoryDelete;\n    window.displayLoadingMask = displayLoadingMask;\n});\n","Magento_Catalog/js/custom-options-type.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'uiRegistry',\n    'Magento_Ui/js/form/element/ui-select'\n], function ($, _, registry, UiSelect) {\n    'use strict';\n\n    return UiSelect.extend({\n        defaults: {\n            previousGroup: null,\n            groupsConfig: {},\n            valuesMap: {},\n            indexesMap: {},\n            filterPlaceholder: 'ns = ${ $.ns }, parentScope = ${ $.parentScope }'\n        },\n\n        /**\n         * Initialize component.\n         * @returns {Element}\n         */\n        initialize: function () {\n            return this\n                ._super()\n                .initMapping()\n                .updateComponents(this.initialValue, true);\n        },\n\n        /**\n         * Create additional mappings.\n         *\n         * @returns {Element}\n         */\n        initMapping: function () {\n            _.each(this.groupsConfig, function (groupData, group) {\n                _.each(groupData.values, function (value) {\n                    this.valuesMap[value] = group;\n                }, this);\n\n                _.each(groupData.indexes, function (index) {\n                    if (!this.indexesMap[index]) {\n                        this.indexesMap[index] = [];\n                    }\n\n                    this.indexesMap[index].push(group);\n                }, this);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Callback that fires when 'value' property is updated.\n         *\n         * @param {String} currentValue\n         * @returns {*}\n         */\n        onUpdate: function (currentValue) {\n            this.updateComponents(currentValue);\n\n            return this._super();\n        },\n\n        /**\n         * Show, hide or clear components based on the current type value.\n         *\n         * @param {String} currentValue\n         * @param {Boolean} isInitialization\n         * @returns {Element}\n         */\n        updateComponents: function (currentValue, isInitialization) {\n            var currentGroup = this.valuesMap[currentValue];\n\n            if (currentGroup !== this.previousGroup) {\n                _.each(this.indexesMap, function (groups, index) {\n                    var template = this.filterPlaceholder + ', index = ' + index,\n                        visible = groups.indexOf(currentGroup) !== -1,\n                        component;\n\n                    switch (index) {\n                        case 'container_type_static':\n                        case 'values':\n                            template = 'ns=' + this.ns +\n                                ', dataScope=' + this.parentScope +\n                                ', index=' + index;\n                            break;\n                    }\n\n                    /*eslint-disable max-depth */\n                    if (isInitialization) {\n                        registry.async(template)(\n                            function (currentComponent) {\n                                currentComponent.visible(visible);\n                            }\n                        );\n                    } else {\n                        component = registry.get(template);\n\n                        if (component) {\n                            component.visible(visible);\n                        }\n                    }\n                }, this);\n\n                this.previousGroup = currentGroup;\n            }\n\n            return this;\n        }\n    });\n});\n","Magento_Catalog/js/options.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/* eslint-disable no-undef */\n// jscs:disable jsDoc\n\ndefine([\n    'jquery',\n    'mage/template',\n    'uiRegistry',\n    'jquery/ui',\n    'prototype',\n    'form',\n    'validation',\n    'mage/translate'\n], function (jQuery, mageTemplate, rg) {\n    'use strict';\n\n    return function (config) {\n        var optionPanel = jQuery('#manage-options-panel'),\n            editForm = jQuery('#edit_form'),\n            attributeOption = {\n                table: $('attribute-options-table'),\n                itemCount: 0,\n                totalItems: 0,\n                rendered: 0,\n                template: mageTemplate('#row-template'),\n                newOptionClass: 'new-option',\n                isReadOnly: config.isReadOnly,\n                add: function (data, render) {\n                    var isNewOption = false,\n                        element;\n\n                    if (typeof data.id == 'undefined') {\n                        data = {\n                            'id': 'option_' + this.itemCount,\n                            'sort_order': this.itemCount + 1,\n                            'rowClasses': this.newOptionClass\n                        };\n                        isNewOption = true;\n                    }\n\n                    if (!data.intype) {\n                        data.intype = this.getOptionInputType();\n                    }\n\n                    element = this.template({\n                        data: data\n                    });\n\n                    if (isNewOption && !this.isReadOnly) {\n                        this.enableNewOptionDeleteButton(data.id);\n                    }\n                    this.itemCount++;\n                    this.totalItems++;\n                    this.elements += element;\n\n                    if (render) {\n                        this.render();\n                        this.updateItemsCountField();\n                    }\n                },\n                remove: function (event) {\n                    var element = $(Event.findElement(event, 'tr')),\n                        elementFlags; // !!! Button already have table parent in safari\n\n                    // Safari workaround\n                    element.ancestors().each(function (parentItem) {\n                        if (parentItem.hasClassName('option-row')) {\n                            element = parentItem;\n                            throw $break;\n                        } else if (parentItem.hasClassName('box')) {\n                            throw $break;\n                        }\n                    });\n\n                    if (element) {\n                        elementFlags = element.getElementsByClassName('delete-flag');\n\n                        if (elementFlags[0]) {\n                            elementFlags[0].value = 1;\n                        }\n\n                        element.addClassName('no-display');\n                        element.addClassName('template');\n                        element.hide();\n                        this.totalItems--;\n                        this.updateItemsCountField();\n                    }\n\n                    if (element.hasClassName(this.newOptionClass)) {\n                        element.remove();\n                    }\n                },\n                updateItemsCountField: function () {\n                    $('option-count-check').value = this.totalItems > 0 ? '1' : '';\n                },\n                enableNewOptionDeleteButton: function (id) {\n                    $$('#delete_button_container_' + id + ' button').each(function (button) {\n                        button.enable();\n                        button.removeClassName('disabled');\n                    });\n                },\n                bindRemoveButtons: function () {\n                    jQuery('#swatch-visual-options-panel').on('click', '.delete-option', this.remove.bind(this));\n                },\n                render: function () {\n                    Element.insert($$('[data-role=options-container]')[0], this.elements);\n                    this.elements = '';\n                },\n                renderWithDelay: function (data, from, step, delay) {\n                    var arrayLength = data.length,\n                        len;\n\n                    for (len = from + step; from < len && from < arrayLength; from++) {\n                        this.add(data[from]);\n                    }\n                    this.render();\n\n                    if (from === arrayLength) {\n                        this.updateItemsCountField();\n                        this.rendered = 1;\n                        jQuery('body').trigger('processStop');\n\n                        return true;\n                    }\n                    setTimeout(this.renderWithDelay.bind(this, data, from, step, delay), delay);\n                },\n                ignoreValidate: function () {\n                    var ignore = '.ignore-validate input, ' +\n                        '.ignore-validate select, ' +\n                        '.ignore-validate textarea';\n\n                    jQuery('#edit_form').data('validator').settings.forceIgnore = ignore;\n                },\n                getOptionInputType: function () {\n                    var optionDefaultInputType = 'radio';\n\n                    if ($('frontend_input') && $('frontend_input').value === 'multiselect') {\n                        optionDefaultInputType = 'checkbox';\n                    }\n\n                    return optionDefaultInputType;\n                }\n            },\n            tableBody = jQuery(),\n            activePanelClass = 'selected-type-options';\n\n        if ($('add_new_option_button')) {\n            Event.observe('add_new_option_button', 'click', attributeOption.add.bind(attributeOption, {}, true));\n        }\n        $('manage-options-panel').on('click', '.delete-option', function (event) {\n            attributeOption.remove(event);\n        });\n\n        optionPanel.on('render', function () {\n            attributeOption.ignoreValidate();\n\n            if (attributeOption.rendered) {\n                return false;\n            }\n            jQuery('body').trigger('processStart');\n            attributeOption.renderWithDelay(config.attributesData, 0, 100, 300);\n            attributeOption.bindRemoveButtons();\n        });\n\n        if (config.isSortable) {\n            jQuery(function ($) {\n                $('[data-role=options-container]').sortable({\n                    distance: 8,\n                    tolerance: 'pointer',\n                    cancel: 'input, button',\n                    axis: 'y',\n                    update: function () {\n                        $('[data-role=options-container] [data-role=order]').each(function (index, element) {\n                            $(element).val(index + 1);\n                        });\n                    }\n                });\n            });\n        }\n        editForm.on('beforeSubmit', function () {\n            var optionContainer = optionPanel.find('table tbody'),\n                optionsValues;\n\n            if (optionPanel.hasClass(activePanelClass)) {\n                optionsValues = jQuery.map(\n                    optionContainer.find('tr'),\n                    function (row) {\n                        return jQuery(row).find('input, select, textarea').serialize();\n                    }\n                );\n                jQuery('<input>')\n                    .attr({\n                        type: 'hidden',\n                        name: 'serialized_options'\n                    })\n                    .val(JSON.stringify(optionsValues))\n                    .prependTo(editForm);\n            }\n            tableBody = optionContainer.detach();\n        });\n        editForm.on('afterValidate.error highlight.validate', function () {\n            if (optionPanel.hasClass(activePanelClass)) {\n                optionPanel.find('table').append(tableBody);\n                jQuery('input[name=\"serialized_options\"]').remove();\n            }\n        });\n        window.attributeOption = attributeOption;\n        window.optionDefaultInputType = attributeOption.getOptionInputType();\n\n        rg.set('manage-options-panel', attributeOption);\n    };\n});\n","Magento_Catalog/js/bundle-proxy-button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n * @deprecated since version 2.2.0\n */\ndefine([\n    'Magento_Ui/js/form/components/button',\n    'uiRegistry',\n    'underscore'\n], function (Button, registry, _) {\n    'use strict';\n\n    return Button.extend({\n        defaults: {\n            currentRecordNamespace: 'bundle_current_record',\n            listingDataProvider: '',\n            value: [],\n            imports: {\n                currentRecordName: '${ $.provider }:${ $.currentRecordNamespace }',\n                listingData: '${ $.provider }:${ $.listingDataProvider }'\n            },\n            links: {\n                value: '${ $.provider }:${ $.dataScope }'\n            },\n            listens: {\n                listingData: 'setListingData'\n            }\n        },\n\n        /**\n         * Initializes component.\n         *\n         * @returns {Object} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initSource();\n\n            return this;\n        },\n\n        /**\n         * Calls 'initObservable' of parent\n         *\n         * @returns {Object} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe([\n                    'value',\n                    'listingData'\n                ]);\n\n            return this;\n        },\n\n        /**\n         * Calls 'destroy' of parent and\n         * clear listing provider source\n         *\n         * @returns {Object} Chainable.\n         */\n        destroy: function () {\n            this._super();\n            this.source.set(this.listingDataProvider, []);\n\n            return this;\n        },\n\n        /**\n         * Call parent \"action\" method\n         * and set new data to record and listing.\n         *\n         * @returns {Object} Chainable.\n         */\n\n        action: function () {\n            this._super();\n            this.source.set(this.currentRecordNamespace, this.name);\n            this.source.set(this.listingDataProvider, this.value());\n\n            return this;\n        },\n\n        /**\n         * Init current source.\n         *\n         * @returns {Object} Chainable.\n         */\n        initSource: function () {\n            if (!_.isFunction(this.source)) {\n                this.source = registry.get(this.provider);\n            }\n\n            return this;\n        },\n\n        /**\n         * Set data to listing source.\n         *\n         * @returns {Object} Chainable.\n         */\n        setListingData: function (data) {\n            if (this.name === this.currentRecordName) {\n                this.source.set(this.dataScope, data);\n            }\n\n            return this;\n        }\n    });\n});\n","Magento_Catalog/js/custom-options.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/template',\n    'Magento_Ui/js/modal/alert',\n    'jquery/ui',\n    'useDefault',\n    'collapsable',\n    'mage/translate',\n    'mage/backend/validation',\n    'Magento_Ui/js/modal/modal'\n], function ($, mageTemplate, alert) {\n    'use strict';\n\n    $.widget('mage.customOptions', {\n        options: {\n            selectionItemCount: {}\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            this.baseTmpl = mageTemplate('#custom-option-base-template');\n            this.rowTmpl = mageTemplate('#custom-option-select-type-row-template');\n\n            this._initOptionBoxes();\n            this._initSortableSelections();\n            this._bindCheckboxHandlers();\n            this._bindReadOnlyMode();\n            this._addValidation();\n        },\n\n        /**\n         * @private\n         */\n        _addValidation: function () {\n            $.validator.addMethod(\n                'required-option-select', function (value) {\n                    return value !== '';\n                }, $.mage.__('Select type of option.'));\n\n            $.validator.addMethod(\n                'required-option-select-type-rows', function (value, element) {\n                    var optionContainerElm = element.up('div[id*=_type_]'),\n                        selectTypesFlag = false,\n                        selectTypeElements = $('#' + optionContainerElm.id + ' .select-type-title');\n\n                    selectTypeElements.each(function () {\n                        if (!$(this).closest('tr').hasClass('ignore-validate')) {\n                            selectTypesFlag = true;\n                        }\n                    });\n\n                    return selectTypesFlag;\n                }, $.mage.__('Please add rows to option.'));\n        },\n\n        /**\n         * @private\n         */\n        _initOptionBoxes: function () {\n            var syncOptionTitle;\n\n            if (!this.options.isReadonly) {\n                this.element.sortable({\n                    axis: 'y',\n                    handle: '[data-role=draggable-handle]',\n                    items: '#product_options_container_top > div',\n                    update: this._updateOptionBoxPositions,\n                    tolerance: 'pointer'\n                });\n            }\n\n            /**\n             * @param {jQuery.Event} event\n             */\n            syncOptionTitle = function (event) {\n                var currentValue = $(event.target).val(),\n                    optionBoxTitle = $(\n                        '.admin__collapsible-title > span',\n                        $(event.target).closest('.fieldset-wrapper')\n                    ),\n                    newOptionTitle = $.mage.__('New Option');\n\n                optionBoxTitle.text(currentValue === '' ? newOptionTitle : currentValue);\n            };\n            this._on({\n                /**\n                 * Reset field value to Default\n                 */\n                'click .use-default-label': function (event) {\n                    $(event.target).closest('label').find('input').prop('checked', true).trigger('change');\n                },\n\n                /**\n                 * Remove custom option or option row for 'select' type of custom option\n                 */\n                'click button[id^=product_option_][id$=_delete]': function (event) {\n                    var element = $(event.target).closest('#product_options_container_top > div.fieldset-wrapper,tr');\n\n                    if (element.length) {\n                        $('#product_' + element.attr('id').replace('product_', '') + '_is_delete').val(1);\n                        element.addClass('ignore-validate').hide();\n                        this.refreshSortableElements();\n                    }\n                },\n\n                /**\n                 * Minimize custom option block\n                 */\n                'click #product_options_container_top [data-target$=-content]': function () {\n                    if (this.options.isReadonly) {\n                        return false;\n                    }\n                },\n\n                /**\n                 * Add new custom option\n                 */\n                'click #add_new_defined_option': function (event) {\n                    this.addOption(event);\n                },\n\n                /**\n                 * Add new option row for 'select' type of custom option\n                 */\n                'click button[id^=product_option_][id$=_add_select_row]': function (event) {\n                    this.addSelection(event);\n                },\n\n                /**\n                 * Import custom options from products\n                 */\n                'click #import_new_defined_option': function () {\n                    var importContainer = $('#import-container'),\n                        widget = this;\n\n                    importContainer.modal({\n                        title: $.mage.__('Select Product'),\n                        type: 'slide',\n\n                        /** @inheritdoc */\n                        opened: function () {\n                            $(document).off().on('click', '#productGrid_massaction-form button', function () {\n                                $('.import-custom-options-apply-button').trigger('click', 'massActionTrigger');\n                            });\n                        },\n                        buttons: [{\n                            text: $.mage.__('Import'),\n                            attr: {\n                                id: 'import-custom-options-apply-button'\n                            },\n                            'class': 'action-primary action-import import-custom-options-apply-button',\n\n                            /** @inheritdoc */\n                            click: function (event, massActionTrigger) {\n                                var request = [];\n\n                                $(this.element).find('input[name=product]:checked').map(function () {\n                                    request.push(this.value);\n                                });\n\n                                if (request.length === 0) {\n                                    if (!massActionTrigger) {\n                                        alert({\n                                            content: $.mage.__('An item needs to be selected. Select and try again.')\n                                        });\n                                    }\n\n                                    return;\n                                }\n\n                                $.post(widget.options.customOptionsUrl, {\n                                    'products[]': request,\n                                    'form_key': widget.options.formKey\n                                }, function ($data) {\n                                    $.each(JSON.parse($data), function (el) {\n                                        var i;\n\n                                        el.id = widget.getFreeOptionId(el.id);\n                                        el['option_id'] = el.id;\n\n                                        if (typeof el.optionValues !== 'undefined') {\n                                            for (i = 0; i < el.optionValues.length; i++) {\n                                                el.optionValues[i]['option_id'] = el.id;\n                                            }\n                                        }\n                                        //Adding option\n                                        widget.addOption(el);\n                                        //Will save new option on server side\n                                        $('#product_option_' + el.id + '_option_id').val(0);\n                                        $('#option_' + el.id + ' input[name$=\"option_type_id]\"]').val(-1);\n                                    });\n                                    importContainer.modal('closeModal');\n                                });\n                            }\n                        }]\n                    });\n                    importContainer.load(\n                        this.options.productGridUrl,\n                        {\n                            'form_key': this.options.formKey,\n                            'current_product_id': this.options.currentProductId\n                        },\n                        function () {\n                            importContainer.modal('openModal');\n                        }\n                    );\n                },\n\n                /**\n                 * Change custom option type\n                 */\n                'change select[id^=product_option_][id$=_type]': function (event, data) {\n                    var widget = this,\n                        currentElement = $(event.target),\n                        parentId = '#' + currentElement.closest('.fieldset-alt').attr('id'),\n                        group = currentElement.find('[value=\"' + currentElement.val() + '\"]')\n                            .closest('optgroup').attr('data-optgroup-name'),\n                        previousGroup = $(parentId + '_previous_group').val(),\n                        previousBlock = $(parentId + '_type_' + previousGroup),\n                        tmpl, disabledBlock, priceType;\n\n                    data = data || {};\n\n                    if (typeof group !== 'undefined') {\n                        group = group.toLowerCase();\n                    }\n\n                    if (previousGroup !== group) {\n                        if (previousBlock.length) {\n                            previousBlock.addClass('ignore-validate').hide();\n                        }\n                        $(parentId + '_previous_group').val(group);\n\n                        if (typeof group === 'undefined') {\n                            return;\n                        }\n                        disabledBlock = $(parentId).find(parentId + '_type_' + group);\n\n                        if (disabledBlock.length) {\n                            disabledBlock.removeClass('ignore-validate').show();\n                        } else {\n                            if ($.isEmptyObject(data)) { //eslint-disable-line max-depth\n                                data['option_id'] = $(parentId + '_id').val();\n                                data.price = data.sku = '';\n                            }\n                            data.group = group;\n\n                            tmpl = widget.element.find('#custom-option-' + group + '-type-template').html();\n                            tmpl = mageTemplate(tmpl, {\n                                data: data\n                            });\n\n                            $(tmpl).insertAfter($(parentId));\n\n                            if (data['price_type']) { //eslint-disable-line max-depth\n                                priceType = $('#' + widget.options.fieldId + '_' + data['option_id'] + '_price_type');\n                                priceType.val(data['price_type']).attr('data-store-label', data['price_type']);\n                            }\n                            this._bindUseDefault(widget.options.fieldId + '_' + data['option_id'], data);\n                            //Add selections\n\n                            if (data.optionValues) { //eslint-disable-line max-depth\n                                data.optionValues.each(function (value) {\n                                    widget.addSelection(value);\n                                });\n                            }\n                        }\n                    }\n                },\n                //Sync title\n                'change .field-option-title > .control > input[id$=\"_title\"]': syncOptionTitle,\n                'keyup .field-option-title > .control > input[id$=\"_title\"]': syncOptionTitle,\n                'paste .field-option-title > .control > input[id$=\"_title\"]': syncOptionTitle\n            });\n        },\n\n        /**\n         * @private\n         */\n        _initSortableSelections: function () {\n            if (!this.options.isReadonly) {\n                this.element.find('[id^=product_option_][id$=_type_select] tbody').sortable({\n                    axis: 'y',\n                    handle: '[data-role=draggable-handle]',\n\n                    /** @inheritdoc */\n                    helper: function (event, ui) {\n                        ui.children().each(function () {\n                            $(this).width($(this).width());\n                        });\n\n                        return ui;\n                    },\n                    update: this._updateSelectionsPositions,\n                    tolerance: 'pointer'\n                });\n            }\n        },\n\n        /**\n         * Sync sort order checkbox with hidden dropdown\n         */\n        _bindCheckboxHandlers: function () {\n            this._on({\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                'change [id^=product_option_][id$=_required]': function (event) {\n                    var $this = $(event.target);\n\n                    $this.closest('#product_options_container_top > div')\n                        .find('[name$=\"[is_require]\"]').val($this.is(':checked') ? 1 : 0);\n                }\n            });\n            this.element.find('[id^=product_option_][id$=_required]').each(function () {\n                $(this).prop('checked', $(this).closest('#product_options_container_top > div')\n                        .find('[name$=\"[is_require]\"]').val() > 0);\n            });\n        },\n\n        /**\n         * Update Custom option position\n         */\n        _updateOptionBoxPositions: function () {\n            $(this).find('div[id^=option_]:not(.ignore-validate) .fieldset-alt > [name$=\"[sort_order]\"]').each(\n                function (index) {\n                    $(this).val(index);\n                });\n        },\n\n        /**\n         * Update selections positions for 'select' type of custom option\n         */\n        _updateSelectionsPositions: function () {\n            $(this).find('tr:not(.ignore-validate) [name$=\"[sort_order]\"]').each(function (index) {\n                $(this).val(index);\n            });\n        },\n\n        /**\n         * Disable input data if \"Read Only\"\n         */\n        _bindReadOnlyMode: function () {\n            if (this.options.isReadonly) {\n                $('div.product-custom-options').find('button,input,select,textarea').each(function () {\n                    $(this).prop('disabled', true);\n\n                    if ($(this).is('button')) {\n                        $(this).addClass('disabled');\n                    }\n                });\n            }\n        },\n\n        /**\n         * @param {String} id\n         * @param {Object} data\n         * @private\n         */\n        _bindUseDefault: function (id, data) {\n            var title = $('#' + id + '_title'),\n                price = $('#' + id + '_price'),\n                priceType = $('#' + id + '_price_type');\n\n            //enable 'use default' link for title\n            if (data.checkboxScopeTitle) {\n                title.useDefault({\n                    field: '.field',\n                    useDefault: 'label[for$=_title]',\n                    checkbox: 'input[id$=_title_use_default]',\n                    label: 'span'\n                });\n            }\n            //enable 'use default' link for price and price_type\n            if (data.checkboxScopePrice) {\n                price.useDefault({\n                    field: '.field',\n                    useDefault: 'label[for$=_price]',\n                    checkbox: 'input[id$=_price_use_default]',\n                    label: 'span'\n                });\n                //not work set default value for second field\n                priceType.useDefault({\n                    field: '.field',\n                    useDefault: 'label[for$=_price]',\n                    checkbox: 'input[id$=_price_use_default]',\n                    label: 'span'\n                });\n            }\n        },\n\n        /**\n         * Add selection value for 'select' type of custom option\n         */\n        addSelection: function (event) {\n            var data = {},\n                element = event.target || event.srcElement || event.currentTarget,\n                rowTmpl, priceType;\n\n            if (typeof element !== 'undefined') {\n                data.id = $(element).closest('#product_options_container_top > div')\n                    .find('[name^=\"product[options]\"][name$=\"[id]\"]').val();\n                data['option_type_id'] = -1;\n\n                if (!this.options.selectionItemCount[data.id]) {\n                    this.options.selectionItemCount[data.id] = 1;\n                }\n\n                data['select_id'] = this.options.selectionItemCount[data.id];\n                data.price = data.sku = '';\n            } else {\n                data = event;\n                data.id = data['option_id'];\n                data['select_id'] = data['option_type_id'];\n                this.options.selectionItemCount[data.id] = data['item_count'];\n            }\n\n            rowTmpl = this.rowTmpl({\n                data: data\n            });\n\n            $(rowTmpl).appendTo($('#select_option_type_row_' + data.id));\n\n            //set selected price_type value if set\n            if (data['price_type']) {\n                priceType = $('#' + this.options.fieldId + '_' + data.id + '_select_' + data['select_id'] +\n                    '_price_type');\n                priceType.val(data['price_type']).attr('data-store-label', data['price_type']);\n            }\n\n            this._bindUseDefault(this.options.fieldId + '_' + data.id + '_select_' + data['select_id'], data);\n            this.refreshSortableElements();\n            this.options.selectionItemCount[data.id] = parseInt(this.options.selectionItemCount[data.id], 10) + 1;\n\n            $('#' + this.options.fieldId + '_' + data.id + '_select_' + data['select_id'] + '_title').trigger('focus');\n        },\n\n        /**\n         * Add custom option\n         */\n        addOption: function (event) {\n            var data = {},\n                element = event.target || event.srcElement || event.currentTarget,\n                baseTmpl;\n\n            if (typeof element !== 'undefined') {\n                data.id = this.options.itemCount;\n                data.type = '';\n                data['option_id'] = 0;\n            } else {\n                data = event;\n                this.options.itemCount = data['item_count'];\n            }\n\n            baseTmpl = this.baseTmpl({\n                data: data\n            });\n\n            $(baseTmpl)\n                .appendTo(this.element.find('#product_options_container_top'))\n                .find('.collapse').collapsable();\n\n            //set selected type value if set\n            if (data.type) {\n                $('#' + this.options.fieldId + '_' + data.id + '_type').val(data.type).trigger('change', data);\n            }\n\n            //set selected is_require value if set\n            if (data['is_require']) {\n                $('#' + this.options.fieldId + '_' + data.id + '_is_require').val(data['is_require']).trigger('change');\n            }\n\n            this.refreshSortableElements();\n            this._bindCheckboxHandlers();\n            this._bindReadOnlyMode();\n            this.options.itemCount++;\n            $('#' + this.options.fieldId + '_' + data.id + '_title').trigger('change');\n        },\n\n        /**\n         * @return {Object}\n         */\n        refreshSortableElements: function () {\n            if (!this.options.isReadonly) {\n                this.element.sortable('refresh');\n                this._updateOptionBoxPositions.apply(this.element);\n                this._updateSelectionsPositions.apply(this.element);\n                this._initSortableSelections();\n            }\n\n            return this;\n        },\n\n        /**\n         * @param {String} id\n         * @return {*}\n         */\n        getFreeOptionId: function (id) {\n            return $('#' + this.options.fieldId + '_' + id).length ? this.getFreeOptionId(parseInt(id, 10) + 1) : id;\n        }\n    });\n\n});\n","Magento_Catalog/js/product/name.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    'Magento_Catalog/js/product/list/column-status-validator',\n    'escaper'\n], function (Column, columnStatusValidator, escaper) {\n    'use strict';\n\n    return Column.extend({\n        defaults: {\n            allowedTags: ['div', 'span', 'b', 'strong', 'i', 'em', 'u', 'a']\n        },\n\n        /**\n         * Depends on this option, product name can be shown or hide. Depends on  backend configuration\n         *\n         * @returns {Boolean}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'name', 'show_attributes');\n        },\n\n        /**\n         * Name column.\n         *\n         * @param {String} label\n         * @returns {String}\n         */\n        getNameUnsanitizedHtml: function (label) {\n            return escaper.escapeHtml(label, this.allowedTags);\n        }\n    });\n});\n","Magento_Catalog/js/product/addtocart-button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/grid/columns/column',\n    'Magento_Catalog/js/product/uenc-processor',\n    'Magento_Catalog/js/product/list/column-status-validator'\n], function (Element, uencProcessor, columnStatusValidator) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            label: ''\n        },\n\n        /**\n         * Prepare data, that will be inserted as data-mage-init attribute into button. With help of this attribute\n         * Add To * buttons can understand post data and urls\n         *\n         * @param {Object} row\n         * @returns {String}\n         */\n        getDataMageInit: function (row) {\n            return '{\"redirectUrl\": { \"url\" : \"'  + uencProcessor(row['add_to_cart_button'].url) + '\"}}';\n        },\n\n        /**\n         * Prepare Data-Post data that will be used in data-mage-init\n         *\n         * @param {Object} row\n         * @return {String}\n         */\n        getDataPost: function (row) {\n            return uencProcessor(row['add_to_cart_button']['post_data']);\n        },\n\n        /**\n         * Check if product has required options.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        hasRequiredOptions: function (row) {\n            return row['add_to_cart_button']['required_options'];\n        },\n\n        /**\n         * Depends on this option, \"Add to cart\" button can be shown or hide\n         *\n         * @param {Object} row\n         * @returns {Boolean}\n         */\n        isSalable: function (row) {\n            return row['is_salable'];\n        },\n\n        /**\n         * Depends on this option, stock status text can be \"In stock\" or \"Out Of Stock\"\n         *\n         * @param {Object} row\n         * @returns {Boolean}\n         */\n        isAvailable: function (row) {\n            return row['is_available'];\n        },\n\n        /**\n         * Depends on this option, \"Add to cart\" button can be shown or hide. Depends on  backend configuration\n         *\n         * @returns {Boolean}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'add_to_cart', 'show_buttons');\n        },\n\n        /**\n         * Get button label.\n         *\n         * @return {String}\n         */\n        getLabel: function () {\n            return this.label;\n        }\n    });\n});\n","Magento_Catalog/js/product/addtocompare-button.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/grid/columns/column',\n    'Magento_Catalog/js/product/uenc-processor',\n    'Magento_Catalog/js/product/list/column-status-validator'\n], function (Column, uencProcessor, columnStatusValidator) {\n    'use strict';\n\n    return Column.extend({\n        defaults: {\n            label: ''\n        },\n\n        /**\n         * Prepare Data-Post data that will be used in data-mage-init\n         *\n         * @param {Object} row\n         * @returns {Array}\n         */\n        getDataPost: function (row) {\n            return uencProcessor(row['add_to_compare_button'].url ||\n                    row['add_to_compare_button']['post_data']);\n        },\n\n        /**\n         * Depends on this option, \"Add to compare\" button can be shown or hide. Depends on  backend configuration\n         *\n         * @returns {Boolean}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'add_to_compare', 'show_buttons');\n        },\n\n        /**\n         * Get button label.\n         *\n         * @return {String}\n         */\n        getLabel: function () {\n            return this.label;\n        }\n    });\n});\n","Magento_Catalog/js/product/learn-more.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/grid/columns/column',\n    'Magento_Catalog/js/product/list/column-status-validator'\n], function (Column, columnStatusValidator) {\n    'use strict';\n\n    return Column.extend({\n        /**\n         * Depends on this option, \"Learn More\" link can be shown or hide. Depends on  backend configuration\n         *\n         * @returns {Boolean}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'learn_more', 'show_attributes');\n        }\n    });\n});\n","Magento_Catalog/js/product/weight-handler.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], function ($) {\n    'use strict';\n\n    return {\n\n        /**\n         * Get weight\n         * @returns {*|jQuery|HTMLElement}\n         */\n        $weight: function () {\n            return $('#weight');\n        },\n\n        /**\n         * Weight Switcher\n         * @returns {*|jQuery|HTMLElement}\n         */\n        $weightSwitcher: function () {\n            return $('[data-role=weight-switcher]');\n        },\n\n        /**\n         * Weight Change Toggle\n         * @returns {*|jQuery|HTMLElement}\n         */\n        $weightChangeToggle: function () {\n            return $('#toggle_weight');\n        },\n\n        /**\n         * Is locked\n         * @returns {*}\n         */\n        isLocked: function () {\n            return this.$weight().is('[data-locked]');\n        },\n\n        /**\n         * Disabled\n         */\n        disabled: function () {\n            this.$weight().addClass('ignore-validate').prop('disabled', true);\n        },\n\n        /**\n         * Enabled\n         */\n        enabled: function () {\n            this.$weight().removeClass('ignore-validate').prop('disabled', false);\n        },\n\n        /**\n         * Disabled Switcher\n         */\n        disabledSwitcher: function () {\n            this.$weightSwitcher().find('input[type=\"radio\"]').addClass('ignore-validate').prop('disabled', true);\n        },\n\n        /**\n         * Enabled Switcher\n         */\n        enabledSwitcher: function () {\n            this.$weightSwitcher().find('input[type=\"radio\"]').removeClass('ignore-validate').prop('disabled', false);\n        },\n\n        /**\n         * Switch Weight\n         * @returns {*}\n         */\n        switchWeight: function () {\n            if (this.hasWeightChangeToggle()) {\n                return;\n            }\n\n            return this.productHasWeightBySwitcher() ? this.enabled() : this.disabled();\n        },\n\n        /**\n         * Toggle Switcher\n         */\n        toggleSwitcher: function () {\n            this.isWeightChanging() ? this.enabledSwitcher() : this.disabledSwitcher();\n        },\n\n        /**\n         * Hide weight switcher\n         */\n        hideWeightSwitcher: function () {\n            this.$weightSwitcher().hide();\n        },\n\n        /**\n         * Has weight switcher\n         * @returns {*}\n         */\n        hasWeightSwitcher: function () {\n            return this.$weightSwitcher().is(':visible');\n        },\n\n        /**\n         * Has weight\n         * @returns {*}\n         */\n        hasWeight: function () {\n            return this.$weight.is(':visible');\n        },\n\n        /**\n         * Has weight change toggle\n         * @returns {*}\n         */\n        hasWeightChangeToggle: function () {\n            return this.$weightChangeToggle().is(':visible');\n        },\n\n        /**\n         * Product has weight\n         * @returns {Bool}\n         */\n        productHasWeightBySwitcher: function () {\n            return $('input:checked', this.$weightSwitcher()).val() === '1';\n        },\n\n        /**\n         * Product weight toggle is checked\n         * @returns {Bool}\n         */\n        isWeightChanging: function () {\n            return this.$weightChangeToggle().is(':checked');\n        },\n\n        /**\n         * Change\n         * @param {String} data\n         */\n        change: function (data) {\n            var value = data !== undefined ? +data : !this.productHasWeightBySwitcher();\n\n            $('input[value=' + value + ']', this.$weightSwitcher()).prop('checked', true);\n            this.switchWeight();\n        },\n\n        /**\n         * Constructor component\n         */\n        'Magento_Catalog/js/product/weight-handler': function () {\n            this.bindAll();\n\n            if (this.hasWeightSwitcher()) {\n                this.switchWeight();\n            }\n\n            if (this.hasWeightChangeToggle()) {\n                this.toggleSwitcher();\n            }\n        },\n\n        /**\n         * Bind all\n         */\n        bindAll: function () {\n            this.$weightSwitcher().find('input').on('change', this.switchWeight.bind(this));\n        }\n    };\n});\n","Magento_Catalog/js/product/list/column-status-validator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore'\n], function (_) {\n    'use strict';\n\n    return _.extend({\n        /**\n         * Check whether we can show column depends on server settings or not\n         *\n         * @param {Object} source\n         * @param {String} attributeCode\n         * @param {String} type\n         * @returns {Boolean}\n         */\n        isValid: function (source, attributeCode, type) {\n            var attributes;\n\n            if (!source[type]) {\n                return false;\n            }\n\n            attributes = source[type].split(',');\n\n            return _.contains(attributes, attributeCode);\n        }\n    });\n});\n","Magento_Catalog/js/product/list/listing.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'Magento_Ui/js/grid/listing'\n], function (ko, _, Listing) {\n    'use strict';\n\n    return Listing.extend({\n        defaults: {\n            additionalClasses: '',\n            filteredRows: {},\n            limit: 5,\n            listens: {\n                elems: 'filterRowsFromCache',\n                '${ $.provider }:data.items': 'filterRowsFromServer'\n            }\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n            this.filteredRows = ko.observable();\n            this.initProductsLimit();\n            this.hideLoader();\n        },\n\n        /**\n         * Initialize product limit\n         * Product limit can be configured through Ui component.\n         * Product limit are present in widget form\n         *\n         * @returns {exports}\n         */\n        initProductsLimit: function () {\n            if (this.source['page_size']) {\n                this.limit = this.source['page_size'];\n            }\n\n            return this;\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Listing} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .track({\n                    rows: []\n                });\n\n            return this;\n        },\n\n        /**\n         * Sort and filter rows, that are already in magento storage cache\n         *\n         * @return void\n         */\n        filterRowsFromCache: function () {\n            this._filterRows(this.rows);\n        },\n\n        /**\n         * Sort and filter rows, that are come from backend\n         *\n         * @param {Object} rows\n         */\n        filterRowsFromServer: function (rows) {\n            this._filterRows(rows);\n        },\n\n        /**\n         * Filter rows by limit and sort them\n         *\n         * @param {Array} rows\n         * @private\n         */\n        _filterRows: function (rows) {\n            this.filteredRows(_.sortBy(rows, 'added_at').reverse().slice(0, this.limit));\n        },\n\n        /**\n         * Can retrieve product url\n         *\n         * @param {Object} row\n         * @returns {String}\n         */\n        getUrl: function (row) {\n            return row.url;\n        },\n\n        /**\n         * Get product attribute by code.\n         *\n         * @param {String} code\n         * @return {Object}\n         */\n        getComponentByCode: function (code) {\n            var elems = this.elems() ? this.elems() : ko.getObservable(this, 'elems'),\n                component;\n\n            component = _.filter(elems, function (elem) {\n                return elem.index === code;\n            }, this).pop();\n\n            return component;\n        }\n    });\n});\n","Magento_Catalog/js/product/list/columns/image.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'Magento_Ui/js/grid/columns/column',\n    'Magento_Catalog/js/product/list/column-status-validator'\n], function (_, Element, columnStatusValidator) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            bodyTmpl: 'Magento_Catalog/product/list/columns/image',\n            imageCode: 'default',\n            image: {}\n        },\n\n        /**\n         * Find image by code in scope of images\n         *\n         * @param {Object} images\n         * @returns {*|T}\n         */\n        getImage: function (images) {\n            return _.filter(images, function (image) {\n                return this.imageCode === image.code;\n            }, this).pop();\n        },\n\n        /**\n         * Get image path.\n         *\n         * @param {Object} row\n         * @return {String}\n         */\n        getImageUrl: function (row) {\n            return this.getImage(row.images).url;\n        },\n\n        /**\n         * Get image box width.\n         *\n         * @param {Object} row\n         * @return {Number}\n         */\n        getWidth: function (row) {\n            return this.getImage(row.images).width;\n        },\n\n        /**\n         * Get image box height.\n         *\n         * @param {Object} row\n         * @return {Number}\n         */\n        getHeight: function (row) {\n            return this.getImage(row.images).height;\n        },\n\n        /**\n         * Get resized image width.\n         *\n         * @param {Object} row\n         * @return {Number}\n         */\n        getResizedImageWidth: function (row) {\n            return this.getImage(row.images)['resized_width'];\n        },\n\n        /**\n         * Get resized image height.\n         *\n         * @param {Object} row\n         * @return {Number}\n         */\n        getResizedImageHeight: function (row) {\n            return this.getImage(row.images)['resized_height'];\n        },\n\n        /**\n         * Get image alt text.\n         *\n         * @param {Object} row\n         * @return {String}\n         */\n        getLabel: function (row) {\n            if (!this.imageExists(row)) {\n                return this._super();\n            }\n\n            return this.getImage(row.images).label;\n        },\n\n        /**\n         * Check if image exist.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        imageExists: function (row) {\n            return this.getImage(row.images) !== 'undefined';\n        },\n\n        /**\n         * Check if component must be shown.\n         *\n         * @return {Boolean}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'image', 'show_attributes');\n        }\n    });\n});\n","Magento_Catalog/js/product/list/columns/pricetype-box.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'underscore',\n    'uiCollection'\n], function (ko, _, Collection) {\n    'use strict';\n\n    return Collection.extend({\n        /**\n         * Find from all price ui components, price with specific code, init source on it and set priceType\n         *\n         * @param {String} code\n         * @returns {*|T}\n         */\n        getPriceByCode: function (code) {\n            var elems = this.elems() ? this.elems() : ko.getObservable(this, 'elems'),\n                price;\n\n            price = _.filter(elems, function (elem) {\n                return elem.index.split('.').shift() === code;\n            }, this).pop();\n\n            price.source = this.source();\n            price.priceType = code;\n\n            return price;\n        },\n\n        /**\n         * Retrieve body template\n         *\n         * @returns {String}\n         */\n        getBody: function () {\n            return this.bodyTmpl;\n        },\n\n        /**\n         * Check whether price has price range, depends on different options, that can be choose\n         *\n         * @param {Object} row\n         * @returns {Boolean}\n         */\n        hasPriceRange: function (row) {\n            return row['price_info']['max_regular_price'] !== row['price_info']['min_regular_price'];\n        }\n    });\n});\n","Magento_Catalog/js/product/list/columns/price-box.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'underscore',\n    'uiRegistry',\n    'mageUtils',\n    'uiCollection',\n    'Magento_Catalog/js/product/list/column-status-validator',\n    'uiLayout'\n], function (ko, _, registry, utils, Collection, columnStatusValidator, layout) {\n    'use strict';\n\n    return Collection.extend({\n        defaults: {\n            label: '',\n            hasSpecialPrice: false,\n            showMinimalPrice: false,\n            useLinkForAsLowAs: false,\n            visible: true,\n            headerTmpl: 'ui/grid/columns/text',\n            bodyTmpl: 'Magento_Catalog/product/price/price_box',\n            disableAction: false,\n            controlVisibility: true,\n            sortable: false,\n            sorting: false,\n            draggable: true,\n            fieldClass: {},\n            renders: {\n                default: {}\n            },\n            ignoreTmpls: {\n                fieldAction: true\n            },\n            statefull: {\n                visible: true,\n                sorting: true\n            },\n            imports: {\n                exportSorting: 'sorting'\n            },\n            listens: {\n                elems: ''\n            },\n            modules: {\n                source: '${ $.provider }'\n            },\n            pricesInit: {}\n        },\n\n        /**\n         * Sort prices api\n         *\n         * @returns {exports}\n         */\n        sort: function () {\n            return this;\n        },\n\n        /**\n         * Check whether is allowed to render price or not\n         *\n         * @returns {*}\n         */\n        isAllowed: function () {\n            return columnStatusValidator.isValid(this.source(), 'price', 'show_attributes');\n        },\n\n        /**\n         * Retrieve array of prices, that should be rendered for specific product\n         *\n         * @param {Array} row\n         * @return {Array}\n         */\n        getPrices: function (row) {\n            var elems = this.elems() ? this.elems() : ko.getObservable(this, 'elems'),\n                result;\n\n            //we cant take type of product from row\n            this.initPrices(row);\n            result = _.filter(elems, function (elem) {\n                return elem.productType === row.type;\n            });\n\n            return result;\n        },\n\n        /**\n         * Recursive Merging of objects\n         *\n         * @param {Array} target\n         * @param {Array} source\n         * @returns {Array}\n         * @private\n         */\n        _deepObjectExtend: function (target, source) {\n            var _target = utils.copy(target);\n\n            _.each(source, function (value, key) {\n                if (_.keys(value).length && typeof _target[key] !== 'undefined') {\n                    _target[key] = this._deepObjectExtend(_target[key], value);\n                } else {\n                    _target[key] = value;\n                }\n            }, this);\n\n            return _target;\n        },\n\n        /**\n         * Init price type box, in cases when product type has custom component or bodyTmpl\n         *\n         * @param {String} productType\n         * @private\n         */\n        _initPriceWithCustomMetaData: function (productType) {\n            var price = this._deepObjectExtend(\n                this.renders.prices['default'],\n                this.renders.prices[productType]\n            );\n\n            price.name = productType + '.default';\n            price.parent = this.name;\n            price.source = this.source;\n            price.productType = productType;\n            layout([price]);\n        },\n\n        /**\n         * Init Prices by product type and add them to layout\n         *\n         * @param {Array} _priceData\n         * @param {String} productType\n         * @private\n         */\n        _initPricesForProductType: function (_priceData, productType) {\n            var prices = [];\n\n            this._setPriceNamesToPrices(_priceData, productType);\n            _.sortBy(_priceData, this._comparePrices);\n\n            _.each(_priceData, function (priceData) {\n                if (!priceData.component) {\n                    return;\n                }\n\n                priceData.parent = this.name;\n                priceData.provider = this.provider;\n                priceData.productType = productType;\n                priceData = utils.template(priceData, this);\n                prices.push(priceData);\n            }, this);\n\n            layout(prices);\n        },\n\n        /**\n         * Init dynamic price components\n         *\n         * @param {Array} row\n         * @returns {void}\n         */\n        initPrices: function (row) {\n            var _priceData = [],\n                productType = row.type,\n                defaultPrice = this.renders.prices['default'];\n\n            if (this.pricesInit[productType]) {\n                return true;\n            }\n\n            this.pricesInit[productType] = true;\n\n            if (this.renders.prices[productType] && this._needToApplyCustomTemplate(this.renders.prices[productType])) {\n                return this._initPriceWithCustomMetaData(productType);\n            }\n\n            if (this.renders.prices[productType] && this.renders.prices[productType].children) {\n                _priceData = this._deepObjectExtend(defaultPrice.children, this.renders.prices[productType].children);\n            } else {\n                _priceData = defaultPrice.children;\n            }\n\n            return this._initPricesForProductType(_priceData, productType);\n        },\n\n        /**\n         * Set name to all price components\n         *\n         * @param {Array} prices\n         * @param {String} productType\n         * @private\n         */\n        _setPriceNamesToPrices: function (prices, productType) {\n            _.each(prices, function (price, name) {\n                price.priceType = name;\n                price.name = name + '.' + productType;\n            });\n\n            return prices;\n        },\n\n        /**\n         * Sort callback to compare prices by sort order\n         *\n         * @param {Number} firstPrice\n         * @param {Number} secondPrice\n         * @returns {Number}\n         * @private\n         */\n        _comparePrices: function (firstPrice, secondPrice) {\n            if (firstPrice.sortOrder < secondPrice.sortOrder) {\n                return -1;\n            }\n\n            if (firstPrice.sortOrder > secondPrice.sortOrder) {\n                return 1;\n            }\n\n            return 0;\n        },\n\n        /**\n         * Check whether metadata of product type prices was changed, and we should\n         * to apply custom template or custom component\n         *\n         * @param {Array} productData\n         * @returns {*}\n         * @private\n         */\n        _needToApplyCustomTemplate: function (productData) {\n            return productData.bodyTmpl || productData.component;\n        },\n\n        /**\n         * Returns path to the columns' body template.\n         *\n         * @returns {String}\n         */\n        getBody: function () {\n            return this.bodyTmpl;\n        },\n\n        /**\n         * Get price label.\n         *\n         * @returns {String}\n         */\n        getLabel: function () {\n            return this.label;\n        }\n    });\n});\n","Magento_Catalog/js/product/list/columns/final-price.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'uiRegistry',\n    'mageUtils',\n    'uiCollection'\n], function (_, registry, utils, Collection) {\n    'use strict';\n\n    return Collection.extend({\n        defaults: {\n            label: false,\n            headerTmpl: 'ui/grid/columns/text',\n            showMinimalPrice: false,\n            showMaximumPrice: false,\n            useLinkForAsLowAs: false,\n            bodyTmpl: 'Magento_Catalog/product/final_price',\n            priceWrapperCssClasses: '',\n            priceWrapperAttr: {}\n        },\n\n        /**\n         * Get product final price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} final price html\n         */\n        getPrice: function (row) {\n            return row['price_info']['formatted_prices']['final_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} final price html\n         */\n        getPriceUnsanitizedHtml: function (row) {\n            return this.getPrice(row);\n        },\n\n        /**\n         * Get product regular price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} regular price html\n         */\n        getRegularPrice: function (row) {\n            return row['price_info']['formatted_prices']['regular_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getRegularPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} regular price html\n         */\n        getRegularPriceUnsanitizedHtml: function (row) {\n            return this.getRegularPrice(row);\n        },\n\n        /**\n         * Check if product has a price range.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        hasPriceRange: function (row) {\n            return row['price_info']['max_regular_price'] !== row['price_info']['min_regular_price'];\n        },\n\n        /**\n         * Check if product has special price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} special price html\n         */\n        hasSpecialPrice: function (row) {\n            return row['price_info']['regular_price'] > row['price_info']['final_price'];\n        },\n\n        /**\n         * Check if product has minimal price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} minimal price html\n         */\n        isMinimalPrice: function (row) {\n            return row['price_info']['minimal_price'] < row['price_info']['final_price'];\n        },\n\n        /**\n         * Get product minimal price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} minimal price html\n         */\n        getMinimalPrice: function (row) {\n            return row['price_info']['formatted_prices']['minimal_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getMinimalPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} minimal price html\n         */\n        getMinimalPriceUnsanitizedHtml: function (row) {\n            return this.getMinimalPrice(row);\n        },\n\n        /**\n         * Check if product is salable.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        isSalable: function (row) {\n            return row['is_salable'];\n        },\n\n        /**\n         * Get product maximum price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} maximum price html\n         */\n        getMaxPrice: function (row) {\n            return row['price_info']['formatted_prices']['max_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getMaxPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} maximum price html\n         */\n        getMaxPriceUnsanitizedHtml: function (row) {\n            return this.getMaxPrice(row);\n        },\n\n        /**\n         * Get product maximum regular price in case of price range and special price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} maximum regular price html\n         */\n        getMaxRegularPrice: function (row) {\n            return row['price_info']['formatted_prices']['max_regular_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getMaxRegularPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} maximum regular price html\n         */\n        getMaxRegularPriceUnsanitizedHtml: function (row) {\n            return this.getMaxRegularPrice(row);\n        },\n\n        /**\n         * Get product minimal regular price in case of price range and special price.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} minimal regular price html\n         */\n        getMinRegularPrice: function (row) {\n            return row['price_info']['formatted_prices']['min_regular_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getMinRegularPrice.\n         *\n         * @param {Object} row\n         * @return {HTMLElement} minimal regular price html\n         */\n        getMinRegularPriceUnsanitizedHtml: function (row) {\n            return this.getMinRegularPrice(row);\n        },\n\n        /**\n         * Get adjustments names and return as string.\n         *\n         * @return {String} adjustments classes\n         */\n        getAdjustmentCssClasses: function () {\n            return _.pluck(this.getAdjustments(), 'index').join(' ');\n        },\n\n        /**\n         * Get product minimal price as number.\n         *\n         * @param {Object} row\n         * @return {Number} minimal price amount\n         */\n        getMinimalPriceAmount: function (row) {\n            return row['price_info']['minimal_price'];\n        },\n\n        /**\n         * UnsanitizedHtml version of getMinimalPriceAmount\n         *\n         * @param {Object} row\n         * @return {Number} minimal price amount\n         */\n        getMinimalPriceAmountUnsanitizedHtml: function (row) {\n            return this.getMinimalPriceAmount(row);\n        },\n\n        /**\n         * Get product minimal regular price as number in case of special price.\n         *\n         * @param {Object} row\n         * @return {Number} minimal regular price amount\n         */\n        getMinimalRegularPriceAmount: function (row) {\n            return row['price_info']['min_regular_price'];\n        },\n\n        /**\n         * Get product maximum price as number.\n         *\n         * @param {Object} row\n         * @return {Number} maximum price amount\n         */\n        getMaximumPriceAmount: function (row) {\n            return row['price_info']['max_price'];\n        },\n\n        /**\n         * Get product maximum regular price as number in case of special price.\n         *\n         * @param {Object} row\n         * @return {Number} maximum regular price amount\n         */\n        getMaximumRegularPriceAmount: function (row) {\n            return row['price_info']['max_regular_price'];\n        },\n\n        /**\n         * Check if minimal regular price exist for product.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        showMinRegularPrice: function (row) {\n            return this.getMinimalPriceAmount(row) < this.getMinimalRegularPriceAmount(row);\n        },\n\n        /**\n         * Check if maximum regular price exist for product.\n         *\n         * @param {Object} row\n         * @return {Boolean}\n         */\n        showMaxRegularPrice: function (row) {\n            return this.getMaximumPriceAmount(row) < this.getMaximumRegularPriceAmount(row);\n        },\n\n        /**\n         * Get path to the columns' body template.\n         *\n         * @returns {String}\n         */\n        getBody: function () {\n            return this.bodyTmpl;\n        },\n\n        /**\n         * Get all price adjustments.\n         *\n         * @returns {Object}\n         */\n        getAdjustments: function () {\n            var adjustments = this.elems();\n\n            _.each(adjustments, function (adjustment) {\n                adjustment.setPriceType(this.priceType);\n                adjustment.source = this.source;\n            }, this);\n\n            return adjustments;\n        }\n    });\n});\n","Magento_Catalog/js/components/new-attribute-form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Ui/js/form/form',\n    'Magento_Ui/js/modal/prompt',\n    'Magento_Ui/js/modal/alert'\n], function ($, Form, prompt, alert) {\n    'use strict';\n\n    return Form.extend({\n        defaults: {\n            newSetPromptMessage: '',\n            listens: {\n                responseData: 'processResponseData'\n            },\n            modules: {\n                productForm: 'product_form.product_form'\n            }\n        },\n\n        /**\n         * Process response data\n         *\n         * @param {Object} data\n         */\n        processResponseData: function (data) {\n            if (data.params['new_attribute_set_id']) {\n                this.productForm().params = {\n                    set: data.params['new_attribute_set_id']\n                };\n            }\n        },\n\n        /**\n         * Process Save In New Attribute Set prompt\n         */\n        saveAttributeInNewSet: function () {\n\n            var self = this;\n\n            this.validate();\n\n            if (!this.additionalInvalid && !this.source.get('params.invalid')) {\n                prompt({\n                    content: this.newSetPromptMessage,\n                    actions: {\n\n                        /**\n                         * @param {String} val\n                         * @this {actions}\n                         */\n                        confirm: function (val) {\n                            var rules = ['required-entry', 'validate-no-html-tags'],\n                                editForm = self,\n                                newAttributeSetName = val,\n                                i,\n                                params = {};\n\n                            if (!newAttributeSetName) {\n                                return;\n                            }\n\n                            for (i = 0; i < rules.length; i++) {\n                                if (!$.validator.methods[rules[i]](newAttributeSetName)) {\n                                    alert({\n                                        content: $.validator.messages[rules[i]]\n                                    });\n\n                                    return;\n                                }\n                            }\n\n                            params['new_attribute_set_name'] = newAttributeSetName;\n                            editForm.setAdditionalData(params);\n                            editForm.save();\n                        }\n                    }\n                });\n            } else {\n                this.focusInvalid();\n            }\n        }\n    });\n});\n","Magento_Catalog/js/components/custom-options-price-type.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'Magento_Ui/js/form/element/select',\n    'uiRegistry'\n], function (_, Select, uiRegistry) {\n    'use strict';\n\n    return Select.extend({\n        /**\n         * {@inheritdoc}\n         */\n        onUpdate: function () {\n            this._super();\n\n            this.updateAddBeforeForPrice();\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        setInitialValue: function () {\n            this._super();\n\n            this.updateAddBeforeForPrice();\n\n            return this;\n        },\n\n        /**\n         * Update addbefore for price field. Change it to currency or % depends of price_type value.\n         */\n        updateAddBeforeForPrice: function () {\n            var addBefore, currentValue, priceIndex, priceName, uiPrice;\n\n            priceIndex = typeof this.imports.priceIndex == 'undefined' ? 'price' : this.imports.priceIndex;\n            priceName = this.parentName + '.' + priceIndex;\n\n            uiPrice = uiRegistry.get(priceName);\n\n            if (uiPrice && uiPrice.addbeforePool) {\n                currentValue = this.value();\n\n                uiPrice.addbeforePool.forEach(function (item) {\n                    if (item.value === currentValue) {\n                        addBefore = item.label;\n                    }\n                });\n\n                if (typeof addBefore != 'undefined') {\n                    uiPrice.addBefore(addBefore);\n                }\n            }\n        }\n    });\n});\n","Magento_Catalog/js/components/attribute-set-select.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/element/ui-select'\n], function (Select) {\n    'use strict';\n\n    return Select.extend({\n        defaults: {\n            listens: {\n                'value': 'changeFormSubmitUrl'\n            },\n            modules: {\n                formProvider: '${ $.provider }'\n            }\n        },\n\n        /**\n         * Change set parameter in save and validate urls of form\n         *\n         * @param {String|Number} value\n         */\n        changeFormSubmitUrl: function (value) {\n            var pattern = /(set\\/)(\\d)*?\\//,\n                change = '$1' + value + '/';\n\n            this.formProvider().client.urls.save = this.formProvider().client.urls.save.replace(pattern, change);\n            this.formProvider().client.urls.beforeSave = this.formProvider().client.urls.beforeSave.replace(\n                pattern,\n                change\n            );\n        }\n    });\n});\n","Magento_Catalog/js/components/reset-dynamic-rows-grid-row-position-on-delete.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'uiRegistry',\n    'rjsResolver',\n    'Magento_Ui/js/dynamic-rows/dynamic-rows-grid'\n], function (_, registry, resolver, dynamicRowsGrid) {\n    'use strict';\n\n    return dynamicRowsGrid.extend({\n\n        /** @inheritdoc */\n        deleteRecord: function () {\n            this._super();\n            this.resetPosition();\n        },\n\n        /**\n         * Reset the position on delete of the record.\n         */\n        resetPosition() {\n            let self = this,\n                position = 0;\n\n            _.filter(this.elems(), function (elem, index) {\n                if (index === 0) {\n                    position = (self.currentPage() - 1) * self.pageSize + 1;\n                }\n                _.filter(elem.elems(),function (childElem) {\n                    if (childElem.index === 'position') {\n                        childElem.value(position);\n                    }\n                });\n                position++;\n            });\n        },\n\n        /** @inheritdoc */\n        nextPage: function () {\n            this._super();\n            resolver(function () {\n                if (this.elems().length) {\n                    this.resetPosition();\n                }\n            }, this);\n        }\n    });\n});\n","Magento_Catalog/js/components/attributes-fieldset.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/components/fieldset',\n    'Magento_Ui/js/core/app'\n], function (Fieldset, app) {\n    'use strict';\n\n    return Fieldset.extend({\n        defaults: {\n            listens: {\n                '${ $.provider }:additionalAttributes': 'onAttributeAdd'\n            }\n        },\n\n        /**\n         * On attribute add trigger\n         *\n         * @param {Object} listOfNewAttributes\n         */\n        onAttributeAdd: function (listOfNewAttributes) {\n            app(listOfNewAttributes, true);\n        }\n    });\n});\n","Magento_Catalog/js/components/attributes-insert-listing.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/lib/view/utils/async',\n    'uiRegistry',\n    'underscore',\n    'Magento_Ui/js/form/components/insert-listing'\n], function ($, registry, _, InsertListing) {\n    'use strict';\n\n    return InsertListing.extend({\n        defaults: {\n            addAttributeUrl: '',\n            attributeSetId: '',\n            attributeIds: '',\n            groupCode: '',\n            groupName: '',\n            groupSortOrder: 0,\n            productId: 0,\n            formProvider: '',\n            modules: {\n                form: '${ $.formProvider }',\n                modal: '${ $.parentName }'\n            },\n            productType: ''\n        },\n\n        /**\n         * Render attribute\n         */\n        render: function () {\n            this._super();\n        },\n\n        /**\n         * Save attribute\n         */\n        save: function () {\n            this.addSelectedAttributes();\n            this._super();\n        },\n\n        /**\n         * Add selected attributes\n         */\n        addSelectedAttributes: function () {\n            $.ajax({\n                url: this.addAttributeUrl,\n                type: 'POST',\n                dataType: 'json',\n                data: {\n                    attributeIds: this.selections().getSelections(),\n                    templateId: this.attributeSetId,\n                    groupCode: this.groupCode,\n                    groupName: this.groupName,\n                    groupSortOrder: this.groupSortOrder,\n                    productId: this.productId,\n                    componentJson: 1\n                },\n                success: function () {\n                    this.form().params = {\n                        set: this.attributeSetId,\n                        id: this.productId,\n                        type: this.productType\n                    };\n                    this.form().reload();\n                    this.modal().state(false);\n                    this.reload();\n                }.bind(this)\n            });\n        }\n    });\n});\n","Magento_Catalog/js/components/attributes-grid-paging.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/grid/paging/paging',\n    'underscore'\n], function (Paging, _) {\n    'use strict';\n\n    return Paging.extend({\n        defaults: {\n            totalTmpl: 'Magento_Catalog/attributes/grid/paging',\n            modules: {\n                selectionColumn: '${ $.selectProvider }'\n            },\n            listens: {\n                '${ $.selectProvider }:selected': 'changeLabel'\n            },\n            label: '',\n            selectedAttrs: []\n        },\n\n        /**\n         * Change label.\n         *\n         * @param {Array} selected\n         */\n        changeLabel: function (selected) {\n            this.selectedAttrs = [];\n            _.each(this.selectionColumn().rows(), function (row) {\n                if (selected.indexOf(row['attribute_id']) !== -1) {\n                    this.selectedAttrs.push(row['attribute_code']);\n                }\n            }, this);\n\n            this.label(this.selectedAttrs.join(', '));\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super()\n                .observe('label');\n\n            return this;\n        }\n    });\n});\n","Magento_Catalog/js/components/website-currency-symbol.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/element/select'\n], function (Select) {\n    'use strict';\n\n    return Select.extend({\n        defaults: {\n            currenciesForWebsites: {},\n            tracks: {\n                currency: true\n            }\n        },\n\n        /**\n         * Set currency symbol per website\n         *\n         * @param {String} value - currency symbol\n         */\n        setDifferedFromDefault: function (value) {\n            this.currency = this.currenciesForWebsites[value];\n\n            return this._super();\n        }\n    });\n});\n","Magento_Catalog/js/components/dynamic-rows-import-custom-options-per-page.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Catalog/js/components/dynamic-rows-import-custom-options',\n    'underscore',\n    'mageUtils',\n    'uiLayout',\n    'rjsResolver'\n], function (DrCustomOptions, _, utils, layout, resolver) {\n    'use strict';\n\n    return DrCustomOptions.extend({\n        defaults: {\n            sizesConfig: {\n                component: 'Magento_Ui/js/grid/paging/sizes',\n                name: '${ $.name }_sizes',\n                options: {\n                    '20': {\n                        value: 20,\n                        label: 20\n                    },\n                    '30': {\n                        value: 30,\n                        label: 30\n                    },\n                    '50': {\n                        value: 50,\n                        label: 50\n                    },\n                    '100': {\n                        value: 100,\n                        label: 100\n                    },\n                    '200': {\n                        value: 200,\n                        label: 200\n                    }\n                },\n                storageConfig: {\n                    provider: '${ $.storageConfig.provider }',\n                    namespace: '${ $.storageConfig.namespace }'\n                },\n                enabled: false\n            },\n            links: {\n                options: '${ $.sizesConfig.name }:options',\n                pageSize: '${ $.sizesConfig.name }:value'\n            },\n            listens: {\n                'pageSize': 'onPageSizeChange'\n            },\n            modules: {\n                sizes: '${ $.sizesConfig.name }'\n            }\n        },\n\n        /**\n         * Initializes paging component.\n         *\n         * @returns {Paging} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initSizes();\n\n            return this;\n        },\n\n        /**\n         * Initializes sizes component.\n         *\n         * @returns {Paging} Chainable.\n         */\n        initSizes: function () {\n            if (this.sizesConfig.enabled) {\n                layout([this.sizesConfig]);\n            }\n\n            return this;\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Paging} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .track([\n                    'pageSize'\n                ]);\n\n            return this;\n        },\n\n        /**\n         * Handles changes of the page size.\n         */\n        onPageSizeChange: function () {\n            resolver(function () {\n                if (this.elems().length) {\n                    this.reload();\n                }\n            }, this);\n        }\n    });\n});\n","Magento_Catalog/js/components/dynamic-rows-import-custom-options.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/dynamic-rows/dynamic-rows-grid',\n    'underscore',\n    'mageUtils'\n], function (DynamicRows, _, utils) {\n    'use strict';\n\n    return DynamicRows.extend({\n        defaults: {\n            mappingSettings: {\n                enabled: false,\n                distinct: false\n            },\n            update: true,\n            map: {\n                'option_id': 'option_id'\n            },\n            identificationProperty: 'option_id',\n            identificationDRProperty: 'option_id'\n        },\n\n        /** @inheritdoc */\n        processingInsertData: function (data) {\n            var options = [],\n                currentOption,\n                generalContext = this;\n\n            if (!data) {\n                return;\n            }\n            _.each(data, function (item) {\n                if (!item.options) {\n                    return;\n                }\n                _.each(item.options, function (option) {\n                    currentOption = utils.copy(option);\n\n                    if (currentOption.hasOwnProperty('option_id')) {\n                        delete currentOption['option_id'];\n                    }\n\n                    if (currentOption.values.length > 0) {\n                        generalContext.removeOptionsIds(currentOption.values);\n                    }\n                    options.push(currentOption);\n                });\n            });\n\n            if (!options.length) {\n                return;\n            }\n            this.cacheGridData = options;\n            _.each(options, function (opt) {\n                this.mappingValue(opt);\n            }, this);\n\n            this.insertData([]);\n        },\n\n        /**\n         * Removes option_id and option_type_id from every option\n         *\n         * @param {Array} options\n         */\n        removeOptionsIds: function (options) {\n            _.each(options, function (optionValue) {\n                delete optionValue['option_id'];\n                delete optionValue['option_type_id'];\n            });\n        },\n\n        /** @inheritdoc */\n        processingAddChild: function (ctx, index, prop) {\n            if (!ctx) {\n                this.showSpinner(true);\n                this.addChild(ctx, index, prop);\n\n                return;\n            }\n\n            this._super(ctx, index, prop);\n        },\n\n        /**\n         * Set empty array to dataProvider\n         */\n        clearDataProvider: function () {\n            this.source.set(this.dataProvider, []);\n        },\n\n        /**\n         * Mutes parent method\n         */\n        updateInsertData: function () {\n            return false;\n        }\n    });\n});\n","Magento_Catalog/js/components/url-key-handle-changes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/form/element/single-checkbox'\n], function (Checkbox) {\n    'use strict';\n\n    return Checkbox.extend({\n        defaults: {\n            imports: {\n                handleUseDefault: '${ $.parentName }.use_default.url_key:checked',\n                urlKey: '${ $.provider }:data.url_key'\n            },\n            listens: {\n                urlKey: 'handleChanges'\n            },\n            modules: {\n                useDefault: '${ $.parentName }.use_default.url_key'\n            }\n        },\n\n        /**\n         * Disable checkbox field, when 'url_key' field without changes or 'use default' field is checked\n         */\n        handleChanges: function (newValue) {\n            this.disabled(newValue === this.valueMap['true'] || this.useDefault.checked);\n        },\n\n        /**\n         * Disable checkbox field, when 'url_key' field without changes or 'use default' field is checked\n         */\n        handleUseDefault: function (checkedUseDefault) {\n            this.disabled(this.urlKey === this.valueMap['true'] || checkedUseDefault);\n        }\n    });\n});\n","Magento_Catalog/js/components/new-category.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/element/ui-select'\n], function (Select) {\n    'use strict';\n\n    return Select.extend({\n\n        /**\n         * Parse data and set it to options.\n         *\n         * @param {Object} data - Response data object.\n         * @returns {Object}\n         */\n        setParsed: function (data) {\n            var option = this.parseData(data);\n\n            if (data.error) {\n                return this;\n            }\n\n            this.options([]);\n            this.setOption(option);\n            this.set('newOption', option);\n        },\n\n        /**\n         * Normalize option object.\n         *\n         * @param {Object} data - Option object.\n         * @returns {Object}\n         */\n        parseData: function (data) {\n            return {\n                'is_active': data.category['is_active'],\n                level: data.category.level,\n                value: data.category['entity_id'],\n                label: data.category.name,\n                parent: data.category.parent\n            };\n        }\n    });\n});\n","Magento_Catalog/js/components/dynamic-rows-per-page.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/dynamic-rows/dynamic-rows',\n    'underscore',\n    'mageUtils',\n    'uiLayout',\n    'rjsResolver'\n], function (DynamicRows, _, utils, layout, resolver) {\n    'use strict';\n\n    return DynamicRows.extend({\n        defaults: {\n            sizesConfig: {\n                component: 'Magento_Ui/js/grid/paging/sizes',\n                name: '${ $.name }_sizes',\n                options: {\n                    '20': {\n                        value: 20,\n                        label: 20\n                    },\n                    '30': {\n                        value: 30,\n                        label: 30\n                    },\n                    '50': {\n                        value: 50,\n                        label: 50\n                    },\n                    '100': {\n                        value: 100,\n                        label: 100\n                    },\n                    '200': {\n                        value: 200,\n                        label: 200\n                    }\n                },\n                storageConfig: {\n                    provider: '${ $.storageConfig.provider }',\n                    namespace: '${ $.storageConfig.namespace }'\n                },\n                enabled: false\n            },\n            links: {\n                options: '${ $.sizesConfig.name }:options',\n                pageSize: '${ $.sizesConfig.name }:value'\n            },\n            listens: {\n                'pageSize': 'onPageSizeChange'\n            },\n            modules: {\n                sizes: '${ $.sizesConfig.name }'\n            }\n        },\n\n        /**\n         * Initializes paging component.\n         *\n         * @returns {Paging} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initSizes();\n\n            return this;\n        },\n\n        /**\n         * Initializes sizes component.\n         *\n         * @returns {Paging} Chainable.\n         */\n        initSizes: function () {\n            if (this.sizesConfig.enabled) {\n                layout([this.sizesConfig]);\n            }\n\n            return this;\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Paging} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .track([\n                    'pageSize'\n                ]);\n\n            return this;\n        },\n\n        /**\n         * Handles changes of the page size.\n         */\n        onPageSizeChange: function () {\n            resolver(function () {\n                if (this.elems().length) {\n                    this.reload();\n                }\n            }, this);\n        }\n    });\n});\n","Magento_Catalog/js/components/product-ui-select.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated see Magento/Ui/view/base/web/js/grid/filters/elements/ui-select.js\n */\ndefine([\n    'Magento_Ui/js/form/element/ui-select',\n    'jquery',\n    'underscore'\n], function (Select, $, _) {\n    'use strict';\n\n    return Select.extend({\n        defaults: {\n            validationUrl: false,\n            loadedOption: [],\n            validationLoading: true\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n\n            this.validateInitialValue();\n\n            return this;\n        },\n\n        /**\n         * Validate initial value actually exists\n         */\n        validateInitialValue: function () {\n            if (!_.isEmpty(this.value())) {\n                $.ajax({\n                    url: this.validationUrl,\n                    type: 'GET',\n                    dataType: 'json',\n                    context: this,\n                    data: {\n                        productId: this.value()\n                    },\n\n                    /** @param {Object} response */\n                    success: function (response) {\n                        if (!_.isEmpty(response)) {\n                            this.options([response]);\n                            this.loadedOption = response;\n                        }\n                    },\n\n                    /** set empty array if error occurs */\n                    error: function () {\n                        this.options([]);\n                    },\n\n                    /** stop loader */\n                    complete: function () {\n                        this.validationLoading(false);\n                        this.setCaption();\n                    }\n                });\n            } else {\n                this.validationLoading(false);\n            }\n        },\n\n        /** @inheritdoc */\n        getSelected: function () {\n            var options = this._super();\n\n            if (!_.isEmpty(this.loadedOption)) {\n                return this.value() === this.loadedOption.value ? [this.loadedOption] : options;\n            }\n\n            return options;\n        }\n    });\n});\n","Magento_Catalog/js/components/import-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/element/abstract',\n    'underscore',\n    'uiRegistry'\n], function (Abstract, _, registry) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            allowImport: true,\n            autoImportIfEmpty: false,\n            values: {},\n            mask: '',\n            queryTemplate: 'ns = ${ $.ns }, index = '\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n\n            if (this.allowImport) {\n                this.setHandlers();\n            }\n        },\n\n        /**\n         * Split mask placeholder and attach events to placeholder fields.\n         */\n        setHandlers: function () {\n            var str = this.mask || '',\n                placeholders;\n\n            placeholders = str.match(/{{(.*?)}}/g); // Get placeholders\n\n            _.each(placeholders, function (placeholder) {\n                placeholder = placeholder.replace(/[{{}}]/g, ''); // Remove curly braces\n\n                registry.get(this.queryTemplate + placeholder, function (component) {\n                    this.values[placeholder] = component.getPreview();\n                    component.on('value', this.updateValue.bind(this, placeholder, component));\n                    component.valueUpdate = 'keyup';\n                }.bind(this));\n            }, this);\n        },\n\n        /**\n         * Update field with mask value, if it's allowed.\n         *\n         * @param {Object} placeholder\n         * @param {Object} component\n         */\n        updateValue: function (placeholder, component) {\n            var string = this.mask || '',\n                nonEmptyValueFlag = false;\n\n            if (placeholder) {\n                this.values[placeholder] = component.getPreview() || '';\n            }\n\n            if (!this.allowImport) {\n                return;\n            }\n\n            _.each(this.values, function (propertyValue, propertyName) {\n                string = string.replace('{{' + propertyName + '}}', propertyValue);\n                nonEmptyValueFlag = nonEmptyValueFlag || !!propertyValue;\n            });\n\n            if (nonEmptyValueFlag) {\n                string = string.replace(/(<([^>]+)>)/ig, ''); // Remove html tags\n                this.value(string);\n            } else {\n                this.value('');\n            }\n        },\n\n        /**\n         * Disallow import when initial value isn't empty string\n         *\n         * @returns {*}\n         */\n        setInitialValue: function () {\n            this._super();\n\n            if (this.initialValue !== '') {\n                this.allowImport = false;\n            }\n\n            return this;\n        },\n\n        /**\n         *  Callback when value is changed by user,\n         *  and disallow/allow import value\n         */\n        userChanges: function () {\n\n            /**\n             *  As userChanges is called before updateValue,\n             *  we forced to get value from component by reference\n             */\n            var actualValue = arguments[1].currentTarget.value;\n\n            this._super();\n\n            if (actualValue === '') {\n                this.allowImport = true;\n\n                if (this.autoImportIfEmpty) {\n                    this.updateValue(null, null);\n                }\n            } else {\n                this.allowImport = false;\n            }\n        }\n    });\n});\n","Magento_Catalog/js/components/disable-hide-select.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/form/element/select',\n    'Magento_Catalog/js/components/visible-on-option/strategy',\n    'Magento_Catalog/js/components/disable-on-option/strategy'\n], function (Element, visibleStrategy, disableStrategy) {\n    'use strict';\n\n    return Element.extend(visibleStrategy).extend(disableStrategy);\n});\n","Magento_Catalog/js/components/new-attribute-insert-form.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/components/insert-form'\n], function (InsertForm) {\n    'use strict';\n\n    return InsertForm.extend({\n        defaults: {\n            modules: {\n                productForm: 'product_form.product_form'\n            },\n            listens: {\n                responseStatus: 'processResponseStatus'\n            },\n            attributeSetId: 0,\n            productId: 0\n        },\n\n        /**\n         * Process response status.\n         */\n        processResponseStatus: function () {\n            if (this.responseStatus()) {\n\n                if (this.productForm().params === undefined) {\n                    this.productForm().params = {\n                        set: this.attributeSetId\n                    };\n                }\n\n                if (this.productId) {\n                    this.productForm().params.id = this.productId;\n                }\n                this.productForm().params.type = this.productType;\n\n                this.productForm().reload();\n                this.resetForm();\n            }\n        }\n    });\n});\n","Magento_Catalog/js/components/custom-options-component.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'Magento_Ui/js/form/element/abstract'\n], function (_, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        /**\n         * {@inheritdoc}\n         */\n        setInitialValue: function () {\n            this._super();\n\n            this.addBefore(this.addbefore);\n\n            return this;\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        initObservable: function () {\n            this._super();\n\n            this.observe('addBefore');\n\n            return this;\n        }\n    });\n});\n","Magento_Catalog/js/components/dynamic-rows-tier-price.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'Magento_Ui/js/dynamic-rows/dynamic-rows'\n], function (_, DynamicRows) {\n    'use strict';\n\n    /**\n     * @deprecated Parent method contains labels sorting.\n     * @see Magento_Ui/js/dynamic-rows/dynamic-rows\n     */\n    return DynamicRows.extend({\n\n        /**\n         * Init header elements\n         */\n        initHeader: function () {\n            var labels;\n\n            this._super();\n            labels = _.clone(this.labels());\n            labels = _.sortBy(labels, function (label) {\n                return label.sortOrder;\n            });\n\n            this.labels(labels);\n        }\n    });\n});\n","Magento_Catalog/js/components/messages.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/components/html'\n], function (Html) {\n    'use strict';\n\n    return Html.extend({\n        defaults: {\n            form: '${ $.namespace }.${ $.namespace }',\n            visible: false,\n            imports: {\n                responseData: '${ $.form }:responseData',\n                visible: 'responseData.error',\n                content: 'responseData.messages'\n            },\n            listens: {\n                '${ $.provider }:data.reset': 'hide'\n            }\n        },\n\n        /**\n         * Show messages.\n         */\n        show: function () {\n            this.visible(true);\n        },\n\n        /**\n         * Hide messages.\n         */\n        hide: function () {\n            this.visible(false);\n        }\n    });\n});\n","Magento_Catalog/js/components/checkbox.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated since version 2.2.0\n */\ndefine([\n    'Magento_Ui/js/form/element/abstract',\n    'knockout'\n], function (Abstract, ko) {\n    'use strict';\n\n    return Abstract.extend({\n\n        /**\n         * Initializes observable properties of instance\n         *\n         * @returns {Element} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe('checked');\n\n            this.value = ko.pureComputed({\n\n                /**\n                 * use 'mappedValue' as value if checked\n                 */\n                read: function () {\n                    return this.checked() ? this.mappedValue : '';\n                },\n\n                /**\n                 * any value made checkbox checked\n                 */\n                write: function (val) {\n                    if (val) {\n                        this.checked(true);\n                    }\n                },\n                owner: this\n            });\n\n            return this;\n        }\n    });\n});\n","Magento_Catalog/js/components/disable-on-option/strategy.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(function () {\n    'use strict';\n\n    return {\n        defaults: {\n            valuesForEnable: [],\n            disabled: true,\n            imports: {\n                toggleDisable:\n                    'product_attribute_add_form.product_attribute_add_form.base_fieldset.frontend_input:value'\n            }\n        },\n\n        /**\n         * Toggle disabled state.\n         *\n         * @param {Number} selected\n         */\n        toggleDisable: function (selected) {\n            this.disabled(!(selected in this.valuesForEnable));\n        }\n    };\n});\n","Magento_Catalog/js/components/disable-on-option/select.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/form/element/select',\n    'Magento_Catalog/js/components/disable-on-option/strategy'\n], function (Element, strategy) {\n    'use strict';\n\n    return Element.extend(strategy);\n});\n","Magento_Catalog/js/components/disable-on-option/input.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/form/element/abstract',\n    'Magento_Catalog/js/components/disable-on-option/strategy'\n], function (Element, strategy) {\n    'use strict';\n\n    return Element.extend(strategy);\n});\n","Magento_Catalog/js/components/disable-on-option/yesno.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/form/element/single-checkbox',\n    'Magento_Catalog/js/components/disable-on-option/strategy'\n], function (Element, strategy) {\n    'use strict';\n\n    var comp = Element.extend(strategy).extend({\n\n        defaults: {\n            listens: {\n                disabled: 'updateValueForDisabledField',\n                visible: 'updateValueForDisabledField'\n            }\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        initialize: function () {\n            this._super();\n            this.updateValueForDisabledField();\n\n            return this;\n        },\n\n        /**\n         * Set element value to O(No) if element is invisible and disabled\n         * Set element value to initialValue if element becomes visible and enable\n         */\n        updateValueForDisabledField: function () {\n            if (!this.disabled() && this.visible()) {\n                this.set('value', this.initialValue);\n            } else {\n                this.set('value', 0);\n            }\n        }\n    });\n\n    return comp.extend(strategy);\n});\n","Magento_Catalog/js/components/visible-on-option/date.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/form/element/date',\n    'Magento_Catalog/js/components/visible-on-option/strategy'\n], function (Element, strategy) {\n    'use strict';\n\n    return Element.extend(strategy);\n});\n","Magento_Catalog/js/components/visible-on-option/fieldset.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/form/components/fieldset',\n    'Magento_Catalog/js/components/visible-on-option/strategy'\n], function (Fieldset, strategy) {\n    'use strict';\n\n    return Fieldset.extend(strategy).extend(\n        {\n            defaults: {\n                openOnShow: true\n            },\n\n            /**\n             * Toggle visibility state.\n             */\n            toggleVisibility: function () {\n                this._super();\n\n                if (this.openOnShow) {\n                    this.opened(this.inverseVisibility ? !this.isShown : this.isShown);\n                }\n            }\n        }\n    );\n});\n","Magento_Catalog/js/components/visible-on-option/textarea.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/form/element/textarea',\n    'Magento_Catalog/js/components/visible-on-option/strategy'\n], function (Element, strategy) {\n    'use strict';\n\n    return Element.extend(strategy);\n});\n","Magento_Catalog/js/components/visible-on-option/strategy.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(function () {\n    'use strict';\n\n    return {\n        defaults: {\n            valuesForOptions: [],\n            imports: {\n                toggleVisibility:\n                    'product_attribute_add_form.product_attribute_add_form.base_fieldset.frontend_input:value'\n            },\n            isShown: false,\n            inverseVisibility: false\n        },\n\n        /**\n         * Toggle visibility state.\n         *\n         * @param {Number} selected\n         */\n        toggleVisibility: function (selected) {\n            this.isShown = selected in this.valuesForOptions;\n            this.visible(this.inverseVisibility ? !this.isShown : this.isShown);\n        }\n    };\n});\n","Magento_Catalog/js/components/visible-on-option/select.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/form/element/select',\n    'Magento_Catalog/js/components/visible-on-option/strategy'\n], function (Element, strategy) {\n    'use strict';\n\n    return Element.extend(strategy);\n});\n","Magento_Catalog/js/components/visible-on-option/input.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/form/element/abstract',\n    'Magento_Catalog/js/components/visible-on-option/strategy'\n], function (Element, strategy) {\n    'use strict';\n\n    return Element.extend(strategy);\n});\n","Magento_Catalog/js/components/visible-on-option/yesno.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/form/element/single-checkbox',\n    'Magento_Catalog/js/components/visible-on-option/strategy'\n], function (Element, strategy) {\n    'use strict';\n\n    return Element.extend(strategy);\n});\n","Magento_Catalog/js/components/use-parent-settings/textarea.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/form/element/textarea'\n], function (Component) {\n    'use strict';\n\n    return Component;\n});\n","Magento_Catalog/js/components/use-parent-settings/single-checkbox.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/form/element/single-checkbox'\n], function (Component) {\n    'use strict';\n\n    return Component;\n});\n","Magento_Catalog/js/components/use-parent-settings/select.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/form/element/select'\n], function (Component) {\n    'use strict';\n\n    return Component;\n});\n","Magento_Catalog/js/components/use-parent-settings/toggle-disabled-mixin.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore'\n], function (_) {\n    'use strict';\n\n    var mixin = {\n        defaults: {\n            imports: {\n                toggleDisabled: '${ $.parentName }.custom_use_parent_settings:checked'\n            },\n            useParent: false,\n            useDefaults: false\n        },\n\n        /**\n         * Disable form input if settings for parent section is used\n         * or default value is applied.\n         *\n         * @param {Boolean} isUseParent\n         */\n        toggleDisabled: function (isUseParent) {\n            var disabled = this.useParent = isUseParent;\n\n            if (!disabled && !_.isUndefined(this.service)) {\n                disabled = !!this.isUseDefault();\n            }\n\n            this.saveUseDefaults();\n            this.disabled(disabled);\n        },\n\n        /**\n         * Stores original state of the field.\n         */\n        saveUseDefaults: function () {\n            this.useDefaults = this.disabled();\n        },\n\n        /** @inheritdoc */\n        setInitialValue: function () {\n            this._super();\n            this.isUseDefault(this.useDefaults);\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        toggleUseDefault: function (state) {\n            this._super();\n            this.disabled(state || this.useParent);\n        }\n    };\n\n    return function (target) {\n        return target.extend(mixin);\n    };\n});\n","Magento_Catalog/js/utils/percentage-price-calculator.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine(['Magento_Ui/js/lib/validation/utils'], function (utils) {\n    'use strict';\n\n    /**\n     * Calculates the price input value when entered percentage value.\n     *\n     * @param {String} price\n     * @param {String} input\n     *\n     * @returns {String}\n     */\n    return function (price, input) {\n        var result,\n            lastInputSymbol = input.slice(-1),\n            inputPercent = input.slice(0, -1),\n            parsedPercent = utils.parseNumber(inputPercent),\n            parsedPrice = utils.parseNumber(price);\n\n        if (lastInputSymbol !== '%') {\n            result = input;\n        } else if (\n            input === '%' ||\n            isNaN(parsedPrice) ||\n            parsedPercent != inputPercent || /* eslint eqeqeq:0 */\n            isNaN(parsedPercent) ||\n            input === ''\n        ) {\n            result = '';\n        } else if (parsedPercent > 100) {\n            result = '0.00';\n        } else if (lastInputSymbol === '%') {\n            result = parsedPrice - parsedPrice * (inputPercent / 100);\n            result = result.toFixed(2);\n        } else {\n            result = input;\n        }\n\n        return result;\n    };\n});\n","Magento_Catalog/js/form/element/input.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'Magento_Ui/js/form/element/abstract'\n], function (_, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            prefixName: '',\n            prefixElementName: '',\n            elementName: '',\n            suffixName: ''\n        },\n\n        /**\n         * Parses options and merges the result with instance\n         *\n         * @returns {Object} Chainable.\n         */\n        initConfig: function () {\n            this._super();\n            this.configureDataScope();\n\n            return this;\n        },\n\n        /**\n         * Configure data scope.\n         */\n        configureDataScope: function () {\n            var recordId,\n                prefixName,\n                suffixName;\n\n            // Get recordId\n            recordId = this.parentName.split('.').last();\n\n            prefixName = this.dataScopeToHtmlArray(this.prefixName);\n            this.elementName = this.prefixElementName + recordId;\n\n            suffixName = '';\n\n            if (!_.isEmpty(this.suffixName) || _.isNumber(this.suffixName)) {\n                suffixName = '[' + this.suffixName + ']';\n            }\n            this.inputName = prefixName + '[' + this.elementName + ']' + suffixName;\n\n            suffixName = '';\n\n            if (!_.isEmpty(this.suffixName) || _.isNumber(this.suffixName)) {\n                suffixName = '.' + this.suffixName;\n            }\n\n            this.exportDataLink = 'data.' + this.prefixName + '.' + this.elementName + suffixName;\n            this.exports.value = this.provider + ':' + this.exportDataLink;\n        },\n\n        /** @inheritdoc */\n        destroy: function () {\n            this._super();\n\n            this.source.remove(this.exportDataLink);\n        },\n\n        /**\n         * Get HTML array from data scope.\n         *\n         * @param {String} dataScopeString\n         * @returns {String}\n         */\n        dataScopeToHtmlArray: function (dataScopeString) {\n            var dataScopeArray, dataScope, reduceFunction;\n\n            /**\n             * Add new level of nesting.\n             *\n             * @param {String} prev\n             * @param {String} curr\n             * @returns {String}\n             */\n            reduceFunction = function (prev, curr) {\n                return prev + '[' + curr + ']';\n            };\n\n            dataScopeArray = dataScopeString.split('.');\n\n            dataScope = dataScopeArray.shift();\n            dataScope += dataScopeArray.reduce(reduceFunction, '');\n\n            return dataScope;\n        }\n    });\n});\n","Magento_Catalog/js/form/element/action-delete.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'Magento_Ui/js/form/element/abstract'\n], function (_, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            prefixName: '',\n            prefixElementName: '',\n            elementName: '',\n            suffixName: ''\n        },\n\n        /**\n         * Parses options and merges the result with instance\n         *\n         * @param  {Object} config\n         * @returns {Object} Chainable.\n         */\n        initConfig: function (config) {\n            this._super(config);\n\n            this.configureDataScope();\n\n            return this;\n        },\n\n        /**\n         * Configure data scope.\n         */\n        configureDataScope: function () {\n            var recordId,\n                prefixName,\n                suffixName;\n\n            // Get recordId\n            recordId = this.parentName.split('.').last();\n\n            prefixName = this.dataScopeToHtmlArray(this.prefixName);\n            this.elementName = this.prefixElementName + recordId;\n\n            suffixName = '';\n\n            if (!_.isEmpty(this.suffixName) || _.isNumber(this.suffixName)) {\n                suffixName = '[' + this.suffixName + ']';\n            }\n            this.inputName = prefixName + '[' + this.elementName + ']' + suffixName;\n\n            suffixName = '';\n\n            if (!_.isEmpty(this.suffixName) || _.isNumber(this.suffixName)) {\n                suffixName = '.' + this.suffixName;\n            }\n            this.dataScope = 'data.' + this.prefixName + '.' + this.elementName + suffixName;\n\n            this.links.value = this.provider + ':' + this.dataScope;\n        },\n\n        /**\n         * Get HTML array from data scope.\n         *\n         * @param {String} dataScopeString\n         * @returns {String}\n         */\n        dataScopeToHtmlArray: function (dataScopeString) {\n            var dataScopeArray, dataScope, reduceFunction;\n\n            /**\n             * Reduce\n             *\n             * @param {String} prev\n             * @param {String} curr\n             * @returns {String}\n             */\n            reduceFunction = function (prev, curr) {\n                return prev + '[' + curr + ']';\n            };\n\n            dataScopeArray = dataScopeString.split('.');\n\n            dataScope = dataScopeArray.shift();\n            dataScope += dataScopeArray.reduce(reduceFunction, '');\n\n            return dataScope;\n        },\n\n        /**\n         * Delete record instance\n         * update data provider dataScope\n         *\n         * @param {Object} parents\n         */\n        deleteRecord: function (parents) {\n            this.value(1);\n            parents[1].deleteRecord(parents[0].index, parents[0].recordId);\n\n            return this;\n        }\n    });\n});\n","Magento_Catalog/js/form/element/checkbox.js":"/**\r\n * Copyright \u00a9 Magento, Inc. All rights reserved.\r\n * See COPYING.txt for license details.\r\n */\r\n\r\ndefine([\r\n    'Magento_Ui/js/form/element/single-checkbox'\r\n], function (Checkbox) {\r\n    'use strict';\r\n\r\n    return Checkbox.extend({\r\n        defaults: {\r\n            inputCheckBoxName: '',\r\n            prefixElementName: '',\r\n            parentDynamicRowName: 'visual_swatch'\r\n        },\r\n\r\n        /**\r\n         * Parses options and merges the result with instance\r\n         *\r\n         * @returns {Object} Chainable.\r\n         */\r\n        initConfig: function () {\r\n            this._super();\r\n            this.configureDataScope();\r\n\r\n            return this;\r\n        },\r\n\r\n        /** @inheritdoc */\r\n        initialize: function () {\r\n            this._super();\r\n\r\n            if (this.rows && this.rows().elems().length === 0) {\r\n                this.checked(true);\r\n            }\r\n\r\n            return this;\r\n        },\r\n\r\n        /**\r\n         * Configure data scope.\r\n         */\r\n        configureDataScope: function () {\r\n            var recordId,\r\n                value;\r\n\r\n            recordId = this.parentName.split('.').last();\r\n            value = this.prefixElementName + recordId;\r\n\r\n            this.dataScope = 'data.' + this.inputCheckBoxName;\r\n            this.inputName = this.dataScopeToHtmlArray(this.inputCheckBoxName);\r\n\r\n            this.initialValue = value;\r\n\r\n            this.links.value = this.provider + ':' + this.dataScope;\r\n        },\r\n\r\n        /**\r\n         * Get HTML array from data scope.\r\n         *\r\n         * @param {String} dataScopeString\r\n         * @returns {String}\r\n         */\r\n        dataScopeToHtmlArray: function (dataScopeString) {\r\n            var dataScopeArray, dataScope, reduceFunction;\r\n\r\n            /**\r\n             * Add new level of nesting.\r\n             *\r\n             * @param {String} prev\r\n             * @param {String} curr\r\n             * @returns {String}\r\n             */\r\n            reduceFunction = function (prev, curr) {\r\n                return prev + '[' + curr + ']';\r\n            };\r\n\r\n            dataScopeArray = dataScopeString.split('.');\r\n\r\n            dataScope = dataScopeArray.shift();\r\n            dataScope += dataScopeArray.reduce(reduceFunction, '');\r\n\r\n            return dataScope;\r\n        }\r\n    });\r\n});\r\n","Magento_Catalog/js/tier-price/value-type-select.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/element/select',\n    'uiRegistry',\n    'underscore'\n], function (Select, uiRegistry, _) {\n    'use strict';\n\n    return Select.extend({\n        defaults: {\n            prices: {}\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        initialize: function () {\n            this._super();\n            delete this.prices.__disableTmpl;\n            this.prepareForm();\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        setInitialValue: function () {\n            this.initialValue = this.getInitialValue();\n\n            if (this.value.peek() !== this.initialValue) {\n                this.value(this.initialValue);\n            }\n\n            this.isUseDefault(this.disabled());\n\n            return this;\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        prepareForm: function () {\n            var elements = this.getElementsByPrices(),\n                prices = this.prices,\n                currencyType = _.keys(prices)[0],\n                select = this;\n\n            uiRegistry.get(elements, function () {\n                _.each(arguments, function (currentValue) {\n                    if (parseFloat(currentValue.value()) > 0) {\n                        _.each(prices, function (priceValue, priceKey) {\n                            if (priceValue === currentValue.name) {\n                                currencyType = priceKey;\n                            }\n                        });\n                    }\n                });\n                select.value(currencyType);\n                select.on('value', select.onUpdate.bind(select));\n                select.onUpdate();\n            });\n        },\n\n        /**\n         * @returns {Array}\n         */\n        getElementsByPrices: function () {\n            var elements = [];\n\n            _.each(this.prices, function (currentValue) {\n                elements.push(currentValue);\n            });\n\n            return elements;\n        },\n\n        /**\n         * Callback that fires when 'value' property is updated\n         */\n        onUpdate: function () {\n            var value = this.value(),\n                prices = this.prices,\n                select = this,\n                parentDataScopeArr = this.dataScope.split('.'),\n                parentDataScope,\n                elements = this.getElementsByPrices();\n\n            parentDataScopeArr.pop();\n            parentDataScope = parentDataScopeArr.join('.');\n\n            uiRegistry.get(elements, function () {\n                var sourceData = select.source.get(parentDataScope);\n\n                _.each(arguments, function (currentElement) {\n                    var index;\n\n                    _.each(prices, function (priceValue, priceKey) {\n                        if (priceValue === currentElement.name) {\n                            index = priceKey;\n                        }\n                    });\n\n                    if (value === index) {\n                        currentElement.visible(true);\n                        sourceData[currentElement.index] = currentElement.value();\n                    } else {\n                        currentElement.value('');\n                        currentElement.visible(false);\n                        delete sourceData[currentElement.index];\n                    }\n                });\n                select.source.set(parentDataScope, sourceData);\n            });\n        }\n    });\n});\n","Magento_Catalog/js/tier-price/percentage-processor.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiElement',\n    'underscore',\n    'Magento_Ui/js/lib/view/utils/async',\n    'Magento_Catalog/js/utils/percentage-price-calculator'\n], function (Element, _, $, percentagePriceCalculator) {\n    'use strict';\n\n    return Element.extend({\n        defaults: {\n            priceElem: '${ $.parentName }.price',\n            selector: 'input',\n            imports: {\n                priceValue: '${ $.priceElem }:priceValue'\n            },\n            exports: {\n                calculatedVal: '${ $.priceElem }:value'\n            }\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        initialize: function () {\n            this._super();\n\n            _.bindAll(this, 'initPriceListener', 'onInput');\n\n            $.async({\n                component: this.priceElem,\n                selector: this.selector\n            }, this.initPriceListener);\n\n            return this;\n        },\n\n        /**\n         * {@inheritdoc}\n         */\n        initObservable: function () {\n            return this._super()\n                .observe(['visible']);\n        },\n\n        /**\n         * Handles keyup event on price input.\n         *\n         * {@param} HTMLElement elem\n         */\n        initPriceListener: function (elem) {\n            $(elem).on('keyup.priceCalc', this.onInput);\n        },\n\n        /**\n         * Delegates calculation of the price input value to percentagePriceCalculator.\n         *\n         * {@param} object event\n         */\n        onInput: function (event) {\n            var value = event.currentTarget.value;\n\n            if (value.slice(-1) === '%') {\n                value = percentagePriceCalculator(this.priceValue, value);\n                this.set('calculatedVal', value);\n            }\n        }\n    });\n});\n","Magento_Catalog/catalog/product-attributes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'underscore',\n    'uiRegistry',\n    'jquery/ui',\n    'mage/translate'\n], function ($, _, registry) {\n    'use strict';\n\n    $.widget('mage.productAttributes', {\n        /** @inheritdoc */\n        _create: function () {\n            this._on({\n                'click': '_showPopup'\n            });\n        },\n\n        /**\n         * @private\n         */\n        _initModal: function () {\n            var self = this;\n\n            this.modal = $('<div id=\"create_new_attribute\"></div>').modal({\n                title: $.mage.__('New Attribute'),\n                type: 'slide',\n                buttons: [],\n\n                /** @inheritdoc */\n                opened: function () {\n                    $(this).parent().addClass('modal-content-new-attribute');\n                    self.iframe = $('<iframe id=\"create_new_attribute_container\"></iframe>').attr({\n                        src: self._prepareUrl(),\n                        frameborder: 0\n                    });\n                    self.modal.append(self.iframe);\n                    self._changeIframeSize();\n                    $(window).off().on('resize.modal', _.debounce(self._changeIframeSize.bind(self), 400));\n                },\n\n                /** @inheritdoc */\n                closed: function () {\n                    var doc = self.iframe.get(0).document;\n\n                    if (doc && typeof doc.execCommand === 'function') {\n                        //IE9 break script loading but not execution on iframe removing\n                        doc.execCommand('stop');\n                        self.iframe.remove();\n                    }\n                    self.modal.data('mageModal').modal.remove();\n                    $(window).off('resize.modal');\n                }\n            });\n        },\n\n        /**\n         * @return {Number}\n         * @private\n         */\n        _getHeight: function () {\n            var modal = this.modal.data('mageModal').modal,\n                modalHead = modal.find('header'),\n                modalHeadHeight = modalHead.outerHeight(),\n                modalHeight = modal.outerHeight(),\n                modalContentPadding = this.modal.parent().outerHeight() - this.modal.parent().height();\n\n            return modalHeight - modalHeadHeight - modalContentPadding;\n        },\n\n        /**\n         * @return {Number}\n         * @private\n         */\n        _getWidth: function () {\n            return this.modal.width();\n        },\n\n        /**\n         * @private\n         */\n        _changeIframeSize: function () {\n            this.modal.parent().outerHeight(this._getHeight());\n            this.iframe.outerHeight(this._getHeight());\n            this.iframe.outerWidth(this._getWidth());\n\n        },\n\n        /**\n         * @return {String}\n         * @private\n         */\n        _prepareUrl: function () {\n            var productSource,\n                attributeSetId = '';\n\n            if (this.options.dataProvider) {\n                try {\n                    productSource = registry.get(this.options.dataProvider);\n                    attributeSetId = productSource.data.product['attribute_set_id'];\n                } catch (e) {}\n            }\n\n            return this.options.url +\n                (/\\?/.test(this.options.url) ? '&' : '?') +\n                'set=' + attributeSetId;\n        },\n\n        /**\n         * @private\n         */\n        _showPopup: function () {\n            this._initModal();\n            this.modal.modal('openModal');\n        }\n    });\n\n    return $.mage.productAttributes;\n});\n","Magento_Catalog/catalog/type-events.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], function ($) {\n    'use strict';\n\n    return {\n        $type: $('#product_type_id'),\n\n        /**\n         * Init\n         */\n        init: function () {\n            this.type = {\n                init: this.$type.val(),\n                current: this.$type.val()\n            };\n\n            this.bindAll();\n        },\n\n        /**\n         * Bind all\n         */\n        bindAll: function () {\n            $(document).on('setTypeProduct', function (event, type) {\n                this.setType(type);\n            }.bind(this));\n\n            //direct change type input\n            this.$type.on('change', function () {\n                this.type.current = this.$type.val();\n                this._notifyType();\n            }.bind(this));\n        },\n\n        /**\n         * Set type\n         * @param {String} type - type product (downloadable, simple, virtual ...)\n         * @returns {*}\n         */\n        setType: function (type) {\n            return this.$type.val(type || this.type.init).trigger('change');\n        },\n\n        /**\n         * Notify type\n         * @private\n         */\n        _notifyType: function () {\n            $(document).trigger('changeTypeProduct', this.type);\n        }\n    };\n});\n","Magento_Catalog/catalog/base-image-uploader.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/template',\n    'Magento_Ui/js/modal/alert',\n    'jquery/ui',\n    'jquery/file-uploader',\n    'mage/translate',\n    'mage/backend/notification'\n], function ($, mageTemplate, alert) {\n    'use strict';\n\n    $.widget('mage.baseImage', {\n        /**\n         * Button creation\n         * @protected\n         */\n        options: {\n            maxImageUploadCount: 10\n        },\n\n        /** @inheritdoc */\n        _create: function () {\n            var $container = this.element,\n                imageTmpl = mageTemplate(this.element.find('[data-template=image]').html()),\n                $dropPlaceholder = this.element.find('.image-placeholder'),\n                $galleryContainer = $('#media_gallery_content'),\n                mainClass = 'base-image',\n                maximumImageCount = 5,\n                $fieldCheckBox = $container.closest('[data-attribute-code=image]').find(':checkbox'),\n                isDefaultChecked = $fieldCheckBox.is(':checked'),\n                findElement, updateVisibility;\n\n            if (isDefaultChecked) {\n                $fieldCheckBox.trigger('click');\n            }\n\n            /**\n             * @param {Object} data\n             * @return {HTMLElement}\n             */\n            findElement = function (data) {\n                return $container.find('.image:not(.image-placeholder)').filter(function () {\n                    if (!$(this).data('image')) {\n                        return false;\n                    }\n\n                    return $(this).data('image').file === data.file;\n                }).first();\n            };\n\n            /** Update image visibility. */\n            updateVisibility = function () {\n                var elementsList = $container.find('.image:not(.removed-item)');\n\n                elementsList.each(function (index) {\n                    $(this)[index < maximumImageCount ? 'show' : 'hide']();\n                });\n                $dropPlaceholder[elementsList.length > maximumImageCount ? 'hide' : 'show']();\n            };\n\n            $galleryContainer.on('setImageType', function (event, data) {\n                if (data.type === 'image') {\n                    $container.find('.' + mainClass).removeClass(mainClass);\n\n                    if (data.imageData) {\n                        findElement(data.imageData).addClass(mainClass);\n                    }\n                }\n            });\n\n            $galleryContainer.on('addItem', function (event, data) {\n                var tmpl = imageTmpl({\n                    data: data\n                });\n\n                $(tmpl).data('image', data).insertBefore($dropPlaceholder);\n\n                updateVisibility();\n            });\n\n            $galleryContainer.on('removeItem', function (event, image) {\n                findElement(image).addClass('removed-item').hide();\n                updateVisibility();\n            });\n\n            $galleryContainer.on('moveElement', function (event, data) {\n                var $element = findElement(data.imageData),\n                    $after;\n\n                if (data.position === 0) {\n                    $container.prepend($element);\n                } else {\n                    $after = $container.find('.image').eq(data.position);\n\n                    if (!$element.is($after)) {\n                        $element.insertAfter($after);\n                    }\n                }\n                updateVisibility();\n            });\n\n            $container.on('click', '[data-role=make-base-button]', function (event) {\n                var data;\n\n                event.preventDefault();\n                data = $(event.target).closest('.image').data('image');\n                $galleryContainer.productGallery('setBase', data);\n            });\n\n            $container.on('click', '[data-role=delete-button]', function (event) {\n                event.preventDefault();\n                $galleryContainer.trigger('removeItem', $(event.target).closest('.image').data('image'));\n            });\n\n            $container.sortable({\n                axis: 'x',\n                items: '.image:not(.image-placeholder)',\n                distance: 8,\n                tolerance: 'pointer',\n\n                /**\n                 * @param {jQuery.Event} event\n                 * @param {Object} data\n                 */\n                stop: function (event, data) {\n                    $galleryContainer.trigger('setPosition', {\n                        imageData: data.item.data('image'),\n                        position: $container.find('.image').index(data.item)\n                    });\n                    $galleryContainer.trigger('resort');\n                }\n            }).disableSelection();\n\n            this.element.find('input[type=\"file\"]').fileupload({\n                dataType: 'json',\n                dropZone: $dropPlaceholder.closest('[data-attribute-code]'),\n                acceptFileTypes: /(\\.|\\/)(gif|jpe?g|png)$/i,\n                maxFileSize: this.element.data('maxFileSize'),\n\n                /**\n                 * @param {jQuery.Event} event\n                 * @param {Object} data\n                 */\n                done: function (event, data) {\n                    $dropPlaceholder.find('.progress-bar').text('').removeClass('in-progress');\n\n                    if (!data.result) {\n                        return;\n                    }\n\n                    if (!data.result.error) {\n                        $galleryContainer.trigger('addItem', data.result);\n                    } else {\n                        alert({\n                            content: $.mage.__('We don\\'t recognize or support this file extension type.')\n                        });\n                    }\n                },\n\n                /**\n                 * @param {jQuery.Event} e\n                 * @param {Object} data\n                 */\n                change: function (e, data) {\n                    if (data.files.length > this.options.maxImageUploadCount) {\n                        $('body').notification('clear').notification('add', {\n                            error: true,\n                            message: $.mage.__('You can\\'t upload more than ' + this.options.maxImageUploadCount +\n                                ' images in one time'),\n\n                            /**\n                             * @param {*} message\n                             */\n                            insertMethod: function (message) {\n                                $('.page-main-actions').after(message);\n                            }\n                        });\n\n                        return false;\n                    }\n                }.bind(this),\n\n                /**\n                 * @param {jQuery.Event} event\n                 * @param {*} data\n                 */\n                add: function (event, data) {\n                    $(this).fileupload('process', data).done(function () {\n                        data.submit();\n                    });\n                },\n\n                /**\n                 * @param {jQuery.Event} e\n                 * @param {Object} data\n                 */\n                progress: function (e, data) {\n                    var progress = parseInt(data.loaded / data.total * 100, 10);\n\n                    $dropPlaceholder.find('.progress-bar').addClass('in-progress').text(progress + '%');\n                },\n\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                start: function (event) {\n                    var uploaderContainer = $(event.target).closest('.image-placeholder');\n\n                    uploaderContainer.addClass('loading');\n                },\n\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                stop: function (event) {\n                    var uploaderContainer = $(event.target).closest('.image-placeholder');\n\n                    uploaderContainer.removeClass('loading');\n                }\n            });\n        }\n    });\n\n    return $.mage.baseImage;\n});\n","Magento_Catalog/catalog/product.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\nrequire([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    window.Product = {};\n\n    /**\n     * @param {String} id\n     * @return {*|jQuery|HTMLElement}\n     */\n    function byId(id) {\n        return $('#' + id);\n    }\n\n    /**\n     * @param {String} fieldId\n     */\n    function disableFieldEditMode(fieldId) {\n        var field = byId(fieldId);\n\n        field.prop('disabled', true);\n\n        if (field.next().hasClass('addafter')) {\n            field.parent().addClass('_update-attributes-disabled');\n        }\n\n        if (byId(fieldId + '_hidden').length) {\n            byId(fieldId + '_hidden').prop('disabled', true);\n        }\n    }\n\n    /**\n     * @param {String} fieldId\n     */\n    function enableFieldEditMode(fieldId) {\n        var field = byId(fieldId);\n\n        field.prop('disabled', false);\n\n        if (field.parent().hasClass('_update-attributes-disabled')) {\n            field.parent().removeClass('_update-attributes-disabled');\n        }\n\n        if (byId(fieldId + '_hidden').length) {\n            byId(fieldId + '_hidden').prop('disabled', false);\n        }\n    }\n\n    /**\n     * @param {String} toogleIdentifier\n     * @param {String} fieldId\n     */\n    function toogleFieldEditMode(toogleIdentifier, fieldId) {\n        if ($(toogleIdentifier).is(':checked')) {\n            enableFieldEditMode(fieldId);\n        } else {\n            disableFieldEditMode(fieldId);\n        }\n    }\n\n    /**\n     * On complete disable.\n     */\n    function onCompleteDisableInited() {\n        var item;\n\n        $.each($('[data-disable]'), function () {\n            item = $(this).data('disable');\n            disableFieldEditMode(item);\n        });\n    }\n\n    /**\n     * @param {String} urlKey\n     */\n    function onUrlkeyChanged(urlKey) {\n        var hidden, chbx, oldValue;\n\n        urlKey = byId(urlKey);\n        hidden = urlKey.siblings('input[type=hidden]');\n        chbx = urlKey.siblings('input[type=checkbox]');\n        oldValue = chbx.val();\n\n        chbx.prop('disabled', oldValue === urlKey.val());\n        hidden.prop('disabled', chbx.prop('disabled'));\n    }\n\n    /**\n     * @param {HTMLElement} element\n     */\n    function onCustomUseParentChanged(element) {\n        var useParent, parent;\n\n        element = $(element);\n        useParent = element.val() == 1; //eslint-disable-line eqeqeq\n        parent = element.offsetParent().parent();\n\n        parent.find('input, select, textarea').each(function (i, el) {\n            el = $(el);\n\n            if (element.prop('id') !== el.prop('id')) {\n                el.prop('disabled', useParent);\n            }\n        });\n\n        parent.find('img').each(function (i, el) {\n            if (useParent) {\n                $(el).hide();\n            } else {\n                $(el).show();\n            }\n        });\n    }\n\n    window.onCustomUseParentChanged = onCustomUseParentChanged;\n    window.onUrlkeyChanged = onUrlkeyChanged;\n    window.toogleFieldEditMode = toogleFieldEditMode;\n\n    $(onCompleteDisableInited);\n});\n","Magento_Catalog/catalog/apply-to-type-switcher.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'Magento_Catalog/catalog/type-events'\n], function ($, productType) {\n    'use strict';\n\n    return {\n\n        /**\n         * Bind event\n         */\n        bindAll: function () {\n            $('[data-form=edit-product] [data-role=tabs]').on(\n                'contentUpdated',\n                this._switchToTypeByApplyAttr.bind(this)\n            );\n\n            $('#product_info_tabs').on(\n                'beforePanelsMove tabscreate tabsactivate',\n                this._switchToTypeByApplyAttr.bind(this)\n            );\n\n            $(document).on('changeTypeProduct', this._switchToTypeByApplyAttr.bind(this));\n        },\n\n        /**\n         * Constructor component\n         */\n        'Magento_Catalog/catalog/apply-to-type-switcher': function () {\n            this.bindAll();\n            this._switchToTypeByApplyAttr();\n        },\n\n        /**\n         * Show/hide elements based on type\n         *\n         * @private\n         */\n        _switchToTypeByApplyAttr: function () {\n            $('[data-apply-to]:not(.removed)').each(function (index, element) {\n                var attrContainer = $(element),\n                    applyTo = attrContainer.data('applyTo') || [],\n                    $inputs = attrContainer.find('select, input, textarea');\n\n                if (applyTo.length === 0 || $.inArray(productType.type.current, applyTo) !== -1) {\n                    attrContainer.removeClass('not-applicable-attribute');\n                    $inputs.removeClass('ignore-validate');\n                } else {\n                    attrContainer.addClass('not-applicable-attribute');\n                    $inputs.addClass('ignore-validate');\n                }\n            });\n        }\n    };\n});\n","Magento_Catalog/catalog/category/assign-products.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'mage/adminhtml/grid'\n], function () {\n    'use strict';\n\n    return function (config) {\n        var selectedProducts = config.selectedProducts,\n            categoryProducts = $H(selectedProducts),\n            gridJsObject = window[config.gridJsObjectName],\n            tabIndex = 1000;\n\n        $('in_category_products').value = Object.toJSON(categoryProducts);\n\n        /**\n         * Register Category Product\n         *\n         * @param {Object} grid\n         * @param {Object} element\n         * @param {Boolean} checked\n         */\n        function registerCategoryProduct(grid, element, checked) {\n            if (checked) {\n                if (element.positionElement) {\n                    element.positionElement.disabled = false;\n                    categoryProducts.set(element.value, element.positionElement.value);\n                }\n            } else {\n                if (element.positionElement) {\n                    element.positionElement.disabled = true;\n                }\n                categoryProducts.unset(element.value);\n            }\n            $('in_category_products').value = Object.toJSON(categoryProducts);\n            grid.reloadParams = {\n                'selected_products[]': categoryProducts.keys()\n            };\n        }\n\n        /**\n         * Click on product row\n         *\n         * @param {Object} grid\n         * @param {String} event\n         */\n        function categoryProductRowClick(grid, event) {\n            var trElement = Event.findElement(event, 'tr'),\n                eventElement = Event.element(event),\n                isInputCheckbox = eventElement.tagName === 'INPUT' && eventElement.type === 'checkbox',\n                isInputPosition = grid.targetElement &&\n                    grid.targetElement.tagName === 'INPUT' &&\n                    grid.targetElement.name === 'position',\n                checked = false,\n                checkbox = null;\n\n            if (eventElement.tagName === 'LABEL' &&\n                trElement.querySelector('#' + eventElement.htmlFor) &&\n                trElement.querySelector('#' + eventElement.htmlFor).type === 'checkbox'\n            ) {\n                event.stopPropagation();\n                trElement.querySelector('#' + eventElement.htmlFor).trigger('click');\n\n                return;\n            }\n\n            if (trElement && !isInputPosition) {\n                checkbox = Element.getElementsBySelector(trElement, 'input');\n\n                if (checkbox[0]) {\n                    checked = isInputCheckbox ? checkbox[0].checked : !checkbox[0].checked;\n                    gridJsObject.setCheckboxChecked(checkbox[0], checked);\n                }\n            }\n        }\n\n        /**\n         * Change product position\n         *\n         * @param {String} event\n         */\n        function positionChange(event) {\n            var element = Event.element(event);\n\n            if (element && element.checkboxElement && element.checkboxElement.checked) {\n                categoryProducts.set(element.checkboxElement.value, element.value);\n                $('in_category_products').value = Object.toJSON(categoryProducts);\n            }\n        }\n\n        /**\n         * Initialize category product row\n         *\n         * @param {Object} grid\n         * @param {String} row\n         */\n        function categoryProductRowInit(grid, row) {\n            var checkbox = $(row).getElementsByClassName('checkbox')[0],\n                position = $(row).getElementsByClassName('input-text')[0];\n\n            if (checkbox && position) {\n                checkbox.positionElement = position;\n                position.checkboxElement = checkbox;\n                position.disabled = !checkbox.checked;\n                position.tabIndex = tabIndex++;\n                Event.observe(position, 'keyup', positionChange);\n            }\n        }\n\n        gridJsObject.rowClickCallback = categoryProductRowClick;\n        gridJsObject.initRowCallback = categoryProductRowInit;\n        gridJsObject.checkboxCheckCallback = registerCategoryProduct;\n\n        if (gridJsObject.rows) {\n            gridJsObject.rows.each(function (row) {\n                categoryProductRowInit(gridJsObject, row);\n            });\n        }\n    };\n});\n","Magento_Catalog/catalog/category/form.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], function ($, alert) {\n    'use strict';\n\n    return function (config) {\n        var categoryForm = {\n            options: {\n                categoryIdSelector: 'input[name=\"id\"]',\n                categoryPathSelector: 'input[name=\"path\"]',\n                categoryParentSelector: 'input[name=\"parent\"]',\n                categoryLevelSelector: 'input[name=\"level\"]',\n                refreshUrl: config.refreshUrl\n            },\n\n            /**\n             * Sending ajax to server to refresh field 'path'\n             * @protected\n             */\n            refreshPath: function () {\n                if (!$(this.options.categoryIdSelector)) {\n                    return false;\n                }\n                $.ajax({\n                    url: this.options.refreshUrl,\n                    method: 'GET',\n                    showLoader: true\n                }).done(this._refreshPathSuccess.bind(this));\n            },\n\n            /**\n             * Refresh field 'path' on ajax success\n             * @param {Object} data\n             * @private\n             */\n            _refreshPathSuccess: function (data) {\n                if (data.error) {\n                    alert({\n                        content: data.message\n                    });\n                } else {\n                    $(this.options.categoryIdSelector).val(data.id).trigger('change');\n                    $(this.options.categoryPathSelector).val(data.path).trigger('change');\n                    $(this.options.categoryParentSelector).val(data.parentId).trigger('change');\n                    $(this.options.categoryLevelSelector).val(data.level).trigger('change');\n                }\n            }\n        };\n\n        $('body').on('categoryMove.tree', $.proxy(categoryForm.refreshPath.bind(categoryForm), this));\n    };\n});\n","Magento_Catalog/catalog/product/composite/configure.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'Magento_Ui/js/lib/view/utils/async',\n    'jquery/ui',\n    'mage/translate',\n    'prototype',\n    'Magento_Ui/js/modal/modal'\n], function (jQuery) {\n\n    window.ProductConfigure = Class.create();\n\n    ProductConfigure.prototype = {\n\n        listTypes:                  $H({}),\n        current:                    $H({}),\n        itemsFilter:                $H({}),\n        blockWindow:                null,\n        blockForm:                  null,\n        blockFormFields:            null,\n        blockFormAdd:               null,\n        blockFormConfirmed:         null,\n        blockConfirmed:             null,\n        blockIFrame:                null,\n        blockCancelBtn:             null,\n        blockMask:                  null,\n        blockMsg:                   null,\n        blockMsgError:              null,\n        windowHeight:               null,\n        confirmedCurrentId:         null,\n        confirmCallback:            {},\n        cancelCallback:             {},\n        onLoadIFrameCallback:       {},\n        showWindowCallback:         {},\n        beforeSubmitCallback:       {},\n        iFrameJSVarname:            null,\n        _listTypeId:                1,\n\n        /**\n         * Initialize object\n         */\n        initialize: function () {\n            var self = this,\n                popupDialog = jQuery('#product_composite_configure');\n\n            this._initWindowElements();\n            jQuery.async('#product_composite_configure', function (el) {\n                if (el !== popupDialog[0]) {\n                    el = popupDialog[0];\n                }\n                self.dialog = jQuery(el).modal({\n                    title: jQuery.mage.__('Configure Product'),\n                    type: 'slide',\n                    buttons: [{\n                        text: jQuery.mage.__('OK'),\n                        'class': 'action-primary',\n                        click: function () {\n                            self.onConfirmBtn();\n                        }\n                    }],\n                    closed: function () {\n                        self.clean('window');\n                    },\n                });\n            });\n        },\n\n        /**\n         * Initialize window elements\n         */\n        _initWindowElements: function () {\n            this.blockWindow                = $('product_composite_configure');\n            this.blockForm                  = $('product_composite_configure_form');\n            this.blockFormFields            = $('product_composite_configure_form_fields');\n            this.blockFormAdd               = $('product_composite_configure_form_additional');\n            this.blockFormConfirmed         = $('product_composite_configure_form_confirmed');\n            this.blockConfirmed             = $('product_composite_configure_confirmed');\n            this.blockIFrame                = $('product_composite_configure_iframe');\n            this.blockCancelBtn             = $('product_composite_configure_form_cancel');\n            this.blockMsg                   = $('product_composite_configure_messages');\n            this.blockMsgError              = this.blockMsg.select('.message.error div')[0];\n            this.iFrameJSVarname            = this.blockForm.select('input[name=\"as_js_varname\"]')[0].value;\n        },\n\n        /**\n         * Returns next unique list type id\n         */\n        _generateListTypeId: function () {\n            return '_internal_lt_' + this._listTypeId++;\n        },\n\n        /**\n         * Add product list types as scope and their urls\n         * example: addListType('product_to_add', {urlFetch: 'http://magento...'})\n         * example: addListType('wishlist', {urlSubmit: 'http://magento...'})\n         *\n         * @param type types as scope\n         * @param urls obj can be\n         *             - {urlFetch: 'http://magento...'} for fetching configuration fields through ajax\n         *             - {urlConfirm: 'http://magento...'} for submit configured data through iFrame when clicked confirm button\n         *             - {urlSubmit: 'http://magento...'} for submit configured data through iFrame\n         */\n        addListType: function (type, urls) {\n            if ('undefined' == typeof this.listTypes[type]) {\n                this.listTypes[type] = {};\n            }\n            Object.extend(this.listTypes[type], urls);\n\n            return this;\n        },\n\n        /**\n         * Adds complex list type - that is used to submit several list types at once\n         * Only urlSubmit is possible for this list type\n         * example: addComplexListType(['wishlist', 'product_list'], 'http://magento...')\n         *\n         * @param type types as scope\n         * @param urls obj can be\n         *             - {urlSubmit: 'http://magento...'} for submit configured data through iFrame\n         * @return type string\n         */\n        addComplexListType: function (types, urlSubmit) {\n            var type = this._generateListTypeId();\n\n            this.listTypes[type] = {};\n            this.listTypes[type].complexTypes = types;\n            this.listTypes[type].urlSubmit = urlSubmit;\n\n            return type;\n        },\n\n        /**\n         * Add filter of items\n         *\n         * @param listType scope name\n         * @param itemsFilter\n         */\n        addItemsFilter: function (listType, itemsFilter) {\n            if (!listType || !itemsFilter) {\n                return false;\n            }\n\n            if ('undefined' == typeof this.itemsFilter[listType]) {\n                this.itemsFilter[listType] = [];\n            }\n            this.itemsFilter[listType] = this.itemsFilter[listType].concat(itemsFilter);\n\n            return this;\n        },\n\n        /**\n         * Returns id of block where configuration for an item is stored\n         *\n         * @param listType scope name\n         * @param itemId\n         * @return string\n         */\n        _getConfirmedBlockId: function (listType, itemId) {\n            return this.blockConfirmed.id + '[' + listType + '][' + itemId + ']';\n        },\n\n        /**\n         * Checks whether item has some configuration fields\n         *\n         * @param listType scope name\n         * @param itemId\n         * @return bool\n         */\n        itemConfigured: function (listType, itemId) {\n            var confirmedBlockId = this._getConfirmedBlockId(listType, itemId);\n            var itemBlock = $(confirmedBlockId);\n\n            return !!(itemBlock && itemBlock.innerHTML);\n        },\n\n        /**\n         * Show configuration fields of item, if it not found then get it through ajax\n         *\n         * @param listType scope name\n         * @param itemId\n         */\n        showItemConfiguration: function (listType, itemId) {\n            if (!listType || !itemId) {\n                return false;\n            }\n\n            this.initialize();\n            this.current.listType = listType;\n            this.current.itemId = itemId;\n            this.confirmedCurrentId = this._getConfirmedBlockId(listType, itemId);\n\n            if (!this.itemConfigured(listType, itemId)) {\n                this._requestItemConfiguration(listType, itemId);\n            } else {\n                this._processFieldsData('item_restore');\n                this._showWindow();\n            }\n        },\n\n        /**\n         * Get configuration fields of product through ajax and show them\n         *\n         * @param listType scope name\n         * @param itemId\n         */\n        _requestItemConfiguration: function (listType, itemId) {\n            if (!this.listTypes[listType].urlFetch) {\n                return false;\n            }\n            var url = this.listTypes[listType].urlFetch;\n\n            if (url) {\n                new Ajax.Request(url, {\n                    parameters: {\n                        id: itemId\n                    },\n                    onSuccess: function (transport) {\n                        var response = transport.responseText;\n\n                        if (response.isJSON()) {\n                            response = response.evalJSON();\n\n                            if (response.error) {\n                                this.blockMsg.show();\n                                this.blockMsgError.innerHTML = response.message;\n                                if(this.blockCancelBtn) {\n                                    this.blockCancelBtn.hide();\n                                }\n                                this.setConfirmCallback(listType, null);\n                                this._showWindow();\n                            }\n                        } else if (response) {\n                            response += '';\n                            this.blockFormFields.update(response);\n\n                            // Add special div to hold mage data, e.g. scripts to execute on every popup show\n                            var mageData = {};\n                            var scripts = response.extractScripts();\n\n                            mageData.scripts = scripts;\n\n                            var scriptHolder = new Element('div', {\n                                'style': 'display:none'\n                            });\n\n                            scriptHolder.mageData = mageData;\n                            this.blockFormFields.insert(scriptHolder);\n\n                            // Show window\n                            this._showWindow();\n                        }\n                    }.bind(this)\n                });\n            }\n        },\n\n        /**\n         * Triggered on confirm button click\n         * Do submit configured data through iFrame if needed\n         */\n        onConfirmBtn: function () {\n            if (jQuery(this.blockForm).valid()) {\n                if (this.listTypes[this.current.listType].urlConfirm) {\n                    this.submit();\n                } else {\n                    this._processFieldsData('item_confirm');\n                    this._closeWindow();\n\n                    if (Object.isFunction(this.confirmCallback[this.current.listType])) {\n                        this.confirmCallback[this.current.listType]();\n                    }\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Triggered on cancel button click\n         */\n        onCancelBtn: function () {\n            this._closeWindow();\n\n            if (Object.isFunction(this.cancelCallback[this.current.listType])) {\n                this.cancelCallback[this.current.listType]();\n            }\n\n            return this;\n        },\n\n        /**\n         * Submit configured data through iFrame\n         *\n         * @param listType scope name\n         */\n        submit: function (listType) {\n            // prepare data\n            if (listType) {\n                this.current.listType = listType;\n                this.current.itemId = null;\n            }\n            var urlConfirm = this.listTypes[this.current.listType].urlConfirm;\n            var urlSubmit = this.listTypes[this.current.listType].urlSubmit;\n\n            if (!urlConfirm && !urlSubmit) {\n                return false;\n            }\n\n            if (urlConfirm) {\n                this.blockForm.action = urlConfirm;\n                this.addFields([new Element('input', {\n                    type: 'hidden', name: 'id', value: this.current.itemId\n                })]);\n            } else {\n                this.blockForm.action = urlSubmit;\n\n                var complexTypes = this.listTypes[this.current.listType].complexTypes;\n\n                if (complexTypes) {\n                    this.addFields([new Element('input', {\n                        type: 'hidden', name: 'configure_complex_list_types', value: complexTypes.join(',')\n                    })]);\n                }\n\n                this._processFieldsData('current_confirmed_to_form');\n\n                // Disable item controls that duplicate added fields (e.g. sometimes qty controls can intersect)\n                // so they won't be submitted\n                var tagNames = ['input', 'select', 'textarea'];\n\n                var names = {}; // Map of added field names\n\n                for (var i = 0, len = tagNames.length; i < len; i++) {\n                    var tagName = tagNames[i];\n                    var elements = this.blockFormAdd.getElementsByTagName(tagName);\n\n                    for (var index = 0, elLen = elements.length; index < elLen; index++) {\n                        names[elements[index].name] = true;\n                    }\n                }\n\n                for (var i = 0, len = tagNames.length; i < len; i++) {\n                    var tagName = tagNames[i];\n                    var elements = this.blockFormConfirmed.getElementsByTagName(tagName);\n\n                    for (var index = 0, elLen = elements.length; index < elLen; index++) {\n                        var element = elements[index];\n\n                        if (names[element.name]) {\n                            element.setAttribute('configure_disabled', 1);\n                            element.setAttribute('configure_prev_disabled', element.disabled ? 1 : 0);\n                            element.disabled = true;\n                        } else {\n                            element.setAttribute('configure_disabled', 0);\n                        }\n                    }\n                }\n            }\n            // do submit\n            if (Object.isFunction(this.beforeSubmitCallback[this.current.listType])) {\n                this.beforeSubmitCallback[this.current.listType]();\n            }\n            this.blockForm.submit();\n\n            // Show loader\n            jQuery(this.blockForm).trigger('processStart');\n\n            return this;\n        },\n\n        /**\n         * Add dynamically additional fields for form\n         *\n         * @param fields\n         */\n        addFields: function (fields) {\n            fields.each(function (elm) {\n                this.blockFormAdd.insert(elm);\n            }.bind(this));\n\n            return this;\n        },\n\n        /**\n         * Triggered when form was submitted and iFrame was loaded. Get response from iFrame and handle it\n         */\n        onLoadIFrame: function () {\n            this.blockFormConfirmed.select('[configure_disabled=1]').each(function (element) {\n                element.disabled = element.getAttribute('configure_prev_disabled') == '1';\n            });\n\n            this._processFieldsData('form_confirmed_to_confirmed');\n\n            var response = this.blockIFrame.contentWindow[this.iFrameJSVarname];\n\n            if (response && 'object' == typeof response) {\n                if (this.listTypes[this.current.listType].urlConfirm) {\n                    if (response.ok) {\n                        this._closeWindow();\n                        this.clean('current');\n                    } else if (response.error) {\n                        this.showItemConfiguration(this.current.listType, this.current.itemId);\n                        this.blockMsg.show();\n                        this.blockMsgError.innerHTML = response.message;\n                        this._showWindow();\n\n                        jQuery(this.blockForm).trigger('processStop');\n                        return false;\n                    }\n                }\n\n                if (Object.isFunction(this.onLoadIFrameCallback[this.current.listType])) {\n                    this.onLoadIFrameCallback[this.current.listType](response);\n                }\n                document.fire(this.current.listType + ':afterIFrameLoaded');\n            }\n            // Hide loader\n            jQuery(this.blockForm).trigger('processStop');\n\n            this.clean('current');\n            this.initialize();\n        },\n\n        /**\n         * Helper for fetching content from iFrame\n         */\n        _getIFrameContent: function () {\n            var content = this.blockIFrame.contentWindow || this.blockIFrame.contentDocument;\n\n            if (content.document) {\n                content = content.document;\n            }\n\n            return content;\n        },\n\n        /**\n         * Helper to find qty of currently confirmed item\n         */\n        getCurrentConfirmedQtyElement: function () {\n            var elms = $(this.confirmedCurrentId).getElementsByTagName('input');\n\n            for (var i = 0; i < elms.length; i++) {\n                if (elms[i].name == 'qty') {\n                    return elms[i];\n                }\n            }\n        },\n\n        /**\n         * Helper to find select element of currently confirmed item\n         */\n        getCurrentConfirmedSelectElement: function () {\n            return $(this.confirmedCurrentId).getElementsByTagName('select');\n        },\n\n        /**\n         * Helper to find qty of active form\n         */\n        getCurrentFormQtyElement: function () {\n            var elms = this.blockFormFields.getElementsByTagName('input');\n\n            for (var i = 0; i < elms.length; i++) {\n                if (elms[i].name == 'qty') {\n                    return elms[i];\n                }\n            }\n        },\n\n        /**\n         * Show configuration window\n         */\n        _showWindow: function () {\n            this.dialog.modal('openModal');\n            //this._toggleSelectsExceptBlock(false);\n\n            if (Object.isFunction(this.showWindowCallback[this.current.listType])) {\n                this.showWindowCallback[this.current.listType]();\n            }\n        },\n\n        /**\n         * Close configuration window\n         */\n        _closeWindow: function () {\n            this.dialog.modal('closeModal');\n            //this.blockWindow.style.display = 'none';\n            //this.clean('window');\n        },\n\n        /**\n         * Attach callback function triggered when confirm button was clicked\n         *\n         * @param confirmCallback\n         */\n        setConfirmCallback: function (listType, confirmCallback) {\n            this.confirmCallback[listType] = confirmCallback;\n\n            return this;\n        },\n\n        /**\n         * Attach callback function triggered when cancel button was clicked\n         *\n         * @param cancelCallback\n         */\n        setCancelCallback: function (listType, cancelCallback) {\n            this.cancelCallback[listType] = cancelCallback;\n\n            return this;\n        },\n\n        /**\n         * Attach callback function triggered when iFrame was loaded\n         *\n         * @param onLoadIFrameCallback\n         */\n        setOnLoadIFrameCallback: function (listType, onLoadIFrameCallback) {\n            this.onLoadIFrameCallback[listType] = onLoadIFrameCallback;\n\n            return this;\n        },\n\n        /**\n         * Attach callback function triggered when iFrame was loaded\n         *\n         * @param showWindowCallback\n         */\n        setShowWindowCallback: function (listType, showWindowCallback) {\n            this.showWindowCallback[listType] = showWindowCallback;\n\n            return this;\n        },\n\n        /**\n         * Attach callback function triggered before submitting form\n         *\n         * @param beforeSubmitCallback\n         */\n        setBeforeSubmitCallback: function (listType, beforeSubmitCallback) {\n            this.beforeSubmitCallback[listType] = beforeSubmitCallback;\n\n            return this;\n        },\n\n        /**\n         * Clean object data\n         *\n         * @param method can be 'all' or 'current'\n         */\n        clean: function (method) {\n            var listInfo = null;\n            var listTypes = null;\n            var removeConfirmed = function (listTypes) {\n                this.blockConfirmed.childElements().each(function (elm) {\n                    for (var i = 0, len = listTypes.length; i < len; i++) {\n                        var pattern = this.blockConfirmed.id + '[' + listTypes[i] + ']';\n\n                        if (elm.id.indexOf(pattern) == 0) {\n                            elm.remove();\n                            break;\n                        }\n                    }\n                }.bind(this));\n            }.bind(this);\n\n            switch (method) {\n                case 'current':\n                    listInfo = this.listTypes[this.current.listType];\n                    listTypes = [this.current.listType];\n\n                    if (listInfo && listInfo.complexTypes) {\n                        listTypes = listTypes.concat(listInfo.complexTypes);\n                    }\n                    removeConfirmed(listTypes);\n                    break;\n\n                case 'window':\n                    this.blockFormFields.update();\n                    this.blockMsg.hide();\n                    this.blockMsgError.update();\n                    if(this.blockCancelBtn) {\n                        this.blockCancelBtn.show();\n                    }\n                    break;\n                default:\n                    // search in list types for its cleaning\n                    if (this.listTypes[method]) {\n                        listInfo = this.listTypes[method];\n                        listTypes = [method];\n\n                        if (listInfo.complexTypes) {\n                            listTypes = listTypes.concat(listInfo.complexTypes);\n                        }\n                        removeConfirmed(listTypes);\n                        // clean all\n                    } else if (!method) {\n                        this.current = $H({});\n                        this.blockConfirmed.update();\n                        this.blockFormFields.update();\n                        this.blockMsg.hide();\n                        this.blockMsgError.update();\n                        if(this.blockCancelBtn) {\n                            this.blockCancelBtn.show();\n                        }\n                    }\n                    break;\n            }\n            this._getIFrameContent().body.innerHTML = '';\n            this.blockIFrame.contentWindow[this.iFrameJSVarname] = {};\n            this.blockFormAdd.update();\n            this.blockFormConfirmed.update();\n            this.blockForm.action = '';\n\n            return this;\n        },\n\n        /**\n         * Process fields data: save, restore, move saved to form and back\n         *\n         * @param method can be 'item_confirm', 'item_restore', 'current_confirmed_to_form', 'form_confirmed_to_confirmed'\n         */\n        _processFieldsData: function (method) {\n            var self = this;\n\n            /**\n             * Internal function for rename fields names of some list type\n             * if listType is not specified, then it won't be added as prefix to all names\n             *\n             * @param method can be 'current_confirmed_to_form', 'form_confirmed_to_confirmed'\n             * @param blockItem\n             */\n            var _renameFields = function (method, blockItem, listType) {\n                var pattern           = null;\n                var patternFlat       = null;\n                var patternPrefix     = RegExp('\\\\s', 'g');\n                var replacement       = null;\n                var replacementFlat   = null;\n                var replacementPrefix = '_';\n                var scopeArr          = blockItem.id.match(/.*\\[\\w+\\]\\[([^\\]]+)\\]$/);\n                var itemId            = scopeArr[1];\n\n                if (method == 'current_confirmed_to_form') {\n                    pattern         = RegExp('(\\\\w+)(\\\\[?)');\n                    patternFlat     = RegExp('(\\\\w+)');\n                    replacement     = 'item[' + itemId + '][$1]$2';\n                    replacementFlat = 'item_' + itemId + '_$1';\n\n                    if (listType) {\n                        replacement = 'list[' + listType + '][item][' + itemId + '][$1]$2';\n                        replacementFlat = 'list_' + listType + '_' + replacementFlat;\n                    }\n                } else if (method == 'form_confirmed_to_confirmed') {\n                    var stPattern = 'item\\\\[' + itemId + '\\\\]\\\\[(\\\\w+)\\\\](.*)';\n                    var stPatternFlat = 'item_' + itemId + '_(\\\\w+)';\n\n                    if (listType) {\n                        stPattern = 'list\\\\[' + listType + '\\\\]\\\\[item\\\\]\\\\[' + itemId + '\\\\]\\\\[(\\\\w+)\\\\](.*)';\n                        stPatternFlat = 'list_' + listType + '_' + stPatternFlat;\n                    }\n                    pattern         = new RegExp(stPattern);\n                    patternFlat     = new RegExp(stPatternFlat);\n                    replacement     = '$1$2';\n                    replacementFlat = '$1';\n                } else {\n                    return false;\n                }\n                var rename = function (elms) {\n                    for (var i = 0; i < elms.length; i++) {\n                        if (elms[i].name && elms[i].type == 'file') {\n                            var prefixName = 'options[files_prefix]',\n                                prefixValue = 'item_' + itemId + '_';\n\n                            self.blockFormFields.insert(new Element('input', {\n                                type: 'hidden',\n                                name: prefixName.replace(pattern, replacement),\n                                value: prefixValue.replace(patternPrefix, replacementPrefix)\n                            }));\n                            elms[i].name = elms[i].name.replace(patternFlat, replacementFlat);\n                        } else if (elms[i].name) {\n                            elms[i].name = elms[i].name.replace(pattern, replacement);\n                        }\n                    }\n                };\n\n                rename(blockItem.getElementsByTagName('input'));\n                rename(blockItem.getElementsByTagName('select'));\n                rename(blockItem.getElementsByTagName('textarea'));\n            };\n\n            switch (method) {\n                case 'item_confirm':\n                    if (!$(this.confirmedCurrentId)) {\n                        this.blockConfirmed.insert(new Element('div', {\n                            id: this.confirmedCurrentId\n                        }));\n                    } else {\n                        $(this.confirmedCurrentId).update();\n                    }\n                    this.blockFormFields.childElements().each(function (elm) {\n                        $(this.confirmedCurrentId).insert(elm);\n                    }.bind(this));\n                    break;\n\n                case 'item_restore':\n                    this.blockFormFields.update();\n\n                    // clone confirmed to form\n                    var mageData = null;\n\n                    $(this.confirmedCurrentId).childElements().each(function (elm) {\n                        var cloned = elm.cloneNode(true);\n\n                        if (elm.mageData) {\n                            cloned.mageData = elm.mageData;\n                            mageData = elm.mageData;\n                        }\n                        this.blockFormFields.insert(cloned);\n                    }.bind(this));\n\n                    // get confirmed values\n                    var fieldsValue = {};\n                    var getConfirmedValues = function (elms) {\n                        for (var i = 0; i < elms.length; i++) {\n                            if (elms[i].name) {\n                                if ('undefined' == typeof fieldsValue[elms[i].name]) {\n                                    fieldsValue[elms[i].name] = {};\n                                }\n\n                                if (elms[i].type == 'checkbox') {\n                                    fieldsValue[elms[i].name][elms[i].value] = elms[i].checked;\n                                } else if (elms[i].type == 'radio') {\n                                    if (elms[i].checked) {\n                                        fieldsValue[elms[i].name] = elms[i].value;\n                                    }\n                                } else {\n                                    fieldsValue[elms[i].name] = Form.Element.getValue(elms[i]);\n                                }\n                            }\n                        }\n                    };\n\n                    getConfirmedValues($(this.confirmedCurrentId).getElementsByTagName('input'));\n                    getConfirmedValues($(this.confirmedCurrentId).getElementsByTagName('select'));\n                    getConfirmedValues($(this.confirmedCurrentId).getElementsByTagName('textarea'));\n\n                    // restore confirmed values\n                    var restoreConfirmedValues = function (elms) {\n                        for (var i = 0; i < elms.length; i++) {\n                            if ('undefined' != typeof fieldsValue[elms[i].name]) {\n                                if (elms[i].type != 'file') {\n                                    if (elms[i].type == 'checkbox') {\n                                        elms[i].checked = fieldsValue[elms[i].name][elms[i].value];\n                                    } else if (elms[i].type == 'radio') {\n                                        if (elms[i].value == fieldsValue[elms[i].name]) {\n                                            elms[i].checked = true;\n                                        }\n                                    } else {\n                                        elms[i].setValue(fieldsValue[elms[i].name]);\n                                    }\n                                }\n                            }\n                        }\n                    };\n\n                    restoreConfirmedValues(this.blockFormFields.getElementsByTagName('input'));\n                    restoreConfirmedValues(this.blockFormFields.getElementsByTagName('select'));\n                    restoreConfirmedValues(this.blockFormFields.getElementsByTagName('textarea'));\n\n                    // Execute scripts\n                    if (mageData && mageData.scripts) {\n                        this.restorePhase = true;\n\n                        try {\n                            mageData.scripts.map(function (script) {\n                                return eval(script);\n                            });\n                        } catch (e) {\n\n                        }\n                        this.restorePhase = false;\n                    }\n                    break;\n\n                case 'current_confirmed_to_form':\n                    var allowedListTypes = {};\n\n                    allowedListTypes[this.current.listType] = true;\n                    var listInfo = this.listTypes[this.current.listType];\n\n                    if (listInfo.complexTypes) {\n                        for (var i = 0, len = listInfo.complexTypes.length; i < len; i++) {\n                            allowedListTypes[listInfo.complexTypes[i]] = true;\n                        }\n                    }\n\n                    this.blockFormConfirmed.update();\n                    this.blockConfirmed.childElements().each(function (blockItem) {\n                        var scopeArr    = blockItem.id.match(/.*\\[(\\w+)\\]\\[([^\\]]+)\\]$/);\n                        var listType    = scopeArr[1];\n                        var itemId    = scopeArr[2];\n\n                        if (allowedListTypes[listType] && (!this.itemsFilter[listType] ||\n                            this.itemsFilter[listType].indexOf(itemId) != -1)) {\n                            _renameFields(method, blockItem, listInfo.complexTypes ? listType : null);\n                            this.blockFormConfirmed.insert(blockItem);\n                        }\n                    }.bind(this));\n                    break;\n\n                case 'form_confirmed_to_confirmed':\n                    var listInfo = this.listTypes[this.current.listType];\n\n                    this.blockFormConfirmed.childElements().each(function (blockItem) {\n                        var scopeArr = blockItem.id.match(/.*\\[(\\w+)\\]\\[([^\\]]+)\\]$/);\n                        var listType = scopeArr[1];\n\n                        _renameFields(method, blockItem, listInfo.complexTypes ? listType : null);\n                        this.blockConfirmed.insert(blockItem);\n                    }.bind(this));\n                    break;\n            }\n        },\n\n        /**\n         * Check if qty selected correctly\n         *\n         * @param object element\n         * @param object event\n         */\n        changeOptionQty: function (element, event) {\n            var checkQty = true;\n\n            if ('undefined' != typeof event) {\n                if (event.keyCode == 8 || event.keyCode == 46) {\n                    checkQty = false;\n                }\n            }\n\n            if (checkQty && (Number(element.value) <= 0 || isNaN(Number(element.value)))) {\n                element.value = 1;\n            }\n        }\n    };\n\n    productConfigure = new ProductConfigure();\n    jQuery(document).trigger('productConfigure:inited');\n    jQuery(document).data('productConfigureInited', true);\n});\n","Magento_Catalog/catalog/product/attribute/unique-validate.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/backend/validation'\n], function (jQuery) {\n    'use strict';\n\n    return function (config) {\n        var msg = '',\n            _config = jQuery.extend({\n                element: null,\n                message: '',\n                uniqueClass: 'required-unique'\n            }, config),\n\n            /** @inheritdoc */\n            messager = function () {\n                return msg;\n            };\n\n        if (typeof _config.element === 'string') {\n            jQuery.validator.addMethod(\n                _config.element,\n\n                function (value, element) {\n                    var inputs = jQuery(element)\n                            .closest('table')\n                            .find('.' + _config.uniqueClass + ':visible'),\n                        valuesHash = {},\n                        isValid = true,\n                        duplicates = [];\n\n                    inputs.each(function (el) {\n                        var inputValue = inputs[el].value;\n\n                        if (typeof valuesHash[inputValue] !== 'undefined') {\n                            isValid = false;\n                            duplicates.push(inputValue);\n                        }\n                        valuesHash[inputValue] = el;\n                    });\n\n                    if (!isValid) {\n                        msg = _config.message + ' (' + duplicates.join(', ') + ')';\n                    }\n\n                    return isValid;\n                },\n\n                messager\n            );\n        }\n    };\n});\n","Magento_Catalog/catalog/product/edit/attribute.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'mage/mage',\n    'validation'\n], function ($) {\n    'use strict';\n\n    return function (config, element) {\n        $(element).mage('form').validation({\n            validationUrl: config.validationUrl\n        });\n    };\n});\n","Magento_Catalog/component/file-type-field.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/element/abstract'\n], function (Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n\n        /**\n         * Checks is relevant value\n         *\n         * @param {String} value\n         * @returns {Boolean}\n         */\n        isRelevant: function (value) {\n            if (value === 'file') {\n                this.disabled(false);\n                this.visible(true);\n\n                return true;\n            }\n\n            this.reset();\n            this.disabled(true);\n            this.visible(false);\n\n            return false;\n        }\n    });\n});\n","Magento_Catalog/component/static-type-container.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Ui/js/form/components/group'\n], function ($, Group) {\n    'use strict';\n\n    return Group.extend({\n\n        /**\n         * Checks is relevant value\n         *\n         * @param {String} value\n         * @returns {Boolean}\n         */\n        isRelevant: function (value) {\n            if ($.inArray(value, ['field', 'area', 'file', 'date', 'date_time', 'time']) !== -1) {\n                this.visible(true);\n\n                return true;\n            }\n\n            this.visible(false);\n\n            return false;\n        }\n    });\n});\n","Magento_Catalog/component/select-type-grid.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/dynamic-rows/dynamic-rows'\n], function ($, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n\n        /**\n         * Checks is relevant value\n         *\n         * @param {String} value\n         * @returns {Boolean}\n         */\n        isRelevant: function (value) {\n            if ($.inArray(value, ['drop_down', 'radio', 'checkbox', 'multiple']) !== -1) {\n                this.disabled(false);\n                this.visible(true);\n\n                return true;\n            }\n\n            this.reset();\n            this.disabled(true);\n            this.visible(false);\n\n            return false;\n        }\n    });\n});\n","Magento_Catalog/component/image-size-field.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/lib/validation/utils',\n    'Magento_Ui/js/form/element/abstract',\n    'Magento_Ui/js/lib/validation/validator',\n    'mage/translate'\n], function ($, utils, Abstract, validator) {\n    'use strict';\n\n    validator.addRule(\n        'validate-image-size-range',\n        function (value) {\n            var dataAttrRange = /^(\\d+)x(\\d+)$/,\n                m;\n\n            if (utils.isEmptyNoTrim(value)) {\n                return true;\n            }\n\n            m = dataAttrRange.exec(value);\n\n            return !!(m &&  m[1] > 0 && m[2] > 0);\n        },\n        $.mage.__('This value does not follow the specified format (for example, 200X300).')\n    );\n\n    return Abstract.extend({\n\n        /**\n         * Checks for relevant value\n         *\n         * @returns {Boolean}\n         */\n        isRangeCorrect: function () {\n            return validator('validate-image-size-range', this.value()).passed;\n        }\n    });\n});\n","Magento_Catalog/component/static-type-input.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiRegistry',\n    'Magento_Ui/js/form/element/abstract'\n], function (registry, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            parentOption: null\n        },\n\n        /**\n         * Initialize component.\n         *\n         * @returns {Element}\n         */\n        initialize: function () {\n            return this\n                ._super()\n                .initLinkToParent();\n        },\n\n        /**\n         * Cache link to parent component - option holder.\n         *\n         * @returns {Element}\n         */\n        initLinkToParent: function () {\n            var pathToParent = this.parentName.replace(/(\\.[^.]*){2}$/, '');\n\n            this.parentOption = registry.async(pathToParent);\n            this.value() && this.parentOption('label', this.value());\n\n            return this;\n        },\n\n        /**\n         * On value change handler.\n         *\n         * @param {String} value\n         */\n        onUpdate: function (value) {\n            this.parentOption(function (component) {\n                component.set('label', value ? value : component.get('headerLabel'));\n            });\n\n            return this._super();\n        }\n    });\n});\n","Magento_Catalog/component/text-type-field.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Ui/js/form/element/abstract'\n], function ($, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n\n        /**\n         * Checks for relevant value\n         *\n         * @param {*} value\n         * @returns {Boolean}\n         */\n        isRelevant: function (value) {\n            if ($.inArray(value, ['field', 'area']) !== -1) {\n                this.disabled(false);\n                this.visible(true);\n\n                return true;\n            }\n\n            this.reset();\n            this.disabled(true);\n            this.visible(false);\n\n            return false;\n        }\n    });\n});\n","Magento_Catalog/component/static-type-select.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Ui/js/form/element/select'\n], function ($, Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n\n        /**\n         * Checks is relevant value\n         *\n         * @param {String} value\n         * @returns {Boolean}\n         */\n        isRelevant: function (value) {\n            if (!value || $.inArray(value, ['drop_down', 'radio', 'checkbox', 'multiple']) !== -1) {\n                this.reset();\n                this.disabled(true);\n\n                return false;\n            }\n\n            this.disabled(false);\n\n            return true;\n        }\n    });\n});\n","Magento_Checkout/js/model/default-post-code-resolver.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([], function () {\n    'use strict';\n\n    /**\n     * Define necessity of using default post code value\n     */\n    var useDefaultPostCode;\n\n    return {\n        /**\n         * Resolve default post code\n         *\n         * @returns {String|null}\n         */\n        resolve: function () {\n            return useDefaultPostCode ?  window.checkoutConfig.defaultPostcode : null;\n        },\n\n        /**\n         * Set state to useDefaultPostCode variable\n         *\n         * @param {Boolean} shouldUseDefaultPostCode\n         * @returns {underscore}\n         */\n        setUseDefaultPostCode: function (shouldUseDefaultPostCode) {\n            useDefaultPostCode = shouldUseDefaultPostCode;\n\n            return this;\n        }\n    };\n});\n","Magento_Bundle/js/price-bundle.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    'mage/template',\n    'priceUtils',\n    'priceBox'\n], function ($, _, mageTemplate, utils) {\n    'use strict';\n\n    var globalOptions = {\n        optionConfig: null,\n        productBundleSelector: 'input.bundle.option, select.bundle.option, textarea.bundle.option',\n        qtyFieldSelector: 'input.qty',\n        priceBoxSelector: '.price-box',\n        optionHandlers: {},\n        optionTemplate: '<%- data.label %>' +\n            '<% if (data.finalPrice.value) { %>' +\n            ' +<%- data.finalPrice.formatted %>' +\n            '<% } %>',\n        controlContainer: 'dd', // should be eliminated\n        priceFormat: {},\n        isFixedPrice: false,\n        optionTierPricesBlocksSelector: '#option-tier-prices-{1} [data-role=\"selection-tier-prices\"]',\n        isOptionsInitialized: false\n    };\n\n    $.widget('mage.priceBundle', {\n        options: globalOptions,\n\n        /**\n         * @private\n         */\n        _init: function initPriceBundle() {\n            var form = this.element,\n                options = $(this.options.productBundleSelector, form);\n\n            options.trigger('change');\n        },\n\n        /**\n         * @private\n         */\n        _create: function createPriceBundle() {\n            var form = this.element,\n                options = $(this.options.productBundleSelector, form),\n                priceBox = $(this.options.priceBoxSelector, form),\n                qty = $(this.options.qtyFieldSelector, form);\n\n            this._updatePriceBox();\n            priceBox.on('price-box-initialized', this._updatePriceBox.bind(this));\n            options.on('change', this._onBundleOptionChanged.bind(this));\n            qty.on('change', this._onQtyFieldChanged.bind(this));\n        },\n\n        /**\n         * Update price box config with bundle option prices\n         * @private\n         */\n        _updatePriceBox: function () {\n            var form = this.element,\n                options = $(this.options.productBundleSelector, form),\n                priceBox = $(this.options.priceBoxSelector, form);\n\n            if (!this.options.isOptionsInitialized) {\n                if (priceBox.data('magePriceBox') &&\n                    priceBox.priceBox('option') &&\n                    priceBox.priceBox('option').priceConfig\n                ) {\n                    if (priceBox.priceBox('option').priceConfig.optionTemplate) { //eslint-disable-line max-depth\n                        this._setOption('optionTemplate', priceBox.priceBox('option').priceConfig.optionTemplate);\n                    }\n                    this._setOption('priceFormat', priceBox.priceBox('option').priceConfig.priceFormat);\n                    priceBox.priceBox('setDefault', this.options.optionConfig.prices);\n                    this.options.isOptionsInitialized = true;\n                }\n                this._applyOptionNodeFix(options);\n            }\n\n            return this;\n        },\n\n        /**\n         * Handle change on bundle option inputs\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _onBundleOptionChanged: function onBundleOptionChanged(event) {\n            var changes,\n                bundleOption = $(event.target),\n                priceBox = $(this.options.priceBoxSelector, this.element),\n                handler = this.options.optionHandlers[bundleOption.data('role')];\n\n            bundleOption.data('optionContainer', bundleOption.closest(this.options.controlContainer));\n            bundleOption.data('qtyField', bundleOption.data('optionContainer').find(this.options.qtyFieldSelector));\n\n            if (handler && handler instanceof Function) {\n                changes = handler(bundleOption, this.options.optionConfig, this);\n            } else {\n                changes = defaultGetOptionValue(bundleOption, this.options.optionConfig);//eslint-disable-line\n            }\n\n            // eslint-disable-next-line no-use-before-define\n            if (isValidQty(bundleOption)) {\n                if (changes) {\n                    priceBox.trigger('updatePrice', changes);\n                }\n\n                this._displayTierPriceBlock(bundleOption);\n                this.updateProductSummary();\n            }\n        },\n\n        /**\n         * Handle change on qty inputs near bundle option\n         * @param {jQuery.Event} event\n         * @private\n         */\n        _onQtyFieldChanged: function onQtyFieldChanged(event) {\n            var field = $(event.target),\n                optionInstance,\n                optionConfig;\n\n            if (field.data('optionId') && field.data('optionValueId')) {\n                optionInstance = field.data('option');\n                optionConfig = this.options.optionConfig\n                    .options[field.data('optionId')]\n                    .selections[field.data('optionValueId')];\n                optionConfig.qty = field.val();\n\n                // eslint-disable-next-line no-use-before-define\n                if (isValidQty(optionInstance)) {\n                    optionInstance.trigger('change');\n                }\n            }\n        },\n\n        /**\n         * Helper to fix backend behavior:\n         *  - if default qty large than 1 then backend multiply price in config\n         *\n         * @deprecated\n         * @private\n         */\n        _applyQtyFix: function applyQtyFix() {\n            var config = this.options.optionConfig;\n\n            if (config.isFixedPrice) {\n                _.each(config.options, function (option) {\n                    _.each(option.selections, function (item) {\n                        if (item.qty && item.qty !== 1) {\n                            _.each(item.prices, function (price) {\n                                price.amount /= item.qty;\n                            });\n                        }\n                    });\n                });\n            }\n        },\n\n        /**\n         * Helper to fix issue with option nodes:\n         *  - you can't place any html in option ->\n         *    so you can't style it via CSS\n         * @param {jQuery} options\n         * @private\n         */\n        _applyOptionNodeFix: function applyOptionNodeFix(options) {\n            var config = this.options,\n                format = config.priceFormat,\n                template = config.optionTemplate;\n\n            template = mageTemplate(template);\n            options.filter('select').each(function (index, element) {\n                var $element = $(element),\n                    optionId = utils.findOptionId($element),\n                    optionConfig = config.optionConfig && config.optionConfig.options[optionId].selections,\n                    value;\n\n                $element.find('option').each(function (idx, option) {\n                    var $option,\n                        optionValue,\n                        toTemplate,\n                        prices;\n\n                    $option = $(option);\n                    optionValue = $option.val();\n\n                    if (!optionValue && optionValue !== 0) {\n                        return;\n                    }\n\n                    toTemplate = {\n                        data: {\n                            label: optionConfig[optionValue] && optionConfig[optionValue].name\n                        }\n                    };\n                    prices = optionConfig[optionValue].prices;\n\n                    _.each(prices, function (price, type) {\n                        value = +price.amount;\n                        value += _.reduce(price.adjustments, function (sum, x) {//eslint-disable-line\n                            return sum + x;\n                        }, 0);\n                        toTemplate.data[type] = {\n                            value: value,\n                            formatted: utils.formatPriceLocale(value, format)\n                        };\n                    });\n\n                    $option.html(template(toTemplate));\n                });\n            });\n        },\n\n        /**\n         * Custom behavior on getting options:\n         * now widget able to deep merge accepted configuration with instance options.\n         * @param  {Object}  options\n         * @return {$.Widget}\n         */\n        _setOptions: function setOptions(options) {\n            $.extend(true, this.options, options);\n\n            this._super(options);\n\n            return this;\n        },\n\n        /**\n         * Show or hide option tier prices block\n         *\n         * @param {Object} optionElement\n         * @private\n         */\n        _displayTierPriceBlock: function (optionElement) {\n            var optionType = optionElement.prop('type'),\n                optionId,\n                optionValue,\n                optionTierPricesElements;\n\n            if (optionType === 'select-one') {\n                optionId = utils.findOptionId(optionElement[0]);\n                optionValue = optionElement.val() || null;\n                optionTierPricesElements = $(this.options.optionTierPricesBlocksSelector.replace('{1}', optionId));\n\n                _.each(optionTierPricesElements, function (tierPriceElement) {\n                    var selectionId = $(tierPriceElement).data('selection-id') + '';\n\n                    if (selectionId === optionValue) {\n                        $(tierPriceElement).show();\n                    } else {\n                        $(tierPriceElement).hide();\n                    }\n                });\n            }\n        },\n\n        /**\n         * Handler to update productSummary box\n         */\n        updateProductSummary: function updateProductSummary() {\n            this.element.trigger('updateProductSummary', {\n                config: this.options.optionConfig\n            });\n        }\n    });\n\n    return $.mage.priceBundle;\n\n    /**\n     * Converts option value to priceBox object\n     *\n     * @param   {jQuery} element\n     * @param   {Object} config\n     * @returns {Object|null} - priceBox object with additional prices\n     */\n    function defaultGetOptionValue(element, config) {\n        var changes = {},\n            optionHash,\n            tempChanges,\n            qtyField,\n            optionId = utils.findOptionId(element[0]),\n            optionValue = element.val() || null,\n            optionName = element.prop('name'),\n            optionType = element.prop('type'),\n            optionConfig = config.options[optionId].selections,\n            optionQty = 0,\n            canQtyCustomize = false,\n            selectedIds = config.selected;\n\n        switch (optionType) {\n            case 'radio':\n            case 'select-one':\n\n                if (optionType === 'radio' && !element.is(':checked')) {\n                    return null;\n                }\n\n                qtyField = element.data('qtyField');\n                qtyField.data('option', element);\n\n                if (optionValue) {\n                    optionQty = optionConfig[optionValue].qty || 0;\n                    canQtyCustomize = optionConfig[optionValue].customQty === '1';\n                    toggleQtyField(qtyField, optionQty, optionId, optionValue, canQtyCustomize);//eslint-disable-line\n                    tempChanges = utils.deepClone(optionConfig[optionValue].prices);\n                    tempChanges = applyTierPrice(//eslint-disable-line\n                        tempChanges,\n                        optionQty,\n                        optionConfig[optionValue]\n                    );\n                    tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n                } else {\n                    tempChanges = {};\n                    toggleQtyField(qtyField, '0', optionId, optionValue, false);//eslint-disable-line\n                }\n                optionHash = 'bundle-option-' + optionName;\n                changes[optionHash] = tempChanges;\n                selectedIds[optionId] = [optionValue];\n                break;\n\n            case 'select-multiple':\n                optionValue = _.compact(optionValue);\n\n                _.each(optionConfig, function (row, optionValueCode) {\n                    optionHash = 'bundle-option-' + optionName + '##' + optionValueCode;\n                    optionQty = row.qty || 0;\n                    tempChanges = utils.deepClone(row.prices);\n                    tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig);//eslint-disable-line\n                    tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n                    changes[optionHash] = _.contains(optionValue, optionValueCode) ? tempChanges : {};\n                });\n\n                selectedIds[optionId] = optionValue || [];\n                break;\n\n            case 'checkbox':\n                optionHash = 'bundle-option-' + optionName + '##' + optionValue;\n                optionQty = optionConfig[optionValue].qty || 0;\n                tempChanges = utils.deepClone(optionConfig[optionValue].prices);\n                tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig);//eslint-disable-line\n                tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n                changes[optionHash] = element.is(':checked') ? tempChanges : {};\n\n                selectedIds[optionId] = selectedIds[optionId] || [];\n\n                if (!_.contains(selectedIds[optionId], optionValue) && element.is(':checked')) {\n                    selectedIds[optionId].push(optionValue);\n                } else if (!element.is(':checked')) {\n                    selectedIds[optionId] = _.without(selectedIds[optionId], optionValue);\n                }\n                break;\n\n            case 'hidden':\n                optionHash = 'bundle-option-' + optionName + '##' + optionValue;\n                optionQty = optionConfig[optionValue].qty || 0;\n                canQtyCustomize = optionConfig[optionValue].customQty === '1';\n                qtyField = element.data('qtyField');\n                qtyField.data('option', element);\n                toggleQtyField(qtyField, optionQty, optionId, optionValue, canQtyCustomize);//eslint-disable-line\n                tempChanges = utils.deepClone(optionConfig[optionValue].prices);\n                tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig);//eslint-disable-line\n                tempChanges = applyQty(tempChanges, optionQty);//eslint-disable-line\n\n                optionHash = 'bundle-option-' + optionName;\n                changes[optionHash] = tempChanges;\n                selectedIds[optionId] = [optionValue];\n                break;\n        }\n\n        return changes;\n    }\n\n    /**\n     * Check the quantity field if negative value occurs.\n     *\n     * @param {Object} bundleOption\n     */\n    function isValidQty(bundleOption) {\n        var isValid = true,\n            qtyElem = bundleOption.data('qtyField'),\n            bundleOptionType = bundleOption.prop('type');\n\n        if (['radio', 'select-one'].includes(bundleOptionType) && qtyElem.val() < 0) {\n            isValid = false;\n        }\n\n        return isValid;\n    }\n\n    /**\n     * Helper to toggle qty field\n     * @param {jQuery} element\n     * @param {String|Number} value\n     * @param {String|Number} optionId\n     * @param {String|Number} optionValueId\n     * @param {Boolean} canEdit\n     */\n    function toggleQtyField(element, value, optionId, optionValueId, canEdit) {\n        element\n            .val(value)\n            .data('optionId', optionId)\n            .data('optionValueId', optionValueId)\n            .attr('disabled', !canEdit);\n\n        if (canEdit) {\n            element.removeClass('qty-disabled');\n        } else {\n            element.addClass('qty-disabled');\n        }\n    }\n\n    /**\n     * Helper to multiply on qty\n     *\n     * @param   {Object} prices\n     * @param   {Number} qty\n     * @returns {Object}\n     */\n    function applyQty(prices, qty) {\n        _.each(prices, function (everyPrice) {\n            everyPrice.amount *= qty;\n            _.each(everyPrice.adjustments, function (el, index) {\n                everyPrice.adjustments[index] *= qty;\n            });\n        });\n\n        return prices;\n    }\n\n    /**\n     * Helper to limit price with tier price\n     *\n     * @param {Object} oneItemPrice\n     * @param {Number} qty\n     * @param {Object} optionConfig\n     * @returns {Object}\n     */\n    function applyTierPrice(oneItemPrice, qty, optionConfig) {\n        var tiers = optionConfig.tierPrice,\n            magicKey = _.keys(oneItemPrice)[0],\n            tiersFirstKey = _.keys(optionConfig)[0],\n            lowest = false;\n\n        if (!tiers) {//tiers is undefined when options has only one option\n            tiers = optionConfig[tiersFirstKey].tierPrice;\n        }\n\n        tiers.sort(function (a, b) {//sorting based on \"price_qty\"\n            return a['price_qty'] - b['price_qty'];\n        });\n\n        _.each(tiers, function (tier, index) {\n            if (tier['price_qty'] > qty) {\n                return;\n            }\n\n            if (tier.prices[magicKey].amount < oneItemPrice[magicKey].amount) {\n                lowest = index;\n            }\n        });\n\n        if (lowest !== false) {\n            oneItemPrice = utils.deepClone(tiers[lowest].prices);\n        }\n\n        return oneItemPrice;\n    }\n});\n","Magento_Bundle/js/bundle-product.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/*global FORM_KEY*/\n/*global bSelection*/\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'Magento_Catalog/js/product/weight-handler',\n    'Magento_Ui/js/modal/modal',\n    'jquery/ui',\n    'mage/translate',\n    'Magento_Theme/js/sortable',\n    'prototype'\n], function ($, weightHandler) {\n    'use strict';\n\n    $.widget('mage.bundleProduct', {\n        /** @inheritdoc */\n        _create: function () {\n            this._initOptionBoxes()\n                ._initSortableSelections()\n                ._bindCheckboxHandlers()\n                ._initCheckboxState()\n                ._bindAddSelectionDialog()\n                ._hideProductTypeSwitcher();\n        },\n\n        /**\n         * @return {Object}\n         * @private\n         */\n        _initOptionBoxes: function () {\n            var syncOptionTitle;\n\n            this.element.sortable({\n                axis: 'y',\n                handle: '[data-role=draggable-handle]',\n                items: '.option-box',\n                update: this._updateOptionBoxPositions,\n                tolerance: 'pointer'\n            });\n\n            /**\n             * @param {jQuery.Event} event\n             */\n            syncOptionTitle = function (event) {\n                var originalValue = $(event.target).attr('data-original-value'),\n                    currentValue = $(event.target).val(),\n                    optionBoxTitle = $('.title > span', $(event.target).closest('.option-box')),\n                    newOptionTitle = $.mage.__('New Option');\n\n                optionBoxTitle.text(currentValue === '' && !originalValue.length ? newOptionTitle : currentValue);\n            };\n            this._on({\n                'change .field-option-title input[name$=\"[title]\"]': syncOptionTitle,\n                'keyup .field-option-title input[name$=\"[title]\"]': syncOptionTitle,\n                'paste .field-option-title input[name$=\"[title]\"]': syncOptionTitle\n            });\n\n            return this;\n        },\n\n        /**\n         * @return {Object}\n         * @private\n         */\n        _initSortableSelections: function () {\n            this.element.find('.option-box .form-list tbody').sortable({\n                axis: 'y',\n                handle: '[data-role=draggable-handle]',\n\n                /**\n                 * @param {jQuery.Event} event\n                 * @param {jQuery} ui\n                 * @return {jQuery}\n                 */\n                helper: function (event, ui) {\n                    ui.children().each(function () {\n                        $(this).width($(this).width());\n                    });\n\n                    return ui;\n                },\n                update: this._updateSelectionsPositions,\n                tolerance: 'pointer'\n            });\n\n            return this;\n        },\n\n        /**\n         * @return {Object}\n         * @private\n         */\n        _initCheckboxState: function () {\n            this.element.find('.is-required').each(function () {\n                $(this).prop('checked', $(this).closest('.option-box').find('[name$=\"[required]\"]').val() > 0);\n            });\n\n            this.element.find('.is-user-defined-qty').each(function () {\n                $(this).prop('checked', $(this).closest('.qty-box').find('.select').val() > 0);\n            });\n\n            return this;\n        },\n\n        /**\n         * @return {Object}\n         * @private\n         */\n        _bindAddSelectionDialog: function () {\n            var widget = this;\n\n            this._on({\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                'click .add-selection': function (event) {\n                    var $optionBox = $(event.target).closest('.option-box'),\n                        $selectionGrid = $optionBox.find('.selection-search').clone(),\n                        optionIndex = $optionBox.attr('id').replace('bundle_option_', ''),\n                        productIds = [],\n                        productSkus = [],\n                        selectedProductList = {};\n\n                    $optionBox.find('[name$=\"[product_id]\"]').each(function () {\n                        if (!$(this).closest('tr').find('[name$=\"[delete]\"]').val()) {\n                            productIds.push($(this).val());\n                            productSkus.push($(this).closest('tr').find('.col-sku').text());\n                        }\n                    });\n\n                    bSelection.gridSelection.set(optionIndex, $H({}));\n                    bSelection.gridRemoval = $H({});\n                    bSelection.gridSelectedProductSkus = productSkus;\n\n                    $selectionGrid.on('contentUpdated', bSelection.gridUpdateCallback);\n                    $selectionGrid.on('change', '.col-id input', function () {\n                        var tr = $(this).closest('tr');\n\n                        if ($(this).is(':checked')) {\n                            selectedProductList[$(this).val()] = {\n                                name: tr.find('.col-name').html().trim(),\n                                sku: tr.find('.col-sku').html().trim(),\n                                'product_id': $(this).val(),\n                                'option_id': $('bundle_selection_id_' + optionIndex).val(),\n                                'selection_price_value': 0,\n                                'selection_qty': 1\n                            };\n                        } else {\n                            delete selectedProductList[$(this).val()];\n                        }\n                    });\n\n                    $selectionGrid.modal({\n                        title: $optionBox.find('input[name$=\"[title]\"]').val() === '' ?\n                            $.mage.__('Add Products to New Option') :\n                            $.mage.__('Add Products to Option \"%1\"').replace(\n                                '%1',\n                                $('<div>').text($optionBox.find('input[name$=\"[title]\"]').val()).html()\n                            ),\n                        modalClass: 'bundle',\n                        type: 'slide',\n\n                        /**\n                         * @param {jQuery.Event} e\n                         * @param {Object} modalWindow\n                         */\n                        closed: function (e, modalWindow) {\n                            modalWindow.modal.remove();\n                        },\n                        buttons: [{\n                            text: $.mage.__('Add Selected Products'),\n                            'class': 'action-primary action-add',\n\n                            /** Click action. */\n                            click: function () {\n                                $.each(selectedProductList, function () {\n                                    window.bSelection.addRow(optionIndex, this);\n                                });\n                                bSelection.gridRemoval.each(function (pair) {\n                                    $optionBox.find('.col-sku').filter(function () {\n                                        let text = $(this).text();\n\n                                        return text.trim() === pair.key; // find row by SKU\n                                    }).closest('tr').find('button.delete').trigger('click');\n                                });\n                                widget.refreshSortableElements();\n                                widget._updateSelectionsPositions.apply(widget.element);\n                                $selectionGrid.modal('closeModal');\n                            }\n                        }]\n                    });\n                    $.ajax({\n                        url: bSelection.selectionSearchUrl,\n                        dataType: 'html',\n                        data: {\n                            index: optionIndex,\n                            products: productIds,\n                            'selected_products': productIds,\n                            'form_key': FORM_KEY\n                        },\n\n                        /**\n                         * @param {*} data\n                         */\n                        success: function (data) {\n                            $selectionGrid.html(data).modal('openModal');\n                        },\n                        context: $('body'),\n                        showLoader: true\n                    });\n                }\n            });\n\n            return this;\n        },\n\n        /**\n         * @private\n         */\n        _hideProductTypeSwitcher: function () {\n            weightHandler.hideWeightSwitcher();\n        },\n\n        /**\n         * @return {Object}\n         * @private\n         */\n        _bindCheckboxHandlers: function () {\n            this._on({\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                'change .is-required': function (event) {\n                    var $this = $(event.target);\n\n                    $this.closest('.option-box').find('[name$=\"[required]\"]').val($this.is(':checked') ? 1 : 0);\n                },\n\n                /**\n                 * @param {jQuery.Event} event\n                 */\n                'change .is-user-defined-qty': function (event) {\n                    var $this = $(event.target);\n\n                    $this.closest('.qty-box').find('.select').val($this.is(':checked') ? 1 : 0);\n                }\n            });\n\n            return this;\n        },\n\n        /**\n         * @return {Object}\n         * @private\n         */\n        _updateOptionBoxPositions: function () {\n            $(this).find('[name^=bundle_options][name$=\"[position]\"]').each(function (index) {\n                $(this).val(index);\n            });\n\n            return this;\n        },\n\n        /**\n         * @return {Object}\n         * @private\n         */\n        _updateSelectionsPositions: function () {\n            $(this).find('[name^=bundle_selections][name$=\"[position]\"]').each(function (index) {\n                $(this).val(index);\n            });\n\n            return this;\n        },\n\n        /**\n         *\n         * @return {Object}\n         */\n        refreshSortableElements: function () {\n            this.element.sortable('refresh');\n            this._updateOptionBoxPositions.apply(this.element);\n            this._initSortableSelections();\n            this._initCheckboxState();\n\n            return this;\n        }\n    });\n\n});\n","Magento_Bundle/js/bundle-type-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'Magento_Catalog/catalog/type-events',\n    'Magento_Catalog/js/product/weight-handler'\n], function ($, productType, weight) {\n    'use strict';\n\n    return {\n\n        /**\n         * Constructor component\n         */\n        'Magento_Bundle/js/bundle-type-handler': function () {\n            this.bindAll();\n            this._initType();\n        },\n\n        /**\n         * Bind all\n         */\n        bindAll: function () {\n            $(document).on('changeTypeProduct', this._initType.bind(this));\n        },\n\n        /**\n         * Init type\n         * @private\n         */\n        _initType: function () {\n            if (\n                productType.type.init === 'bundle' &&\n                productType.type.current !== 'bundle' &&\n                !weight.isLocked()\n            ) {\n                weight.switchWeight();\n            }\n        }\n    };\n});\n","Magento_Bundle/js/components/bundle-dynamic-rows-grid.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'Magento_Ui/js/dynamic-rows/dynamic-rows-grid',\n    'uiLayout',\n    'rjsResolver'\n], function (_, dynamicRowsGrid, layout, resolver) {\n    'use strict';\n\n    return dynamicRowsGrid.extend({\n        defaults: {\n            label: '',\n            columnsHeader: false,\n            columnsHeaderAfterRender: true,\n            addButton: false,\n            isDefaultFieldScope: 'is_default',\n            defaultRecords: {\n                use: [],\n                moreThanOne: false,\n                state: {}\n            },\n            listens: {\n                inputType: 'onInputTypeChange',\n                isDefaultValue: 'onIsDefaultValue',\n                pageSize: 'onPageSizeChange'\n            },\n            sizesConfig: {\n                component: 'Magento_Ui/js/grid/paging/sizes',\n                name: '${ $.name }_sizes',\n                options: {\n                    '20': {\n                        value: 20,\n                        label: 20\n                    },\n                    '30': {\n                        value: 30,\n                        label: 30\n                    },\n                    '50': {\n                        value: 50,\n                        label: 50\n                    },\n                    '100': {\n                        value: 100,\n                        label: 100\n                    },\n                    '200': {\n                        value: 200,\n                        label: 200\n                    }\n                },\n                storageConfig: {\n                    provider: '${ $.storageConfig.provider }',\n                    namespace: '${ $.storageConfig.namespace }'\n                },\n                enabled: false\n            },\n            links: {\n                options: '${ $.sizesConfig.name }:options',\n                pageSize: '${ $.sizesConfig.name }:value'\n            },\n            modules: {\n                sizes: '${ $.sizesConfig.name }'\n            }\n        },\n\n        /**\n         * Initializes paging component.\n         *\n         * @returns {Paging} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initSizes();\n\n            return this;\n        },\n\n        /**\n         * Initializes sizes component.\n         *\n         * @returns {Paging} Chainable.\n         */\n        initSizes: function () {\n            if (this.sizesConfig.enabled) {\n                layout([this.sizesConfig]);\n            }\n\n            return this;\n        },\n\n        /**\n         * Handler for type select.\n         *\n         * @param {String} inputType - changed.\n         */\n        onInputTypeChange: function (inputType) {\n            if (this.defaultRecords.moreThanOne && (inputType === 'radio' || inputType === 'select')) {\n                _.each(this.defaultRecords.use, function (index, counter) {\n                    this.source.set(\n                        this.dataScope + '.bundle_selections.' + index + '.' + this.isDefaultFieldScope,\n                        counter ? '0' : '1'\n                    );\n                }.bind(this));\n            }\n        },\n\n        /**\n         * Handler for is_default field.\n         *\n         * @param {Object} data - changed data.\n         */\n        onIsDefaultValue: function (data) {\n            var cb,\n                use = 0;\n\n            this.defaultRecords.use = [];\n\n            cb = function (elem, key) {\n\n                if (~~elem) {\n                    this.defaultRecords.use.push(key);\n                    use++;\n                }\n\n                this.defaultRecords.moreThanOne = use > 1;\n            }.bind(this);\n\n            _.each(data, cb);\n        },\n\n        /**\n         * Initialize elements from grid\n         *\n         * @param {Array} data\n         *\n         * @returns {Object} Chainable.\n         */\n        initElements: function (data) {\n            var newData = this.getNewData(data),\n                recordIndex;\n\n            this.parsePagesData(data);\n\n            if (newData.length) {\n                if (this.insertData().length) {\n                    recordIndex = data.length - newData.length - 1;\n\n                    _.each(newData, function (newRecord) {\n                        this.processingAddChild(newRecord, ++recordIndex, newRecord[this.identificationProperty]);\n                    }, this);\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Mapping value from grid\n         *\n         * @param {Array} data\n         */\n        mappingValue: function (data) {\n            if (_.isEmpty(data)) {\n                return;\n            }\n\n            this._super();\n        },\n\n        /**\n         * Handles changes of the page size.\n         */\n        onPageSizeChange: function () {\n            resolver(function () {\n                if (this.elems().length) {\n                    this.reload();\n                }\n            }, this);\n        }\n    });\n});\n","Magento_Bundle/js/components/bundle-record.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'Magento_Ui/js/dynamic-rows/record',\n    'uiRegistry'\n], function (Record, registry) {\n    'use strict';\n\n    return Record.extend({\n        /**\n         * @param {String} val - type of Input Type\n         */\n        onTypeChanged: function (val) {\n            var columnVisibility  = !(val === 'multi' || val === 'checkbox');\n\n            registry.async(this.name + '.' + 'selection_can_change_qty')(function (elem) {\n                elem.visible(columnVisibility);\n            });\n        }\n    });\n});\n","Magento_Bundle/js/components/bundle-input-type.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @deprecated Not used anymore\n * @see Magento_Bundle/js/components/bundle-record\n * @see Magento_Bundle/js/components/bundle-checkbox\n */\ndefine([\n    'Magento_Ui/js/form/element/select',\n    'uiRegistry'\n], function (Select, registry) {\n    'use strict';\n\n    return Select.extend({\n        defaults: {\n            previousType: '',\n            parentContainer: '',\n            selections: '',\n            targetIndex: '',\n            typeMap: {}\n        },\n\n        /**\n         * @inheritdoc\n         */\n        onUpdate: function () {\n            var type = this.typeMap[this.value()];\n\n            if (type !== this.previousType) {\n                this.previousType = type;\n                this.processSelections(type === 'radio');\n            }\n\n            this._super();\n        },\n\n        /**\n         * Toggle 'User Defined' column and clears values\n         * @param {Boolean} isRadio\n         */\n        processSelections: function (isRadio) {\n            var records = registry.get(this.retrieveParentName(this.parentContainer) + '.' + this.selections),\n                checkedFound = false;\n\n            records.elems.each(function (record) {\n                record.elems.filter(function (comp) {\n                    return comp.index === this.userDefinedIndex;\n                }, this).each(function (comp) {\n                    comp.visible(isRadio);\n                });\n\n                if (isRadio) {\n                    record.elems.filter(function (comp) {\n                        return comp.index === this.isDefaultIndex;\n                    }, this).each(function (comp) {\n                        if (comp.checked()) {\n                            if (checkedFound) {\n                                comp.clearing = true;\n                                comp.clear();\n                                comp.clearing = false;\n                            }\n\n                            checkedFound = true;\n                        }\n                    });\n                }\n            }, this);\n        },\n\n        /**\n         * Retrieve name for the most global parent with provided index.\n         *\n         * @param {String} parent - parent name.\n         * @returns {String}\n         */\n        retrieveParentName: function (parent) {\n            return this.name.replace(new RegExp('^(.+?\\\\.)?' + parent + '\\\\..+'), '$1' + parent);\n        }\n    });\n});\n","Magento_Bundle/js/components/bundle-option-qty.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/element/abstract'\n], function (Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            valueUpdate: 'input',\n            isInteger: true,\n            validation: {\n                'validate-number': true\n            }\n        },\n\n        /**\n         * @inheritdoc\n         */\n        setInitialValue: function () {\n            this.initialValue = this.getInitialValue();\n\n            if (this.initialValue === undefined || this.initialValue === '') {\n                this.initialValue = 1;\n            }\n\n            if (this.value.peek() !== this.initialValue) {\n                this.value(this.initialValue);\n            }\n\n            this.on('value', this.onUpdate.bind(this));\n            this.isUseDefault(this.disabled());\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        onUpdate: function () {\n            this.validation['validate-digits'] = this.isInteger;\n            this._super();\n        },\n\n        /**\n         * @inheritdoc\n         */\n        hasChanged: function () {\n            var notEqual = this.value() !== this.initialValue.toString();\n\n            return !this.visible() ? false : notEqual;\n        }\n    });\n});\n","Magento_Bundle/js/components/bundle-checkbox.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/element/single-checkbox',\n    'uiRegistry'\n], function (Checkbox, registry) {\n    'use strict';\n\n    return Checkbox.extend({\n        defaults: {\n            clearing: false,\n            parentContainer: '',\n            parentSelections: '',\n            changer: '',\n            exports: {\n                value: '${$.parentName}:isDefaultValue'\n            }\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initObservable: function () {\n            this._super().\n                observe('elementTmpl');\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initConfig: function () {\n            this._super();\n            this.imports.changeType = this.retrieveParentName(this.parentContainer) + '.' + this.changer + ':value';\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        onUpdate: function () {\n            if (this.prefer === 'radio' && this.checked() && !this.clearing) {\n                this.clearValues();\n            }\n\n            this._super();\n        },\n\n        /**\n         * Checkbox to radio type changer.\n         *\n         * @param {String} type - type to change.\n         */\n        changeType: function (type) {\n            var typeMap = registry.get(this.retrieveParentName(this.parentContainer) + '.' + this.changer).typeMap;\n\n            this.prefer = typeMap[type];\n            this.elementTmpl(this.templates[typeMap[type]]);\n        },\n\n        /**\n         * Clears values in components like this.\n         */\n        clearValues: function () {\n            var records = registry.get(this.retrieveParentName(this.parentSelections)),\n                index = this.index,\n                uid = this.uid;\n\n            records.elems.each(function (record) {\n                record.elems.filter(function (comp) {\n                    return comp.index === index && comp.uid !== uid;\n                }).each(function (comp) {\n                    comp.clearing = true;\n                    comp.clear();\n                    comp.clearing = false;\n                });\n            });\n        },\n\n        /**\n         * Retrieve name for the most global parent with provided index.\n         *\n         * @param {String} parent - parent name.\n         * @returns {String}\n         */\n        retrieveParentName: function (parent) {\n            return this.name.replace(new RegExp('^(.+?\\\\.)?' + parent + '\\\\..+'), '$1' + parent);\n        }\n    });\n});\n","Magento_Bundle/js/components/bundle-user-defined-checkbox.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'Magento_Ui/js/form/element/single-checkbox'\n], function (Checkbox) {\n    'use strict';\n\n    return Checkbox.extend({\n        defaults: {\n            listens: {\n                inputType: 'onInputTypeChange'\n            }\n        },\n\n        /**\n         * Handler for \"inputType\" property\n         *\n         * @param {String} data\n         */\n        onInputTypeChange: function (data) {\n            data === 'checkbox' || data === 'multi' ?\n                this.clear()\n                    .visible(false) :\n                this.visible(true);\n        }\n    });\n});\n","Magento_Bundle/js/components/bundle-dynamic-rows.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore',\n    'mageUtils',\n    'uiRegistry',\n    'Magento_Ui/js/dynamic-rows/dynamic-rows'\n], function (_, utils, registry, dynamicRows) {\n    'use strict';\n\n    return dynamicRows.extend({\n        defaults: {\n            label: '',\n            collapsibleHeader: true,\n            columnsHeader: false,\n            deleteProperty: false,\n            addButton: false\n        },\n\n        /**\n         * Set new data to dataSource,\n         * delete element\n         *\n         * @param {Array} data - record data\n         */\n        _updateData: function (data) {\n            var elems = _.clone(this.elems()),\n                path,\n                dataArr,\n                optionBaseData;\n\n            dataArr = this.recordData.splice(this.startIndex, this.recordData().length - this.startIndex);\n            dataArr.splice(0, this.pageSize);\n            elems = _.sortBy(this.elems(), function (elem) {\n                return ~~elem.index;\n            });\n\n            data.concat(dataArr).forEach(function (rec, idx) {\n                if (elems[idx]) {\n                    elems[idx].recordId = rec[this.identificationProperty];\n                }\n\n                if (!rec.position) {\n                    rec.position = this.maxPosition;\n                    this.setMaxPosition();\n                }\n\n                path = this.dataScope + '.' + this.index + '.' + (this.startIndex + idx);\n                optionBaseData = _.pick(rec, function (value) {\n                    return !_.isObject(value);\n                });\n                this.source.set(path, optionBaseData);\n                this.source.set(path + '.bundle_button_proxy', []);\n                this.source.set(path + '.bundle_selections', []);\n                this.removeBundleItemsFromOption(idx);\n                _.each(rec['bundle_selections'], function (obj, index) {\n                    this.source.set(path + '.bundle_button_proxy' + '.' + index, rec['bundle_button_proxy'][index]);\n                    this.source.set(path + '.bundle_selections' + '.' + index, obj);\n                }, this);\n            }, this);\n\n            this.elems(elems);\n        },\n\n        /**\n         *  Removes nested dynamic-rows-grid rendered records from option\n         *\n         * @param {Number|String} index - element index\n         */\n        removeBundleItemsFromOption: function (index) {\n            var bundleSelections = registry.get(this.name + '.' + index + '.' + this.bundleSelectionsName),\n                bundleSelectionsLength = (bundleSelections.elems() || []).length,\n                i;\n\n            if (bundleSelectionsLength) {\n                for (i = 0; i < bundleSelectionsLength; i++) {\n                    bundleSelections.elems()[0].destroy();\n                }\n            }\n        },\n\n        /**\n        * {@inheritdoc}\n        */\n        processingAddChild: function (ctx, index, prop) {\n            var recordIds = _.map(this.recordData(), function (rec) {\n                return parseInt(rec['record_id'], 10);\n            }),\n            maxRecordId = _.max(recordIds);\n\n            prop = maxRecordId > -1 ? maxRecordId + 1 : prop;\n            this._super(ctx, index, prop);\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/dynamic-rows/dnd.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'ko',\n    'jquery',\n    'underscore',\n    'uiElement',\n    'Magento_Ui/js/lib/view/utils/async'\n], function (ko, $, _, Element) {\n    'use strict';\n\n    var transformProp;\n\n    /**\n     * Get element context\n     */\n    function getContext(elem) {\n        return ko.contextFor(elem);\n    }\n\n    /**\n     * Defines supported css 'transform' property.\n     *\n     * @returns {String|Undefined}\n     */\n    transformProp = (function () {\n        var style = document.createElement('div').style,\n            base = 'Transform',\n            vendors = ['webkit', 'moz', 'ms', 'o'],\n            vi = vendors.length,\n            property;\n\n        if (typeof style.transform !== 'undefined') {\n            return 'transform';\n        }\n\n        while (vi--) {\n            property = vendors[vi] + base;\n\n            if (typeof style[property] !== 'undefined') {\n                return property;\n            }\n        }\n    })();\n\n    return Element.extend({\n        defaults: {\n            separatorsClass: {\n                top: '_dragover-top',\n                bottom: '_dragover-bottom'\n            },\n            step: 'auto',\n            tableClass: 'table.admin__dynamic-rows',\n            recordsCache: [],\n            draggableElement: {},\n            draggableElementClass: '_dragged',\n            elemPositions: [],\n            listens: {\n                '${ $.recordsProvider }:elems': 'setCacheRecords'\n            },\n            modules: {\n                parentComponent: '${ $.recordsProvider }'\n            }\n        },\n\n        /**\n         * Initialize component\n         *\n         * @returns {Object} Chainable.\n         */\n        initialize: function () {\n            _.bindAll(\n                this,\n                'mousemoveHandler',\n                'mouseupHandler'\n            );\n\n            this._super()\n                .body = $('body');\n\n            return this;\n        },\n\n        /**\n         * Calls 'initObservable' of parent, initializes 'options' and 'initialOptions'\n         *     properties, calls 'setOptions' passing options to it\n         *\n         * @returns {Object} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe([\n                    'recordsCache'\n                ]);\n\n            return this;\n        },\n\n        /**\n         * Init listens to start drag\n         *\n         * @param {Object} elem - DOM element\n         * @param {Object} data - element data\n         */\n        initListeners: function (elem, data) {\n            $(elem).on('mousedown touchstart', this.mousedownHandler.bind(this, data, elem));\n        },\n\n        /**\n         * Mouse down handler\n         *\n         * @param {Object} data - element data\n         * @param {Object} elem - element\n         * @param {Object} event - key down event\n         */\n        mousedownHandler: function (data, elem, event) {\n            var recordNode = this.getRecordNode(elem),\n                originRecord = $(elem).parents('tr').eq(0),\n                drEl = this.draggableElement,\n                $table = $(elem).parents('table').eq(0),\n                $tableWrapper = $table.parent(),\n                outerHight =\n                    $table.children('thead').outerHeight() === undefined ? 0 : $table.children('thead').outerHeight();\n\n            this.disableScroll();\n            $(recordNode).addClass(this.draggableElementClass);\n            $(originRecord).addClass(this.draggableElementClass);\n            this.step = this.step === 'auto' ? originRecord.height() / 2 : this.step;\n            drEl.originRow = originRecord;\n            drEl.instance = recordNode = this.processingStyles(recordNode, elem);\n            drEl.instanceCtx = this.getRecord(originRecord[0]);\n            drEl.eventMousedownY = this.getPageY(event);\n            drEl.minYpos =\n                $table.offset().top - originRecord.offset().top + outerHight;\n            drEl.maxYpos = drEl.minYpos + $table.children('tbody').outerHeight() - originRecord.outerHeight();\n            $tableWrapper.append(recordNode);\n            this.body.on('mousemove touchmove', this.mousemoveHandler);\n            this.body.on('mouseup touchend', this.mouseupHandler);\n        },\n\n        /**\n         * Mouse move handler\n         *\n         * @param {Object} event - mouse move event\n         */\n        mousemoveHandler: function (event) {\n            var depEl = this.draggableElement,\n                pageY = this.getPageY(event),\n                positionY = pageY - depEl.eventMousedownY,\n                processingPositionY = positionY + 'px',\n                processingMaxYpos = depEl.maxYpos + 'px',\n                processingMinYpos = depEl.minYpos + 'px',\n                depElement = this.getDepElement(depEl.instance, positionY, depEl.originRow);\n\n            if (depElement) {\n                depEl.depElement ? depEl.depElement.elem.removeClass(depEl.depElement.className) : false;\n                depEl.depElement = depElement;\n                depEl.depElement.insert !== 'none' ? depEl.depElement.elem.addClass(depElement.className) : false;\n            } else if (depEl.depElement && depEl.depElement.insert !== 'none') {\n                depEl.depElement.elem.removeClass(depEl.depElement.className);\n                depEl.depElement.insert = 'none';\n            }\n\n            if (positionY > depEl.minYpos && positionY < depEl.maxYpos) {\n                $(depEl.instance)[0].style[transformProp] = 'translateY(' + processingPositionY + ')';\n            } else if (positionY < depEl.minYpos) {\n                $(depEl.instance)[0].style[transformProp] = 'translateY(' + processingMinYpos + ')';\n            } else if (positionY >= depEl.maxYpos) {\n                $(depEl.instance)[0].style[transformProp] = 'translateY(' + processingMaxYpos + ')';\n            }\n        },\n\n        /**\n         * Mouse up handler\n         */\n        mouseupHandler: function (event) {\n            var depElementCtx,\n                drEl = this.draggableElement,\n                pageY = this.getPageY(event),\n                positionY = pageY - drEl.eventMousedownY;\n\n            this.enableScroll();\n            drEl.depElement = this.getDepElement(drEl.instance, positionY, this.draggableElement.originRow);\n\n            drEl.instance.remove();\n\n            if (drEl.depElement) {\n                depElementCtx = this.getRecord(drEl.depElement.elem[0]);\n                drEl.depElement.elem.removeClass(drEl.depElement.className);\n\n                if (drEl.depElement.insert !== 'none') {\n                    this.setPosition(drEl.depElement.elem, depElementCtx, drEl);\n                }\n            }\n\n            drEl.originRow.removeClass(this.draggableElementClass);\n\n            this.body.off('mousemove touchmove', this.mousemoveHandler);\n            this.body.off('mouseup touchend', this.mouseupHandler);\n\n            this.draggableElement = {};\n        },\n\n        /**\n         * Set position to element\n         *\n         * @param {Object} depElem - dep element\n         * @param {Object} depElementCtx - dep element context\n         * @param {Object} dragData - data draggable element\n         */\n        setPosition: function (depElem, depElementCtx, dragData) {\n            var depElemPosition = ~~depElementCtx.position;\n\n            if (dragData.depElement.insert === 'after') {\n                dragData.instanceCtx.position = depElemPosition + 1;\n            } else if (dragData.depElement.insert === 'before') {\n                dragData.instanceCtx.position = depElemPosition;\n            }\n        },\n\n        /**\n         * Get dependency element\n         *\n         * @param {Object} curInstance - current element instance\n         * @param {Number} position\n         * @param {Object} row\n         */\n        getDepElement: function (curInstance, position, row) {\n            var tableSelector = this.tableClass + ' tr',\n                $table = $(row).parents('table').eq(0),\n                $curInstance = $(curInstance),\n                recordsCollection = $table.find('table').length ?\n                    $table.find('tbody > tr').filter(function (index, elem) {\n                        return !$(elem).parents(tableSelector).length;\n                    }) :\n                    $table.find('tbody > tr'),\n                curInstancePositionTop = $curInstance.position().top,\n                curInstancePositionBottom = curInstancePositionTop + $curInstance.height();\n\n            if (position < 0) {\n                return this._getDepElement(recordsCollection, 'before', curInstancePositionTop);\n            } else if (position > 0) {\n                return this._getDepElement(recordsCollection, 'after', curInstancePositionBottom);\n            }\n        },\n\n        /**\n         * Get dependency element private\n         *\n         * @param {Array} collection - record collection\n         * @param {String} position - position to add\n         * @param {Number} dragPosition - position drag element\n         */\n        _getDepElement: function (collection, position, dragPosition) {\n            var rec,\n                rangeEnd,\n                rangeStart,\n                result,\n                className,\n                i = 0,\n                length = collection.length;\n\n            for (i; i < length; i++) {\n                rec = collection.eq(i);\n\n                if (position === 'before') {\n                    rangeStart = collection.eq(i).position().top - this.step;\n                    rangeEnd = rangeStart + this.step * 2;\n                    className = this.separatorsClass.top;\n                } else if (position === 'after') {\n                    rangeEnd = rec.position().top + rec.height() + this.step;\n                    rangeStart = rangeEnd - this.step * 2;\n                    className = this.separatorsClass.bottom;\n                }\n\n                if (dragPosition > rangeStart && dragPosition < rangeEnd) {\n                    result = {\n                        elem: rec,\n                        insert: rec[0] === this.draggableElement.originRow[0] ? 'none' : position,\n                        className: className\n                    };\n                }\n            }\n\n            return result;\n        },\n\n        /**\n         * Set default position of draggable element\n         *\n         * @param {Object} elem - current element instance\n         * @param {Object} data - current element data\n         */\n        _setDefaultPosition: function (elem, data) {\n            var originRecord = $(elem).parents('tr').eq(0),\n                position = originRecord.position();\n\n            ++position.top;\n            $(data).css(position);\n        },\n\n        /**\n         * Set records to cache\n         *\n         * @param {Object} records - record instance\n         */\n        setCacheRecords: function (records) {\n            this.recordsCache(records);\n        },\n\n        /**\n         * Set styles to draggable element\n         *\n         * @param {Object} data - data\n         * @param {Object} elem - elem instance\n         * @returns {Object} instance data.\n         */\n        processingStyles: function (data, elem) {\n            var table = $(elem).parents('table').eq(0),\n                columns = table.find('th'),\n                recordColumns = $(data).find('td');\n\n            this._setDefaultPosition(elem, $(data));\n            this._setColumnsWidth(columns, recordColumns);\n            this._setTableWidth(table, $(data));\n\n            return data;\n        },\n\n        /**\n         * Set table width.\n         *\n         * @param {Object} originalTable - original record instance\n         * @param {Object} recordTable - draggable record instance\n         */\n        _setTableWidth: function (originalTable, recordTable) {\n            recordTable.outerWidth(originalTable.outerWidth());\n        },\n\n        /**\n         * Set columns width.\n         *\n         * @param {Object} originColumns - original record instance\n         * @param {Object} recordColumns - draggable record instance\n         */\n        _setColumnsWidth: function (originColumns, recordColumns) {\n            var i = 0,\n                length = originColumns.length;\n\n            for (i; i < length; i++) {\n                recordColumns.eq(i).outerWidth(originColumns.eq(i).outerWidth());\n            }\n        },\n\n        /**\n         * Get copy original record\n         *\n         * @param {Object} record - original record instance\n         * @returns {Object} draggable record instance\n         */\n        getRecordNode: function (record) {\n            var $record = $(record),\n                table = $record.parents('table')[0].cloneNode(true),\n                $table = $(table);\n\n            $table.find('tr').remove();\n            $table.append($record.parents('tr')[0].cloneNode(true));\n\n            return table;\n        },\n\n        /**\n         * Get record context by element\n         *\n         * @param {Object} elem - original element\n         * @returns {Object} draggable record context\n         */\n        getRecord: function (elem) {\n            var ctx = getContext(elem),\n                index = _.isFunction(ctx.$index) ? ctx.$index() : ctx.$index;\n\n            return this.recordsCache()[index];\n        },\n\n        /**\n         * Get correct page Y\n         *\n         * @param {Object} event - current event\n         * @returns {integer}\n         */\n        getPageY: function (event) {\n            var pageY;\n\n            if (event.type.indexOf('touch') >= 0) {\n                if (event.originalEvent.touches[0]) {\n                    pageY = event.originalEvent.touches[0].pageY;\n                } else {\n                    pageY = event.originalEvent.changedTouches[0].pageY;\n                }\n            } else {\n                pageY = event.pageY;\n            }\n\n            return pageY;\n        },\n\n        /**\n         * Disable page scrolling\n         */\n        disableScroll: function () {\n            document.body.addEventListener('touchmove', this.preventDefault, {\n                passive: false\n            });\n        },\n\n        /**\n         * Enable page scrolling\n         */\n        enableScroll: function () {\n            document.body.removeEventListener('touchmove', this.preventDefault, {\n                passive: false\n            });\n        },\n\n        /**\n         * Prevent default function\n         *\n         * @param {Object} event - event object\n         */\n        preventDefault: function (event) {\n            event.preventDefault();\n        }\n\n    });\n});\n","Magento_Ui/js/dynamic-rows/record.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    'uiRegistry'\n], function (_, uiCollection, registry) {\n    'use strict';\n\n    return uiCollection.extend({\n        defaults: {\n            visible: true,\n            disabled: true,\n            headerLabel: '',\n            label: '',\n            positionProvider: 'position',\n            imports: {\n                data: '${ $.provider }:${ $.dataScope }'\n            },\n            listens: {\n                position: 'initPosition',\n                elems: 'setColumnVisibleListener'\n            },\n            links: {\n                position: '${ $.name }.${ $.positionProvider }:value'\n            },\n            exports: {\n                recordId: '${ $.provider }:${ $.dataScope }.record_id'\n            },\n            modules: {\n                parentComponent: '${ $.parentName }'\n            }\n        },\n\n        /**\n         * Extends instance with default config, calls initialize of parent\n         * class, calls initChildren method, set observe variable.\n         * Use parent \"track\" method - wrapper observe array\n         *\n         * @returns {Object} Chainable.\n         */\n        initialize: function () {\n            var self = this;\n\n            this._super();\n\n            registry.async(this.name + '.' + this.positionProvider)(function (component) {\n\n                /**\n                 * Overwrite hasChanged method\n                 *\n                 * @returns {Boolean}\n                 */\n                component.hasChanged = function () {\n\n                    /* eslint-disable eqeqeq */\n                    return this.value().toString() != this.initialValue.toString();\n\n                    /* eslint-enable eqeqeq */\n                };\n\n                if (!component.initialValue) {\n                    component.initialValue = self.parentComponent().maxPosition;\n                    component.bubble('update', component.hasChanged());\n                }\n            });\n\n            return this;\n        },\n\n        /**\n         * Init config\n         *\n         * @returns {Object} Chainable.\n         */\n        initConfig: function () {\n            this._super();\n\n            this.label = this.label || this.headerLabel;\n\n            return this;\n        },\n\n        /**\n         * Calls 'initObservable' of parent\n         *\n         * @returns {Object} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .track('position')\n                .observe([\n                    'visible',\n                    'disabled',\n                    'data',\n                    'label'\n                ]);\n\n            return this;\n        },\n\n        /**\n         * Init element position\n         *\n         * @param {Number} position - element position\n         */\n        initPosition: function (position) {\n            var pos = parseInt(position, 10);\n\n            this.parentComponent().setMaxPosition(pos, this);\n\n            if (!pos && pos !== 0) {\n                this.position = this.parentComponent().maxPosition;\n            }\n        },\n\n        /**\n         * Set column visibility listener\n         */\n        setColumnVisibleListener: function () {\n            var elem = _.find(this.elems(), function (curElem) {\n                return !curElem.hasOwnProperty('visibleListener');\n            });\n\n            if (!elem) {\n                return;\n            }\n\n            this.childVisibleListener(elem);\n\n            if (!elem.visibleListener) {\n                elem.on('visible', this.childVisibleListener.bind(this, elem));\n            }\n\n            elem.visibleListener = true;\n        },\n\n        /**\n         * Child visibility listener\n         *\n         * @param {Object} data\n         */\n        childVisibleListener: function (data) {\n            this.setVisibilityColumn(data.index, data.visible());\n        },\n\n        /**\n         * Reset data to initial value.\n         * Call method reset on child elements.\n         */\n        reset: function () {\n            var elems = this.elems(),\n                nameIsEqual,\n                dataScopeIsEqual;\n\n            _.each(elems, function (elem) {\n                nameIsEqual = this.name + '.' + this.positionProvider === elem.name;\n                dataScopeIsEqual = this.dataScope === elem.dataScope;\n\n                if (!(nameIsEqual || dataScopeIsEqual) && _.isFunction(elem.reset)) {\n                    elem.reset();\n                }\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Clear data\n         *\n         * @returns {Collection} Chainable.\n         */\n        clear: function () {\n            var elems = this.elems(),\n                nameIsEqual,\n                dataScopeIsEqual;\n\n            _.each(elems, function (elem) {\n                nameIsEqual = this.name + '.' + this.positionProvider === elem.name;\n                dataScopeIsEqual = this.dataScope === elem.dataScope;\n\n                if (!(nameIsEqual || dataScopeIsEqual) && _.isFunction(elem.reset)) {\n                    elem.clear();\n                }\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Get label for collapsible header\n         *\n         * @param {String} label\n         *\n         * @returns {String}\n         */\n        getLabel: function (label) {\n            if (_.isString(label)) {\n                this.label(label);\n            } else if (label && this.label()) {\n                return this.label();\n            } else {\n                this.label(this.headerLabel);\n            }\n\n            return this.label();\n        },\n\n        /**\n         * Set visibility to record child\n         *\n         * @param {Boolean} state\n         */\n        setVisible: function (state) {\n            this.elems.each(function (cell) {\n                cell.visible(state);\n            });\n        },\n\n        /**\n         * Set visibility to child by index\n         *\n         * @param {Number} index\n         * @param {Boolean} state\n         */\n        setVisibilityColumn: function (index, state) {\n            var elems = this.elems(),\n                curElem = parseInt(index, 10),\n                label;\n\n            if (!this.parentComponent()) {\n                return false;\n            }\n\n            if (_.isNaN(curElem)) {\n                _.findWhere(elems, {\n                    index: index\n                }).visible(state);\n                label = _.findWhere(this.parentComponent().labels(), {\n                    name: index\n                });\n                label.defaultLabelVisible && label.visible(state);\n            } else {\n                elems[curElem].visible(state);\n            }\n        },\n\n        /**\n         * Set disabled to child\n         *\n         * @param {Boolean} state\n         */\n        setDisabled: function (state) {\n            this.elems.each(function (cell) {\n                cell.disabled(state);\n            });\n        },\n\n        /**\n         * Set disabled to child by index\n         *\n         * @param {Number} index\n         * @param {Boolean} state\n         */\n        setDisabledColumn: function (index, state) {\n            index = ~~index;\n            this.elems()[index].disabled(state);\n        }\n    });\n});\n","Magento_Ui/js/dynamic-rows/dynamic-rows-grid.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    './dynamic-rows'\n], function (_, dynamicRows) {\n    'use strict';\n\n    return dynamicRows.extend({\n        defaults: {\n            dataProvider: '',\n            insertData: [],\n            map: null,\n            cacheGridData: [],\n            deleteProperty: false,\n            positionProvider: 'position',\n            dataLength: 0,\n            identificationProperty: 'id',\n            identificationDRProperty: 'id',\n            listens: {\n                'insertData': 'processingInsertData',\n                'recordData': 'initElements setToInsertData'\n            },\n            mappingSettings: {\n                enabled: true,\n                distinct: true\n            }\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initialize: function () {\n            this.setToInsertData = _.debounce(this.setToInsertData, 200);\n\n            return this._super();\n        },\n\n        /**\n         * Calls 'initObservable' of parent\n         *\n         * @returns {Object} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe([\n                    'insertData'\n                ]);\n\n            return this;\n        },\n\n        /**\n         * Set data from recordData to insertData\n         */\n        setToInsertData: function () {\n            var insertData = [],\n                obj;\n\n            if (this.recordData().length && !this.update) {\n                _.each(this.recordData(), function (recordData) {\n                    obj = {};\n                    obj[this.map[this.identificationProperty]] = recordData[this.identificationProperty];\n                    insertData.push(obj);\n                }, this);\n\n                if (insertData.length) {\n                    this.source.set(this.dataProvider, insertData);\n                }\n            }\n        },\n\n        /**\n         * Initialize children\n         *\n         * @returns {Object} Chainable.\n         */\n        initChildren: function () {\n            this.getChildItems().forEach(function (data, index) {\n                this.processingAddChild(data, this.startIndex + index, data[this.identificationDRProperty]);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Initialize elements from grid\n         *\n         * @param {Array} data\n         *\n         * @returns {Object} Chainable.\n         */\n        initElements: function (data) {\n            var newData = this.getNewData(data);\n\n            this.parsePagesData(data);\n\n            if (newData.length) {\n                if (this.insertData().length) {\n                    this.processingAddChild(newData[0], data.length - 1, newData[0][this.identificationProperty]);\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Delete record instance\n         * update data provider dataScope\n         *\n         * @param {String|Number} index - record index\n         * @param {String|Number} recordId\n         */\n        deleteRecord: function (index, recordId) {\n            this.updateInsertData(recordId);\n            this._super();\n        },\n\n        /**\n         * Updates insertData when record is deleted\n         *\n         * @param {String|Number} recordId\n         */\n        updateInsertData: function (recordId) {\n            var data = this.getElementData(this.insertData(), recordId),\n            prop = this.map[this.identificationDRProperty];\n\n            this.insertData(_.reject(this.source.get(this.dataProvider), function (recordData) {\n                return recordData[prop].toString() === data[prop].toString();\n            }, this));\n        },\n\n        /**\n         * Find data object by index\n         *\n         * @param {Array} array - data collection\n         * @param {Number} index - element index\n         * @param {String} property - to find by property\n         *\n         * @returns {Object} data object\n         */\n        getElementData: function (array, index, property) {\n            var obj = {},\n                result;\n\n            property ? obj[property] = index : obj[this.map[this.identificationDRProperty]] = index;\n            result = _.findWhere(array, obj);\n\n            if (!result) {\n                property ?\n                    obj[property] = index.toString() :\n                    obj[this.map[this.identificationDRProperty]] = index.toString();\n            }\n\n            result = _.findWhere(array, obj);\n\n            return result;\n        },\n\n        /**\n         * Processing pages before addChild\n         *\n         * @param {Object} ctx - element context\n         * @param {Number|String} index - element index\n         * @param {Number|String} prop - additional property to element\n         */\n        processingAddChild: function (ctx, index, prop) {\n            if (this._elems.length > this.pageSize) {\n                return false;\n            }\n\n            this.showSpinner(true);\n            this.addChild(ctx, index, prop);\n        },\n\n        /**\n         * Contains old data with new\n         *\n         * @param {Array} data\n         *\n         * @returns {Array} changed data\n         */\n        getNewData: function (data) {\n            var changes = [],\n                tmpObj = {};\n\n            if (data.length !== this.relatedData.length) {\n                _.each(data, function (obj) {\n                    tmpObj[this.identificationDRProperty] = obj[this.identificationDRProperty];\n\n                    if (!_.findWhere(this.relatedData, tmpObj)) {\n                        changes.push(obj);\n                    }\n                }, this);\n            }\n\n            return changes;\n        },\n\n        /**\n         * Processing insert data\n         *\n         * @param {Object} data\n         */\n        processingInsertData: function (data) {\n            var changes,\n                obj = {};\n\n            changes = this._checkGridData(data);\n            this.cacheGridData = data;\n\n            if (changes.length) {\n                obj[this.identificationDRProperty] = changes[0][this.map[this.identificationProperty]];\n\n                if (_.findWhere(this.recordData(), obj)) {\n                    return false;\n                }\n\n                changes.forEach(function (changedObject) {\n                    this.mappingValue(changedObject);\n                }, this);\n            }\n        },\n\n        /**\n         * Mapping value from grid\n         *\n         * @param {Array} data\n         */\n        mappingValue: function (data) {\n            var obj = {},\n                tmpObj = {};\n\n            if (this.mappingSettings.enabled) {\n                _.each(this.map, function (prop, index) {\n                    obj[index] = !_.isUndefined(data[prop]) ? data[prop] : '';\n                }, this);\n            } else {\n                obj = data;\n            }\n\n            if (this.mappingSettings.distinct) {\n                tmpObj[this.identificationDRProperty] = obj[this.identificationDRProperty];\n\n                if (_.findWhere(this.recordData(), tmpObj)) {\n                    return false;\n                }\n            }\n\n            if (!obj.hasOwnProperty(this.positionProvider)) {\n                this.setMaxPosition();\n                obj[this.positionProvider] = this.maxPosition;\n            }\n\n            this.source.set(this.dataScope + '.' + this.index + '.' + this.recordData().length, obj);\n        },\n\n        /**\n         * Check changed records\n         *\n         * @param {Array} data - array with records data\n         * @returns {Array} Changed records\n         */\n        _checkGridData: function (data) {\n            var cacheLength = this.cacheGridData.length,\n                curData = data.length,\n                max = cacheLength > curData ? this.cacheGridData : data,\n                changes = [],\n                obj = {};\n\n            max.forEach(function (record, index) {\n                obj[this.map[this.identificationDRProperty]] = record[this.map[this.identificationDRProperty]];\n\n                if (!_.where(this.cacheGridData, obj).length) {\n                    changes.push(data[index]);\n                }\n            }, this);\n\n            return changes;\n        }\n    });\n});\n","Magento_Ui/js/dynamic-rows/action-delete.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'Magento_Ui/js/form/element/abstract'\n], function (Abstract) {\n    'use strict';\n\n    return Abstract.extend({\n        defaults: {\n            links: {\n                value: false\n            }\n        },\n\n        /**\n         * Delete record handler.\n         *\n         * @param {Number} index\n         * @param {Number} id\n         */\n        deleteRecord: function (index, id) {\n            this.bubble('deleteRecord', index, id);\n        }\n    });\n});\n","Magento_Ui/js/dynamic-rows/dynamic-rows.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'ko',\n    'mageUtils',\n    'underscore',\n    'uiLayout',\n    'uiCollection',\n    'uiRegistry',\n    'mage/translate',\n    'jquery'\n], function (ko, utils, _, layout, uiCollection, registry, $t, $) {\n    'use strict';\n\n    /**\n     * Checks value type and cast to boolean if needed\n     *\n     * @param {*} value\n     *\n     * @returns {Boolean|*} casted or origin value\n     */\n    function castValue(value) {\n        if (_.isUndefined(value) || value === '' || _.isNull(value)) {\n            return false;\n        }\n\n        return value;\n    }\n\n    /**\n     * Compares arrays.\n     *\n     * @param {Array} base - array as method bases its decision on first argument.\n     * @param {Array} current - second array\n     *\n     * @returns {Boolean} result - is current array equal to base array\n     */\n    function compareArrays(base, current) {\n        var index = 0,\n            length = base.length;\n\n        if (base.length !== current.length) {\n            return false;\n        }\n\n        /*eslint-disable max-depth, eqeqeq, no-use-before-define */\n        for (index; index < length; index++) {\n            if (_.isArray(base[index]) && _.isArray(current[index])) {\n                if (!compareArrays(base[index], current[index])) {\n                    return false;\n                }\n            } else if (typeof base[index] === 'object' && typeof current[index] === 'object') {\n                if (!compareObjects(base[index], current[index])) {\n                    return false;\n                }\n            } else if (castValue(base[index]) != castValue(current[index])) {\n                return false;\n            }\n        }/*eslint-enable max-depth, eqeqeq, no-use-before-define */\n\n        return true;\n    }\n\n    /**\n     * Compares objects. Compares only properties from origin object,\n     * if current object has more properties - they are not considered\n     *\n     * @param {Object} base - first object\n     * @param {Object} current - second object\n     *\n     * @returns {Boolean} result - is current object equal to base object\n     */\n    function compareObjects(base, current) {\n        var prop;\n\n        /*eslint-disable max-depth, eqeqeq*/\n        for (prop in base) {\n            if (_.isArray(base[prop]) && _.isArray(current[prop])) {\n                if (!compareArrays(base[prop], current[prop])) {\n                    return false;\n                }\n            } else if (typeof base[prop] === 'object' && typeof current[prop] === 'object') {\n                if (!compareObjects(base[prop], current[prop])) {\n                    return false;\n                }\n            } else if (castValue(base[prop]) != castValue(current[prop])) {\n                return false;\n            }\n        }/*eslint-enable max-depth, eqeqeq */\n\n        return true;\n    }\n\n    return uiCollection.extend({\n        defaults: {\n            defaultRecord: false,\n            columnsHeader: true,\n            columnsHeaderAfterRender: false,\n            columnsHeaderClasses: '',\n            labels: [],\n            recordTemplate: 'record',\n            collapsibleHeader: false,\n            additionalClasses: {},\n            visible: true,\n            disabled: false,\n            fit: false,\n            addButton: true,\n            addButtonLabel: $t('Add'),\n            recordData: [],\n            maxPosition: 0,\n            deleteProperty: 'delete',\n            identificationProperty: 'record_id',\n            deleteValue: true,\n            showSpinner: true,\n            isDifferedFromDefault: false,\n            defaultState: [],\n            defaultPagesState: {},\n            pagesChanged: {},\n            hasInitialPagesState: {},\n            changed: false,\n            fallbackResetTpl: 'ui/form/element/helper/fallback-reset-link',\n            dndConfig: {\n                name: '${ $.name }_dnd',\n                component: 'Magento_Ui/js/dynamic-rows/dnd',\n                template: 'ui/dynamic-rows/cells/dnd',\n                recordsProvider: '${ $.name }',\n                enabled: true\n            },\n            templates: {\n                record: {\n                    parent: '${ $.$data.collection.name }',\n                    name: '${ $.$data.index }',\n                    dataScope: '${ $.$data.collection.index }.${ $.name }',\n                    nodeTemplate: '${ $.parent }.${ $.$data.collection.recordTemplate }'\n                }\n            },\n            links: {\n                recordData: '${ $.provider }:${ $.dataScope }.${ $.index }'\n            },\n            listens: {\n                visible: 'setVisible',\n                disabled: 'setDisabled',\n                childTemplate: 'initHeader',\n                recordTemplate: 'onUpdateRecordTemplate',\n                recordData: 'setDifferedFromDefault parsePagesData setRecordDataToCache',\n                currentPage: 'changePage',\n                elems: 'checkSpinner',\n                changed: 'updateTrigger'\n            },\n            modules: {\n                dnd: '${ $.dndConfig.name }'\n            },\n            pages: 1,\n            pageSize: 20,\n            relatedData: [],\n            currentPage: 1,\n            recordDataCache: [],\n            startIndex: 0\n        },\n\n        /**\n         * Sets record data to cache\n         */\n        setRecordDataToCache: function (data) {\n            this.recordDataCache = data;\n        },\n\n        /**\n         * Extends instance with default config, calls initialize of parent\n         * class, calls initChildren method, set observe variable.\n         * Use parent \"track\" method - wrapper observe array\n         *\n         * @returns {Object} Chainable.\n         */\n        initialize: function () {\n            _.bindAll(this,\n                'processingDeleteRecord',\n                'onChildrenUpdate',\n                'checkDefaultState',\n                'renderColumnsHeader',\n                'deleteHandler',\n                'setDefaultState'\n            );\n\n            this._super()\n                .initChildren()\n                .initDnd()\n                .initDefaultRecord()\n                .setInitialProperty()\n                .setColumnsHeaderListener()\n                .checkSpinner();\n\n            this.on('recordData', this.checkDefaultState);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        bubble: function (event) {\n            if (event === 'deleteRecord' || event === 'update') {\n                return false;\n            }\n\n            return this._super();\n        },\n\n        /**\n         * Inits DND module\n         *\n         * @returns {Object} Chainable.\n         */\n        initDnd: function () {\n            if (this.dndConfig.enabled) {\n                layout([this.dndConfig]);\n            }\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        destroy: function () {\n            if (this.dnd()) {\n                this.dnd().destroy();\n            }\n            this._super();\n        },\n\n        /**\n         * Calls 'initObservable' of parent\n         *\n         * @returns {Object} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .track('childTemplate')\n                .observe([\n                    'pages',\n                    'currentPage',\n                    'recordData',\n                    'columnsHeader',\n                    'visible',\n                    'disabled',\n                    'labels',\n                    'showSpinner',\n                    'isDifferedFromDefault',\n                    'changed'\n                ]);\n\n            return this;\n        },\n\n        /**\n         * @inheritdoc\n         */\n        initElement: function (elem) {\n            this._super();\n            elem.on({\n                'deleteRecord': this.deleteHandler,\n                'update': this.onChildrenUpdate,\n                'addChild': this.setDefaultState\n            });\n\n            return this;\n        },\n\n        /**\n         * Handler for deleteRecord event\n         *\n         * @param {Number|String} index - element index\n         * @param {Number|String} id\n         */\n        deleteHandler: function (index, id) {\n            var defaultState;\n\n            this.setDefaultState();\n            defaultState = this.defaultPagesState[this.currentPage()];\n            this.processingDeleteRecord(index, id);\n            this.pagesChanged[this.currentPage()] =\n                !compareArrays(defaultState, this.arrayFilter(this.getChildItems()));\n            this.changed(_.some(this.pagesChanged));\n        },\n\n        /**\n         * Set initial property to records data\n         *\n         * @returns {Object} Chainable.\n         */\n        setInitialProperty: function () {\n            if (_.isArray(this.recordData())) {\n                this.recordData.each(function (data, index) {\n                    this.source.set(this.dataScope + '.' + this.index + '.' + index + '.initialize', true);\n                }, this);\n            }\n\n            return this;\n        },\n\n        /**\n         * Handler for update event\n         *\n         * @param {Boolean} state\n         */\n        onChildrenUpdate: function (state) {\n            var changed,\n                dataScope,\n                changedElemDataScope;\n\n            if (state && !this.hasInitialPagesState[this.currentPage()]) {\n                this.setDefaultState();\n                changed = this.getChangedElems(this.elems());\n                dataScope = this.elems()[0].dataScope.split('.');\n                dataScope.splice(dataScope.length - 1, 1);\n                changed.forEach(function (elem) {\n                    changedElemDataScope = elem.dataScope.split('.');\n                    changedElemDataScope.splice(0, dataScope.length);\n                    changedElemDataScope[0] =\n                        (parseInt(changedElemDataScope[0], 10) - this.pageSize * (this.currentPage() - 1)).toString();\n                    this.setValueByPath(\n                        this.defaultPagesState[this.currentPage()],\n                        changedElemDataScope, elem.initialValue\n                    );\n                }, this);\n            }\n\n            if (this.defaultPagesState[this.currentPage()]) {\n                this.setChangedForCurrentPage();\n            }\n        },\n\n        /**\n         * Set default dynamic-rows state or state before changing data\n         *\n         * @param {Array} data - defaultState data\n         */\n        setDefaultState: function (data) {\n            var componentData,\n                childItems;\n\n            if (!this.hasInitialPagesState[this.currentPage()]) {\n                childItems = this.getChildItems();\n                componentData = childItems.length ?\n                    utils.copy(childItems) :\n                    utils.copy(this.getChildItems(this.recordDataCache));\n                componentData.forEach(function (dataObj) {\n                    if (dataObj.hasOwnProperty('initialize')) {\n                        delete dataObj.initialize;\n                    }\n                });\n\n                this.hasInitialPagesState[this.currentPage()] = true;\n                this.defaultPagesState[this.currentPage()] = data ? data : this.arrayFilter(componentData);\n            }\n        },\n\n        /**\n         * Sets value to object by string path\n         *\n         * @param {Object} obj\n         * @param {Array|String} path\n         * @param {*} value\n         */\n        setValueByPath: function (obj, path, value) {\n            var prop;\n\n            if (_.isString(path)) {\n                path = path.split('.');\n            }\n\n            if (path.length - 1) {\n                prop = obj[path[0]];\n                path.splice(0, 1);\n                this.setValueByPath(prop, path, value);\n            } else if (path.length && obj) {\n                obj[path[0]] = value;\n            }\n        },\n\n        /**\n         * Returns elements which changed self state\n         *\n         * @param {Array} array - data array\n         * @param {Array} changed - array with changed elements\n         * @returns {Array} changed - array with changed elements\n         */\n        getChangedElems: function (array, changed) {\n            changed = changed || [];\n\n            array.forEach(function (elem) {\n                if (_.isFunction(elem.elems)) {\n                    this.getChangedElems(elem.elems(), changed);\n                } else if (_.isFunction(elem.hasChanged) && elem.hasChanged()) {\n                    changed.push(elem);\n                }\n            }, this);\n\n            return changed;\n        },\n\n        /**\n         * Checks columnsHeaderAfterRender property,\n         * and set listener on elems if needed\n         *\n         * @returns {Object} Chainable.\n         */\n        setColumnsHeaderListener: function () {\n            if (this.columnsHeaderAfterRender) {\n                this.on('recordData', this.renderColumnsHeader);\n\n                if (_.isArray(this.recordData()) && this.recordData().length) {\n                    this.renderColumnsHeader();\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Checks whether component's state is default or not\n         */\n        checkDefaultState: function () {\n            var isRecordDataArray = _.isArray(this.recordData()),\n                initialize,\n                hasNotDefaultRecords = isRecordDataArray ? !!this.recordData().filter(function (data) {\n                    return !data.initialize;\n                }).length : false;\n\n            if (!this.hasInitialPagesState[this.currentPage()] && isRecordDataArray && hasNotDefaultRecords) {\n                this.hasInitialPagesState[this.currentPage()] = true;\n                this.defaultPagesState[this.currentPage()] = utils.copy(this.getChildItems().filter(function (data) {\n                    initialize = data.initialize;\n                    delete data.initialize;\n\n                    return initialize;\n                }));\n\n                this.setChangedForCurrentPage();\n            } else if (this.hasInitialPagesState[this.currentPage()]) {\n                this.setChangedForCurrentPage();\n            }\n        },\n\n        /**\n         * Filters out deleted items from array\n         *\n         * @param {Array} data\n         *\n         * @returns {Array} filtered array\n         */\n        arrayFilter: function (data) {\n            var prop;\n\n            /*eslint-disable no-loop-func*/\n            data.forEach(function (elem) {\n                for (prop in elem) {\n                    if (_.isArray(elem[prop])) {\n                        elem[prop] = _.filter(elem[prop], function (elemProp) {\n                            return elemProp[this.deleteProperty] !== this.deleteValue;\n                        }, this);\n\n                        elem[prop].forEach(function (elemProp) {\n                            if (_.isArray(elemProp)) {\n                                elem[prop] = this.arrayFilter(elemProp);\n                            }\n                        }, this);\n                    }\n                }\n            }, this);\n\n            /*eslint-enable no-loop-func*/\n\n            return data;\n        },\n\n        /**\n         * Triggers update event\n         *\n         * @param {Boolean} val\n         */\n        updateTrigger: function (val) {\n            this.trigger('update', val);\n        },\n\n        /**\n         * Returns component state\n         */\n        hasChanged: function () {\n            return this.changed();\n        },\n\n        /**\n         * Render column header\n         */\n        renderColumnsHeader: function () {\n            this.recordData().length ? this.columnsHeader(true) : this.columnsHeader(false);\n        },\n\n        /**\n         * Init default record\n         *\n         * @returns Chainable.\n         */\n        initDefaultRecord: function () {\n            if (this.defaultRecord && !this.recordData().length) {\n                this.addChild();\n            }\n\n            return this;\n        },\n\n        /**\n         * Create header template\n         *\n         * @param {Object} prop - instance obj\n         *\n         * @returns {Object} Chainable.\n         */\n        createHeaderTemplate: function (prop) {\n            var visible = prop.visible !== false,\n                disabled = _.isUndefined(prop.disabled) ? this.disabled() : prop.disabled;\n\n            return {\n                visible: ko.observable(visible),\n                disabled: ko.observable(disabled)\n            };\n        },\n\n        /**\n         * Init header elements\n         */\n        initHeader: function () {\n            var labels = [],\n                data;\n\n            if (!this.labels().length) {\n                _.each(this.childTemplate.children, function (cell) {\n                    data = this.createHeaderTemplate(cell.config);\n                    cell.config.labelVisible = false;\n                    _.extend(data, {\n                        defaultLabelVisible: data.visible(),\n                        label: cell.config.label,\n                        name: cell.name,\n                        required: !!cell.config.validation,\n                        columnsHeaderClasses: cell.config.columnsHeaderClasses,\n                        sortOrder: cell.config.sortOrder\n                    });\n                    labels.push(data);\n                }, this);\n                this.labels(_.sortBy(labels, 'sortOrder'));\n            }\n        },\n\n        /**\n         * Set max element position\n         *\n         * @param {Number} position - element position\n         * @param {Object} elem - instance\n         */\n        setMaxPosition: function (position, elem) {\n            if (position || position === 0) {\n                this.checkMaxPosition(position);\n                this.sort(position, elem);\n            } else {\n                this.maxPosition += 1;\n            }\n        },\n\n        /**\n         * Sort element by position\n         *\n         * @param {Number} position - element position\n         * @param {Object} elem - instance\n         */\n        sort: function (position, elem) {\n            var that = this,\n                sorted,\n                updatedCollection;\n\n            if (this.elems().filter(function (el) {\n                    return el.position || el.position === 0;\n                }).length !== this.getChildItems().length) {\n\n                return false;\n            }\n\n            if (!elem.containers.length) {\n                registry.get(elem.name, function () {\n                    that.sort(position, elem);\n                });\n\n                return false;\n            }\n\n            sorted = this.elems().sort(function (propOne, propTwo) {\n                return ~~propOne.position - ~~propTwo.position;\n            });\n\n            updatedCollection = this.updatePosition(sorted, position, elem.name);\n            this.elems(updatedCollection);\n        },\n\n        /**\n         * Checking loader visibility\n         *\n         * @param {Array} elems\n         */\n        checkSpinner: function (elems) {\n            this.showSpinner(!(!this.recordData().length || elems && elems.length === this.getChildItems().length));\n        },\n\n        /**\n         * Filtering data and calculates the quantity of pages\n         *\n         * @param {Array} data\n         */\n        parsePagesData: function (data) {\n            this.relatedData = this.deleteProperty ?\n                _.filter(data, function (elem) {\n                    return elem && elem[this.deleteProperty] !== this.deleteValue;\n                }, this) : data;\n\n            this._updatePagesQuantity();\n        },\n\n        /**\n         * Reinit record data in order to remove deleted values\n         *\n         * @return void\n         */\n        reinitRecordData: function () {\n            this.recordData(\n                _.filter(this.recordData(), function (elem) {\n                    return elem && elem[this.deleteProperty] !== this.deleteValue;\n                }, this)\n            );\n        },\n\n        /**\n         * Get items to rendering on current page\n         *\n         * @returns {Array} data\n         */\n        getChildItems: function (data, page) {\n            var dataRecord = data || this.relatedData,\n                startIndex;\n\n            this.startIndex = (~~this.currentPage() - 1) * this.pageSize;\n\n            startIndex = page || this.startIndex;\n\n            return dataRecord.slice(startIndex, this.startIndex + parseInt(this.pageSize, 10));\n        },\n\n        /**\n         * Get record count with filtered delete property.\n         *\n         * @returns {Number} count\n         */\n        getRecordCount: function () {\n            return _.filter(this.recordData(), function (record) {\n                return record && record[this.deleteProperty] !== this.deleteValue;\n            }, this).length;\n        },\n\n        /**\n         * Get number of columns\n         *\n         * @returns {Number} columns\n         */\n        getColumnsCount: function () {\n            return this.labels().length + (this.dndConfig.enabled ? 1 : 0);\n        },\n\n        /**\n         * Processing pages before addChild\n         *\n         * @param {Object} ctx - element context\n         * @param {Number|String} index - element index\n         * @param {Number|String} prop - additional property to element\n         */\n        processingAddChild: function (ctx, index, prop) {\n            this.bubble('addChild', false);\n\n            if (this.relatedData.length && this.relatedData.length % this.pageSize === 0) {\n                this.pages(this.pages() + 1);\n                this.nextPage();\n            } else if (~~this.currentPage() !== this.pages()) {\n                this.currentPage(this.pages());\n            }\n\n            this.addChild(ctx, index, prop);\n        },\n\n        /**\n         * Processing pages before deleteRecord\n         *\n         * @param {Number|String} index - element index\n         * @param {Number|String} recordId\n         */\n        processingDeleteRecord: function (index, recordId) {\n            this.deleteRecord(index, recordId);\n        },\n\n        /**\n         * Change page\n         *\n         * @param {Number} page - current page\n         */\n        changePage: function (page) {\n            this.clear();\n\n            if (page === 1 && !this.recordData().length) {\n                return false;\n            }\n\n            if (~~page > this.pages()) {\n                this.currentPage(this.pages());\n\n                return false;\n            } else if (~~page < 1) {\n                this.currentPage(1);\n\n                return false;\n            }\n\n            this.initChildren();\n\n            return true;\n        },\n\n        /**\n         * Check page\n         *\n         * @returns {Boolean} is page first or not\n         */\n        isFirst: function () {\n            return this.currentPage() === 1;\n        },\n\n        /**\n         * Check page\n         *\n         * @returns {Boolean} is page last or not\n         */\n        isLast: function () {\n            return this.currentPage() === this.pages();\n        },\n\n        /**\n         * Change page to next\n         */\n        nextPage: function () {\n            this.currentPage(this.currentPage() + 1);\n        },\n\n        /**\n         * Change page to previous\n         */\n        previousPage: function () {\n            this.currentPage(this.currentPage() - 1);\n        },\n\n        /**\n         * Check dependency and set position to elements\n         *\n         * @param {Array} collection - elems\n         * @param {Number} position - current position\n         * @param {String} elemName - element name\n         *\n         * @returns {Array} collection\n         */\n        updatePosition: function (collection, position, elemName) {\n            var curPos,\n                parsePosition = ~~position,\n                result = _.filter(collection, function (record) {\n                    return ~~record.position === parsePosition;\n                });\n\n            if (result[1]) {\n                curPos = parsePosition + 1;\n                result[0].name === elemName ? result[1].position = curPos : result[0].position = curPos;\n                this.updatePosition(collection, curPos);\n            }\n\n            return collection;\n        },\n\n        /**\n         * Check max elements position and set if max\n         *\n         * @param {Number} position - current position\n         */\n        checkMaxPosition: function (position) {\n            var max = 0,\n                pos;\n\n            this.recordData.each(function (record) {\n                pos = ~~record.position;\n                pos > max ? max = pos : false;\n            });\n\n            max < position ? max = position : false;\n            this.maxPosition = max;\n        },\n\n        /**\n         * Remove and set new max position\n         */\n        removeMaxPosition: function () {\n            this.maxPosition = 0;\n            this.elems.each(function (record) {\n                this.maxPosition < record.position ? this.maxPosition = ~~record.position : false;\n            }, this);\n        },\n\n        /**\n         * Update record template and rerender elems\n         *\n         * @param {String} recordName - record name\n         */\n        onUpdateRecordTemplate: function (recordName) {\n            if (recordName) {\n                this.recordTemplate = recordName;\n                this.reload();\n            }\n        },\n\n        /**\n         * Delete record\n         *\n         * @param {Number} index - row index\n         *\n         */\n        deleteRecord: function (index, recordId) {\n            var recordInstance,\n                lastRecord,\n                recordsData,\n                lastRecordIndex;\n\n            if (this.deleteProperty) {\n                recordsData = this.recordData();\n                recordInstance = _.find(this.elems(), function (elem) {\n                    return elem.index === index;\n                });\n                recordInstance.destroy();\n                this.elems([]);\n                this._updateCollection();\n                this.removeMaxPosition();\n                recordsData[recordInstance.index][this.deleteProperty] = this.deleteValue;\n                this.recordData(recordsData);\n                this.reinitRecordData();\n                this.reload();\n            } else {\n                this.update = true;\n\n                if (~~this.currentPage() === this.pages()) {\n                    lastRecordIndex = this.startIndex + this.getChildItems().length - 1;\n                    lastRecord =\n                        _.findWhere(this.elems(), {\n                            index: lastRecordIndex\n                        }) ||\n                        _.findWhere(this.elems(), {\n                            index: lastRecordIndex.toString()\n                        });\n\n                    lastRecord.destroy();\n                }\n\n                this.removeMaxPosition();\n                recordsData = this._getDataByProp(recordId);\n                this._updateData(recordsData);\n                this.update = false;\n            }\n\n            this._reducePages();\n            this._sort();\n        },\n\n        /**\n         * Update number of pages.\n         *\n         * @private\n         * @return void\n         */\n        _updatePagesQuantity: function () {\n            var pages = Math.ceil(this.relatedData.length / this.pageSize) || 1;\n\n            this.pages(pages);\n        },\n\n        /**\n         * Reduce the number of pages\n         *\n         * @private\n         * @return void\n         */\n        _reducePages: function () {\n            if (this.pages() < ~~this.currentPage()) {\n                this.currentPage(this.pages());\n            }\n        },\n\n        /**\n         * Get data object by some property\n         *\n         * @param {Number} id - element id\n         * @param {String} prop - property\n         */\n        _getDataByProp: function (id, prop) {\n            prop = prop || this.identificationProperty;\n\n            return _.reject(this.getChildItems(), function (recordData) {\n                return recordData[prop].toString() === id.toString();\n            }, this);\n        },\n\n        /**\n         * Sort elems by position property\n         */\n        _sort: function () {\n            this.elems(this.elems().sort(function (propOne, propTwo) {\n                return ~~propOne.position - ~~propTwo.position;\n            }));\n        },\n\n        /**\n         * Set new data to dataSource,\n         * delete element\n         *\n         * @param {Array} data - record data\n         */\n        _updateData: function (data) {\n            var elems = _.clone(this.elems()),\n                path,\n                dataArr;\n\n            dataArr = this.recordData.splice(this.startIndex, this.recordData().length - this.startIndex);\n            dataArr.splice(0, this.pageSize);\n            elems = _.sortBy(this.elems(), function (elem) {\n                return ~~elem.index;\n            });\n\n            data.concat(dataArr).forEach(function (rec, idx) {\n                if (elems[idx]) {\n                    elems[idx].recordId = rec[this.identificationProperty];\n                }\n\n                if (!rec.position) {\n                    rec.position = this.maxPosition;\n                    this.setMaxPosition();\n                }\n\n                path = this.dataScope + '.' + this.index + '.' + (this.startIndex + idx);\n                this.source.set(path, rec);\n            }, this);\n\n            this.elems(elems);\n        },\n\n        /**\n         * Rerender dynamic-rows elems\n         */\n        reload: function () {\n            this.clear();\n            this.initChildren(false, true);\n            this._updatePagesQuantity();\n\n            /* After change page size need to check existing current page */\n            this._reducePages();\n        },\n\n        /**\n         * Update page size based on select change event.\n         * The value needs to be retrieved from select as ko value handler is executed after the event handler.\n         *\n         * @param {Object} component\n         * @param {jQuery.Event} event\n         */\n        updatePageSize: function (component, event) {\n            this.pageSize = $(event.target).val();\n            this.reload();\n        },\n\n        /**\n         * Destroy all dynamic-rows elems\n         *\n         * @returns {Object} Chainable.\n         */\n        clear: function () {\n            this.destroyChildren();\n\n            return this;\n        },\n\n        /**\n         * Reset data to initial value.\n         * Call method reset on child elements.\n         */\n        reset: function () {\n            var elems = this.elems();\n\n            _.each(elems, function (elem) {\n                if (_.isFunction(elem.reset)) {\n                    elem.reset();\n                }\n            });\n        },\n\n        /**\n         * Set classes\n         *\n         * @param {Object} data\n         *\n         * @returns {Object} Classes\n         */\n        setClasses: function (data) {\n            var additional;\n\n            if (_.isString(data.additionalClasses)) {\n                additional = data.additionalClasses.split(' ');\n                data.additionalClasses = {};\n\n                additional.forEach(function (name) {\n                    data.additionalClasses[name] = true;\n                });\n            }\n\n            if (!data.additionalClasses) {\n                data.additionalClasses = {};\n            }\n\n            _.extend(data.additionalClasses, {\n                '_fit': data.fit,\n                '_required': data.required,\n                '_error': data.error,\n                '_empty': !this.elems().length,\n                '_no-header': this.columnsHeaderAfterRender || this.collapsibleHeader\n            });\n\n            return data.additionalClasses;\n        },\n\n        /**\n         * Initialize children\n         *\n         * @returns {Object} Chainable.\n         */\n        initChildren: function () {\n            this.showSpinner(true);\n            this.getChildItems().forEach(function (data, index) {\n                this.addChild(data, this.startIndex + index);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Set visibility to dynamic-rows child\n         *\n         * @param {Boolean} state\n         */\n        setVisible: function (state) {\n            this.elems.each(function (record) {\n                record.setVisible(state);\n            }, this);\n        },\n\n        /**\n         * Set disabled property to dynamic-rows child\n         *\n         * @param {Boolean} state\n         */\n        setDisabled: function (state) {\n            this.elems.each(function (record) {\n                record.setDisabled(state);\n            }, this);\n        },\n\n        /**\n         * Set visibility to column\n         *\n         * @param {Number} index - column index\n         * @param {Boolean} state\n         */\n        setVisibilityColumn: function (index, state) {\n            this.elems.each(function (record) {\n                record.setVisibilityColumn(index, state);\n            }, this);\n        },\n\n        /**\n         * Set disabled property to column\n         *\n         * @param {Number} index - column index\n         * @param {Boolean} state\n         */\n        setDisabledColumn: function (index, state) {\n            this.elems.each(function (record) {\n                record.setDisabledColumn(index, state);\n            }, this);\n        },\n\n        /**\n         * Add child components\n         *\n         * @param {Object} data - component data\n         * @param {Number} index - record(row) index\n         * @param {Number|String} prop - custom identify property\n         *\n         * @returns {Object} Chainable.\n         */\n        addChild: function (data, index, prop) {\n            var template = this.templates.record,\n                child;\n\n            index = index || _.isNumber(index) ? index : this.recordData().length;\n            prop = prop || _.isNumber(prop) ? prop : index;\n\n            _.extend(this.templates.record, {\n                recordId: prop\n            });\n\n            child = utils.template(template, {\n                collection: this,\n                index: index\n            });\n\n            layout([child]);\n\n            return this;\n        },\n\n        /**\n         * Restore value to default\n         */\n        restoreToDefault: function () {\n            this.recordData(utils.copy(this.default));\n            this.reload();\n        },\n\n        /**\n         * Update whether value differs from default value\n         */\n        setDifferedFromDefault: function () {\n            var recordData;\n\n            if (this.default) {\n                recordData = utils.copy(this.recordData());\n\n                Array.isArray(recordData) && recordData.forEach(function (item) {\n                    delete item['record_id'];\n                });\n\n                this.isDifferedFromDefault(!_.isEqual(recordData, this.default));\n            }\n        },\n\n        /**\n         * Set the changed property if the current page is different\n         * than the default state\n         *\n         * @return void\n         */\n        setChangedForCurrentPage: function () {\n            this.pagesChanged[this.currentPage()] =\n                !compareArrays(this.defaultPagesState[this.currentPage()], this.arrayFilter(this.getChildItems()));\n            this.changed(_.some(this.pagesChanged));\n        }\n    });\n});\n","Magento_Ui/js/lib/key-codes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([], function () {\n    'use strict';\n\n    return {\n        13: 'enterKey',\n        27: 'escapeKey',\n        40: 'pageDownKey',\n        38: 'pageUpKey',\n        32: 'spaceKey',\n        9:  'tabKey',\n        37: 'pageLeftKey',\n        39: 'pageRightKey',\n        17: 'ctrlKey',\n        18: 'altKey',\n        16: 'shiftKey',\n        191: 'forwardSlashKey',\n        66: 'bKey',\n        73: 'iKey',\n        85: 'uKey'\n    };\n});\n","Magento_Ui/js/lib/collapsible.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'uiComponent'\n], function (Component) {\n    'use strict';\n\n    return Component.extend({\n        defaults: {\n            opened: false,\n            collapsible: true\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Collapsible} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe('opened');\n\n            return this;\n        },\n\n        /**\n         * Toggles value of the 'opened' property.\n         *\n         * @returns {Collapsible} Chainable.\n         */\n        toggleOpened: function () {\n            this.opened() ?\n                this.close() :\n                this.open();\n\n            return this;\n        },\n\n        /**\n         * Sets 'opened' flag to false.\n         *\n         * @returns {Collapsible} Chainable.\n         */\n        close: function () {\n            if (this.collapsible) {\n                this.opened(false);\n            }\n\n            return this;\n        },\n\n        /**\n         * Sets 'opened' flag to true.\n         *\n         * @returns {Collapsible} Chainable.\n         */\n        open: function () {\n            if (this.collapsible) {\n                this.opened(true);\n            }\n\n            return this;\n        }\n    });\n});\n","Magento_Ui/js/lib/step-wizard.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'uiRegistry',\n    'uiComponent',\n    'jquery',\n    'underscore',\n    'ko',\n    'mage/backend/notification',\n    'mage/translate'\n], function (uiRegistry, Component, $, _, ko) {\n    'use strict';\n\n    var Wizard;\n\n    ko.utils.domNodeDisposal.cleanExternalData = _.wrap(\n        ko.utils.domNodeDisposal.cleanExternalData,\n        function (func, node) {\n            if (!$(node).closest('[data-type=skipKO]').length) {\n                func(node);\n            }\n        }\n    );\n\n    /**\n     * Wizard constructor.\n     *\n     * @param {Array} steps\n     * @param {String} modalClass\n     * @constructor\n     */\n    Wizard = function (steps, modalClass) {\n        this.steps = steps;\n        this.index = 0;\n        this.data = {};\n        this.nextLabelText = $.mage.__('Next');\n        this.prevLabelText = $.mage.__('Back');\n        this.elementSelector = '[data-role=steps-wizard-main]';\n        this.element = modalClass ? $('.' + modalClass + this.elementSelector) : $(this.elementSelector);\n        this.nextLabel = '[data-role=\"step-wizard-next\"]';\n        this.prevLabel = '[data-role=\"step-wizard-prev\"]';\n        this.element.notification();\n\n        /**\n         * Move to newIndex.\n         *\n         * @param {Number} newIndex\n         * @return {String}\n         */\n        this.move = function (newIndex) {\n            if (!this.preventSwitch(newIndex)) {\n                if (newIndex > this.index) {\n                    this._next(newIndex);\n                } else if (newIndex < this.index) {\n                    this._prev(newIndex);\n                }\n            }\n            this.updateLabels(this.getStep());\n            this.showNotificationMessage();\n\n            return this.getStep().name;\n        };\n\n        /**\n         * Move wizard to next step.\n         *\n         * @return {String}\n         */\n        this.next = function () {\n            this.move(this.index + 1);\n\n            return this.getStep().name;\n        };\n\n        /**\n         * Move wizard to previous step.\n         *\n         * @return {String}\n         */\n        this.prev = function () {\n            this.move(this.index - 1);\n\n            return this.getStep().name;\n        };\n\n        /**\n         * @return {*}\n         */\n        this.preventSwitch = function (newIndex) {\n            return newIndex < 0 || (newIndex - this.index) > 1;//eslint-disable-line no-extra-parens\n        };\n\n        /**\n         * @param {Number} newIndex\n         * @return {Boolean}\n         * @private\n         */\n        this._next = function (newIndex) {\n            newIndex = _.isNumber(newIndex) ? newIndex : this.index + 1;\n\n            try {\n                this.getStep().force(this);\n\n                if (newIndex >= steps.length) {\n                    return false;\n                }\n            } catch (e) {\n                this.setNotificationMessage(e.message, true);\n\n                return false;\n            }\n            this.cleanErrorNotificationMessage();\n            this.index = newIndex;\n            this.cleanNotificationMessage();\n            this.render();\n        };\n\n        /**\n         * @param {Number} newIndex\n         * @private\n         */\n        this._prev = function (newIndex) {\n            newIndex = _.isNumber(newIndex) ? newIndex : this.index - 1;\n            this.getStep().back(this);\n            this.index = newIndex;\n        };\n\n        /**\n         * @param {Number} stepIndex\n         * @return {Object}\n         */\n        this.getStep = function (stepIndex) {\n            return this.steps[stepIndex || this.index] || {};\n        };\n\n        /**\n         * @param {String} message\n         * @param {String} error\n         */\n        this.notifyMessage = function (message, error) {\n            $(this.element).notification('clear').notification('add', {\n                error: error,\n                message: message\n            });\n        };\n\n        /**\n         * @param {Object} step\n         */\n        this.updateLabels = function (step) {\n            this.element.find(this.nextLabel).find('button').text(step.nextLabelText || this.nextLabelText);\n            this.element.find(this.prevLabel).find('button').text(step.prevLabelText || this.prevLabelText);\n        };\n\n        /**\n         * Show notification message.\n         */\n        this.showNotificationMessage = function () {\n            if (!_.isEmpty(this.getStep())) {\n                this.hideNotificationMessage();\n\n                if (this.getStep().notificationMessage.text !== null) {\n                    this.notifyMessage(\n                        this.getStep().notificationMessage.text,\n                        this.getStep().notificationMessage.error\n                    );\n                }\n            }\n        };\n\n        /**\n         * Remove notification message.\n         */\n        this.cleanNotificationMessage = function () {\n            this.getStep().notificationMessage.text = null;\n            this.hideNotificationMessage();\n        };\n\n        /**\n         * Remove error message.\n         */\n        this.cleanErrorNotificationMessage = function () {\n            if (this.getStep().notificationMessage.error === true) {\n                this.cleanNotificationMessage();\n            }\n        };\n\n        /**\n         * @param {String} text\n         * @param {String} error\n         */\n        this.setNotificationMessage = function (text, error) {\n            error = error !== undefined;\n\n            if (!_.isEmpty(this.getStep())) {\n                this.getStep().notificationMessage.text = text;\n                this.getStep().notificationMessage.error = error;\n                this.showNotificationMessage();\n            }\n        };\n\n        /**\n         * Hide notification message.\n         */\n        this.hideNotificationMessage = function () {\n            $(this.element).notification('clear');\n        };\n\n        /**\n         * Render step.\n         */\n        this.render = function () {\n            this.hideNotificationMessage();\n            this.getStep().render(this);\n        };\n\n        /**\n         * Initialize step.\n         */\n        this.init = function () {\n            this.updateLabels(this.getStep());\n            this.render();\n        };\n        this.init();\n    };\n\n    return Component.extend({\n        defaults: {\n            modalClass: '',\n            initData: [],\n            stepsNames: [],\n            selectedStep: '',\n            steps: [],\n            disabled: true\n        },\n\n        /** @inheritdoc */\n        initialize: function () {\n            this._super();\n            this.selectedStep.subscribe(this.wrapDisabledBackButton.bind(this));\n        },\n\n        /** @inheritdoc */\n        initElement: function (step) {\n            step.initData = this.initData;\n            step.mode = _.all(this.initData, _.isEmpty) ? 'create' : 'edit';\n            this.steps[this.getStepIndexByName(step.name)] = step;\n        },\n\n        /** @inheritdoc */\n        initObservable: function () {\n            this._super().observe([\n                'selectedStep',\n                'disabled'\n            ]);\n\n            return this;\n        },\n\n        /** @inheritdoc */\n        destroy: function () {\n            _.each(this.steps, function (step) {\n                step.destroy();\n            });\n\n            this._super();\n        },\n\n        /**\n         * Toggle disable property.\n         *\n         * @param {String} stepName\n         */\n        wrapDisabledBackButton: function (stepName) {\n            if (_.first(this.stepsNames) === stepName) {\n                this.disabled(true);\n            } else {\n                this.disabled(false);\n            }\n        },\n\n        /**\n         * Get step by index name.\n         *\n         * @param {String} stepName\n         */\n        getStepIndexByName: function (stepName) {\n            return _.indexOf(this.stepsNames, stepName);\n        },\n        //controls, todo to another object\n        /**\n         * Select next step.\n         */\n        next: function () {\n            this.selectedStep(this.wizard.next());\n        },\n\n        /**\n         * Select previous step.\n         */\n        back: function () {\n            this.selectedStep(this.wizard.prev());\n        },\n\n        /**\n         * Open wizard.\n         */\n        open: function () {\n            this.selectedStep(this.stepsNames.first());\n            this.wizard = new Wizard(this.steps, this.modalClass);\n        },\n\n        /**\n         * Close wizard.\n         */\n        close: function () {\n            var modal =  uiRegistry.get(this.initData.configurableModal);\n\n            if (!_.isUndefined(modal)) {\n                modal.closeModal();\n            }\n        },\n\n        /**\n         * @param {Object} data\n         * @param {Object} event\n         */\n        showSpecificStep: function (data, event) {\n            var index = _.indexOf(this.stepsNames, event.target.hash.substr(1)),\n                stepName = this.wizard.move(index);\n\n            this.selectedStep(stepName);\n        }\n    });\n});\n","Magento_Ui/js/lib/spinner.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery'\n], function ($) {\n    'use strict';\n\n    var selector = '[data-role=\"spinner\"]',\n        spinner = $(selector);\n\n    return {\n        /**\n         * Show spinner.\n         */\n        show: function () {\n            spinner.show();\n        },\n\n        /**\n         * Hide spinner.\n         */\n        hide: function () {\n            spinner.hide();\n        },\n\n        /**\n         * Get spinner by selector.\n         *\n         * @param {String} id\n         * @return {jQuery}\n         */\n        get: function (id) {\n            return $(selector + '[data-component=\"' + id + '\"]');\n        }\n    };\n});\n","Magento_Ui/js/lib/view/utils/dom-observer.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'jquery',\n    'underscore',\n    'domReady!'\n], function ($, _) {\n    'use strict';\n\n    var counter = 1,\n        watchers,\n        globalObserver,\n        disabledNodes = [];\n\n    watchers = {\n        selectors: {},\n        nodes: {}\n    };\n\n    /**\n     * Checks if node represents an element node (nodeType === 1).\n     *\n     * @param {HTMLElement} node\n     * @returns {Boolean}\n     */\n    function isElementNode(node) {\n        return node.nodeType === 1;\n    }\n\n    /**\n     * Extracts all child descendant\n     * elements of a specified node.\n     *\n     * @param {HTMLElement} node\n     * @returns {Array}\n     */\n    function extractChildren(node) {\n        var children = node.querySelectorAll('*');\n\n        return _.toArray(children);\n    }\n\n    /**\n     * Extracts node identifier. If ID is not specified,\n     * then it will be created for the provided node.\n     *\n     * @param {HTMLElement} node\n     * @returns {Number}\n     */\n    function getNodeId(node) {\n        var id = node._observeId;\n\n        if (!id) {\n            id = node._observeId = counter++;\n        }\n\n        return id;\n    }\n\n    /**\n     * Invokes callback passing node to it.\n     *\n     * @param {HTMLElement} node\n     * @param {Object} data\n     */\n    function trigger(node, data) {\n        var id = getNodeId(node),\n            ids = data.invoked;\n\n        if (_.contains(ids, id)) {\n            return;\n        }\n\n        data.callback(node);\n        data.invoked.push(id);\n    }\n\n    /**\n     * Adds node to the observer list.\n     *\n     * @param {HTMLElement} node\n     * @returns {Object}\n     */\n    function createNodeData(node) {\n        var nodes   = watchers.nodes,\n            id      = getNodeId(node);\n\n        nodes[id] = nodes[id] || {};\n\n        return nodes[id];\n    }\n\n    /**\n     * Returns data associated with a specified node.\n     *\n     * @param {HTMLElement} node\n     * @returns {Object|Undefined}\n     */\n    function getNodeData(node) {\n        var nodeId = node._observeId;\n\n        return watchers.nodes[nodeId];\n    }\n\n    /**\n     * Removes data associated with a specified node.\n     *\n     * @param {HTMLElement} node\n     */\n    function removeNodeData(node) {\n        var nodeId = node._observeId;\n\n        delete watchers.nodes[nodeId];\n    }\n\n    /**\n     * Adds removal listener for a specified node.\n     *\n     * @param {HTMLElement} node\n     * @param {Object} data\n     */\n    function addRemovalListener(node, data) {\n        var nodeData = createNodeData(node);\n\n        (nodeData.remove = nodeData.remove || []).push(data);\n    }\n\n    /**\n     * Adds listener for the nodes which matches specified selector.\n     *\n     * @param {String} selector - CSS selector.\n     * @param {Object} data\n     */\n    function addSelectorListener(selector, data) {\n        var storage = watchers.selectors;\n\n        (storage[selector] = storage[selector] || []).push(data);\n    }\n\n    /**\n     * Calls handlers associated with an added node.\n     * Adds listeners for the node removal.\n     *\n     * @param {HTMLElement} node - Added node.\n     */\n    function processAdded(node) {\n        _.each(watchers.selectors, function (listeners, selector) {\n            listeners.forEach(function (data) {\n                if (!data.ctx.contains(node) || !$(node, data.ctx).is(selector)) {\n                    return;\n                }\n\n                if (data.type === 'add') {\n                    trigger(node, data);\n                } else if (data.type === 'remove') {\n                    addRemovalListener(node, data);\n                }\n            });\n        });\n    }\n\n    /**\n     * Calls handlers associated with a removed node.\n     *\n     * @param {HTMLElement} node - Removed node.\n     */\n    function processRemoved(node) {\n        var nodeData    = getNodeData(node),\n            listeners   = nodeData && nodeData.remove;\n\n        if (!listeners) {\n            return;\n        }\n\n        listeners.forEach(function (data) {\n            trigger(node, data);\n        });\n\n        removeNodeData(node);\n    }\n\n    /**\n     * Removes all non-element nodes from provided array\n     * and appends to it descendant elements.\n     *\n     * @param {Array} nodes\n     * @returns {Array}\n     */\n    function formNodesList(nodes) {\n        var result = [],\n            children;\n\n        nodes = _.toArray(nodes).filter(isElementNode);\n\n        nodes.forEach(function (node) {\n            result.push(node);\n\n            children = extractChildren(node);\n            result   = result.concat(children);\n        });\n\n        return result;\n    }\n\n    /**\n     * Collects all removed and added nodes from\n     * mutation records into separate arrays\n     * while removing duplicates between both types of changes.\n     *\n     * @param {Array} mutations - An array of mutation records.\n     * @returns {Object} Object with 'removed' and 'added' nodes arrays.\n     */\n    function formChangesLists(mutations) {\n        var removed = [],\n            added = [];\n\n        mutations.forEach(function (record) {\n            removed = removed.concat(_.toArray(record.removedNodes));\n            added   = added.concat(_.toArray(record.addedNodes));\n        });\n\n        removed = removed.filter(function (node) {\n            var addIndex = added.indexOf(node),\n                wasAdded = !!~addIndex;\n\n            if (wasAdded) {\n                added.splice(addIndex, 1);\n            }\n\n            return !wasAdded;\n        });\n\n        return {\n            removed: formNodesList(removed),\n            added: formNodesList(added)\n        };\n    }\n\n    /**\n     * Verify if the DOM node is a child of a defined disabled node, if so we shouldn't observe provided mutation.\n     *\n     * @param {Object} mutation - a single mutation\n     * @returns {Boolean}\n     */\n    function shouldObserveMutation(mutation) {\n        var isDisabled;\n\n        if (disabledNodes.length > 0) {\n            // Iterate through the disabled nodes and determine if this mutation is occurring inside one of them\n            isDisabled = _.find(disabledNodes, function (node) {\n                return node === mutation.target || $.contains(node, mutation.target);\n            });\n\n            // If we find a matching node we should not observe the mutation\n            return !isDisabled;\n        }\n\n        return true;\n    }\n\n    /**\n     * Should we observe these mutations? Check the first and last mutation to determine if this is a disabled mutation,\n     * we check both the first and last in case one has been removed from the DOM during the process of the mutation.\n     *\n     * @param {Array} mutations - An array of mutation records.\n     * @returns {Boolean}\n     */\n    function shouldObserveMutations(mutations) {\n        var firstMutation,\n            lastMutation;\n\n        if (mutations.length > 0) {\n            firstMutation = mutations[0];\n            lastMutation = mutations[mutations.length - 1];\n\n            return shouldObserveMutation(firstMutation) && shouldObserveMutation(lastMutation);\n        }\n\n        return true;\n    }\n\n    globalObserver = new MutationObserver(function (mutations) {\n        var changes;\n\n        if (shouldObserveMutations(mutations)) {\n            changes = formChangesLists(mutations);\n\n            changes.removed.forEach(processRemoved);\n            changes.added.forEach(processAdded);\n        }\n    });\n\n    globalObserver.observe(document.body, {\n        subtree: true,\n        childList: true\n    });\n\n    return {\n        /**\n         * Disable a node from being observed by the mutations, you may want to disable specific aspects of the\n         * application which are heavy on DOM changes. The observer running on some actions could cause significant\n         * delays and degrade the performance of that specific part of the application exponentially.\n         *\n         * @param {HTMLElement} node - a HTML node within the document\n         */\n        disableNode: function (node) {\n            disabledNodes.push(node);\n        },\n\n        /**\n         * Adds listener for the appearance of nodes that matches provided\n         * selector and which are inside of the provided context. Callback will be\n         * also invoked on elements which a currently present.\n         *\n         * @param {String} selector - CSS selector.\n         * @param {Function} callback - Function that will invoked when node appears.\n         * @param {HTMLElement} [ctx=document.body] - Context inside of which to search for the node.\n         */\n        get: function (selector, callback, ctx) {\n            var data,\n                nodes;\n\n            data = {\n                ctx: ctx || document.body,\n                type: 'add',\n                callback: callback,\n                invoked: []\n            };\n\n            nodes = $(selector, data.ctx).toArray();\n\n            nodes.forEach(function (node) {\n                trigger(node, data);\n            });\n\n            addSelectorListener(selector, data);\n        },\n\n        /**\n         * Adds listener for the nodes removal.\n         *\n         * @param {(jQueryObject|HTMLElement|Array|String)} selector\n         * @param {Function} callback - Function that will invoked when node is removed.\n         * @param {HTMLElement} [ctx=document.body] - Context inside of which to search for the node.\n         */\n        remove: function (selector, callback, ctx) {\n            var nodes = [],\n                data;\n\n            data = {\n                ctx: ctx || document.body,\n                type: 'remove',\n                callback: callback,\n                invoked: []\n            };\n\n            if (typeof selector === 'object') {\n                nodes = !_.isUndefined(selector.length) ?\n                    _.toArray(selector) :\n                    [selector];\n            } else if (_.isString(selector)) {\n                nodes = $(selector, ctx).toArray();\n\n                addSelectorListener(selector, data);\n            }\n\n            nodes.forEach(function (node) {\n                addRemovalListener(node, data);\n            });\n        },\n\n        /**\n         * Removes listeners.\n         *\n         * @param {String} selector\n         * @param {Function} [fn]\n         */\n        off: function (selector, fn) {\n            var selectors = watchers.selectors,\n                listeners = selectors[selector];\n\n            if (selector && !fn) {\n                delete selectors[selector];\n            } else if (listeners && fn) {\n                selectors[selector] = listeners.filter(function (data) {\n                    return data.callback !== fn;\n                });\n            }\n        }\n    };\n});\n","Magento_Ui/js/lib/view/utils/raf.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    var processMap = new WeakMap(),\n        origRaf,\n        raf;\n\n    origRaf = window.requestAnimationFrame ||\n        window.webkitRequestAnimationFrame ||\n        window.mozRequestAnimationFrame ||\n        window.onRequestAnimationFrame ||\n        window.msRequestAnimationFrame ||\n        function (callback) {\n            if (typeof callback != 'function') {\n                throw new Error('raf argument \"callback\" must be of type function');\n            }\n            window.setTimeout(callback, 1000 / 60);\n        };\n\n    /**\n     * Creates new process object or extracts the\n     * the existing one.\n     *\n     * @param {*} id - Process identifier.\n     * @param {Number} fps - Required FPS count.\n     * @returns {Object}\n     */\n    function getProcess(id, fps) {\n        var process = processMap.get(id);\n\n        if (!process) {\n            process = {};\n            processMap.set(id, process);\n        }\n\n        if (process.fps !== fps) {\n            process.fps        = fps;\n            process.interval   = 1000 / fps;\n            process.update     = Date.now();\n        }\n\n        return process;\n    }\n\n    /**\n     * Proxy method which delegates call to the 'requestAnimationFrame'\n     * function and optionally can keep track of the FPS with which\n     * provided function is called.\n     *\n     * @param {Function} callback - Callback function to be passed to 'requestAnimationFrame'.\n     * @param {Number} [fps] - If specified, will update FPS counter for the provided function.\n     * @returns {Number|Boolean} ID of request or a flag which indicates\n     *      whether callback fits specified FPS.\n     */\n    raf = function (callback, fps) {\n        var rafId = origRaf(callback);\n\n        return fps ? raf.tick(callback, fps) : rafId;\n    };\n\n    /**\n     * Updates FPS counter for the specified process\n     * and returns a flag which indicates whether\n     * counter value is equal or greater than the required FPS.\n     *\n     * @param {*} id - Process identifier.\n     * @param {Number} fps - Required FPS count.\n     * @returns {Boolean}\n     */\n    raf.tick = function (id, fps) {\n        var process  = getProcess(id, fps),\n            now      = Date.now(),\n            delta    = now - process.update,\n            interval = process.interval;\n\n        if (fps >= 60 || delta >= interval) {\n            process.update = now - delta % interval;\n\n            return true;\n        }\n\n        return false;\n    };\n\n    return raf;\n});\n","Magento_Ui/js/lib/view/utils/bindings.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    'underscore'\n], function (ko, $, _) {\n    'use strict';\n\n    /**\n     * Checks if provided  value is a dom element.\n     *\n     * @param {*} node - Value to be checked.\n     * @returns {Boolean}\n     */\n    function isDomElement(node) {\n        return typeof node === 'object' && node.tagName && node.nodeType;\n    }\n\n    /**\n     * Removes from the provided array all non-root nodes located inside\n     * of the comment element as long as the closing comment tags.\n     *\n     * @param {(Array|ArrayLike)} nodes - An array of nodes to be processed.\n     * @returns {Array}\n     */\n    function normalize(nodes) {\n        var result;\n\n        nodes   = _.toArray(nodes);\n        result  = nodes.slice();\n\n        nodes.forEach(function (node) {\n            if (node.nodeType === 8) {\n                result = !ko.virtualElements.hasBindingValue(node) ?\n                    _.without(result, node) :\n                    _.difference(result, ko.virtualElements.childNodes(node));\n            }\n        });\n\n        return result;\n    }\n\n    /**\n     * Extends binding context of each item in the collection.\n     *\n     * @param {...Object} extenders - Multiple extender objects to be applied to the context.\n     * @returns {jQueryCollection} Chainable.\n     */\n    $.fn.extendCtx = function () {\n        var nodes       = normalize(this),\n            extenders   = _.toArray(arguments);\n\n        nodes.forEach(function (node) {\n            var ctx  = ko.contextFor(node),\n                data = [ctx].concat(extenders);\n\n            _.extend.apply(_, data);\n        });\n\n        return this;\n    };\n\n    /**\n     * Evaluates bindings specified in each DOM element of collection.\n     *\n     * @param {(HTMLElement|Object)} [ctx] - Context to use for bindings evaluation.\n     *      If not specified then current context of a collections' item will be used.\n     * @returns {jQueryCollection} Chainable.\n     */\n    $.fn.applyBindings = function (ctx) {\n        var nodes = normalize(this),\n            nodeCtx;\n\n        if (isDomElement(ctx)) {\n            ctx = ko.contextFor(ctx);\n        }\n\n        nodes.forEach(function (node) {\n            nodeCtx = ctx || ko.contextFor(node);\n\n            ko.applyBindings(nodeCtx, node);\n        });\n\n        return this;\n    };\n\n    /**\n     * Adds specified bindings to each DOM element in\n     * collection and evaluates them with provided context.\n     *\n     * @param {(Object|Function)} data - Either bindings object or a function\n     *      which returns bindings data for each element in collection.\n     * @param {(HTMLElement|Object)} [ctx] - Context to use for bindings evaluation.\n     *      If not specified then current context of a collections' item will be used.\n     * @returns {jQueryCollection} Chainable.\n     */\n    $.fn.bindings = function (data, ctx) {\n        var nodes    = normalize(this),\n            bindings = data,\n            nodeCtx;\n\n        if (isDomElement(ctx)) {\n            ctx = ko.contextFor(ctx);\n        }\n\n        nodes.forEach(function (node) {\n            nodeCtx = ctx || ko.contextFor(node);\n\n            if (_.isFunction(data)) {\n                bindings = data(nodeCtx, node);\n            }\n\n            ko.applyBindingsToNode(node, bindings, nodeCtx);\n        });\n\n        return this;\n    };\n});\n","Magento_Ui/js/lib/view/utils/async.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'ko',\n    'jquery',\n    'underscore',\n    'uiRegistry',\n    './dom-observer',\n    'Magento_Ui/js/lib/knockout/extender/bound-nodes',\n    './bindings'\n], function (ko, $, _, registry, domObserver, boundedNodes) {\n    'use strict';\n\n    /**\n     * Checks if provided value is a dom element.\n     *\n     * @param {*} node - Value to be checked.\n     * @returns {Boolean}\n     */\n    function isDomElement(node) {\n        return typeof node === 'object' && node.tagName && node.nodeType;\n    }\n\n    /**\n     * Parses provided string and extracts\n     * component, context and selector data from it.\n     *\n     * @param {String} str - String to be processed.\n     * @returns {Object} Data retrieved from string.\n     *\n     * @example Sample format.\n     *      '{{component}}:{{ctx}} -> {{selector}}'\n     *\n     *      component - Name of component.\n     *      ctx - Selector of the root node upon which component is binded.\n     *      selector - Selector of DOM elements located\n     *          inside of a previously specified context.\n     */\n    function parseSelector(str) {\n        var data    = str.trim().split('->'),\n            result  = {},\n            componentData;\n\n        if (data.length === 1) {\n            if (!~data[0].indexOf(':')) {\n                result.selector = data[0];\n            } else {\n                componentData = data[0];\n            }\n        } else {\n            componentData   = data[0];\n            result.selector = data[1];\n        }\n\n        if (componentData) {\n            componentData = componentData.split(':');\n\n            result.component = componentData[0];\n            result.ctx = componentData[1];\n        }\n\n        _.each(result, function (value, key) {\n            result[key] = value.trim();\n        });\n\n        return result;\n    }\n\n    /**\n     * Internal method used to normalize argumnets passed\n     * to 'async' module methods.\n     *\n     * @param {(String|Object)} selector\n     * @param {(HTMLElement|Object|String)} [ctx]\n     * @returns {Object}\n     */\n    function parseData(selector, ctx) {\n        var data = {};\n\n        if (arguments.length === 2) {\n            data.selector = selector;\n\n            if (isDomElement(ctx)) {\n                data.ctx = ctx;\n            } else {\n                data.component = ctx;\n                data.ctx = '*';\n            }\n        } else {\n            data = _.isString(selector) ?\n                parseSelector(selector) :\n                selector;\n        }\n\n        return data;\n    }\n\n    /**\n     * Creates promise that will be resolved\n     * when requested component is registred.\n     *\n     * @param {String} name - Name of component.\n     * @returns {jQueryPromise}\n     */\n    function waitComponent(name) {\n        var deffer = $.Deferred();\n\n        if (_.isString(name)) {\n            registry.get(name, function (component) {\n                deffer.resolve(component);\n            });\n        } else {\n            deffer.resolve(name);\n        }\n\n        return deffer.promise();\n    }\n\n    /**\n     * Creates listener for the nodes binded to provided component.\n     *\n     * @param {Object} data - Listener data.\n     * @param {Object} component - Associated with nodes component.\n     */\n    function setRootListener(data, component) {\n        boundedNodes.get(component, function (root) {\n            if (!$(root).is(data.ctx || '*')) {\n                return;\n            }\n\n            data.selector ?\n                domObserver.get(data.selector, data.fn, root) :\n                data.fn(root);\n        });\n    }\n\n    /*eslint-disable no-unused-vars*/\n    /**\n     * Sets listener for the appearance of elements which\n     * matches specified selector data.\n     *\n     * @param {(String|Object)} selector - Valid css selector or a string\n     *      in format acceptable by 'parseSelector' method or an object with\n     *      'component', 'selector' and 'ctx' properties.\n     * @param {(HTMLElement|Object|String)} [ctx] - Optional context parameter\n     *      which might be a DOM element, component instance or components' name.\n     * @param {Function} fn - Callback that will be invoked\n     *      when required DOM element appears.\n     *\n     * @example\n     *      Creating listener of the 'span' nodes appearance,\n     *      located inside of 'div' nodes, which are binded to 'cms_page_listing' component:\n     *\n     *      $.async('cms_page_listing:div -> span', function (node) {});\n     *\n     * @example Another syntaxes of the previous example.\n     *      $.async({\n     *          component: 'cms_page_listing',\n     *          ctx: 'div',\n     *          selector: 'span'\n     *       }, function (node) {});\n     *\n     * @example Listens for appearance of any child node inside of specified component.\n     *      $.async('> *', 'cms_page_lsiting', function (node) {});\n     *\n     * @example Listens for appearance of 'span' nodes inside of specific context.\n     *      $.async('span', document.getElementById('test'), function (node) {});\n     */\n    $.async = function (selector, ctx, fn) {\n        var args = _.toArray(arguments),\n            data = parseData.apply(null, _.initial(args));\n\n        data.fn = _.last(args);\n\n        if (data.component) {\n            waitComponent(data.component)\n                .then(setRootListener.bind(null, data));\n        } else {\n            domObserver.get(data.selector, data.fn, data.ctx);\n        }\n    };\n\n    /*eslint-enable no-unused-vars*/\n\n    _.extend($.async, {\n\n        /*eslint-disable no-unused-vars*/\n        /**\n         * Returns collection of elements found by provided selector data.\n         *\n         * @param {(String|Object)} selector - See 'async' definition.\n         * @param {(HTMLElement|Object|String)} [ctx] - See 'async' definition.\n         * @returns {Array} An array of DOM elements.\n         */\n        get: function (selector, ctx) {\n            var data        = parseData.apply(null, arguments),\n                component   = data.component,\n                nodes;\n\n            if (!component) {\n                return $(data.selector, data.ctx).toArray();\n            } else if (_.isString(component)) {\n                component = registry.get(component);\n            }\n\n            if (!component) {\n                return [];\n            }\n\n            nodes = boundedNodes.get(component);\n            nodes = $(nodes).filter(data.ctx).toArray();\n\n            return data.selector ?\n                $(data.selector, nodes).toArray() :\n                nodes;\n        },\n\n        /*eslint-enable no-unused-vars*/\n\n        /**\n         * Sets removal listener of the specified nodes.\n         *\n         * @param {(HTMLElement|Array|ArrayLike)} nodes - Nodes whose removal to track.\n         * @param {Function} fn - Callback that will be invoked when node is removed.\n         */\n        remove: function (nodes, fn) {\n            domObserver.remove(nodes, fn);\n        },\n\n        parseSelector: parseSelector\n    });\n\n    return $;\n});\n","Magento_Ui/js/lib/validation/rules.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore',\n    './utils',\n    'moment',\n    'tinycolor',\n    'jquery/validate',\n    'mage/translate'\n], function ($, _, utils, moment, tinycolor) {\n    'use strict';\n\n    /**\n     * validate credit card number using mod10\n     * @param {String} s\n     * @return {Boolean}\n     */\n    function validateCreditCard(s) {\n        // remove non-numerics\n        var v = '0123456789',\n            w = '',\n            i, j, k, m, c, a, x;\n\n        for (i = 0; i < s.length; i++) {\n            x = s.charAt(i);\n\n            if (v.indexOf(x, 0) !== -1) {\n                w += x;\n            }\n        }\n        // validate number\n        j = w.length / 2;\n        k = Math.floor(j);\n        m = Math.ceil(j) - k;\n        c = 0;\n\n        for (i = 0; i < k; i++) {\n            a = w.charAt(i * 2 + m) * 2;\n            c += a > 9 ? Math.floor(a / 10 + a % 10) : a;\n        }\n\n        for (i = 0; i < k + m; i++) {\n            c += w.charAt(i * 2 + 1 - m) * 1;\n        }\n\n        return c % 10 === 0;\n    }\n\n    /**\n     * Collection of validation rules including rules from additional-methods.js\n     * @type {Object}\n     */\n    return _.mapObject({\n        'min_text_length': [\n            function (value, params) {\n                return _.isUndefined(value) || value.length === 0 || value.length >= +params;\n            },\n            $.mage.__('Please enter more or equal than {0} symbols.')\n        ],\n        'max_text_length': [\n            function (value, params) {\n                return !_.isUndefined(value) && value.length <= +params;\n            },\n            $.mage.__('Please enter less or equal than {0} symbols.')\n        ],\n        'max-words': [\n            function (value, params) {\n                return utils.isEmpty(value) || utils.stripHtml(value).match(/\\b\\w+\\b/g).length < params;\n            },\n            $.mage.__('Please enter {0} words or less.')\n        ],\n        'min-words': [\n            function (value, params) {\n                return utils.isEmpty(value) || utils.stripHtml(value).match(/\\b\\w+\\b/g).length >= params;\n            },\n            $.mage.__('Please enter at least {0} words.')\n        ],\n        'range-words': [\n            function (value, params) {\n                var match = utils.stripHtml(value).match(/\\b\\w+\\b/g) || [];\n\n                return utils.isEmpty(value) || match.length >= params[0] &&\n                    match.length <= params[1];\n            },\n            $.mage.__('Please enter between {0} and {1} words.')\n        ],\n        'letters-with-basic-punc': [\n            function (value) {\n                return utils.isEmpty(value) || /^[a-z\\-.,()\\u0027\\u0022\\s]+$/i.test(value);\n            },\n            $.mage.__('Letters or punctuation only please')\n        ],\n        'alphanumeric': [\n            function (value) {\n                return utils.isEmpty(value) || /^\\w+$/i.test(value);\n            },\n            $.mage.__('Letters, numbers, spaces or underscores only please')\n        ],\n        'letters-only': [\n            function (value) {\n                return utils.isEmpty(value) || /^[a-z]+$/i.test(value);\n            },\n            $.mage.__('Letters only please')\n        ],\n        'no-whitespace': [\n            function (value) {\n                return utils.isEmpty(value) || /^\\S+$/i.test(value);\n            },\n            $.mage.__('No white space please')\n        ],\n        'no-marginal-whitespace': [\n            function (value) {\n                return !/^\\s+|\\s+$/i.test(value);\n            },\n            $.mage.__('No marginal white space please')\n        ],\n        'zip-range': [\n            function (value) {\n                return utils.isEmpty(value) || /^90[2-5]-\\d{2}-\\d{4}$/.test(value);\n            },\n            $.mage.__('Your ZIP-code must be in the range 902xx-xxxx to 905-xx-xxxx')\n        ],\n        'integer': [\n            function (value) {\n                return utils.isEmpty(value) || /^-?\\d+$/.test(value);\n            },\n            $.mage.__('A positive or negative non-decimal number please')\n        ],\n        'vinUS': [\n            function (value) {\n                if (utils.isEmpty(value)) {\n                    return true;\n                }\n\n                if (value.length !== 17) {\n                    return false;\n                }\n                var i, n, d, f, cd, cdv,//eslint-disable-line vars-on-top\n                    LL = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],//eslint-disable-line max-len\n                    VL = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 7, 9, 2, 3, 4, 5, 6, 7, 8, 9],\n                    FL = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2],\n                    rs = 0;\n\n                for (i = 0; i < 17; i++) {\n                    f = FL[i];\n                    d = value.slice(i, i + 1);\n\n                    if (i === 8) {\n                        cdv = d;\n                    }\n\n                    if (!isNaN(d)) {\n                        d *= f;\n                    } else {\n                        for (n = 0; n < LL.length; n++) {//eslint-disable-line max-depth\n                            if (d.toUpperCase() === LL[n]) {//eslint-disable-line max-depth\n                                d = VL[n];\n                                d *= f;\n\n                                if (isNaN(cdv) && n === 8) {//eslint-disable-line max-depth\n                                    cdv = LL[n];\n                                }\n                                break;\n                            }\n                        }\n                    }\n                    rs += d;\n                }\n                cd = rs % 11;\n\n                if (cd === 10) {\n                    cd = 'X';\n                }\n\n                if (cd === cdv) {\n                    return true;\n                }\n\n                return false;\n            },\n            $.mage.__('The specified vehicle identification number (VIN) is invalid.')\n        ],\n        'dateITA': [\n            function (value) {\n                var check = false,\n                    re = /^\\d{1,2}\\/\\d{1,2}\\/\\d{4}$/,\n                    adata, gg, mm, aaaa, xdata;\n\n                if (re.test(value)) {\n                    adata = value.split('/');\n                    gg = parseInt(adata[0], 10);\n                    mm = parseInt(adata[1], 10);\n                    aaaa = parseInt(adata[2], 10);\n                    xdata = new Date(aaaa, mm - 1, gg);\n\n                    if (xdata.getFullYear() === aaaa &&\n                        xdata.getMonth() === mm - 1 &&\n                        xdata.getDate() === gg\n                    ) {\n                        check = true;\n                    } else {\n                        check = false;\n                    }\n                } else {\n                    check = false;\n                }\n\n                return check;\n            },\n            $.mage.__('Please enter a correct date')\n        ],\n        'dateNL': [\n            function (value) {\n                return /^\\d\\d?[\\.\\/-]\\d\\d?[\\.\\/-]\\d\\d\\d?\\d?$/.test(value);\n            },\n            $.mage.__('Vul hier een geldige datum in.')\n        ],\n        'time': [\n            function (value) {\n                return utils.isEmpty(value) || /^([01]\\d|2[0-3])(:[0-5]\\d){0,2}$/.test(value);\n            },\n            $.mage.__('Please enter a valid time, between 00:00 and 23:59')\n        ],\n        'time12h': [\n            function (value) {\n                return utils.isEmpty(value) || /^((0?[1-9]|1[012])(:[0-5]\\d){0,2}(\\s[AP]M))$/i.test(value);\n            },\n            $.mage.__('Please enter a valid time, between 00:00 am and 12:00 pm')\n        ],\n        'phoneUS': [\n            function (value) {\n                value = value.replace(/\\s+/g, '');\n\n                return utils.isEmpty(value) || value.length > 9 &&\n                    value.match(/^(1-?)?(\\([2-9]\\d{2}\\)|[2-9]\\d{2})-?[2-9]\\d{2}-?\\d{4}$/);\n            },\n            $.mage.__('Please specify a valid phone number')\n        ],\n        'phoneUK': [\n            function (value) {\n                return utils.isEmpty(value) || value.length > 9 &&\n                    value.match(/^(\\(?(0|\\+44)[1-9]{1}\\d{1,4}?\\)?\\s?\\d{3,4}\\s?\\d{3,4})$/);\n            },\n            $.mage.__('Please specify a valid phone number')\n        ],\n        'mobileUK': [\n            function (value) {\n                return utils.isEmpty(value) || value.length > 9 && value.match(/^((0|\\+44)7\\d{3}\\s?\\d{6})$/);\n            },\n            $.mage.__('Please specify a valid mobile number')\n        ],\n        'stripped-min-length': [\n            function (value, param) {\n                return _.isUndefined(value) || value.length === 0 || utils.stripHtml(value).length >= param;\n            },\n            $.mage.__('Please enter at least {0} characters')\n        ],\n        'email2': [\n            function (value) {\n                return utils.isEmpty(value) || /^((([a-z]|\\d|[!#\\$%&\\u0027\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&\\u0027\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\u0022)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\u0022)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?$/i.test(value);//eslint-disable-line max-len\n            },\n            $.validator.messages.email\n        ],\n        'url2': [\n            function (value) {\n                return utils.isEmpty(value) || /^(https?|ftp):\\/\\/(((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)*(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)|[\\uE000-\\uF8FF]|\\/|\\?)*)?(\\#((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&\\u0027\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.test(value);//eslint-disable-line max-len\n            },\n            $.validator.messages.url\n        ],\n        'credit-card-types': [\n            function (value, param) {\n                var validTypes;\n\n                if (utils.isEmpty(value)) {\n                    return true;\n                }\n\n                if (/[^0-9-]+/.test(value)) {\n                    return false;\n                }\n                value = value.replace(/\\D/g, '');\n                validTypes = 0x0000;\n\n                if (param.mastercard) {\n                    validTypes |= 0x0001;\n                }\n\n                if (param.visa) {\n                    validTypes |= 0x0002;\n                }\n\n                if (param.amex) {\n                    validTypes |= 0x0004;\n                }\n\n                if (param.dinersclub) {\n                    validTypes |= 0x0008;\n                }\n\n                if (param.enroute) {\n                    validTypes |= 0x0010;\n                }\n\n                if (param.discover) {\n                    validTypes |= 0x0020;\n                }\n\n                if (param.jcb) {\n                    validTypes |= 0x0040;\n                }\n\n                if (param.unknown) {\n                    validTypes |= 0x0080;\n                }\n\n                if (param.all) {\n                    validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;\n                }\n\n                if (validTypes & 0x0001 && /^(51|52|53|54|55)/.test(value)) { //mastercard\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0002 && /^(4)/.test(value)) { //visa\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0004 && /^(34|37)/.test(value)) { //amex\n                    return value.length === 15;\n                }\n\n                if (validTypes & 0x0008 && /^(300|301|302|303|304|305|36|38)/.test(value)) { //dinersclub\n                    return value.length === 14;\n                }\n\n                if (validTypes & 0x0010 && /^(2014|2149)/.test(value)) { //enroute\n                    return value.length === 15;\n                }\n\n                if (validTypes & 0x0020 && /^(6011)/.test(value)) { //discover\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0040 && /^(3)/.test(value)) { //jcb\n                    return value.length === 16;\n                }\n\n                if (validTypes & 0x0040 && /^(2131|1800)/.test(value)) { //jcb\n                    return value.length === 15;\n                }\n\n                if (validTypes & 0x0080) { //unknown\n                    return true;\n                }\n\n                return false;\n            },\n            $.mage.__('Please enter a valid credit card number.')\n        ],\n        'ipv4': [\n            function (value) {\n                return utils.isEmpty(value) || /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i.test(value);//eslint-disable-line max-len\n            },\n            $.mage.__('Please enter a valid IP v4 address.')\n        ],\n        'ipv6': [\n            function (value) {\n                return utils.isEmpty(value) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b)\\.){3}(\\b((25[0-5])|(1\\d{2})|(2[0-4]\\d)|(\\d{1,2}))\\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value);//eslint-disable-line max-len\n            },\n            $.mage.__('Please enter a valid IP v6 address.')\n        ],\n        'pattern': [\n            function (value, param) {\n                return utils.isEmpty(value) || new RegExp(param).test(value);\n            },\n            $.mage.__('Invalid format.')\n        ],\n        'validate-no-html-tags': [\n            function (value) {\n                return !/<(\\/)?\\w+/.test(value);\n            },\n            $.mage.__('HTML tags are not allowed.')\n        ],\n        'validate-select': [\n            function (value) {\n                return value !== 'none' && value != null && value.length !== 0;\n            },\n            $.mage.__('Please select an option.')\n        ],\n        'validate-no-empty': [\n            function (value) {\n                return !utils.isEmpty(value);\n            },\n            $.mage.__('Empty Value.')\n        ],\n        'validate-alphanum-with-spaces': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[a-zA-Z0-9 ]+$/.test(value);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or spaces only in this field.')\n        ],\n        'validate-data': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[A-Za-z]+[A-Za-z0-9_]+$/.test(value);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.')//eslint-disable-line max-len\n        ],\n        'validate-street': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) ||\n                    /^[ \\w]{3,}([A-Za-z]\\.)?([ \\w]*\\#\\d+)?(\\r\\n| )[ \\w]{3,}/.test(value);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z), numbers (0-9), spaces and \"#\" in this field.')\n        ],\n        'validate-phoneStrict': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^(\\()?\\d{3}(\\))?(-|\\s)?\\d{3}(-|\\s)\\d{4}$/.test(value);\n            },\n            $.mage.__('Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.')\n        ],\n        'validate-phoneLax': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) ||\n                    /^((\\d[\\-. ]?)?((\\(\\d{3}\\))|\\d{3}))?[\\-. ]?\\d{3}[\\-. ]?\\d{4}$/.test(value);\n            },\n            $.mage.__('Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.')\n        ],\n        'validate-fax': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^(\\()?\\d{3}(\\))?(-|\\s)?\\d{3}(-|\\s)\\d{4}$/.test(value);\n            },\n            $.mage.__('Please enter a valid fax number (Ex: 123-456-7890).')\n        ],\n        'validate-email': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9,!\\#\\$%&'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*@([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z0-9-]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*\\.(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]){2,})$/i.test(value);//eslint-disable-line max-len\n            },\n            $.mage.__('Please enter a valid email address (Ex: [email protected]).')\n        ],\n        'validate-emailSender': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[\\S ]+$/.test(value);\n            },\n            $.mage.__('Please enter a valid email address (Ex: [email protected]).')\n        ],\n        'validate-password': [\n            function (value) {\n                var pass;\n\n                if (value == null) {\n                    return false;\n                }\n\n                pass = value.trim();\n\n                if (!pass.length) {\n                    return true;\n                }\n\n                return !(pass.length > 0 && pass.length < 6);\n            },\n            $.mage.__('Please enter 6 or more characters. Leading and trailing spaces will be ignored.')\n        ],\n        'validate-admin-password': [\n            function (value) {\n                var pass;\n\n                if (value == null) {\n                    return false;\n                }\n\n                pass = value.trim();\n\n                if (pass.length === 0) {\n                    return true;\n                }\n\n                if (!/[a-z]/i.test(value) || !/[0-9]/.test(value)) {\n                    return false;\n                }\n\n                if (pass.length < 7) {\n                    return false;\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter 7 or more characters, using both numeric and alphabetic.')\n        ],\n        'validate-customer-password': [\n            function (v, elm) {\n                var validator = this,\n                    counter = 0,\n                    passwordMinLength = $(elm).data('password-min-length'),\n                    passwordMinCharacterSets = $(elm).data('password-min-character-sets'),\n                    pass = v.trim(),\n                    result = pass.length >= passwordMinLength;\n\n                if (result === false) {\n                    validator.passwordErrorMessage = $.mage.__('Minimum length of this field must be equal or greater than %1 symbols. Leading and trailing spaces will be ignored.').replace('%1', passwordMinLength);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                if (pass.match(/\\d+/)) {\n                    counter++;\n                }\n\n                if (pass.match(/[a-z]+/)) {\n                    counter++;\n                }\n\n                if (pass.match(/[A-Z]+/)) {\n                    counter++;\n                }\n\n                if (pass.match(/[^a-zA-Z0-9]+/)) {\n                    counter++;\n                }\n\n                if (counter < passwordMinCharacterSets) {\n                    result = false;\n                    validator.passwordErrorMessage = $.mage.__('Minimum of different classes of characters in password is %1. Classes of characters: Lower Case, Upper Case, Digits, Special Characters.').replace('%1', passwordMinCharacterSets);//eslint-disable-line max-len\n                }\n\n                return result;\n            }, function () {\n                return this.passwordErrorMessage;\n            }\n        ],\n        'validate-url': [\n            function (value) {\n                if (utils.isEmptyNoTrim(value)) {\n                    return true;\n                }\n                value = (value || '').replace(/^\\s+/, '').replace(/\\s+$/, '');\n\n                return (/^(http|https|ftp):\\/\\/(([A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))(\\.[A-Z0-9]([A-Z0-9_-]*[A-Z0-9]|))*)(:(\\d+))?(\\/[A-Z0-9~](([A-Z0-9_~-]|\\.)*[A-Z0-9~]|))*\\/?(.*)?$/i).test(value);//eslint-disable-line max-len\n\n            },\n            $.mage.__('Please enter a valid URL. Protocol is required (http://, https:// or ftp://).')\n        ],\n        'validate-clean-url': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^(http|https|ftp):\\/\\/(([A-Z0-9][A-Z0-9_-]*)(\\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\\d+))?\\/?/i.test(value) || /^(www)((\\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\\d+))?\\/?/i.test(value);//eslint-disable-line max-len\n\n            },\n            $.mage.__('Please enter a valid URL. For example http://www.example.com or www.example.com.')\n        ],\n        'validate-xml-identifier': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[A-Z][A-Z0-9_\\/-]*$/i.test(value);\n\n            },\n            $.mage.__('Please enter a valid XML-identifier (Ex: something_1, block5, id-4).')\n        ],\n        'validate-ssn': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^\\d{3}-?\\d{2}-?\\d{4}$/.test(value);\n\n            },\n            $.mage.__('Please enter a valid social security number (Ex: 123-45-6789).')\n        ],\n        'validate-zip-us': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /(^\\d{5}$)|(^\\d{5}-\\d{4}$)/.test(value);\n\n            },\n            $.mage.__('Please enter a valid zip code (Ex: 90602 or 90602-1234).')\n        ],\n        'validate-date-au': [\n            function (value) {\n                var regex = /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/,\n                    d;\n\n                if (utils.isEmptyNoTrim(value)) {\n                    return true;\n                }\n\n                if (utils.isEmpty(value) || !regex.test(value)) {\n                    return false;\n                }\n                d = new Date(value.replace(regex, '$2/$1/$3'));\n\n                return parseInt(RegExp.$2, 10) === 1 + d.getMonth() &&\n                    parseInt(RegExp.$1, 10) === d.getDate() &&\n                    parseInt(RegExp.$3, 10) === d.getFullYear();\n\n            },\n            $.mage.__('Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.')\n        ],\n        'validate-currency-dollar': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^\\$?\\-?([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}\\d*(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$/.test(value);//eslint-disable-line max-len\n\n            },\n            $.mage.__('Please enter a valid $ amount. For example $100.00.')\n        ],\n        'validate-not-negative-number': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value))\n                    && value >= 0 && (/^\\s*-?\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n\n            },\n            $.mage.__('Please enter a number 0 or greater, without comma in this field.')\n        ],\n        // validate-not-negative-number should be replaced in all places with this one and then removed\n        'validate-zero-or-greater': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value))\n                    && value >= 0 && (/^\\s*-?\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n            },\n            $.mage.__('Please enter a number 0 or greater, without comma in this field.')\n        ],\n        'validate-greater-than-zero': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value))\n                    && value > 0 && (/^\\s*-?\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n            },\n            $.mage.__('Please enter a number greater than 0, without comma in this field.')\n        ],\n        'validate-css-length': [\n            function (value) {\n                if (value !== '') {\n                    return (/^[0-9]*\\.*[0-9]+(px|pc|pt|ex|em|mm|cm|in|%)?$/).test(value);\n                }\n\n                return true;\n            },\n            $.mage.__('Please input a valid CSS-length (Ex: 100px, 77pt, 20em, .5ex or 50%).')\n        ],\n        'validate-number': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) ||\n                    !isNaN(utils.parseNumber(value)) &&\n                    /^\\s*-?\\d*(?:[.,|'|\\s]\\d+)*(?:[.,|'|\\s]\\d{2})?-?\\s*$/.test(value);\n            },\n            $.mage.__('Please enter a valid number in this field.')\n        ],\n        'validate-integer': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || !isNaN(utils.parseNumber(value)) && /^\\s*-?\\d*\\s*$/.test(value);\n            },\n            $.mage.__('Please enter a valid integer in this field.')\n        ],\n        'validate-number-range': [\n            function (value, param) {\n                var numValue, dataAttrRange, result, range, m;\n\n                if (utils.isEmptyNoTrim(value)) {\n                    return true;\n                }\n\n                numValue = utils.parseNumber(value);\n\n                if (isNaN(numValue)) {\n                    return false;\n                }\n\n                dataAttrRange = /^(-?[\\d.,]+)?-(-?[\\d.,]+)?$/;\n                result = true;\n                range = param;\n\n                if (range) {\n                    m = dataAttrRange.exec(range);\n\n                    if (m) {\n                        result = result && utils.isBetween(numValue, m[1], m[2]);\n                    }\n                }\n\n                return result;\n            },\n            $.mage.__('The value is not within the specified range.')\n        ],\n        'validate-positive-percent-decimal': [\n            function (value) {\n                var numValue;\n\n                if (utils.isEmptyNoTrim(value) || !/^\\s*-?\\d*(\\.\\d*)?\\s*$/.test(value)) {\n                    return false;\n                }\n\n                numValue = utils.parseNumber(value);\n\n                if (isNaN(numValue)) {\n                    return false;\n                }\n\n                return utils.isBetween(numValue, 0.01, 100);\n            },\n            $.mage.__('Please enter a valid percentage discount value greater than 0.')\n        ],\n        'validate-digits': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || !/[^\\d]/.test(value);\n            },\n            $.mage.__('Please enter a valid number in this field.')\n        ],\n        'validate-digits-range': [\n            function (value, param) {\n                var numValue, dataAttrRange, result, range, m;\n\n                if (utils.isEmptyNoTrim(value)) {\n                    return true;\n                }\n\n                numValue = utils.parseNumber(value);\n\n                if (isNaN(numValue)) {\n                    return false;\n                }\n\n                dataAttrRange = /^(-?\\d+)?-(-?\\d+)?$/;\n                result = true;\n                range = param;\n\n                if (range) {\n                    m = dataAttrRange.exec(range);\n\n                    if (m) {\n                        result = result && utils.isBetween(numValue, m[1], m[2]);\n                    }\n                }\n\n                return result;\n            },\n            $.mage.__('The value is not within the specified range.')\n        ],\n        'validate-range': [\n            function (value) {\n                var minValue, maxValue, ranges;\n\n                if (utils.isEmptyNoTrim(value)) {\n                    return true;\n                } else if ($.validator.methods['validate-digits'] && $.validator.methods['validate-digits'](value)) {\n                    minValue = maxValue = utils.parseNumber(value);\n                } else {\n                    ranges = /^(-?\\d+)?-(-?\\d+)?$/.exec(value);\n\n                    if (ranges) {\n                        minValue = utils.parseNumber(ranges[1]);\n                        maxValue = utils.parseNumber(ranges[2]);\n\n                        if (minValue > maxValue) {//eslint-disable-line max-depth\n                            return false;\n                        }\n                    } else {\n                        return false;\n                    }\n                }\n            },\n            $.mage.__('The value is not within the specified range.')\n        ],\n        'validate-alpha': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[a-zA-Z]+$/.test(value);\n            },\n            $.mage.__('Please use letters only (a-z or A-Z) in this field.')\n        ],\n        'validate-code': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[a-z]+[a-z0-9_]+$/.test(value);\n            },\n            $.mage.__('Please use only lowercase letters (a-z), numbers (0-9) or underscore (_) in this field, and the first character should be a letter.')//eslint-disable-line max-len\n        ],\n        'validate-alphanum': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[a-zA-Z0-9]+$/.test(value);\n            },\n            $.mage.__('Please use only letters (a-z or A-Z) or numbers (0-9) in this field. No spaces or other characters are allowed.')//eslint-disable-line max-len\n        ],\n        'validate-not-number-first': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[^0-9-\\.].*$/.test(value.trim());\n            },\n            $.mage.__('First character must be letter.')\n        ],\n        'validate-date': [\n            function (value, params, additionalParams) {\n                var test = moment(value, additionalParams.dateFormat);\n\n                return utils.isEmptyNoTrim(value) || test.isValid();\n            },\n            $.mage.__('Please enter a valid date.')\n        ],\n        'validate-date-range': [\n            function (value, params) {\n                var fromDate = $('input[name*=\"' + params + '\"]').val();\n\n                return moment.utc(value).unix() >= moment.utc(fromDate).unix() || isNaN(moment.utc(value).unix());\n            },\n            $.mage.__('Make sure the To Date is later than or the same as the From Date.')\n        ],\n        'validate-identifier': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^[a-z0-9][a-z0-9_\\/-]+(\\.[a-z0-9_-]+)?$/.test(value);\n            },\n            $.mage.__('Please enter a valid URL Key (Ex: \"example-page\", \"example-page.html\" or \"anotherlevel/example-page\").')//eslint-disable-line max-len\n        ],\n        'validate-trailing-hyphen': [\n            function (value) {\n                return utils.isEmptyNoTrim(value) || /^(?!-)(?!.*-$).+$/.test(value);\n            },\n            $.mage.__('Trailing hyphens are not allowed.')\n        ],\n        'validate-zip-international': [\n\n            /*function(v) {\n            // @TODO: Cleanup\n            return Validation.get('IsEmpty').test(v) || /(^[A-z0-9]{2,10}([\\s]{0,1}|[\\-]{0,1})[A-z0-9]{2,10}$)/.test(v);\n            }*/\n            function () {\n                return true;\n            },\n            $.mage.__('Please enter a valid zip code.')\n        ],\n        'validate-state': [\n            function (value) {\n                return value !== 0;\n            },\n            $.mage.__('Please select State/Province.')\n        ],\n        'less-than-equals-to': [\n            function (value, params) {\n                value = utils.parseNumber(value);\n\n                if (isNaN(parseFloat(params))) {\n                    params = $(params).val();\n                }\n\n                params = utils.parseNumber(params);\n\n                if (!isNaN(params) && !isNaN(value)) {\n                    this.lteToVal = params;\n\n                    return value <= params;\n                }\n\n                return true;\n            },\n            function () {\n                return $.mage.__('Please enter a value less than or equal to %s.').replace('%s', this.lteToVal);\n            }\n        ],\n        'greater-than-equals-to': [\n            function (value, params) {\n                value = utils.parseNumber(value);\n\n                if (isNaN(parseFloat(params))) {\n                    params = $(params).val();\n                }\n\n                params = utils.parseNumber(params);\n\n                if (!isNaN(params) && !isNaN(value)) {\n                    this.gteToVal = params;\n\n                    return value >= params;\n                }\n\n                return true;\n            },\n            function () {\n                return $.mage.__('Please enter a value greater than or equal to %s.').replace('%s', this.gteToVal);\n            }\n        ],\n        'validate-emails': [\n            function (value) {\n                var validRegexp, emails, i;\n\n                if (utils.isEmpty(value)) {\n                    return true;\n                }\n                validRegexp = /^[a-z0-9\\._-]{1,30}@([a-z0-9_-]{1,30}\\.){1,5}[a-z]{2,4}$/i;\n                emails = value.split(/[\\s\\n\\,]+/g);\n\n                for (i = 0; i < emails.length; i++) {\n                    if (!validRegexp.test(emails[i].strip())) {\n                        return false;\n                    }\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter valid email addresses, separated by commas. For example, [email protected], [email protected].')//eslint-disable-line max-len\n        ],\n        'validate-cc-number': [\n\n            /**\n             * Validate credit card number based on mod 10.\n             *\n             * @param {String} value - credit card number\n             * @return {Boolean}\n             */\n            function (value) {\n                if (value) {\n                    return validateCreditCard(value);\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter a valid credit card number.')\n        ],\n        'validate-cc-ukss': [\n\n            /**\n             * Validate Switch/Solo/Maestro issue number and start date is filled.\n             *\n             * @param {String} value - input field value\n             * @return {*}\n             */\n            function (value) {\n                return value;\n            },\n            $.mage.__('Please enter issue number or start date for switch/solo card type.')\n        ],\n        'required-entry': [\n            function (value) {\n                return !utils.isEmpty(value);\n            },\n            $.mage.__('This is a required field.')\n        ],\n        'checked': [\n            function (value) {\n                return value;\n            },\n            $.mage.__('This is a required field.')\n        ],\n        'not-negative-amount': [\n            function (value) {\n                if (value.length) {\n                    return (/^\\s*\\d+([,.]\\d+)*\\s*%?\\s*$/).test(value);\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter positive number in this field.')\n        ],\n        'validate-per-page-value-list': [\n            function (value) {\n                var isValid = true,\n                    values = value.split(','),\n                    i;\n\n                if (utils.isEmpty(value)) {\n                    return isValid;\n                }\n\n                for (i = 0; i < values.length; i++) {\n                    if (!/^[0-9]+$/.test(values[i])) {\n                        isValid = false;\n                    }\n                }\n\n                return isValid;\n            },\n            $.mage.__('Please enter a valid value, ex: 10,20,30')\n        ],\n        'validate-new-password': [\n            function (value) {\n                if ($.validator.methods['validate-password'] && !$.validator.methods['validate-password'](value)) {\n                    return false;\n                }\n\n                if (utils.isEmpty(value) && value !== '') {\n                    return false;\n                }\n\n                return true;\n            },\n            $.mage.__('Please enter 6 or more characters. Leading and trailing spaces will be ignored.')\n        ],\n        'validate-item-quantity': [\n            function (value, params) {\n                var validator = this,\n                    result = false,\n                    // obtain values for validation\n                    qty = utils.parseNumber(value),\n                    isMinAllowedValid = typeof params.minAllowed === 'undefined' ||\n                        qty >= utils.parseNumber(params.minAllowed),\n                    isMaxAllowedValid = typeof params.maxAllowed === 'undefined' ||\n                        qty <= utils.parseNumber(params.maxAllowed),\n                    isQtyIncrementsValid = typeof params.qtyIncrements === 'undefined' ||\n                        qty % utils.parseNumber(params.qtyIncrements) === 0;\n\n                result = qty > 0;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('Please enter a quantity greater than 0.');//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                result = isMinAllowedValid;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('The fewest you may purchase is %1.').replace('%1', params.minAllowed);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                result = isMaxAllowedValid;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('The maximum you may purchase is %1.').replace('%1', params.maxAllowed);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                result = isQtyIncrementsValid;\n\n                if (result === false) {\n                    validator.itemQtyErrorMessage = $.mage.__('You can buy this product only in quantities of %1 at a time.').replace('%1', params.qtyIncrements);//eslint-disable-line max-len\n\n                    return result;\n                }\n\n                return result;\n            }, function () {\n                return this.itemQtyErrorMessage;\n            }\n        ],\n        'equalTo': [\n            function (value, param) {\n                return value === $(param).val();\n            },\n            $.validator.messages.equalTo\n        ],\n        'validate-file-type': [\n            function (name, types) {\n                var extension = name.split('.').pop().toLowerCase();\n\n                if (types && typeof types === 'string') {\n                    types = types.split(' ');\n                }\n\n                return !types || !types.length || ~types.indexOf(extension);\n            },\n            $.mage.__('We don\\'t recognize or support this file extension type.')\n        ],\n        'validate-max-size': [\n            function (size, maxSize) {\n                return maxSize === false || size < maxSize;\n            },\n            $.mage.__('File you are trying to upload exceeds maximum file size limit.')\n        ],\n        'validate-if-tag-script-exist': [\n            function (value) {\n                return !value || (/<script\\b[^>]*>([\\s\\S]*?)<\\/script>$/ig).test(value);\n            },\n            $.mage.__('Please use tag SCRIPT with SRC attribute or with proper content to include JavaScript to the document.')//eslint-disable-line max-len\n        ],\n        'date_range_min': [\n            function (value, minValue, params) {\n                return moment.utc(value, params.dateFormat).unix() >= minValue;\n            },\n            $.mage.__('The date is not within the specified range.')\n        ],\n        'date_range_max': [\n            function (value, maxValue, params) {\n                return moment.utc(value, params.dateFormat).unix() <= maxValue;\n            },\n            $.mage.__('The date is not within the specified range.')\n        ],\n        'validate-color': [\n            function (value) {\n                if (value === '') {\n                    return true;\n                }\n\n                return tinycolor(value).isValid();\n            },\n            $.mage.__('Wrong color format. Please specify color in HEX, RGBa, HSVa, HSLa or use color name.')\n        ],\n        'blacklist-url': [\n            function (value, param) {\n                return new RegExp(param).test(value);\n            },\n            $.mage.__('This link is not allowed.')\n        ],\n        'validate-dob': [\n            function (value, param, params) {\n                if (value === '') {\n                    return true;\n                }\n\n                return moment.utc(value, params.dateFormat).isSameOrBefore(moment.utc());\n            },\n            $.mage.__('The Date of Birth should not be greater than today.')\n        ],\n        'validate-no-utf8mb4-characters': [\n            function (value) {\n                var validator = this,\n                    message = $.mage.__('Please remove invalid characters: {0}.'),\n                    matches = value.match(/(?:[\\uD800-\\uDBFF][\\uDC00-\\uDFFF])/g),\n                    result = matches === null;\n\n                if (!result) {\n                    validator.charErrorMessage = message.replace('{0}', matches.join());\n                }\n\n                return result;\n            }, function () {\n                return this.charErrorMessage;\n            }\n        ]\n    }, function (data) {\n        return {\n            handler: data[0],\n            message: data[1]\n        };\n    });\n});\n","Magento_Ui/js/lib/validation/validator.js":"/*\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    './rules'\n], function (_, rulesList) {\n    'use strict';\n\n    /**\n     * Validates provided value be the specified rule.\n     *\n     * @param {String} id - Rule identifier.\n     * @param {*} value - Value to be checked.\n     * @param {*} [params]\n     * @param {*} additionalParams - additional validation params set by method caller\n     * @returns {Object}\n     */\n    function validate(id, value, params, additionalParams) {\n        var rule,\n            message,\n            valid,\n            result = {\n                rule: id,\n                passed: true,\n                message: ''\n            };\n\n        if (_.isObject(params)) {\n            message = params.message || '';\n        }\n\n        if (!rulesList[id]) {\n            return result;\n        }\n\n        rule    = rulesList[id];\n        message = message || rule.message;\n        valid   = rule.handler(value, params, additionalParams);\n\n        if (!valid) {\n            params = Array.isArray(params) ?\n                params :\n                [params];\n\n            if (typeof message === 'function') {\n                message = message.call(rule);\n            }\n\n            message = params.reduce(function (msg, param, idx) {\n                return msg.replace(new RegExp('\\\\{' + idx + '\\\\}', 'g'), param);\n            }, message);\n\n            result.passed = false;\n            result.message = message;\n        }\n\n        return result;\n    }\n\n    /**\n     * Validates provided value by a specified set of rules.\n     *\n     * @param {(String|Object)} rules - One or many validation rules.\n     * @param {*} value - Value to be checked.\n     * @param {*} additionalParams - additional validation params set by method caller\n     * @returns {Object}\n     */\n    function validator(rules, value, additionalParams) {\n        var result;\n\n        if (typeof rules === 'object') {\n            result = {\n                passed: true\n            };\n\n            _.every(rules, function (ruleParams, id) {\n                if (ruleParams.validate || ruleParams !== false || additionalParams) {\n                    result = validate(id, value, ruleParams, additionalParams);\n\n                    return result.passed;\n                }\n\n                return true;\n            });\n\n            return result;\n        }\n\n        return validate.apply(null, arguments);\n    }\n\n    /**\n     * Adds new validation rule.\n     *\n     * @param {String} id - Rule identifier.\n     * @param {Function} handler - Validation function.\n     * @param {String} message - Error message.\n     */\n    validator.addRule = function (id, handler, message) {\n        rulesList[id] = {\n            handler: handler,\n            message: message\n        };\n    };\n\n    /**\n     * Returns rule object found by provided identifier.\n     *\n     * @param {String} id - Rule identifier.\n     * @returns {Object}\n     */\n    validator.getRule = function (id) {\n        return rulesList[id];\n    };\n\n    return validator;\n});\n","Magento_Ui/js/lib/validation/utils.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine(function () {\n    'use strict';\n\n    var utils = {\n        /**\n         * Check if string is empty with trim.\n         *\n         * @param {String} value\n         * @return {Boolean}\n         */\n        isEmpty: function (value) {\n            return value === '' || value == null || value.length === 0 || /^\\s+$/.test(value);\n        },\n\n        /**\n         * Check if string is empty no trim.\n         *\n         * @param {String} value\n         * @return {Boolean}\n         */\n        isEmptyNoTrim: function (value) {\n            return value === '' || value == null || value.length === 0;\n        },\n\n        /**\n         * Checks if {value} is between numbers {from} and {to}.\n         *\n         * @param {String} value\n         * @param {String} from\n         * @param {String} to\n         * @return {Boolean}\n         */\n        isBetween: function (value, from, to) {\n            return (from === null || from === '' || value >= utils.parseNumber(from)) &&\n                   (to === null || to === '' || value <= utils.parseNumber(to));\n        },\n\n        /**\n         * Parse price string.\n         *\n         * @param {String} value\n         * @return {Number}\n         */\n        parseNumber: function (value) {\n            var isDot, isComa;\n\n            if (typeof value !== 'string') {\n                return parseFloat(value);\n            }\n            isDot = value.indexOf('.');\n            isComa = value.indexOf(',');\n\n            if (isDot !== -1 && isComa !== -1) {\n                if (isComa > isDot) {\n                    value = value.replace('.', '').replace(',', '.');\n                } else {\n                    value = value.replace(',', '');\n                }\n            } else if (isComa !== -1) {\n                value = value.replace(',', '.');\n            }\n\n            return parseFloat(value);\n        },\n\n        /**\n         * Removes HTML tags and space characters, numbers and punctuation.\n         *\n         * @param {String} value -  Value being stripped.\n         * @return {String}\n         */\n        stripHtml: function (value) {\n            return value.replace(/<.[^<>]*?>/g, ' ').replace(/&nbsp;|&#160;/gi, ' ')\n                .replace(/[0-9.(),;:!?%#$'\"_+=\\/-]*/g, '');\n        }\n    };\n\n    return utils;\n});\n","Magento_Ui/js/lib/registry/registry.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'jquery',\n    'underscore'\n], function ($, _) {\n    'use strict';\n\n    var privateData = new WeakMap();\n\n    /**\n     * Extracts private item storage associated\n     * with a provided registry instance.\n     *\n     * @param {Object} container\n     * @returns {Object}\n     */\n    function getItems(container) {\n        return privateData.get(container).items;\n    }\n\n    /**\n     * Extracts private requests array associated\n     * with a provided registry instance.\n     *\n     * @param {Object} container\n     * @returns {Array}\n     */\n    function getRequests(container) {\n        return privateData.get(container).requests;\n    }\n\n    /**\n     * Wrapper function used for convenient access to the elements.\n     * See 'async' method for examples of usage and comparison\n     * with a regular 'get' method.\n     *\n     * @param {(String|Object|Function)} name - Key of the requested element.\n     * @param {Registry} registry - Instance of a registry\n     *      where to search for the element.\n     * @param {(Function|String)} [method] - Optional callback function\n     *      or a name of the elements' method which\n     *      will be invoked when element is available in registry.\n     * @returns {*}\n     */\n    function async(name, registry, method) {\n        var args = _.toArray(arguments).slice(3);\n\n        if (_.isString(method)) {\n            registry.get(name, function (component) {\n                component[method].apply(component, args);\n            });\n        } else if (_.isFunction(method)) {\n            registry.get(name, method);\n        } else if (!args.length) {\n            return registry.get(name);\n        }\n    }\n\n    /**\n     * Checks that every property of the query object\n     * is present and equal to the corresponding\n     * property in target object.\n     * Note that non-strict comparison is used.\n     *\n     * @param {Object} query - Query object.\n     * @param {Object} target - Target object.\n     * @returns {Boolean}\n     */\n    function compare(query, target) {\n        var matches = true,\n            index,\n            keys,\n            key;\n\n        if (!_.isObject(query) || !_.isObject(target)) {\n            return false;\n        }\n\n        keys = Object.getOwnPropertyNames(query);\n        index = keys.length;\n\n        while (matches && index--) {\n            key = keys[index];\n\n            /* eslint-disable eqeqeq */\n            if (target[key] != query[key]) {\n                matches = false;\n            }\n\n            /* eslint-enable eqeqeq */\n        }\n\n        return matches;\n    }\n\n    /**\n     * Explodes incoming string into object if\n     * string is defined as a set of key = value pairs.\n     *\n     * @param {(String|*)} query - String to be processed.\n     * @returns {Object|*} Either created object or an unmodified incoming\n     *      value if conversion was not possible.\n     * @example Sample conversions.\n     *      'key = value, key2 = value2'\n     *      => {key: 'value', key2: 'value2'}\n     */\n    function explode(query) {\n        var result = {},\n            index,\n            data;\n\n        if (typeof query !== 'string' || !~query.indexOf('=')) {\n            return query;\n        }\n\n        query = query.split(',');\n        index = query.length;\n\n        while (index--) {\n            data = query[index].split('=');\n\n            result[data[0].trim()] = data[1].trim();\n        }\n\n        return result;\n    }\n\n    /**\n     * Extracts items from the provided data object\n     * which matches specified search criteria.\n     *\n     * @param {Object} data - Data object where to perform a lookup.\n     * @param {(String|Object|Function)} query - Search criteria.\n     * @param {Boolean} findAll - Flag that defines whether to\n     *      search for all applicable items or to stop on a first found entry.\n     * @returns {Array|Object|*}\n     */\n    function find(data, query, findAll) {\n        var iterator,\n            item;\n\n        query = explode(query);\n\n        if (typeof query === 'string') {\n            item = data[query];\n\n            if (findAll) {\n                return item ? [item] : [];\n            }\n\n            return item;\n        }\n\n        iterator = !_.isFunction(query) ?\n            compare.bind(null, query) :\n            query;\n\n        return findAll ?\n            _.filter(data, iterator) :\n            _.find(data, iterator);\n    }\n\n    /**\n     * @constructor\n     */\n    function Registry() {\n        var data = {\n            items: {},\n            requests: []\n        };\n\n        this._updateRequests = _.debounce(this._updateRequests.bind(this), 10);\n        privateData.set(this, data);\n    }\n\n    Registry.prototype = {\n        constructor: Registry,\n\n        /**\n         * Retrieves item from registry which matches specified search criteria.\n         *\n         * @param {(Object|String|Function|Array)} query - Search condition (see examples).\n         * @param {Function} [callback] - Callback that will be invoked when\n         *      all of the requested items are available.\n         * @returns {*}\n         *\n         * @example Requesting item by it's name.\n         *      var obj = {index: 'test', sample: true};\n         *\n         *      registry.set('first', obj);\n         *      registry.get('first') === obj;\n         *      => true\n         *\n         * @example Requesting item with a specific properties.\n         *      registry.get('sample = 1, index = test') === obj;\n         *      => true\n         *      registry.get('sample = 0, index = foo') === obj;\n         *      => false\n         *\n         * @example Declaring search criteria as an object.\n         *      registry.get({sample: true}) === obj;\n         *      => true;\n         *\n         * @example Providing custom search handler.\n         *      registry.get(function (item) { return item.sample === true; }) === obj;\n         *      => true\n         *\n         * @example Sample asynchronous request declaration.\n         *      registry.get('index = test', function (item) {});\n         *\n         * @example Requesting multiple elements.\n         *      registry.set('second', {index: 'test2'});\n         *      registry.get(['first', 'second'], function (first, second) {});\n         */\n        get: function (query, callback) {\n            if (typeof callback !== 'function') {\n                return find(getItems(this), query);\n            }\n\n            this._addRequest(query, callback);\n        },\n\n        /**\n         * Sets provided item to the registry.\n         *\n         * @param {String} id - Item's identifier.\n         * @param {*} item - Item's data.\n         * returns {Registry} Chainable.\n         */\n        set: function (id, item) {\n            getItems(this)[id] = item;\n\n            this._updateRequests();\n\n            return this;\n        },\n\n        /**\n         * Removes specified item from registry.\n         * Note that search query is not applicable.\n         *\n         * @param {String} id - Item's identifier.\n         * @returns {Registry} Chainable.\n         */\n        remove: function (id) {\n            delete getItems(this)[id];\n\n            return this;\n        },\n\n        /**\n         * Retrieves a collection of elements that match\n         * provided search criteria.\n         *\n         * @param {(Object|String|Function)} query - Search query.\n         *      See 'get' method for the syntax examples.\n         * @returns {Array} Found elements.\n         */\n        filter: function (query) {\n            return find(getItems(this), query, true);\n        },\n\n        /**\n         * Checks that at least one element in collection\n         * matches provided search criteria.\n         *\n         * @param {(Object|String|Function)} query - Search query.\n         *      See 'get' method for the syntax examples.\n         * @returns {Boolean}\n         */\n        has: function (query) {\n            return !!this.get(query);\n        },\n\n        /**\n         * Checks that registry contains a provided item.\n         *\n         * @param {*} item - Item to be checked.\n         * @returns {Boolean}\n         */\n        contains: function (item) {\n            return _.contains(getItems(this), item);\n        },\n\n        /**\n         * Extracts identifier of an item if it's present in registry.\n         *\n         * @param {*} item - Item whose identifier will be extracted.\n         * @returns {String|Undefined}\n         */\n        indexOf: function (item) {\n            return _.findKey(getItems(this), function (elem) {\n                return item === elem;\n            });\n        },\n\n        /**\n         * Same as a 'get' method except that it returns\n         * a promise object instead of invoking provided callback.\n         *\n         * @param {(String|Function|Object|Array)} query - Search query.\n         *      See 'get' method for the syntax examples.\n         * @returns {jQueryPromise}\n         */\n        promise: function (query) {\n            var defer    = $.Deferred(),\n                callback = defer.resolve.bind(defer);\n\n            this.get(query, callback);\n\n            return defer.promise();\n        },\n\n        /**\n         * Creates a wrapper function over the provided search query\n         * in order to provide somehow more convenient access to the\n         * registry's items.\n         *\n         * @param {(String|Object|Function)} query - Search criteria.\n         *      See 'get' method for the syntax examples.\n         * @returns {Function}\n         *\n         * @example Comparison with a 'get' method on retrieving items.\n         *      var module = registry.async('name');\n         *\n         *      module();\n         *      => registry.get('name');\n         *\n         * @example Asynchronous request.\n         *      module(function (component) {});\n         *      => registry.get('name', function (component) {});\n         *\n         * @example Requesting item and invoking it's method with specified parameters.\n         *      module('trigger', true);\n         *      => registry.get('name', function (component) {\n         *          component.trigger(true);\n         *      });\n         */\n        async: function (query) {\n            return async.bind(null, query, this);\n        },\n\n        /**\n         * Creates new instance of a Registry.\n         *\n         * @returns {Registry} New instance.\n         */\n        create: function () {\n            return new Registry;\n        },\n\n        /**\n         * Adds new request to the queue or resolves it immediately\n         * if all of the required items are available.\n         *\n         * @private\n         * @param {(Object|String|Function|Array)} queries - Search criteria.\n         *      See 'get' method for the syntax examples.\n         * @param {Function} callback - Callback that will be invoked when\n         *      all of the requested items are available.\n         * @returns {Registry}\n         */\n        _addRequest: function (queries, callback) {\n            var request;\n\n            if (!Array.isArray(queries)) {\n                queries = queries ? [queries] : [];\n            }\n\n            request = {\n                queries: queries.map(explode),\n                callback: callback\n            };\n\n            this._canResolve(request) ?\n                this._resolveRequest(request) :\n                getRequests(this).push(request);\n\n            return this;\n        },\n\n        /**\n         * Updates requests list resolving applicable items.\n         *\n         * @private\n         * @returns {Registry} Chainable.\n         */\n        _updateRequests: function () {\n            getRequests(this)\n                .filter(this._canResolve, this)\n                .forEach(this._resolveRequest, this);\n\n            return this;\n        },\n\n        /**\n         * Resolves provided request invoking it's callback\n         * with items specified in query parameters.\n         *\n         * @private\n         * @param {Object} request - Request object.\n         * @returns {Registry} Chainable.\n         */\n        _resolveRequest: function (request) {\n            var requests = getRequests(this),\n                items    = request.queries.map(this.get, this),\n                index    = requests.indexOf(request);\n\n            request.callback.apply(null, items);\n\n            if (~index) {\n                requests.splice(index, 1);\n            }\n\n            return this;\n        },\n\n        /**\n         * Checks if provided request can be resolved.\n         *\n         * @private\n         * @param {Object} request - Request object.\n         * @returns {Boolean}\n         */\n        _canResolve: function (request) {\n            var queries = request.queries;\n\n            return queries.every(this.has, this);\n        }\n    };\n\n    return new Registry;\n});\n","Magento_Ui/js/lib/logger/entry-factory.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './entry'\n], function (LogEntry) {\n    'use strict';\n\n    return {\n        /**\n         * @param {String} message\n         * @param {Number} level\n         * @param {Object} [messageData]\n         * @returns {LogEntry}\n         */\n        createEntry: function (message, level, messageData) {\n            return new LogEntry(message, level, messageData);\n        }\n    };\n});\n","Magento_Ui/js/lib/logger/logger-utils.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([], function () {\n    'use strict';\n\n    /**\n     * Utils methods for logger\n     * @param {Logger} logger\n     */\n    function LogUtils(logger) {\n        this.logger = logger;\n\n    }\n\n    /**\n     * Method for logging asynchronous operations\n     * @param {Promise} promise\n     * @param {Object} config\n     */\n    LogUtils.prototype.asyncLog = function (promise, config) {\n        var levels,\n            messages,\n            wait;\n\n        config = config || {};\n        levels = config.levels || this.createLevels();\n        messages = config.messages || this.createMessages();\n        wait = config.wait || 5000;\n\n        this.logger[levels.requested](messages.requested, config.data);\n        setTimeout(function () {\n            promise.state() === 'pending' ?\n                this.logger[levels.failed](messages.failed, config.data) :\n                this.logger[levels.loaded](messages.loaded, config.data);\n        }.bind(this), wait);\n    };\n\n    /**\n     * Method that creates object of messages\n     * @param {String} requested - log message that showing that request for class is started\n     * @param {String} loaded - log message that show when requested class is loaded\n     * @param {String} failed - log message that show when requested class is failed\n     * @returns {Object}\n     */\n    LogUtils.prototype.createMessages = function (requested, loaded, failed) {\n        return {\n            requested: requested || '',\n            loaded: loaded || '',\n            failed: failed || ''\n        };\n    };\n\n    /**\n     * Method that creates object of log levels\n     * @param {String} requested - log message that showing that request for class is started\n     * @param {String} loaded - log message that show when requested class is loaded\n     * @param {String} failed - log message that show when requested class is failed\n     * @returns {Object}\n     */\n    LogUtils.prototype.createLevels = function (requested, loaded, failed) {\n        return {\n            requested: requested || 'info',\n            loaded: loaded || 'info',\n            failed: failed || 'warn'\n        };\n    };\n\n    return LogUtils;\n});\n","Magento_Ui/js/lib/logger/entry.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './levels-pool'\n], function (logLevels) {\n    'use strict';\n\n    /**\n     * @param {String} message\n     * @param {Number} level\n     * @param {Object} [data]\n     */\n    function LogEntry(message, level, data) {\n        /**\n         * @readonly\n         * @type {Number}\n         */\n        this.timestamp = Date.now();\n\n        /**\n         * @readonly\n         * @type {Number}\n         */\n        this.level = level;\n\n        /**\n         * @readonly\n         * @type {String}\n         */\n        this.levelName = logLevels.getNameByCode(level);\n\n        /**\n         * @readonly\n         * @type {Object}\n         */\n        this.data = data;\n\n        /**\n         * @readonly\n         * @type {String}\n         */\n        this.message = message;\n    }\n\n    return LogEntry;\n});\n","Magento_Ui/js/lib/logger/formatter.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'moment',\n    'mage/utils/template'\n], function (moment, mageTemplate) {\n    'use strict';\n\n    /**\n     * @param {String} dateFormat\n     * @param {String} template\n     */\n    function LogFormatter(dateFormat, template) {\n        /**\n         * @protected\n         * @type {String}\n         */\n        this.dateFormat_ = 'YYYY-MM-DD hh:mm:ss';\n\n        /**\n         * @protected\n         * @type {String}\n         */\n        this.template_ = '[${ $.date }] [${ $.entry.levelName }] ${ $.message }';\n\n        if (dateFormat) {\n            this.dateFormat_ = dateFormat;\n        }\n\n        if (template) {\n            this.template_ = template;\n        }\n    }\n\n    /**\n     * @param {LogEntry} entry\n     * @returns {String}\n     */\n    LogFormatter.prototype.process = function (entry) {\n        var message = mageTemplate.template(entry.message, entry.data),\n            date = moment(entry.timestamp).format(this.dateFormat_);\n\n        return mageTemplate.template(this.template_, {\n            date: date,\n            entry: entry,\n            message: message\n        });\n    };\n\n    return LogFormatter;\n});\n","Magento_Ui/js/lib/logger/levels-pool.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'underscore'\n], function (_) {\n    'use strict';\n\n    var LEVELS,\n        CODE_MAP;\n\n    LEVELS = {\n        NONE: 0,\n        ERROR: 1,\n        WARN: 2,\n        INFO: 3,\n        DEBUG: 4,\n        ALL: 5\n    };\n\n    CODE_MAP = _.invert(LEVELS);\n\n    return {\n        /**\n         * Returns the list of available log levels.\n         *\n         * @returns {Object}\n         */\n        getLevels: function () {\n            return LEVELS;\n        },\n\n        /**\n         * Returns name of the log level that matches to the provided code.\n         *\n         * @returns {String}\n         */\n        getNameByCode: function (code) {\n            return CODE_MAP[code];\n        }\n    };\n});\n","Magento_Ui/js/lib/logger/console-logger.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './logger',\n    './entry-factory',\n    './console-output-handler',\n    './formatter',\n    './message-pool',\n    './levels-pool',\n    'Magento_Ui/js/lib/core/storage/local',\n    'underscore',\n    './logger-utils'\n], function (Logger, entryFactory, ConsoleHandler, Formatter, messagePoll, levelsPoll, storage, _, LoggerUtils) {\n    'use strict';\n\n    var STORAGE_NAMESPACE = 'CONSOLE_LOGGER';\n\n    /**\n     * Singleton Logger's sub-class instance of which is configured to display its\n     * messages to the console. It also provides the support of predefined messages\n     * and persists its display level.\n     */\n    function ConsoleLogger() {\n        var formatter = new Formatter(),\n            consoleHandler = new ConsoleHandler(formatter),\n            savedLevel = storage.get(STORAGE_NAMESPACE),\n            utils = new LoggerUtils(this);\n\n        Logger.call(this, consoleHandler, entryFactory);\n\n        if (savedLevel) {\n            this.displayLevel_ = savedLevel;\n        }\n\n        this.utils = utils;\n        this.messages = messagePoll;\n        this.levels = levelsPoll.getLevels();\n    }\n\n    _.extend(ConsoleLogger, Logger);\n\n    ConsoleLogger.prototype = Object.create(Logger.prototype);\n    ConsoleLogger.prototype.constructor = ConsoleLogger;\n\n    /**\n     * Overrides parent method to save the provided display level.\n     *\n     * @override\n     */\n    ConsoleLogger.prototype.setDisplayLevel = function (level) {\n        Logger.prototype.setDisplayLevel.call(this, level);\n\n        storage.set(STORAGE_NAMESPACE, level);\n    };\n\n    /**\n     * Adds the support of predefined messages.\n     *\n     * @protected\n     * @override\n     */\n    ConsoleLogger.prototype.createEntry_ = function (message, level, data) {\n        var code;\n\n        if (messagePoll.hasMessage(message)) {\n            data = data || {};\n            code = message;\n            message = messagePoll.getMessage(code);\n\n            data.messageCode = code;\n        }\n\n        return Logger.prototype.createEntry_.call(this, message, level, data);\n    };\n\n    return new ConsoleLogger();\n});\n","Magento_Ui/js/lib/logger/message-pool.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine(function () {\n    'use strict';\n\n    var MESSAGES = {\n        templateStartLoading:\n            'The \"${ $.template }\" template requested by  the \"${$.component}\" component started loading.',\n        templateLoadedFromServer:\n            'The \"${ $.template }\" template requested by the \"${$.component}\" component  was loaded from server.\"',\n        templateLoadedFromCache:\n            'The \"${ $.template }\" template  requested by the \"${$.component}\" component was loaded from cache.\"',\n        templateLoadingFail: 'Failed to load the \"${ $.template }\" template requested by \"${$.component}\".',\n        componentStartInitialization:\n            'Component \"${$.component}\" start initialization with instance name \"${$.componentName}\".',\n        componentStartLoading: ' Started loading the \"${$.component}\" component.',\n        componentFinishLoading: 'The \"${$.component}\" component was loaded.',\n        componentLoadingFail: 'Failed to load the \"${$.component}\" component.',\n        depsLoadingFail: 'Could not get the declared \"${$.deps}\" dependency for the \"${$.component}\" instance.',\n        depsStartRequesting: 'Requesting the \"${$.deps}\" dependency for the \"${$.component}\" instance.',\n        depsFinishRequesting: 'The \"${$.deps}\" dependency for the \"${$.component}\" instance was received.',\n        requestingComponent: 'Requesting the \"${$.component}\" component.',\n        requestingComponentIsLoaded: 'The requested \"${$.component}\" component was received.',\n        requestingComponentIsFailed: 'Could not get the requested \"${$.component}\" component.'\n    };\n\n    return {\n        /**\n         * Returns message that matches the provided code.\n         *\n         * @param {String} code - Message's identifier\n         * @returns {String}\n         */\n        getMessage: function (code) {\n            return MESSAGES[code];\n        },\n\n        /**\n         * Adds a new message to the poll.\n         *\n         * @param {String} code - Message's identifier.\n         * @param {String} message - Text of the message\n         */\n        addMessage: function (code, message) {\n            MESSAGES[code] = message;\n        },\n\n        /**\n         * Tells whether message with provide code exists in the poll.\n         *\n         * @param {String} code - Message's identifier.\n         * @returns {Boolean}\n         */\n        hasMessage: function (code) {\n            return MESSAGES.hasOwnProperty(code);\n        }\n    };\n});\n","Magento_Ui/js/lib/logger/console-output-handler.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './levels-pool'\n], function (logLevels) {\n    'use strict';\n\n    var levels = logLevels.getLevels();\n\n    /**\n     * @param {LogFormatter} formatter\n     */\n    function ConsoleOutputHandler(formatter) {\n        /**\n         * @protected\n         * @type {LogFormatter}\n         */\n        this.formatter_ = formatter;\n    }\n\n    /**\n     * Display data of the provided entry to the console.\n     *\n     * @param {LogEntry} entry - Entry to be displayed.\n     */\n    ConsoleOutputHandler.prototype.show = function (entry) {\n        var displayString = this.formatter_.process(entry);\n\n        switch (entry.level) {\n            case levels.ERROR:\n                console.error(displayString);\n                break;\n\n            case levels.WARN:\n                console.warn(displayString);\n                break;\n\n            case levels.INFO:\n                console.info(displayString);\n                break;\n\n            case levels.DEBUG:\n                console.log(displayString);\n                break;\n        }\n    };\n\n    /**\n     * Displays the array of entries.\n     *\n     * @param {Array<LogEntry>} entries\n     */\n    ConsoleOutputHandler.prototype.dump = function (entries) {\n        entries.forEach(this.show, this);\n    };\n\n    return ConsoleOutputHandler;\n});\n","Magento_Ui/js/lib/logger/logger.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    './levels-pool'\n], function (logLevels) {\n    'use strict';\n\n    var levels = logLevels.getLevels();\n\n    /**\n     * @param {LogOutputHandler} outputHandler\n     * @param {LogEntryFactory} entryFactory\n     */\n    function Logger(outputHandler, entryFactory) {\n        /**\n         * An array of log entries.\n         *\n         * @protected\n         * @type {Array<LogEntry>}\n         */\n        this.entries_ = [];\n\n        /**\n         * Current display level.\n         *\n         * @protected\n         * @type {Number}\n         */\n        this.displayLevel_ = levels.ERROR;\n\n        /**\n         * An array of display criteria.\n         *\n         * @protected\n         * @type {Array<LogCriteria>}\n         */\n        this.displayCriteria_ = [];\n\n        /**\n         * @protected\n         * @type {LogEntryFactory}\n         */\n        this.entryFactory_ = entryFactory;\n\n        /**\n         * @protected\n         * @type {Array<LogOutputHandler>}\n         */\n        this.outputHandlers_ = [outputHandler];\n\n        this.addDisplayCriteria(this.matchesLevel_);\n    }\n\n    /**\n     * Swaps current display level with the provided one.\n     *\n     * @param {Number} level - Level's code.\n     */\n    Logger.prototype.setDisplayLevel = function (level) {\n        var levelName = logLevels.getNameByCode(level);\n\n        if (!levelName) {\n            throw new TypeError('The provided level is not defined in the levels list.');\n        }\n\n        this.displayLevel_ = level;\n    };\n\n    /**\n     * Sets up the criteria by which log entries will be filtered out from the output.\n     *\n     * @param {LogCriteria} criteria\n     */\n    Logger.prototype.addDisplayCriteria = function (criteria) {\n        this.displayCriteria_.push(criteria);\n    };\n\n    /**\n     * Removes previously defined criteria.\n     *\n     * @param {LogCriteria} criteria\n     */\n    Logger.prototype.removeDisplayCriteria = function (criteria) {\n        var index = this.displayCriteria_.indexOf(criteria);\n\n        if (~index) {\n            this.displayCriteria_.splice(index, 1);\n        }\n    };\n\n    /**\n     * @param {String} message\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.error = function (message, messageData) {\n        return this.log_(message, levels.ERROR, messageData);\n    };\n\n    /**\n     * @param {String} message\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.warn = function (message, messageData) {\n        return this.log_(message, levels.WARN, messageData);\n    };\n\n    /**\n     * @param {String} message\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.info = function (message, messageData) {\n        return this.log_(message, levels.INFO, messageData);\n    };\n\n    /**\n     * @param {String} message\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.debug = function (message, messageData) {\n        return this.log_(message, levels.DEBUG, messageData);\n    };\n\n    /**\n     * @protected\n     * @param {String} message\n     * @param {Number} level\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.log_ = function (message, level, messageData) {\n        var entry = this.createEntry_(message, level, messageData);\n\n        this.entries_.push(entry);\n\n        if (this.matchesCriteria_(entry)) {\n            this.processOutput_(entry);\n        }\n\n        return entry;\n    };\n\n    /**\n     * @protected\n     * @param {String} message\n     * @param {Number} level\n     * @param {Object} [messageData]\n     * @returns {LogEntry}\n     */\n    Logger.prototype.createEntry_ = function (message, level, messageData) {\n        return this.entryFactory_.createEntry(message, level, messageData);\n    };\n\n    /**\n     * Returns an array of log entries that have been added to the logger.\n     *\n     * @param {LogCriteria} [criteria] - Optional filter criteria.\n     * @returns {Array<LogEntry>}\n     */\n    Logger.prototype.getEntries = function (criteria) {\n        if (criteria) {\n            return this.entries_.filter(criteria);\n        }\n\n        return this.entries_;\n    };\n\n    /**\n     * @param {LogCriteria} [criteria]\n     */\n    Logger.prototype.dump = function (criteria) {\n        var entries;\n\n        if (!criteria) {\n            criteria = this.matchesCriteria_;\n        }\n\n        entries = this.entries_.filter(criteria, this);\n\n        this.outputHandlers_.forEach(function (handler) {\n            handler.dump(entries);\n        });\n    };\n\n    /**\n     * @protected\n     * @param {LogEntry} entry\n     */\n    Logger.prototype.processOutput_ = function (entry) {\n        this.outputHandlers_.forEach(function (handler) {\n            handler.show(entry);\n        });\n    };\n\n    /**\n     * @protected\n     * @param {LogEntry} entry\n     * @returns {Boolean}\n     */\n    Logger.prototype.matchesCriteria_ = function (entry) {\n        return this.displayCriteria_.every(function (criteria) {\n            return criteria.call(this, entry);\n        }, this);\n    };\n\n    /**\n     * Checks that the level of provided entry passes the \"displayLevel_\" threshold.\n     *\n     * @protected\n     * @param {LogEntry} entry - Entry to be checked.\n     * @returns {Boolean}\n     */\n    Logger.prototype.matchesLevel_ = function (entry) {\n        return entry.level <= this.displayLevel_;\n    };\n\n    return Logger;\n});\n","Magento_Ui/js/lib/core/class.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    'mage/utils/wrapper'\n], function (_, utils, wrapper) {\n    'use strict';\n\n    var Class;\n\n    /**\n     * Returns property of an object if\n     * it's his own property.\n     *\n     * @param {Object} obj - Object whose property should be retrieved.\n     * @param {String} prop - Name of the property.\n     * @returns {*} Value of the property or false.\n     */\n    function getOwn(obj, prop) {\n        return _.isObject(obj) && obj.hasOwnProperty(prop) && obj[prop];\n    }\n\n    /**\n     * Creates constructor function which allows\n     * initialization without usage of a 'new' operator.\n     *\n     * @param {Object} protoProps - Prototypal properties of a new constructor.\n     * @param {Function} constructor\n     * @returns {Function} Created constructor.\n     */\n    function createConstructor(protoProps, constructor) {\n        var UiClass = constructor;\n\n        if (!UiClass) {\n\n            /**\n             * Default constructor function.\n             */\n            UiClass = function () {\n                var obj = this;\n\n                if (!_.isObject(obj) || Object.getPrototypeOf(obj) !== UiClass.prototype) {\n                    obj = Object.create(UiClass.prototype);\n                }\n\n                obj.initialize.apply(obj, arguments);\n\n                return obj;\n            };\n        }\n\n        UiClass.prototype = protoProps;\n        UiClass.prototype.constructor = UiClass;\n\n        return UiClass;\n    }\n\n    Class = createConstructor({\n\n        /**\n         * Entry point to the initialization of constructor's instance.\n         *\n         * @param {Object} [options={}]\n         * @returns {Class} Chainable.\n         */\n        initialize: function (options) {\n            this.initConfig(options);\n\n            return this;\n        },\n\n        /**\n         * Recursively extends data specified in constructors' 'defaults'\n         * property with provided options object. Evaluates resulting\n         * object using string templates (see: mage/utils/template.js).\n         *\n         * @param {Object} [options={}]\n         * @returns {Class} Chainable.\n         */\n        initConfig: function (options) {\n            var defaults    = this.constructor.defaults,\n                config      = utils.extend({}, defaults, options || {}),\n                ignored     = config.ignoreTmpls || {},\n                cached      = utils.omit(config, ignored);\n\n            config = utils.template(config, this, false, true);\n\n            _.each(cached, function (value, key) {\n                utils.nested(config, key, value);\n            });\n\n            return _.extend(this, config);\n        }\n    });\n\n    _.extend(Class, {\n        defaults: {\n            ignoreTmpls: {\n                templates: true\n            }\n        },\n\n        /**\n         * Creates new constructor based on a current prototype properties,\n         * extending them with properties specified in 'exender' object.\n         *\n         * @param {Object} [extender={}]\n         * @returns {Function} New constructor.\n         */\n        extend: function (extender) {\n            var parent      = this,\n                parentProto = parent.prototype,\n                childProto  = Object.create(parentProto),\n                child       = createConstructor(childProto, getOwn(extender, 'constructor')),\n                defaults;\n\n            extender = extender || {};\n            defaults = extender.defaults;\n\n            delete extender.defaults;\n\n            _.each(extender, function (method, name) {\n                childProto[name] = wrapper.wrapSuper(parentProto[name], method);\n            });\n\n            child.defaults = utils.extend({}, parent.defaults || {});\n\n            if (defaults) {\n                utils.extend(child.defaults, defaults);\n                extender.defaults = defaults;\n            }\n\n            return _.extend(child, {\n                __super__:  parentProto,\n                extend:     parent.extend\n            });\n        }\n    });\n\n    return Class;\n});\n","Magento_Ui/js/lib/core/events.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore'\n], function (ko, _) {\n    'use strict';\n\n    var eventsMap = new WeakMap();\n\n    /**\n     * Returns events map or a specific event\n     * data associated with a provided object.\n     *\n     * @param {Object} obj - Key in the events weakmap.\n     * @param {String} [name] - Name of the event.\n     * @returns {Map|Array|Boolean}\n     */\n    function getEvents(obj, name) {\n        var events = eventsMap.get(obj);\n\n        if (!events) {\n            return false;\n        }\n\n        return name ? events.get(name) : events;\n    }\n\n    /**\n     * Adds new event handler.\n     *\n     * @param {Object} obj - Key in the events weakmap.\n     * @param {String} ns - Callback namespace.\n     * @param {Function} callback - Event callback.\n     * @param {String} name - Name of the event.\n     */\n    function addHandler(obj, ns, callback, name) {\n        var events      = getEvents(obj),\n            observable,\n            data;\n\n        observable = !ko.isObservable(obj[name]) ?\n            ko.getObservable(obj, name) :\n            obj[name];\n\n        if (observable) {\n            observable.subscribe(callback);\n\n            return;\n        }\n\n        if (!events) {\n            events = new Map();\n\n            eventsMap.set(obj, events);\n        }\n\n        data = {\n            callback: callback,\n            ns: ns\n        };\n\n        events.has(name) ?\n            events.get(name).push(data) :\n            events.set(name, [data]);\n    }\n\n    /**\n     * Invokes provided callbacks with a specified arguments.\n     *\n     * @param {Array} handlers\n     * @param {Array} args\n     * @returns {Boolean}\n     */\n    function trigger(handlers, args) {\n        var bubble = true,\n            callback;\n\n        handlers.forEach(function (handler) {\n            callback = handler.callback;\n\n            if (callback.apply(null, args) === false) {\n                bubble = false;\n            }\n        });\n\n        return bubble;\n    }\n\n    return {\n\n        /**\n         * Calls callback when name event is triggered.\n         * @param  {String}   events\n         * @param  {Function} callback\n         * @param  {Function} ns\n         * @return {Object} reference to this\n         */\n        on: function (events, callback, ns) {\n            var iterator;\n\n            if (arguments.length < 2) {\n                ns = callback;\n            }\n\n            iterator = addHandler.bind(null, this, ns);\n\n            _.isObject(events) ?\n                _.each(events, iterator) :\n                iterator(callback, events);\n\n            return this;\n        },\n\n        /**\n         * Removed callback from listening to target event\n         * @param  {String} ns\n         * @return {Object} reference to this\n         */\n        off: function (ns) {\n            var storage = getEvents(this);\n\n            if (!storage) {\n                return this;\n            }\n\n            storage.forEach(function (handlers, name) {\n                handlers = handlers.filter(function (handler) {\n                    return !ns ? false : handler.ns !== ns;\n                });\n\n                handlers.length ?\n                    storage.set(name, handlers) :\n                    storage.delete(name);\n            });\n\n            return this;\n        },\n\n        /**\n         * Triggers event and executes all attached callbacks.\n         *\n         * @param {String} name - Name of the event to be triggered.\n         * @returns {Boolean}\n         */\n        trigger: function (name) {\n            var handlers,\n                args;\n\n            handlers = getEvents(this, name),\n            args = _.toArray(arguments).slice(1);\n\n            if (!handlers || !name) {\n                return true;\n            }\n\n            return trigger(handlers, args);\n        }\n    };\n});\n","Magento_Ui/js/lib/core/collection.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'underscore',\n    'mageUtils',\n    'uiRegistry',\n    'uiElement'\n], function (_, utils, registry, Element) {\n    'use strict';\n\n    /**\n     * Removes non plain object items from the specified array.\n     *\n     * @param {Array} container - Array whose value should be filtered.\n     * @returns {Array}\n     */\n    function compact(container) {\n        return _.values(container).filter(utils.isObject);\n    }\n\n    /**\n     * Defines index of an item in a specified container.\n     *\n     * @param {*} item - Item whose index should be defined.\n     * @param {Array} container - Container upon which to perform search.\n     * @returns {Number}\n     */\n    function _findIndex(item, container) {\n        var index = _.findKey(container, function (value) {\n            return value === item;\n        });\n\n        if (typeof index === 'undefined') {\n            index = _.findKey(container, function (value) {\n                return value && value.name === item;\n            });\n        }\n\n        return typeof index === 'undefined' ? -1 : index;\n    }\n\n    /**\n     * Inserts specified item into container at a specified position.\n     *\n     * @param {*} item - Item to be inserted into container.\n     * @param {Array} container - Container of items.\n     * @param {*} [position=-1] - Position at which item should be inserted.\n     *      Position can represent:\n     *          - specific index in container\n     *          - item which might already be present in container\n     *          - structure with one of these properties: after, before\n     * @returns {Boolean|*}\n     *      - true if element has changed its' position\n     *      - false if nothing has changed\n     *      - inserted value if it wasn't present in container\n     */\n    function _insertAt(item, container, position) {\n        var currentIndex = _findIndex(item, container),\n            newIndex,\n            target;\n\n        if (typeof position === 'undefined') {\n            position = -1;\n        } else if (typeof position === 'string') {\n            position = isNaN(+position) ? position : +position;\n        }\n\n        newIndex = position;\n\n        if (~currentIndex) {\n            target = container.splice(currentIndex, 1)[0];\n\n            if (typeof item === 'string') {\n                item = target;\n            }\n        }\n\n        if (typeof position !== 'number') {\n            target = position.after || position.before || position;\n\n            newIndex = _findIndex(target, container);\n\n            if (~newIndex && (position.after || newIndex >= currentIndex)) {\n                newIndex++;\n            }\n        }\n\n        if (newIndex < 0) {\n            newIndex += container.length + 1;\n        }\n\n        container[newIndex] ?\n            container.splice(newIndex, 0, item) :\n            container[newIndex] = item;\n\n        return !~currentIndex ? item : currentIndex !== newIndex;\n    }\n\n    return Element.extend({\n        defaults: {\n            template: 'ui/collection',\n            _elems: [],\n            ignoreTmpls: {\n                childDefaults: true\n            }\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Model} Chainable.\n         */\n        initObservable: function () {\n            this._super()\n                .observe({\n                    elems: []\n                });\n\n            return this;\n        },\n\n        /**\n         * Called when another element was added to current component.\n         *\n         * @param {Object} elem - Instance of an element that was added.\n         * @returns {Collection} Chainable.\n         */\n        initElement: function (elem) {\n            elem.initContainer(this);\n\n            return this;\n        },\n\n        /**\n         * Returns instance of a child found by provided index.\n         *\n         * @param {String} index - Index of a child.\n         * @returns {Object}\n         */\n        getChild: function (index) {\n            return _.findWhere(this.elems(), {\n                index: index\n            });\n        },\n\n        /**\n         * Requests specified components to insert\n         * them into 'elems' array starting from provided position.\n         *\n         * @param {(String|Array)} elems - Name of the component to insert.\n         * @param {Number} [position=-1] - Position at which to insert elements.\n         * @returns {Collection} Chainable.\n         */\n        insertChild: function (elems, position) {\n            var container   = this._elems,\n                insert      = this._insert.bind(this),\n                update;\n\n            if (!Array.isArray(elems)) {\n                elems = [elems];\n            }\n\n            elems.map(function (item) {\n                return item.elem ?\n                    _insertAt(item.elem, container, item.position) :\n                    _insertAt(item, container, position);\n            }).forEach(function (item) {\n                if (item === true) {\n                    update = true;\n                } else if (_.isString(item)) {\n                    registry.get(item, insert);\n                } else if (utils.isObject(item)) {\n                    insert(item);\n                }\n            });\n\n            if (update) {\n                this._updateCollection();\n            }\n\n            return this;\n        },\n\n        /**\n         * Removes specified child from collection.\n         *\n         * @param {(Object|String)} elem - Child or index of a child to be removed.\n         * @param {Boolean} skipUpdate - skip collection update when element to be destroyed.\n         *\n         * @returns {Collection} Chainable.\n         */\n        removeChild: function (elem, skipUpdate) {\n            if (_.isString(elem)) {\n                elem = this.getChild(elem);\n            }\n\n            if (elem) {\n                utils.remove(this._elems, elem);\n\n                if (!skipUpdate) {\n                    this._updateCollection();\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Destroys collection children with its' elements.\n         */\n        destroyChildren: function () {\n            this.elems.each(function (elem) {\n                elem.destroy(true);\n            });\n\n            this._updateCollection();\n        },\n\n        /**\n         * Clear data. Call method \"clear\"\n         * in child components\n         *\n         * @returns {Object} Chainable.\n         */\n        clear: function () {\n            var elems = this.elems();\n\n            _.each(elems, function (elem) {\n                if (_.isFunction(elem.clear)) {\n                    elem.clear();\n                }\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Checks if specified child exists in collection.\n         *\n         * @param {String} index - Index of a child.\n         * @returns {Boolean}\n         */\n        hasChild: function (index) {\n            return !!this.getChild(index);\n        },\n\n        /**\n         * Creates 'async' wrapper for the specified child\n         * using uiRegistry 'async' method and caches it\n         * in a '_requested' components  object.\n         *\n         * @param {String} index - Index of a child.\n         * @returns {Function} Async module wrapper.\n         */\n        requestChild: function (index) {\n            var name = this.formChildName(index);\n\n            return this.requestModule(name);\n        },\n\n        /**\n         * Creates complete child name based on a provided index.\n         *\n         * @param {String} index - Index of a child.\n         * @returns {String}\n         */\n        formChildName: function (index) {\n            return this.name + '.' + index;\n        },\n\n        /**\n         * Retrieves requested region.\n         * Creates region if it was not created yet\n         *\n         * @returns {ObservableArray}\n         */\n        getRegion: function (name) {\n            var regions = this.regions = this.regions || {};\n\n            if (!regions[name]) {\n                regions[name] = [];\n\n                this.observe.call(regions, name);\n            }\n\n            return regions[name];\n        },\n\n        /**\n         * Checks if the specified region has any elements\n         * associated with it.\n         *\n         * @param {String} name\n         * @returns {Boolean}\n         */\n        regionHasElements: function (name) {\n            var region = this.getRegion(name);\n\n            return region().length > 0;\n        },\n\n        /**\n         * Replaces specified regions' data with a provided one.\n         * Creates region if it was not created yet.\n         *\n         * @param {Array} items - New regions' data.\n         * @param {String} name - Name of the region.\n         * @returns {Collection} Chainable.\n         */\n        updateRegion: function (items, name) {\n            this.getRegion(name)(items);\n\n            return this;\n        },\n\n        /**\n         * Destroys collection along with its' elements.\n         */\n        destroy: function () {\n            this._super();\n\n            this.elems.each('destroy');\n        },\n\n        /**\n         * Inserts provided component into 'elems' array at a specified position.\n         * @private\n         *\n         * @param {Object} elem - Element to insert.\n         */\n        _insert: function (elem) {\n            var index = _.findKey(this._elems, function (value) {\n                return value === elem.name;\n            });\n\n            if (typeof index !== 'undefined') {\n                this._elems[index] = elem;\n            }\n\n            this._updateCollection()\n                .initElement(elem);\n        },\n\n        /**\n         * Synchronizes multiple elements arrays with a core '_elems' container.\n         * Performs elemets grouping by theirs 'displayArea' property.\n         * @private\n         *\n         * @returns {Collection} Chainable.\n         */\n        _updateCollection: function () {\n            var _elems = compact(this._elems),\n                grouped;\n\n            grouped = _elems.filter(function (elem) {\n                return elem.displayArea && _.isString(elem.displayArea);\n            });\n            grouped = _.groupBy(grouped, 'displayArea');\n\n            _.each(grouped, this.updateRegion, this);\n\n            _.each(this.regions, function (items) {\n                var hasObsoleteComponents = items().length && !_.intersection(_elems, items()).length;\n\n                if (hasObsoleteComponents) {\n                    items.removeAll();\n                }\n            });\n\n            this.elems(_elems);\n\n            return this;\n        },\n\n        /**\n         * Tries to call specified method of a current component,\n         * otherwise delegates attempt to its' children.\n         *\n         * @param {String} target - Name of the method.\n         * @param {...*} parameters - Arguments that will be passed to method.\n         * @returns {*} Result of the method calls.\n         */\n        delegate: function (target) {\n            var args = _.toArray(arguments);\n\n            target = this[target];\n\n            if (_.isFunction(target)) {\n                return target.apply(this, args.slice(1));\n            }\n\n            return this._delegate(args);\n        },\n\n        /**\n         * Calls 'delegate' method of all of it's children components.\n         * @private\n         *\n         * @param {Array} args - An array of arguments to pass to the next delegation call.\n         * @returns {Array} An array of delegation results.\n         */\n        _delegate: function (args) {\n            var result;\n\n            result = this.elems.map(function (elem) {\n                var target;\n\n                if (!_.isFunction(elem.delegate)) {\n                    target = elem[args[0]];\n\n                    if (_.isFunction(target)) {\n                        return target.apply(elem, args.slice(1));\n                    }\n                } else {\n                    return elem.delegate.apply(elem, args);\n                }\n            });\n\n            return _.flatten(result);\n        }\n    });\n});\n","Magento_Ui/js/lib/core/storage/local.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'underscore',\n    'uiRegistry',\n    'mageUtils',\n    'uiEvents'\n], function (_, registry, utils, EventsBus) {\n    'use strict';\n\n    var root = 'appData',\n        localStorage,\n        hasSupport,\n        storage;\n\n    /**\n     * Flag which indicates whether localStorage is supported.\n     */\n    hasSupport = (function () {\n        var key = '_storageSupported';\n\n        try {\n            localStorage = window.localStorage;\n            localStorage.setItem(key, 'true');\n\n            if (localStorage.getItem(key) === 'true') {\n                localStorage.removeItem(key);\n\n                return true;\n            }\n\n            return false;\n        } catch (e) {\n            return false;\n        }\n    })();\n\n    if (!hasSupport) {\n        localStorage = {\n            _data: {},\n\n            /**\n             * Sets value of the specified item.\n             *\n             * @param {String} key - Key of the property.\n             * @param {*} value - Properties' value.\n             */\n            setItem: function (key, value) {\n                this._data[key] = value + '';\n            },\n\n            /**\n             * Retrieves specified item.\n             *\n             * @param {String} key - Key of the property to be retrieved.\n             */\n            getItem: function (key) {\n                return this._data[key];\n            },\n\n            /**\n             * Removes specified item.\n             *\n             * @param {String} key - Key of the property to be removed.\n             */\n            removeItem: function (key) {\n                delete this._data[key];\n            },\n\n            /**\n             * Removes all items.\n             */\n            clear: function () {\n                this._data = {};\n            }\n        };\n    }\n\n    /**\n     * Extracts and parses data stored in localStorage by the\n     * key specified in 'root' variable.\n     *\n     * @returns {Object}\n     */\n    function getRoot() {\n        var data = localStorage.getItem(root),\n            result = {};\n\n        if (!_.isNull(data) && typeof data != 'undefined') {\n            result = JSON.parse(data);\n        }\n\n        return result;\n    }\n\n    /**\n     * Writes provided data to the localStorage.\n     *\n     * @param {*} data - Data to be stored.\n     */\n    function setRoot(data) {\n        localStorage.setItem(root, JSON.stringify(data));\n    }\n\n    /**\n     * Provides methods to work with a localStorage\n     * as a single nested structure.\n     */\n    storage = _.extend({\n\n        /**\n         * Retrieves value of the specified property.\n         *\n         * @param {String} path - Path to the property.\n         *\n         * @example Retrieving data.\n         *      localStorage =>\n         *          'appData' => '\n         *              \"one\": {\"two\": \"three\"}\n         *          '\n         *      storage.get('one.two')\n         *      => \"three\"\n         *\n         *      storage.get('one')\n         *      => {\"two\": \"three\"}\n         */\n        get: function (path) {\n            var data = getRoot();\n\n            return utils.nested(data, path);\n        },\n\n        /**\n         * Sets specified data to the localStorage.\n         *\n         * @param {String} path - Path of the property.\n         * @param {*} value - Value of the property.\n         *\n         * @example Setting data.\n         *      storage.set('one.two', 'four');\n         *      => localStorage =>\n         *          'appData' => '\n         *              \"one\": {\"two\": \"four\"}\n         *          '\n         */\n        set: function (path, value) {\n            var data = getRoot();\n\n            utils.nested(data, path, value);\n\n            setRoot(data);\n        },\n\n        /**\n         * Removes specified data from the localStorage.\n         *\n         * @param {String} path - Path to the property that should be removed.\n         *\n         * @example Removing data.\n         *      storage.remove('one.two', 'four');\n         *      => localStorage =>\n         *          'appData' => '\n         *              \"one\": {}\n         *          '\n         */\n        remove: function (path) {\n            var data = getRoot();\n\n            utils.nestedRemove(data, path);\n\n            setRoot(data);\n        }\n    }, EventsBus);\n\n    registry.set('localStorage', storage);\n\n    return storage;\n});\n","Magento_Ui/js/lib/core/element/element.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\n/**\n * @api\n */\ndefine([\n    'ko',\n    'underscore',\n    'mageUtils',\n    'uiRegistry',\n    'uiEvents',\n    'uiClass',\n    './links',\n    '../storage/local'\n], function (ko, _, utils, registry, Events, Class, links) {\n    'use strict';\n\n    var Element;\n\n    /**\n     * Creates observable property using knockouts'\n     * 'observableArray' or 'observable' methods,\n     * depending on a type of 'value' parameter.\n     *\n     * @param {Object} obj - Object to whom property belongs.\n     * @param {String} key - Key of the property.\n     * @param {*} value - Initial value.\n     */\n    function observable(obj, key, value) {\n        var method = Array.isArray(value) ? 'observableArray' : 'observable';\n\n        if (_.isFunction(obj[key]) && !ko.isObservable(obj[key])) {\n            return;\n        }\n\n        if (ko.isObservable(value)) {\n            value = value();\n        }\n\n        ko.isObservable(obj[key]) ?\n            obj[key](value) :\n            obj[key] = ko[method](value);\n    }\n\n    /**\n     * Creates observable property using 'track' method.\n     *\n     * @param {Object} obj - Object to whom property belongs.\n     * @param {String} key - Key of the property.\n     * @param {*} value - Initial value.\n     */\n    function accessor(obj, key, value) {\n        if (_.isFunction(obj[key]) || ko.isObservable(obj[key])) {\n            return;\n        }\n\n        obj[key] = value;\n\n        if (!ko.es5.isTracked(obj, key)) {\n            ko.track(obj, [key]);\n        }\n    }\n\n    Element = _.extend({\n        defaults: {\n            _requested: {},\n            containers: [],\n            exports: {},\n            imports: {},\n            links: {},\n            listens: {},\n            name: '',\n            ns: '${ $.name.split(\".\")[0] }',\n            provider: '',\n            registerNodes: true,\n            source: null,\n            statefull: {},\n            template: '',\n            tracks: {},\n            storageConfig: {\n                provider: 'localStorage',\n                namespace: '${ $.name }',\n                path: '${ $.storageConfig.provider }:${ $.storageConfig.namespace }'\n            },\n            maps: {\n                imports: {},\n                exports: {}\n            },\n            modules: {\n                storage: '${ $.storageConfig.provider }'\n            }\n        },\n\n        /**\n         * Initializes model instance.\n         *\n         * @returns {Element} Chainable.\n         */\n        initialize: function () {\n            this._super()\n                .initObservable()\n                .initModules()\n                .initStatefull()\n                .initLinks()\n                .initUnique();\n\n            return this;\n        },\n\n        /**\n         * Initializes observable properties.\n         *\n         * @returns {Element} Chainable.\n         */\n        initObservable: function () {\n            _.each(this.tracks, function (enabled, key) {\n                if (enabled) {\n                    this.track(key);\n                }\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Parses 'modules' object and creates\n         * async wrappers for specified components.\n         *\n         * @returns {Element} Chainable.\n         */\n        initModules: function () {\n            _.each(this.modules, function (name, property) {\n                if (name) {\n                    this[property] = this.requestModule(name);\n                }\n            }, this);\n\n            if (!_.isFunction(this.source)) {\n                this.source = registry.get(this.provider);\n            }\n\n            return this;\n        },\n\n        /**\n         * Called when current element was injected to another component.\n         *\n         * @param {Object} parent - Instance of a 'parent' component.\n         * @returns {Collection} Chainable.\n         */\n        initContainer: function (parent) {\n            this.containers.push(parent);\n\n            return this;\n        },\n\n        /**\n         * Initializes statefull properties\n         * based on the keys of 'statefull' object.\n         *\n         * @returns {Element} Chainable.\n         */\n        initStatefull: function () {\n            _.each(this.statefull, function (path, key) {\n                if (path) {\n                    this.setStatefull(key, path);\n                }\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Initializes links between properties.\n         *\n         * @returns {Element} Chainbale.\n         */\n        initLinks: function () {\n            return this.setListeners(this.listens)\n                       .setLinks(this.links, 'imports')\n                       .setLinks(this.links, 'exports')\n                       .setLinks(this.exports, 'exports')\n                       .setLinks(this.imports, 'imports');\n        },\n\n        /**\n         * Initializes listeners of the unique property.\n         *\n         * @returns {Element} Chainable.\n         */\n        initUnique: function () {\n            var update = this.onUniqueUpdate.bind(this),\n                uniqueNs = this.uniqueNs;\n\n            this.hasUnique = this.uniqueProp && uniqueNs;\n\n            if (this.hasUnique) {\n                this.source.on(uniqueNs, update, this.name);\n            }\n\n            return this;\n        },\n\n        /**\n         * Makes specified property to be stored automatically.\n         *\n         * @param {String} key - Name of the property\n         *      that will be stored.\n         * @param {String} [path=key] - Path to the property in storage.\n         * @returns {Element} Chainable.\n         */\n        setStatefull: function (key, path) {\n            var link = {};\n\n            path        = !_.isString(path) || !path ? key : path;\n            link[key]   = this.storageConfig.path + '.' + path;\n\n            this.setLinks(link, 'imports')\n                .setLinks(link, 'exports');\n\n            return this;\n        },\n\n        /**\n         * Updates property specified in uniqueNs\n         * if elements' unique property is set to 'true'.\n         *\n         * @returns {Element} Chainable.\n         */\n        setUnique: function () {\n            var property = this.uniqueProp;\n\n            if (this[property]()) {\n                this.source.set(this.uniqueNs, this.name);\n            }\n\n            return this;\n        },\n\n        /**\n         * Creates 'async' wrapper for the specified component\n         * using uiRegistry 'async' method and caches it\n         * in a '_requested' components  object.\n         *\n         * @param {String} name - Name of requested component.\n         * @returns {Function} Async module wrapper.\n         */\n        requestModule: function (name) {\n            var requested = this._requested;\n\n            if (!requested[name]) {\n                requested[name] = registry.async(name);\n            }\n\n            return requested[name];\n        },\n\n        /**\n         * Returns path to elements' template.\n         *\n         * @returns {String}\n         */\n        getTemplate: function () {\n            return this.template;\n        },\n\n        /**\n         * Checks if template was specified for an element.\n         *\n         * @returns {Boolean}\n         */\n        hasTemplate: function () {\n            return !!this.template;\n        },\n\n        /**\n         * Returns value of the nested property.\n         *\n         * @param {String} path - Path to the property.\n         * @returns {*} Value of the property.\n         */\n        get: function (path) {\n            return utils.nested(this, path);\n        },\n\n        /**\n         * Sets provided value as a value of the specified nested property.\n         * Triggers changes notifications, if value has mutated.\n         *\n         * @param {String} path - Path to property.\n         * @param {*} value - New value of the property.\n         * @returns {Element} Chainable.\n         */\n        set: function (path, value) {\n            var data = this.get(path),\n                diffs;\n\n            diffs = !_.isFunction(data) && !this.isTracked(path) ?\n                utils.compare(data, value, path) :\n                false;\n\n            utils.nested(this, path, value);\n\n            if (diffs) {\n                this._notifyChanges(diffs);\n            }\n\n            return this;\n        },\n\n        /**\n         * Removes nested property from the object.\n         *\n         * @param {String} path - Path to the property.\n         * @returns {Element} Chainable.\n         */\n        remove: function (path) {\n            var data = utils.nested(this, path),\n                diffs;\n\n            if (_.isUndefined(data) || _.isFunction(data)) {\n                return this;\n            }\n\n            diffs = utils.compare(data, undefined, path);\n\n            utils.nestedRemove(this, path);\n\n            this._notifyChanges(diffs);\n\n            return this;\n        },\n\n        /**\n         * Creates observable properties for the current object.\n         *\n         * If 'useTrack' flag is set to 'true' then each property will be\n         * created with a ES5 get/set accessor descriptors, instead of\n         * making them an observable functions.\n         * See 'knockout-es5' library for more information.\n         *\n         * @param {Boolean} [useAccessors=false] - Whether to create an\n         *      observable function or to use property accesessors.\n         * @param {(Object|String|Array)} properties - List of observable properties.\n         * @returns {Element} Chainable.\n         *\n         * @example Sample declaration and equivalent knockout methods.\n         *      this.key = 'value';\n         *      this.array = ['value'];\n         *\n         *      this.observe(['key', 'array']);\n         *      =>\n         *          this.key = ko.observable('value');\n         *          this.array = ko.observableArray(['value']);\n         *\n         * @example Another syntaxes of the previous example.\n         *      this.observe({\n         *          key: 'value',\n         *          array: ['value']\n         *      });\n         */\n        observe: function (useAccessors, properties) {\n            var model = this,\n                trackMethod;\n\n            if (typeof useAccessors !== 'boolean') {\n                properties   = useAccessors;\n                useAccessors = false;\n            }\n\n            trackMethod = useAccessors ? accessor : observable;\n\n            if (_.isString(properties)) {\n                properties = properties.split(' ');\n            }\n\n            if (Array.isArray(properties)) {\n                properties.forEach(function (key) {\n                    trackMethod(model, key, model[key]);\n                });\n            } else if (typeof properties === 'object') {\n                _.each(properties, function (value, key) {\n                    trackMethod(model, key, value);\n                });\n            }\n\n            return this;\n        },\n\n        /**\n         * Delegates call to 'observe' method but\n         * with a predefined 'useAccessors' flag.\n         *\n         * @param {(String|Array|Object)} properties - List of observable properties.\n         * @returns {Element} Chainable.\n         */\n        track: function (properties) {\n            this.observe(true, properties);\n\n            return this;\n        },\n\n        /**\n         * Checks if specified property is tracked.\n         *\n         * @param {String} property - Property to be checked.\n         * @returns {Boolean}\n         */\n        isTracked: function (property) {\n            return ko.es5.isTracked(this, property);\n        },\n\n        /**\n         * Invokes subscribers for the provided changes.\n         *\n         * @param {Object} diffs - Object with changes descriptions.\n         * @returns {Element} Chainable.\n         */\n        _notifyChanges: function (diffs) {\n            diffs.changes.forEach(function (change) {\n                this.trigger(change.path, change.value, change);\n            }, this);\n\n            _.each(diffs.containers, function (changes, name) {\n                var value = utils.nested(this, name);\n\n                this.trigger(name, value, changes);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Extracts all stored data and sets it to element.\n         *\n         * @returns {Element} Chainable.\n         */\n        restore: function () {\n            var ns = this.storageConfig.namespace,\n                storage = this.storage();\n\n            if (storage) {\n                utils.extend(this, storage.get(ns));\n            }\n\n            return this;\n        },\n\n        /**\n         * Stores value of the specified property in components' storage module.\n         *\n         * @param {String} property\n         * @param {*} [data=this[property]]\n         * @returns {Element} Chainable.\n         */\n        store: function (property, data) {\n            var ns = this.storageConfig.namespace,\n                path = utils.fullPath(ns, property);\n\n            if (arguments.length < 2) {\n                data = this.get(property);\n            }\n\n            this.storage('set', path, data);\n\n            return this;\n        },\n\n        /**\n         * Extracts specified property from storage.\n         *\n         * @param {String} [property] - Name of the property\n         *      to be extracted. If not specified then all of the\n         *      stored will be returned.\n         * @returns {*}\n         */\n        getStored: function (property) {\n            var ns = this.storageConfig.namespace,\n                path = utils.fullPath(ns, property),\n                storage = this.storage(),\n                data;\n\n            if (storage) {\n                data = storage.get(path);\n            }\n\n            return data;\n        },\n\n        /**\n         * Removes stored property.\n         *\n         * @param {String} property - Property to be removed from storage.\n         * @returns {Element} Chainable.\n         */\n        removeStored: function (property) {\n            var ns = this.storageConfig.namespace,\n                path = utils.fullPath(ns, property);\n\n            this.storage('remove', path);\n\n            return this;\n        },\n\n        /**\n         * Destroys current instance along with all of its' children.\n         * @param {Boolean} skipUpdate - skip collection update when element to be destroyed.\n         */\n        destroy: function (skipUpdate) {\n            this._dropHandlers()\n                ._clearRefs(skipUpdate);\n        },\n\n        /**\n         * Removes events listeners.\n         * @private\n         *\n         * @returns {Element} Chainable.\n         */\n        _dropHandlers: function () {\n            this.off();\n\n            if (_.isFunction(this.source)) {\n                this.source().off(this.name);\n            } else if (this.source) {\n                this.source.off(this.name);\n            }\n\n            return this;\n        },\n\n        /**\n         * Removes all references to current instance and\n         * calls 'destroy' method on all of its' children.\n         * @private\n         * @param {Boolean} skipUpdate - skip collection update when element to be destroyed.\n         *\n         * @returns {Element} Chainable.\n         */\n        _clearRefs: function (skipUpdate) {\n            registry.remove(this.name);\n\n            this.containers.forEach(function (parent) {\n                parent.removeChild(this, skipUpdate);\n            }, this);\n\n            return this;\n        },\n\n        /**\n         * Overrides 'EventsBus.trigger' method to implement events bubbling.\n         *\n         * @param {...*} arguments - Any number of arguments that should be passed to the events' handler.\n         * @returns {Boolean} False if event bubbling was canceled.\n         */\n        bubble: function () {\n            var args = _.toArray(arguments),\n                bubble = this.trigger.apply(this, args),\n                result;\n\n            if (!bubble) {\n                return false;\n            }\n\n            this.containers.forEach(function (parent) {\n                result = parent.bubble.apply(parent, args);\n\n                if (result === false) {\n                    bubble = false;\n                }\n            });\n\n            return !!bubble;\n        },\n\n        /**\n         * Callback which fires when property under uniqueNs has changed.\n         */\n        onUniqueUpdate: function (name) {\n            var active = name === this.name,\n                property = this.uniqueProp;\n\n            this[property](active);\n        },\n\n        /**\n         * Clean data form data source.\n         *\n         * @returns {Element}\n         */\n        cleanData: function () {\n            if (this.source && this.source.componentType === 'dataSource') {\n                if (this.elems) {\n                    _.each(this.elems(), function (val) {\n                        val.cleanData();\n                    });\n                } else {\n                    this.source.remove(this.dataScope);\n                }\n            }\n\n            return this;\n        },\n\n        /**\n         * Fallback data.\n         */\n        cacheData: function () {\n            this.cachedComponent = utils.copy(this);\n        },\n\n        /**\n         * Update configuration in component.\n         *\n         * @param {*} oldValue\n         * @param {*} newValue\n         * @param {String} path - path to value.\n         * @returns {Element}\n         */\n        updateConfig: function (oldValue, newValue, path) {\n            var names = path.split('.'),\n                index = _.lastIndexOf(names, 'config') + 1;\n\n            names = names.splice(index, names.length - index).join('.');\n            this.set(names, newValue);\n\n            return this;\n        }\n    }, Events, links);\n\n    return Class.extend(Element);\n});\n","Magento_Ui/js/lib/core/element/links.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'mageUtils',\n    'uiRegistry'\n], function (ko, _, utils, registry) {\n    'use strict';\n\n    /**\n     * Parse provided data.\n     *\n     * @param {String} placeholder\n     * @param {String} data\n     * @param {String} direction\n     * @returns {Boolean|Object}\n     */\n    function parseData(placeholder, data, direction) {\n        if (typeof data !== 'string') {\n            return false;\n        }\n\n        data = data.split(':');\n\n        if (!data[0]) {\n            return false;\n        }\n\n        if (!data[1]) {\n            data[1] = data[0];\n            data[0] = placeholder;\n        }\n\n        return {\n            target: data[0],\n            property: data[1],\n            direction: direction\n        };\n    }\n\n    /**\n     * Check if value not empty.\n     *\n     * @param {*} value\n     * @returns {Boolean}\n     */\n    function notEmpty(value) {\n        return typeof value !== 'undefined' && value != null;\n    }\n\n    /**\n     * Update value for linked component.\n     *\n     * @param {Object} data\n     * @param {Object} owner\n     * @param {Object} target\n     * @param {*} value\n     */\n    function updateValue(data, owner, target, value) {\n        var component = target.component,\n            property = target.property,\n            linked = data.linked;\n\n        if (data.mute) {\n            return;\n        }\n\n        if (linked) {\n            linked.mute = true;\n        }\n\n        if (owner.component !== target.component) {\n            value = data.inversionValue ? !utils.copy(value) : utils.copy(value);\n        }\n\n        component.set(property, value, owner);\n\n        if (property === 'disabled' && value) {\n            component.set('validate', value, owner);\n        }\n\n        if (linked) {\n            linked.mute = false;\n        }\n    }\n\n    /**\n     * Get value form owner component property.\n     *\n     * @param {Object} owner\n     * @returns {*}\n     */\n    function getValue(owner) {\n        var component = owner.component,\n            property = owner.property;\n\n        return component.get(property);\n    }\n\n    /**\n     * Format provided params to object.\n     *\n     * @param {String} ownerComponent\n     * @param {String} targetComponent\n     * @param {String} ownerProp\n     * @param {String} targetProp\n     * @param {String} direction\n     * @returns {Object}\n     */\n    function form(ownerComponent, targetComponent, ownerProp, targetProp, direction) {\n        var result,\n            tmp;\n\n        result = {\n            owner: {\n                component: ownerComponent,\n                property: ownerProp\n            },\n            target: {\n                component: targetComponent,\n                property: targetProp\n            }\n        };\n\n        if (direction === 'exports') {\n            tmp = result.owner;\n            result.owner = result.target;\n            result.target = tmp;\n        }\n\n        return result;\n    }\n\n    /**\n     * Set data to linked property.\n     *\n     * @param {Object} map\n     * @param {Object} data\n     */\n    function setLinked(map, data) {\n        var match;\n\n        if (!map) {\n            return;\n        }\n\n        match = _.findWhere(map, {\n            linked: false,\n            target: data.target,\n            property: data.property\n        });\n\n        if (match) {\n            match.linked = data;\n            data.linked = match;\n        }\n    }\n\n    /**\n     * Set data by direction.\n     *\n     * @param {Object} maps\n     * @param {String} property\n     * @param {Object} data\n     */\n    function setData(maps, property, data) {\n        var direction   = data.direction,\n            map         = maps[direction];\n\n        data.linked = false;\n\n        (map[property] = map[property] || []).push(data);\n\n        direction = direction === 'imports' ? 'exports' : 'imports';\n\n        setLinked(maps[direction][property], data);\n    }\n\n    /**\n     * Set links for components.\n     *\n     * @param {String} target\n     * @param {String} owner\n     * @param {Object} data\n     * @param {String} property\n     * @param {Boolean} immediate\n     */\n    function setLink(target, owner, data, property, immediate) {\n        var direction = data.direction,\n            formated = form(target, owner, data.property, property, direction),\n            callback,\n            value;\n\n        owner = formated.owner;\n        target = formated.target;\n\n        callback = updateValue.bind(null, data, owner, target);\n\n        owner.component.on(owner.property, callback, target.component.name);\n\n        if (immediate) {\n            value = getValue(owner);\n\n            if (notEmpty(value)) {\n                updateValue(data, owner, target, value);\n            }\n        }\n    }\n\n    /**\n     * Transfer data between components.\n     *\n     * @param {Object} owner\n     * @param {Object} data\n     */\n    function transfer(owner, data) {\n        var args = _.toArray(arguments);\n\n        if (data.target.substr(0, 1) === '!') {\n            data.target = data.target.substr(1);\n            data.inversionValue = true;\n        }\n\n        if (owner.name === data.target) {\n            args.unshift(owner);\n\n            setLink.apply(null, args);\n        } else {\n            registry.get(data.target, function (target) {\n                args.unshift(target);\n\n                setLink.apply(null, args);\n            });\n        }\n    }\n\n    return {\n        /**\n         * Assign listeners.\n         *\n         * @param {Object} listeners\n         * @returns {Object} Chainable\n         */\n        setListeners: function (listeners) {\n            var owner = this,\n                data;\n\n            _.each(listeners, function (callbacks, sources) {\n                sources = sources.split(' ');\n                callbacks = callbacks.split(' ');\n\n                sources.forEach(function (target) {\n                    callbacks.forEach(function (callback) {//eslint-disable-line max-nested-callbacks\n                        data = parseData(owner.name, target, 'imports');\n\n                        if (data) {\n                            setData(owner.maps, callback, data);\n                            transfer(owner, data, callback);\n                        }\n                    });\n                });\n            });\n\n            return this;\n        },\n\n        /**\n         * Set links in provided direction.\n         *\n         * @param {Object} links\n         * @param {String} direction\n         * @returns {Object} Chainable\n         */\n        setLinks: function (links, direction) {\n            var owner = this,\n                property,\n                data;\n\n            for (property in links) {\n                if (links.hasOwnProperty(property)) {\n                    data = parseData(owner.name, links[property], direction);\n\n                    if (data) {//eslint-disable-line max-depth\n                        setData(owner.maps, property, data);\n                        transfer(owner, data, property, true);\n                    }\n                }\n            }\n\n            return this;\n        }\n    };\n});\n","Magento_Ui/js/lib/knockout/bootstrap.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/** Loads all available knockout bindings, sets custom template engine, initializes knockout on page */\n\ndefine([\n    'ko',\n    './template/engine',\n    'knockoutjs/knockout-es5',\n    './bindings/bootstrap',\n    './extender/observable_array',\n    './extender/bound-nodes',\n    'domReady!'\n], function (ko, templateEngine) {\n    'use strict';\n\n    ko.uid = 0;\n\n    ko.setTemplateEngine(templateEngine);\n    ko.applyBindings();\n});\n","Magento_Ui/js/lib/knockout/extender/observable_array.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore'\n], function (ko, _) {\n    'use strict';\n\n    /**\n     * Iterator function.\n     *\n     * @param {String} callback\n     * @param {Array} args\n     * @param {Object} elem\n     * @returns {*}\n     */\n    function iterator(callback, args, elem) {\n        callback = elem[callback];\n\n        if (_.isFunction(callback)) {\n            return callback.apply(elem, args);\n        }\n\n        return callback;\n    }\n\n    /**\n     * Wrapper function.\n     *\n     * @param {String} method\n     * @returns {Function}\n     */\n    function wrapper(method) {\n        return function (iteratee) {\n            var callback = iteratee,\n                elems = this(),\n                args = _.toArray(arguments);\n\n            if (_.isString(iteratee)) {\n                callback = iterator.bind(null, iteratee, args.slice(1));\n\n                args.unshift(callback);\n            }\n\n            args.unshift(elems);\n\n            return _[method].apply(_, args);\n        };\n    }\n\n    _.extend(ko.observableArray.fn, {\n        each: wrapper('each'),\n\n        map: wrapper('map'),\n\n        filter: wrapper('filter'),\n\n        some: wrapper('some'),\n\n        every: wrapper('every'),\n\n        groupBy: wrapper('groupBy'),\n\n        sortBy: wrapper('sortBy'),\n\n        /**\n         * Wrapper for underscore findWhere function.\n         *\n         * @param {Object} properties\n         * @return {Object}\n         */\n        findWhere: function (properties) {\n            return _.findWhere(this(), properties);\n        },\n\n        /**\n         * Wrapper for underscore contains function.\n         *\n         * @param {*} value\n         * @return {Boolean}\n         */\n        contains: function (value) {\n            return _.contains(this(), value);\n        },\n\n        /**\n         * Inverse contains call.\n         *\n         * @return {Boolean}\n         */\n        hasNo: function () {\n            return !this.contains.apply(this, arguments);\n        },\n\n        /**\n         * Getter for length property.\n         *\n         * @return {Number}\n         */\n        getLength: function () {\n            return this().length;\n        },\n\n        /**\n         * Create object with keys that gets from each object property.\n         *\n         * @return {Object}\n         */\n        indexBy: function (key) {\n            return _.indexBy(this(), key);\n        },\n\n        /**\n         * Returns a copy of the array with all instances of the values removed.\n         *\n         * @return {Array}\n         */\n        without: function () {\n            var args = Array.prototype.slice.call(arguments);\n\n            args.unshift(this());\n\n            return _.without.apply(_, args);\n        },\n\n        /**\n         * Returns the first element of an array.\n         *\n         * @return {*}\n         */\n        first: function () {\n            return _.first(this());\n        },\n\n        /**\n         * Returns the last element of an array\n         *\n         * @return {*}\n         */\n        last: function () {\n            return _.last(this());\n        },\n\n        /**\n         * Iterate and pick provided properties.\n         *\n         * @return {Array}\n         */\n        pluck: function () {\n            var args = Array.prototype.slice.call(arguments);\n\n            args.unshift(this());\n\n            return _.pluck.apply(_, args);\n        }\n    });\n});\n","Magento_Ui/js/lib/knockout/extender/bound-nodes.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'mage/utils/wrapper',\n    'uiEvents'\n], function (ko, _, wrapper, Events) {\n    'use strict';\n\n    var nodesMap = new WeakMap();\n\n    /**\n     * Returns a array of nodes associated with a specified model.\n     *\n     * @param {Object} model\n     * @returns {Undefined|Array}\n     */\n    function getBounded(model) {\n        return nodesMap.get(model);\n    }\n\n    /**\n     * Removes specified node to models' associations list, if it's\n     * a root node (node is not a descendant of any previously added nodes).\n     * Triggers 'addNode' event.\n     *\n     * @param {Object} model\n     * @param {HTMLElement} node\n     */\n    function addBounded(model, node) {\n        var nodes = getBounded(model),\n            isRoot;\n\n        if (!nodes) {\n            nodesMap.set(model, [node]);\n\n            Events.trigger.call(model, 'addNode', node);\n\n            return;\n        }\n\n        isRoot = nodes.every(function (bounded) {\n            return !bounded.contains(node);\n        });\n\n        if (isRoot) {\n            nodes.push(node);\n\n            Events.trigger.call(model, 'addNode', node);\n        }\n    }\n\n    /**\n     * Removes specified node from models' associations list.\n     * Triggers 'removeNode' event.\n     *\n     * @param {Object} model\n     * @param {HTMLElement} node\n     */\n    function removeBounded(model, node) {\n        var nodes = getBounded(model),\n            index;\n\n        if (!nodes) {\n            return;\n        }\n\n        index = nodes.indexOf(node);\n\n        if (~index) {\n            nodes.splice(index, 0);\n\n            Events.trigger.call(model, 'removeNode', node);\n        }\n\n        if (!nodes.length) {\n            nodesMap.delete(model);\n        }\n    }\n\n    /**\n     * Returns node's first sibling of 'element' type within the common component scope\n     *\n     * @param {HTMLElement} node\n     * @param {*} data\n     * @returns {HTMLElement}\n     */\n    function getElement(node, data) {\n        var elem;\n\n        while (node.nextElementSibling) {\n            node = node.nextElementSibling;\n\n            if (node.nodeType === 1 && ko.dataFor(node) === data) {\n                elem = node;\n                break;\n            }\n        }\n\n        return elem;\n    }\n\n    wrapper.extend(ko, {\n\n        /**\n         * Extends knockouts' 'applyBindings'\n         * to track nodes associated with model.\n         *\n         * @param {Function} orig - Original 'applyBindings' method.\n         * @param {Object} ctx\n         * @param {HTMLElement} node - Original 'applyBindings' method.\n         */\n        applyBindings: function (orig, ctx, node) {\n            var result = orig(),\n                data = ctx && (ctx.$data || ctx);\n\n            if (node && node.nodeType === 8) {\n                node = getElement(node, data);\n            }\n\n            if (!node || node.nodeType !== 1) {\n                return result;\n            }\n\n            if (data && data.registerNodes) {\n                addBounded(data, node);\n            }\n\n            return result;\n        },\n\n        /**\n         * Extends knockouts' cleanNode\n         * to track nodes associated with model.\n         *\n         * @param {Function} orig - Original 'cleanNode' method.\n         * @param {HTMLElement} node - Original 'cleanNode' method.\n         */\n        cleanNode: function (orig, node) {\n            var result = orig(),\n                data;\n\n            if (node.nodeType !== 1) {\n                return result;\n            }\n\n            data = ko.dataFor(node);\n\n            if (data && data.registerNodes) {\n                removeBounded(data, node);\n            }\n\n            return result;\n        }\n    });\n\n    return {\n\n        /**\n         * Returns root nodes associated with a model. If callback is provided,\n         * will iterate through all of the present nodes triggering callback\n         * for each of it. Also it will subscribe to the 'addNode' event.\n         *\n         * @param {Object} model\n         * @param {Function} [callback]\n         * @returns {Array|Undefined}\n         */\n        get: function (model, callback) {\n            var nodes = getBounded(model) || [];\n\n            if (!_.isFunction(callback)) {\n                return nodes;\n            }\n\n            nodes.forEach(function (node) {\n                callback(node);\n            });\n\n            this.add.apply(this, arguments);\n        },\n\n        /**\n         * Subscribes to adding of nodes associated with a model.\n         *\n         * @param {Object} model\n         */\n        add: function (model) {\n            var args = _.toArray(arguments).slice(1);\n\n            args.unshift('addNode');\n\n            Events.on.apply(model, args);\n        },\n\n        /**\n         * Subscribes to removal of nodes associated with a model.\n         *\n         * @param {Object} model\n         */\n        remove: function (model) {\n            var args = _.toArray(arguments).slice(1);\n\n            args.unshift('removeNode');\n\n            Events.on.apply(model, args);\n        },\n\n        /**\n         * Removes subscriptions from the model.\n         *\n         * @param {Object} model\n         */\n        off: function (model) {\n            var args = _.toArray(arguments).slice(1);\n\n            Events.off.apply(model, args);\n        }\n    };\n});\n","Magento_Ui/js/lib/knockout/bindings/simple-checked.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    '../template/renderer'\n], function (ko, renderer) {\n    'use strict';\n\n    ko.bindingHandlers.simpleChecked = {\n        'after': ['attr'],\n\n        /**\n         * Implements same functionality as a standard 'simpleChecked' binding,\n         * but with a difference that it wont' change values array if\n         * value of DOM element changes.\n         */\n        init: function (element, valueAccessor) {\n            var isCheckbox = element.type === 'checkbox',\n                isRadio = element.type === 'radio',\n                updateView,\n                updateModel;\n\n            if (!isCheckbox && !isRadio) {\n                return;\n            }\n\n            /**\n             * Updates checked observable\n             */\n            updateModel = function () {\n                var  modelValue = ko.dependencyDetection.ignore(valueAccessor),\n                    isChecked = element.checked;\n\n                if (ko.computedContext.isInitial()) {\n                    return;\n                }\n\n                if (modelValue.peek() === isChecked) {\n                    return;\n                }\n\n                if (isRadio && !isChecked) {\n                    return;\n                }\n\n                modelValue(isChecked);\n            };\n\n            /**\n             * Updates checkbox state\n             */\n            updateView = function () {\n                var modelValue = ko.utils.unwrapObservable(valueAccessor());\n\n                element.checked = !!modelValue;\n            };\n\n            ko.utils.registerEventHandler(element, 'change', updateModel);\n\n            ko.computed(updateModel, null, {\n                disposeWhenNodeIsRemoved: element\n            });\n            ko.computed(updateView, null, {\n                disposeWhenNodeIsRemoved: element\n            });\n        }\n    };\n\n    ko.expressionRewriting._twoWayBindings.simpleChecked = true;\n\n    renderer.addAttribute('simpleChecked');\n    renderer.addAttribute('simple-checked', {\n        binding: 'simpleChecked'\n    });\n});\n","Magento_Ui/js/lib/knockout/bindings/tooltip.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'ko',\n    'underscore',\n    'mage/template',\n    'text!ui/template/tooltip/tooltip.html',\n    '../template/renderer'\n], function ($, ko, _, template, tooltipTmpl, renderer) {\n    'use strict';\n\n    var tooltip,\n        defaults,\n        positions,\n        transformProp,\n        checkedPositions = {},\n        iterator = 0,\n        previousTooltip,\n        tooltipData,\n        positionData = {},\n        tooltipsCollection = {},\n        isTouchDevice = (function () {\n            return 'ontouchstart' in document.documentElement;\n        })(),\n        CLICK_EVENT = (function () {\n            return isTouchDevice ? 'touchstart' : 'click';\n        })();\n\n    defaults = {\n        tooltipWrapper: '[data-tooltip=tooltip-wrapper]',\n        tooltipContentBlock: 'data-tooltip-content',\n        closeButtonClass: 'action-close',\n        tailClass: 'data-tooltip-tail',\n        action: 'hover',\n        delay: 300,\n        track: false,\n        step: 20,\n        position: 'top',\n        closeButton: false,\n        showed: false,\n        strict: true,\n        center: false,\n        closeOnScroll: true\n    };\n\n    tooltipData = {\n        tooltipClasses: '',\n        trigger: false,\n        timeout: 0,\n        element: false,\n        event: false,\n        targetElement: {},\n        showed: false,\n        currentID: 0\n    };\n\n    /**\n     * Polyfill for css transform\n     */\n    transformProp = (function () {\n        var style = document.createElement('div').style,\n            base = 'Transform',\n            vendors = ['webkit', 'moz', 'ms', 'o'],\n            vi = vendors.length,\n            property;\n\n        if (typeof style.transform !== 'undefined') {\n            return 'transform';\n        }\n\n        while (vi--) {\n            property = vendors[vi] + base;\n\n            if (typeof style[property] !== 'undefined') {\n                return property;\n            }\n        }\n    })();\n\n    positions = {\n\n        /*eslint max-depth: [0, 0]*/\n\n        map: {\n            horizontal: {\n                s: 'w',\n                p: 'left'\n            },\n            vertical: {\n                s: 'h',\n                p: 'top'\n            }\n        },\n\n        /**\n         * Wrapper function to get tooltip data (position, className, etc)\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        top: function (s) {\n            return positions._topLeftChecker(s, positions.map, 'vertical', '_bottom', 'top', 'right');\n        },\n\n        /**\n         * Wrapper function to get tooltip data (position, className, etc)\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        left: function (s) {\n            return positions._topLeftChecker(s, positions.map, 'horizontal', '_right', 'left', 'top');\n        },\n\n        /**\n         * Wrapper function to get tooltip data (position, className, etc)\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        bottom: function (s) {\n            return positions._bottomRightChecker(s, positions.map, 'vertical', '_top', 'bottom', 'left');\n        },\n\n        /**\n         * Wrapper function to get tooltip data (position, className, etc)\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        right: function (s) {\n            return positions._bottomRightChecker(s, positions.map, 'horizontal', '_left', 'right', 'bottom');\n        },\n\n        /**\n         * Check can tooltip setted on current position or not. If can't setted - delegate call.\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} map - mapping for get direction positions\n         * @param {String} direction - vertical or horizontal\n         * @param {String} className - class whats should be setted to tooltip\n         * @param {String} side - parent method name\n         * @param {String} delegate - method name if tooltip can't be setted in current position\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        _topLeftChecker: function (s, map, direction, className, side, delegate) {\n            var result = {\n                    position: {}\n                },\n                config = tooltip.getTooltip(tooltipData.currentID),\n                startPosition = !config.strict ? s.eventPosition : s.elementPosition,\n                changedDirection;\n\n            checkedPositions[side] = true;\n\n            if (\n                startPosition[map[direction].p] - s.tooltipSize[map[direction].s] - config.step >\n                s.scrollPosition[map[direction].p]\n            ) {\n                result.position[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] -\n                    config.step;\n                result.className = className;\n                result.side = side;\n                changedDirection = direction === 'vertical' ? 'horizontal' : 'vertical';\n                result = positions._normalize(s, result, config, delegate, map, changedDirection);\n            } else if (!checkedPositions[delegate]) {\n                result = positions[delegate].apply(null, arguments);\n            } else {\n                result = positions.positionCenter(s, result);\n            }\n\n            return result;\n        },\n\n        /**\n         * Check can tooltip setted on current position or not. If can't setted - delegate call.\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} map - mapping for get direction positions\n         * @param {String} direction - vertical or horizontal\n         * @param {String} className - class whats should be setted to tooltip\n         * @param {String} side - parent method name\n         * @param {String} delegate - method name if tooltip can't be setted in current position\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        _bottomRightChecker: function (s, map, direction, className, side, delegate) {\n            var result = {\n                    position: {}\n                },\n                config = tooltip.getTooltip(tooltipData.currentID),\n                startPosition = !config.strict ? s.eventPosition : {\n                    top: s.elementPosition.top + s.elementSize.h,\n                    left: s.elementPosition.left + s.elementSize.w\n                },\n                changedDirection;\n\n            checkedPositions[side] = true;\n\n            if (\n                startPosition[map[direction].p] + s.tooltipSize[map[direction].s] + config.step <\n                s.scrollPosition[map[direction].p] + s.windowSize[map[direction].s]\n            ) {\n                result.position[map[direction].p] = startPosition[map[direction].p] + config.step;\n                result.className = className;\n                result.side = side;\n                changedDirection = direction === 'vertical' ? 'horizontal' : 'vertical';\n                result = positions._normalize(s, result, config, delegate, map, changedDirection);\n            } else if (!checkedPositions[delegate]) {\n                result = positions[delegate].apply(null, arguments);\n            } else {\n                result = positions.positionCenter(s, result);\n            }\n\n            return result;\n        },\n\n        /**\n         * Centered tooltip if tooltip does not fit in window\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} data - current data (position, className, etc)\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        positionCenter: function (s, data) {\n            data = positions._positionCenter(s, data, 'horizontal', positions.map);\n            data = positions._positionCenter(s, data, 'vertical', positions.map);\n\n            return data;\n        },\n\n        /**\n         * Centered tooltip side\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} data - current data (position, className, etc)\n         * @param {String} direction - vertical or horizontal\n         * @param {Object} map - mapping for get direction positions\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        _positionCenter: function (s, data, direction, map) {\n            if (s.tooltipSize[map[direction].s] < s.windowSize[map[direction].s]) {\n                data.position[map[direction].p] = (s.windowSize[map[direction].s] -\n                    s.tooltipSize[map[direction].s]) / 2 + s.scrollPosition[map[direction].p];\n            } else {\n                data.position[map[direction].p] = s.scrollPosition[map[direction].p];\n                data.tooltipSize = {};\n                data.tooltipSize[map[direction].s] = s.windowSize[map[direction].s];\n            }\n\n            return data;\n        },\n\n        /**\n         * Normalize horizontal or vertical position.\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} data - current data (position, className, etc)\n         * @param {Object} config - tooltip config\n         * @param {String} delegate - method name if tooltip can't be setted in current position\n         * @param {Object} map - mapping for get direction positions\n         * @param {String} direction - vertical or horizontal\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        _normalize: function (s, data, config, delegate, map, direction) {\n            var startPosition = !config.center ? s.eventPosition : {\n                    left: s.elementPosition.left + s.elementSize.w / 2,\n                    top: s.elementPosition.top + s.elementSize.h / 2\n                },\n                depResult;\n\n            if (startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2 >\n                s.scrollPosition[map[direction].p] && startPosition[map[direction].p] +\n                s.tooltipSize[map[direction].s] / 2 <\n                s.scrollPosition[map[direction].p] + s.windowSize[map[direction].s]\n            ) {\n                data.position[map[direction].p] = startPosition[map[direction].p] - s.tooltipSize[map[direction].s] / 2;\n            } else {\n\n                /*eslint-disable no-lonely-if*/\n                if (!checkedPositions[delegate]) {\n                    depResult = positions[delegate].apply(null, arguments);\n\n                    if (depResult.hasOwnProperty('className')) {\n                        data = depResult;\n                    } else {\n                        data = positions._normalizeTail(s, data, config, delegate, map, direction, startPosition);\n                    }\n                } else {\n                    data = positions._normalizeTail(s, data, config, delegate, map, direction, startPosition);\n                }\n            }\n\n            return data;\n        },\n\n        /**\n         * Calc tail position.\n         *\n         * @param {Object} s - object with sizes and positions elements\n         * @param {Object} data - current data (position, className, etc)\n         * @param {Object} config - tooltip config\n         * @param {String} delegate - method name if tooltip can't be setted in current position\n         * @param {Object} map - mapping for get direction positions\n         * @param {String} direction - vertical or horizontal\n         * @param {Object} startPosition - start position\n         * @returns {Object} tooltip data (position, className, etc)\n         */\n        _normalizeTail: function (s, data, config, delegate, map, direction, startPosition) {\n            data.tail = {};\n\n            if (s.tooltipSize[map[direction].s] < s.windowSize[map[direction].s]) {\n\n                if (\n                    startPosition[map[direction].p] >\n                    s.windowSize[map[direction].s] / 2 + s.scrollPosition[map[direction].p]\n                ) {\n                    data.position[map[direction].p] = s.windowSize[map[direction].s] +\n                        s.scrollPosition[map[direction].p] - s.tooltipSize[map[direction].s];\n                    data.tail[map[direction].p] = startPosition[map[direction].p] -\n                        s.tooltipSize[map[direction].s] / 2 - data.position[map[direction].p];\n                } else {\n                    data.position[map[direction].p] = s.scrollPosition[map[direction].p];\n                    data.tail[map[direction].p] = startPosition[map[direction].p] -\n                        s.tooltipSize[map[direction].s] / 2 - data.position[map[direction].p];\n                }\n            } else {\n                data.position[map[direction].p] = s.scrollPosition[map[direction].p];\n                data.tail[map[direction].p] = s.eventPosition[map[direction].p] - s.windowSize[map[direction].s] / 2;\n                data.tooltipSize = {};\n                data.tooltipSize[map[direction].s] = s.windowSize[map[direction].s];\n            }\n\n            return data;\n        }\n    };\n\n    tooltip = {\n\n        /**\n         * Set new tooltip to tooltipCollection, save config, and add unic id\n         *\n         * @param {Object} config - tooltip config\n         * @returns {String} tooltip id\n         */\n        setTooltip: function (config) {\n            var property = 'id-' + iterator;\n\n            tooltipsCollection[property] = config;\n            iterator++;\n\n            return property;\n        },\n\n        /**\n         * Get tooltip config by id\n         *\n         * @param {String} id - tooltip id\n         * @returns {Object} tooltip config\n         */\n        getTooltip: function (id) {\n            return tooltipsCollection[id];\n        },\n\n        /**\n         * Set content to current tooltip\n         *\n         * @param {Object} tooltipElement - tooltip element\n         * @param {Object} viewModel - tooltip view model\n         * @param {String} id - tooltip id\n         * @param {Object} bindingCtx - tooltip context\n         * @param {Object} event - action event\n         */\n        setContent: function (tooltipElement, viewModel, id, bindingCtx, event) {\n            var html = $(tooltipElement).html(),\n                config = tooltip.getTooltip(id),\n                body = $('body');\n\n            tooltipData.currentID = id;\n            tooltipData.trigger = $(event.currentTarget);\n            tooltip.setTargetData(event);\n            body.on('mousemove.setTargetData', tooltip.setTargetData);\n            tooltip.clearTimeout(id);\n\n            tooltipData.timeout = _.delay(function () {\n                body.off('mousemove.setTargetData', tooltip.setTargetData);\n\n                if (tooltipData.trigger[0] === tooltipData.targetElement) {\n                    tooltip.destroy(id);\n                    event.stopPropagation();\n                    tooltipElement = tooltip.createTooltip(id);\n                    tooltipElement.find('.' + defaults.tooltipContentBlock).append(html);\n                    tooltipElement.applyBindings(bindingCtx);\n                    tooltip.setHandlers(id);\n                    tooltip.setPosition(tooltipElement, id);\n                    previousTooltip = id;\n                }\n\n            }, config.delay);\n        },\n\n        /**\n         * Set position to current tooltip\n         *\n         * @param {Object} tooltipElement - tooltip element\n         * @param {String} id - tooltip id\n         */\n        setPosition: function (tooltipElement, id) {\n            var config = tooltip.getTooltip(id);\n\n            tooltip.sizeData = {\n                windowSize: {\n                    h: $(window).outerHeight(),\n                    w: $(window).outerWidth()\n                },\n                scrollPosition: {\n                    top: $(window).scrollTop(),\n                    left: $(window).scrollLeft()\n                },\n                tooltipSize: {\n                    h: tooltipElement.outerHeight(),\n                    w: tooltipElement.outerWidth()\n                },\n                elementSize: {\n                    h: tooltipData.trigger.outerHeight(),\n                    w: tooltipData.trigger.outerWidth()\n                },\n                elementPosition: tooltipData.trigger.offset(),\n                eventPosition: this.getEventPosition(tooltipData.event)\n            };\n\n            _.extend(positionData, positions[config.position](tooltip.sizeData));\n            tooltipElement.css(positionData.position);\n            tooltipElement.addClass(positionData.className);\n            tooltip._setTooltipSize(positionData, tooltipElement);\n            tooltip._setTailPosition(positionData, tooltipElement);\n            checkedPositions = {};\n        },\n\n        /**\n         * Check position data and change tooltip size if needs\n         *\n         * @param {Object} data - position data\n         * @param {Object} tooltipElement - tooltip element\n         */\n        _setTooltipSize: function (data, tooltipElement) {\n            if (data.tooltipSize) {\n                data.tooltipSize.w ?\n                    tooltipElement.css('width', data.tooltipSize.w) :\n                    tooltipElement.css('height', data.tooltipSize.h);\n            }\n        },\n\n        /**\n         * Check position data and set position to tail\n         *\n         * @param {Object} data - position data\n         * @param {Object} tooltipElement - tooltip element\n         */\n        _setTailPosition: function (data, tooltipElement) {\n            var tail,\n                tailMargin;\n\n            if (data.tail) {\n                tail = tooltipElement.find('.' + defaults.tailClass);\n\n                if (data.tail.left) {\n                    tailMargin = parseInt(tail.css('margin-left'), 10);\n                    tail.css('margin-left', tailMargin + data.tail.left);\n                } else {\n                    tailMargin = parseInt(tail.css('margin-top'), 10);\n                    tail.css('margin-top', tailMargin + data.tail.top);\n                }\n            }\n        },\n\n        /**\n         * Resolves position for tooltip\n         *\n         * @param {Object} event\n         * @returns {Object}\n         */\n        getEventPosition: function (event) {\n            var position = {\n                left: event.originalEvent && event.originalEvent.pageX || 0,\n                top: event.originalEvent && event.originalEvent.pageY || 0\n            };\n\n            if (position.left === 0 && position.top === 0) {\n                _.extend(position, event.target.getBoundingClientRect());\n            }\n\n            return position;\n        },\n\n        /**\n         * Close tooltip if action happened outside handler and tooltip element\n         *\n         * @param {String} id - tooltip id\n         * @param {Object} event - action event\n         */\n        outerClick: function (id, event) {\n            var tooltipElement = $(event.target).parents(defaults.tooltipWrapper)[0],\n                isTrigger = event.target === tooltipData.trigger[0] || $.contains(tooltipData.trigger[0], event.target);\n\n            if (tooltipData.showed && tooltipElement !== tooltipData.element[0] && !isTrigger) {\n                tooltip.destroy(id);\n            }\n        },\n\n        /**\n         * Parse keydown event and if event trigger is escape key - close tooltip\n         *\n         * @param {Object} event - action event\n         */\n        keydownHandler: function (event) {\n            if (tooltipData.showed && event.keyCode === 27) {\n                tooltip.destroy(tooltipData.currentID);\n            }\n        },\n\n        /**\n         * Change tooltip position when track is enabled\n         *\n         * @param {Object} event - current event\n         */\n        track: function (event) {\n            var inequality = {},\n                map = positions.map,\n                translate = {\n                    left: 'translateX',\n                    top: 'translateY'\n                },\n                eventPosition = {\n                    left: event.pageX,\n                    top: event.pageY\n                },\n                tooltipSize = {\n                    w: tooltipData.element.outerWidth(),\n                    h: tooltipData.element.outerHeight()\n                },\n                direction = positionData.side === 'bottom' || positionData.side === 'top' ? 'horizontal' : 'vertical';\n\n            inequality[map[direction].p] = eventPosition[map[direction].p] - (positionData.position[map[direction].p] +\n                tooltipSize[map[direction].s] / 2);\n\n            if (positionData.position[map[direction].p] + inequality[map[direction].p] +\n                tooltip.sizeData.tooltipSize[map[direction].s] >\n                tooltip.sizeData.windowSize[map[direction].s] + tooltip.sizeData.scrollPosition[map[direction].p] ||\n                inequality[map[direction].p] + positionData.position[map[direction].p] <\n                tooltip.sizeData.scrollPosition[map[direction].p]) {\n\n                return false;\n            }\n\n            tooltipData.element[0].style[transformProp] = translate[map[direction].p] +\n                '(' + inequality[map[direction].p] + 'px)';\n        },\n\n        /**\n         * Set handlers to tooltip\n         *\n         * @param {String} id - tooltip id\n         */\n        setHandlers: function (id) {\n            var config = tooltip.getTooltip(id);\n\n            if (config.track) {\n                tooltipData.trigger.on('mousemove.track', tooltip.track);\n            }\n\n            if (config.action === 'click') {\n                $(window).on(CLICK_EVENT + '.outerClick', tooltip.outerClick.bind(null, id));\n            }\n\n            if (config.closeButton) {\n                $('.' + config.closeButtonClass).on('click.closeButton', tooltip.destroy.bind(null, id));\n            }\n\n            if (config.closeOnScroll) {\n                document.addEventListener('scroll', tooltip.destroy, true);\n                $(window).on('scroll.tooltip', tooltip.outerClick.bind(null, id));\n            }\n\n            $(window).on('keydown.tooltip', tooltip.keydownHandler);\n            $(window).on('resize.outerClick', tooltip.outerClick.bind(null, id));\n        },\n\n        /**\n         * Toggle tooltip\n         *\n         * @param {Object} tooltipElement - tooltip element\n         * @param {Object} viewModel - tooltip view model\n         * @param {String} id - tooltip id\n         */\n        toggleTooltip: function (tooltipElement, viewModel, id) {\n            if (previousTooltip === id && tooltipData.showed) {\n                tooltip.destroy(id);\n\n                return false;\n            }\n\n            tooltip.setContent.apply(null, arguments);\n\n            return false;\n        },\n\n        /**\n         * Create tooltip and append to DOM\n         *\n         * @param {String} id - tooltip id\n         * @returns {Object} tooltip element\n         */\n        createTooltip: function (id) {\n            var body = $('body'),\n                config = tooltip.getTooltip(id);\n\n            $(template(tooltipTmpl, {\n                data: config\n            })).appendTo(body);\n\n            tooltipData.showed = true;\n            tooltipData.element = $(config.tooltipWrapper);\n\n            return tooltipData.element;\n        },\n\n        /**\n         * Check action and clean timeout\n         *\n         * @param {String} id - tooltip id\n         */\n        clearTimeout: function (id) {\n            var config = tooltip.getTooltip(id);\n\n            if (config.action === 'hover') {\n                clearTimeout(tooltipData.timeout);\n            }\n        },\n\n        /**\n         * Check previous tooltip\n         */\n        checkPreviousTooltip: function () {\n            if (!tooltipData.timeout) {\n                tooltip.destroy();\n            }\n        },\n\n        /**\n         * Destroy tooltip instance\n         */\n        destroy: function () {\n            if (tooltipData.element) {\n                tooltipData.element.remove();\n                tooltipData.showed = false;\n            }\n\n            positionData = {};\n            tooltipData.timeout = false;\n            tooltip.removeHandlers();\n        },\n\n        /**\n         * Remove tooltip handlers\n         */\n        removeHandlers: function () {\n            $('.' + defaults.closeButtonClass).off('click.closeButton');\n            tooltipData.trigger.off('mousemove.track');\n            document.removeEventListener('scroll', tooltip.destroy, true);\n            $(window).off('scroll.tooltip');\n            $(window).off(CLICK_EVENT + '.outerClick');\n            $(window).off('keydown.tooltip');\n            $(window).off('resize.outerClick');\n        },\n\n        /**\n         * Set target element\n         *\n         * @param {Object} event - current event\n         */\n        setTargetData: function (event) {\n            tooltipData.event = event;\n\n            //TODO: bug chrome v.49; Link to issue https://bugs.chromium.org/p/chromium/issues/detail?id=161464\n            if (event.timeStamp - (tooltipData.timestamp || 0) < 1) {\n                return;\n            }\n\n            if (event.type === 'mousemove') {\n                tooltipData.targetElement = event.target;\n            } else {\n                tooltipData.targetElement = event.currentTarget;\n                tooltipData.timestamp = event.timeStamp;\n            }\n        },\n\n        /**\n         * Merged user config with defaults configuration\n         *\n         * @param {Object} config - user config\n         * @returns {Object} merged config\n         */\n        processingConfig: function (config) {\n            return _.extend({}, defaults, config);\n        }\n    };\n\n    ko.bindingHandlers.tooltip = {\n\n        /**\n         * Initialize tooltip\n         *\n         * @param {Object} elem - tooltip DOM element\n         * @param {Function} valueAccessor - ko observable property, tooltip data\n         * @param {Object} allBindings - all bindings on current element\n         * @param {Object} viewModel - current element viewModel\n         * @param {Object} bindingCtx - current element binding context\n         */\n        init: function (elem, valueAccessor, allBindings, viewModel, bindingCtx) {\n            var config = tooltip.processingConfig(valueAccessor()),\n                $parentScope = config.parentScope ? $(config.parentScope) : $(elem).parent(),\n                tooltipId;\n\n            $(elem).addClass('hidden');\n\n            if (isTouchDevice) {\n                config.action = 'click';\n            }\n            tooltipId = tooltip.setTooltip(config);\n\n            if (config.action === 'hover') {\n                $parentScope.on(\n                    'mouseenter',\n                    config.trigger,\n                    tooltip.setContent.bind(null, elem, viewModel, tooltipId, bindingCtx)\n                );\n                $parentScope.on(\n                    'mouseleave',\n                    config.trigger,\n                    tooltip.checkPreviousTooltip.bind(null, tooltipId)\n                );\n            } else if (config.action === 'click') {\n                $parentScope.on(\n                    'click',\n                    config.trigger,\n                    tooltip.toggleTooltip.bind(null, elem, viewModel, tooltipId, bindingCtx)\n                );\n            }\n\n            return {\n                controlsDescendantBindings: true\n            };\n        }\n    };\n\n    renderer.addAttribute('tooltip');\n});\n","Magento_Ui/js/lib/knockout/bindings/autoselect.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    '../template/renderer'\n], function (ko, $, renderer) {\n    'use strict';\n\n    /**\n     * 'Focus' event handler.\n     *\n     * @param {EventObject} e\n     */\n    function onFocus(e) {\n        e.target.select();\n    }\n\n    ko.bindingHandlers.autoselect = {\n\n        /**\n         * Adds event handler which automatically\n         * selects inputs' element text when field gets focused.\n         */\n        init: function (element, valueAccessor) {\n            var enabled = ko.unwrap(valueAccessor());\n\n            if (enabled !== false) {\n                $(element).on('focus', onFocus);\n            }\n        }\n    };\n\n    renderer.addAttribute('autoselect');\n});\n","Magento_Ui/js/lib/knockout/bindings/optgroup.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'mageUtils'\n    ], function (ko, utils) {\n    'use strict';\n\n    var captionPlaceholder = {},\n        optgroupTmpl = '<optgroup label=\"${ $.label }\"></optgroup>',\n        nbspRe = /&nbsp;/g,\n        optionsText,\n        optionsValue,\n        optionTitle;\n\n    ko.bindingHandlers.optgroup = {\n        /**\n         * @param {*} element\n         */\n        init: function (element) {\n            if (ko.utils.tagNameLower(element) !== 'select') {\n                throw new Error('options binding applies only to SELECT elements');\n            }\n\n            // Remove all existing <option>s.\n            while (element.length > 0) {\n                element.remove(0);\n            }\n        },\n\n        /**\n         * @param {*} element\n         * @param {*} valueAccessor\n         * @param {*} allBindings\n         */\n        update: function (element, valueAccessor, allBindings) {\n            var selectWasPreviouslyEmpty = element.length === 0,\n                previousScrollTop = !selectWasPreviouslyEmpty && element.multiple ? element.scrollTop : null,\n                includeDestroyed = allBindings.get('optionsIncludeDestroyed'),\n                arrayToDomNodeChildrenOptions = {},\n                captionValue,\n                unwrappedArray = ko.utils.unwrapObservable(valueAccessor()),\n                filteredArray,\n                previousSelectedValues,\n                itemUpdate = false,\n                callback = setSelectionCallback,//eslint-disable-line no-use-before-define\n                nestedOptionsLevel = -1;\n\n            optionsText = ko.utils.unwrapObservable(allBindings.get('optionsText')) || 'text';\n            optionsValue = ko.utils.unwrapObservable(allBindings.get('optionsValue')) || 'value';\n            optionTitle = optionsText + 'title';\n\n            if (element.multiple) {\n                previousSelectedValues = ko.utils.arrayMap(\n                    selectedOptions(),//eslint-disable-line no-use-before-define\n                    ko.selectExtensions.readValue\n                );\n            } else {\n                previousSelectedValues = element.selectedIndex >= 0 ?\n                    [ko.selectExtensions.readValue(element.options[element.selectedIndex])] :\n                    [];\n            }\n\n            if (unwrappedArray) {\n                if (typeof unwrappedArray.length === 'undefined') { // Coerce single value into array\n                    unwrappedArray = [unwrappedArray];\n                }\n\n                // Filter out any entries marked as destroyed\n                filteredArray = ko.utils.arrayFilter(unwrappedArray, function (item) {\n                    if (item && !item.label) {\n                        return false;\n                    }\n\n                    return includeDestroyed ||\n                        item === undefined ||\n                        item === null ||\n                        !ko.utils.unwrapObservable(item._destroy);\n                });\n                filteredArray.map(recursivePathBuilder, null);//eslint-disable-line no-use-before-define\n            }\n\n            /**\n             * @param {*} option\n             */\n            arrayToDomNodeChildrenOptions.beforeRemove = function (option) {\n                element.removeChild(option);\n            };\n\n            if (allBindings.has('optionsAfterRender')) {\n\n                /**\n                 * @param {*} arrayEntry\n                 * @param {*} newOptions\n                 */\n                callback = function (arrayEntry, newOptions) {\n                    setSelectionCallback(arrayEntry, newOptions);//eslint-disable-line no-use-before-define\n                    ko.dependencyDetection.ignore(\n                        allBindings.get('optionsAfterRender'),\n                        null,\n                        [newOptions[0],\n                        arrayEntry !== captionPlaceholder ? arrayEntry : undefined]\n                    );\n                };\n            }\n\n            filteredArray = formatOptions(filteredArray);//eslint-disable-line no-use-before-define\n            ko.utils.setDomNodeChildrenFromArrayMapping(\n                element,\n                filteredArray,\n                optionNodeFromArray,//eslint-disable-line no-use-before-define\n                arrayToDomNodeChildrenOptions,\n                callback\n            );\n\n            ko.dependencyDetection.ignore(function () {\n                var selectionChanged;\n\n                if (allBindings.get('valueAllowUnset') && allBindings.has('value')) {\n                    // The model value is authoritative, so make sure its value is the one selected\n                    ko.selectExtensions.writeValue(\n                        element,\n                        ko.utils.unwrapObservable(allBindings.get('value')),\n                        true /* allowUnset */\n                    );\n                } else {\n                    // Determine if the selection has changed as a result of updating the options list\n                    if (element.multiple) {\n                        // For a multiple-select box, compare the new selection count to the previous one\n                        // But if nothing was selected before, the selection can't have changed\n                        selectionChanged = previousSelectedValues.length &&\n                            selectedOptions().length < //eslint-disable-line no-use-before-define\n                            previousSelectedValues.length;\n                    } else {\n                        // For a single-select box, compare the current value to the previous value\n                        // But if nothing was selected before or nothing is selected now,\n                        // just look for a change in selection\n                        selectionChanged = previousSelectedValues.length && element.selectedIndex >= 0 ?\n                            ko.selectExtensions.readValue(element.options[element.selectedIndex]) !==\n                            previousSelectedValues[0] : previousSelectedValues.length || element.selectedIndex >= 0;\n                    }\n\n                    // Ensure consistency between model value and selected option.\n                    // If the dropdown was changed so that selection is no longer the same,\n                    // notify the value or selectedOptions binding.\n                    if (selectionChanged) {\n                        ko.utils.triggerEvent(element, 'change');\n                    }\n                }\n            });\n\n            /*eslint-enable max-len, no-use-before-define*/\n\n            if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20) {\n                element.scrollTop = previousScrollTop;\n            }\n\n            /**\n             * @returns {*}\n             */\n            function selectedOptions() {\n                return ko.utils.arrayFilter(element.options, function (node) {\n                    return node.selected;\n                });\n            }\n\n            /**\n             * @param {*} object\n             * @param {*} predicate\n             * @param {*} defaultValue\n             * @returns {*}\n             */\n            function applyToObject(object, predicate, defaultValue) {\n                var predicateType = typeof predicate;\n\n                if (predicateType === 'function') {   // run it against the data value\n                    return predicate(object);\n                } else if (predicateType === 'string') { // treat it as a property name on the data value\n                    return object[predicate];\n                }\n\n                return defaultValue;\n            }\n\n            /**\n             * @param {*} obj\n             */\n            function recursivePathBuilder(obj) {\n\n                obj[optionTitle] = (this && this[optionTitle] ? this[optionTitle] + '/' : '') + obj[optionsText].trim();\n\n                if (Array.isArray(obj[optionsValue])) {\n                    obj[optionsValue].map(recursivePathBuilder, obj);\n                }\n            }\n\n            /**\n             * @param {Array} arrayEntry\n             * @param {*} oldOptions\n             * @returns {*[]}\n             */\n            function optionNodeFromArray(arrayEntry, oldOptions) {\n                var option;\n\n                if (oldOptions.length) {\n                    previousSelectedValues = oldOptions[0].selected ?\n                        [ko.selectExtensions.readValue(oldOptions[0])] : [];\n                    itemUpdate = true;\n                }\n\n                if (arrayEntry === captionPlaceholder) { // empty value, label === caption\n                    option = element.ownerDocument.createElement('option');\n                    ko.utils.setTextContent(option, allBindings.get('optionsCaption'));\n                    ko.selectExtensions.writeValue(option, undefined);\n                } else if (typeof arrayEntry[optionsValue] === 'undefined') { // empty value === optgroup\n                    if (arrayEntry.__disableTmpl) {\n                        option = '<optgroup label=\"' + arrayEntry[optionsText] + '\"></optgroup>';\n                    } else {\n                        option = utils.template(optgroupTmpl, {\n                            label: arrayEntry[optionsText],\n                            title: arrayEntry[optionsText + 'title']\n                        });\n                    }\n                    option = ko.utils.parseHtmlFragment(option)[0];\n\n                } else {\n                    option = element.ownerDocument.createElement('option');\n                    option.setAttribute('data-title', arrayEntry[optionsText + 'title']);\n                    ko.selectExtensions.writeValue(option, arrayEntry[optionsValue]);\n                    ko.utils.setTextContent(option, arrayEntry[optionsText]);\n                }\n\n                return [option];\n            }\n\n            /**\n             * @param {*} newOptions\n             */\n            function setSelectionCallback(newOptions) {\n                var isSelected;\n\n                // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.\n                // That's why we first added them without selection. Now it's time to set the selection.\n                if (previousSelectedValues.length && newOptions.value) {\n                    isSelected = ko.utils.arrayIndexOf(\n                        previousSelectedValues,\n                        ko.selectExtensions.readValue(newOptions.value)\n                    ) >= 0;\n\n                    ko.utils.setOptionNodeSelectionState(newOptions.value, isSelected);\n\n                    // If this option was changed from being selected during a single-item update, notify the change\n                    if (itemUpdate && !isSelected) {\n                        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, 'change']);\n                    }\n                }\n            }\n\n            /**\n             * @param {*} string\n             * @param {Number} times\n             * @returns {Array}\n             */\n            function strPad(string, times) {\n                return new Array(times + 1).join(string);\n            }\n\n            /**\n             * @param {*} options\n             * @returns {Array}\n             */\n            function formatOptions(options) {\n                var res = [];\n\n                nestedOptionsLevel++;\n\n                if (!nestedOptionsLevel) { // zero level\n                    // If caption is included, add it to the array\n                    if (allBindings.has('optionsCaption')) {\n                        captionValue = ko.utils.unwrapObservable(allBindings.get('optionsCaption'));\n                        // If caption value is null or undefined, don't show a caption\n                        if (//eslint-disable-line max-depth\n                            captionValue !== null &&\n                            captionValue !== undefined &&\n                            captionValue !== false\n                        ) {\n                            res.push(captionPlaceholder);\n                        }\n                    }\n                }\n\n                ko.utils.arrayForEach(options, function (option) {\n                    var value = applyToObject(option, optionsValue, option),\n                        label = applyToObject(option, optionsText, value) || '',\n                        disabled = applyToObject(option, 'disabled', false) || false,\n                        obj = {},\n                        space = '\\u2007\\u2007\\u2007';\n\n                    obj[optionTitle] = applyToObject(option, optionsText + 'title', value);\n\n                    if (disabled) {\n                        obj.disabled = disabled;\n                    }\n\n                    if (option.hasOwnProperty('__disableTmpl')) {\n                        obj.__disableTmpl = option.__disableTmpl;\n                    }\n\n                    label = label.replace(nbspRe, '').trim();\n\n                    if (Array.isArray(value)) {\n                        obj[optionsText] = strPad('&nbsp;', nestedOptionsLevel * 4) + label;\n                        res.push(obj);\n                        res = res.concat(formatOptions(value));\n                    } else {\n                        obj[optionsText] = strPad(space, nestedOptionsLevel * 2) + label;\n                        obj[optionsValue] = value;\n                        res.push(obj);\n                    }\n                });\n                nestedOptionsLevel--;\n\n                return res;\n            }\n        }\n    };\n});\n","Magento_Ui/js/lib/knockout/bindings/collapsible.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    'underscore',\n    '../template/renderer'\n], function (ko, $, _, renderer) {\n    'use strict';\n\n    var collapsible,\n        defaults;\n\n    defaults = {\n        closeOnOuter: true,\n        onTarget: false,\n        openClass: '_active',\n        as: '$collapsible'\n    };\n\n    collapsible = {\n\n        /**\n         * Sets 'opened' property to true.\n         */\n        open: function () {\n            this.opened(true);\n        },\n\n        /**\n         * Sets 'opened' property to false.\n         */\n        close: function () {\n            this.opened(false);\n        },\n\n        /**\n         * Toggles value of the 'opened' property.\n         */\n        toggle: function () {\n            this.opened(!this.opened());\n        }\n    };\n\n    /**\n     * Document click handler which in case if event target is not\n     * a descendant of provided container element, closes collapsible model.\n     *\n     * @param {HTMLElement} container\n     * @param {Object} model\n     * @param {EventObject} e\n     */\n    function onOuterClick(container, model, e) {\n        var target = e.target;\n\n        if (target !== container && !container.contains(target)) {\n            model.close();\n        }\n    }\n\n    /**\n     * Creates 'css' binding which toggles\n     * class specified in 'name' parameter.\n     *\n     * @param {Object} model\n     * @param {String} name\n     * @returns {Object}\n     */\n    function getClassBinding(model, name) {\n        var binding = {};\n\n        binding[name] = model.opened;\n\n        return {\n            css: binding\n        };\n    }\n\n    /**\n     * Prepares configuration for the binding based\n     * on a default properties and provided options.\n     *\n     * @param {Object} [options={}]\n     * @returns {Object} Complete instance configuration.\n     */\n    function buildConfig(options) {\n        if (typeof options !== 'object') {\n            options = {};\n        }\n\n        return _.extend({}, defaults, options);\n    }\n\n    ko.bindingHandlers.collapsible = {\n\n        /**\n         * Initializes 'collapsible' binding.\n         */\n        init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n            var $collapsible = Object.create(collapsible),\n                config = buildConfig(valueAccessor()),\n                outerClick,\n                bindings;\n\n            _.bindAll($collapsible, 'open', 'close', 'toggle');\n\n            $collapsible.opened = ko.observable(!!config.opened);\n\n            bindingCtx[config.as] = $collapsible;\n\n            if (config.closeOnOuter) {\n                outerClick = onOuterClick.bind(null, element, $collapsible);\n\n                $(document).on('click', outerClick);\n\n                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n                    $(document).off('click', outerClick);\n                });\n            }\n\n            if (config.openClass) {\n                bindings = getClassBinding($collapsible, config.openClass);\n\n                ko.applyBindingsToNode(element, bindings, bindingCtx);\n            }\n\n            if (config.onTarget) {\n                $(element).on('click', $collapsible.toggle);\n            }\n\n            if (viewModel && _.isFunction(viewModel.on)) {\n                viewModel.on({\n                    close:          $collapsible.close,\n                    open:           $collapsible.open,\n                    toggleOpened:   $collapsible.toggle\n                });\n            }\n        }\n    };\n\n    ko.bindingHandlers.closeCollapsible = {\n\n        /**\n         * Creates listener for the click event on provided DOM element,\n         * which closes associated with it collapsible model.\n         */\n        init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n            var name = valueAccessor() || defaults.as,\n                $collapsible = bindingCtx[name];\n\n            if ($collapsible) {\n                $(element).on('click', $collapsible.close);\n            }\n        }\n    };\n\n    ko.bindingHandlers.openCollapsible = {\n\n        /**\n         * Creates listener for the click event on provided DOM element,\n         * which opens associated with it collapsible model.\n         */\n        init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n            var name = valueAccessor() || defaults.as,\n                $collapsible = bindingCtx[name];\n\n            if ($collapsible) {\n                $(element).on('click', $collapsible.open);\n            }\n        }\n    };\n\n    ko.bindingHandlers.toggleCollapsible = {\n\n        /**\n         * Creates listener for the click event on provided DOM element,\n         * which toggles associated with it collapsible model.\n         */\n        init: function (element, valueAccessor, allBindings, viewModel, bindingCtx) {\n            var name = valueAccessor() || defaults.as,\n                $collapsible = bindingCtx[name];\n\n            if ($collapsible) {\n                $(element).on('click', $collapsible.toggle);\n            }\n        }\n    };\n\n    renderer\n        .addAttribute('collapsible')\n        .addAttribute('openCollapsible')\n        .addAttribute('closeCollapsible')\n        .addAttribute('toggleCollapsible');\n});\n","Magento_Ui/js/lib/knockout/bindings/i18n.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'ko',\n    'module',\n    '../template/renderer',\n    'mage/translate'\n], function ($, ko, module, renderer) {\n    'use strict';\n\n    var locations = {\n            'legend': 'Caption for the fieldset element',\n            'label': 'Label for an input element.',\n            'button': 'Push button',\n            'a': 'Link label',\n            'b': 'Bold text',\n            'strong': 'Strong emphasized text',\n            'i': 'Italic text',\n            'em': 'Emphasized text',\n            'u': 'Underlined text',\n            'sup': 'Superscript text',\n            'sub': 'Subscript text',\n            'span': 'Span element',\n            'small': 'Smaller text',\n            'big': 'Bigger text',\n            'address': 'Contact information',\n            'blockquote': 'Long quotation',\n            'q': 'Short quotation',\n            'cite': 'Citation',\n            'caption': 'Table caption',\n            'abbr': 'Abbreviated phrase',\n            'acronym': 'An acronym',\n            'var': 'Variable part of a text',\n            'dfn': 'Term',\n            'strike': 'Strikethrough text',\n            'del': 'Deleted text',\n            'ins': 'Inserted text',\n            'h1': 'Heading level 1',\n            'h2': 'Heading level 2',\n            'h3': 'Heading level 3',\n            'h4': 'Heading level 4',\n            'h5': 'Heading level 5',\n            'h6': 'Heading level 6',\n            'center': 'Centered text',\n            'select': 'List options',\n            'img': 'Image',\n            'input': 'Form element'\n        },\n\n        /**\n         * Generates [data-translate] attribute's value\n         * @param {Object} translationData\n         * @param {String} location\n         */\n        composeTranslateAttr = function (translationData, location) {\n            var obj = [{\n                'shown': translationData.shown,\n                'translated': translationData.translated,\n                'original': translationData.original,\n                'location': locations[location] || 'Text'\n            }];\n\n            return JSON.stringify(obj);\n        },\n\n        /**\n         * Sets text for the element\n         * @param {Object} el\n         * @param {String} text\n         */\n        setText = function (el, text) {\n            $(el).text(text);\n        },\n\n        /**\n         * Sets [data-translate] attribute for the element\n         * @param {Object} el - The element which is binded\n         * @param {String} original - The original value of the element\n         */\n        setTranslateProp = function (el, original) {\n            var location = $(el).prop('tagName').toLowerCase(),\n                translated = $.mage.__(original),\n                translationData = {\n                    shown: translated,\n                    translated: translated,\n                    original: original\n                },\n                translateAttr = composeTranslateAttr(translationData, location);\n\n            $(el).attr('data-translate', translateAttr);\n\n            setText(el, translationData.shown);\n        },\n\n        /**\n         * Checks if node represents ko virtual node (nodeType === 8, nodeName === '#comment').\n         *\n         * @param {HTMLElement} node\n         * @returns {Boolean}\n         */\n        isVirtualElement = function (node) {\n            return node.nodeType === 8;\n        },\n\n        /**\n        * Checks if it's real DOM element\n        * in case of virtual element, returns span wrapper\n        * @param {Object} el\n        * @param {bool} isUpdate\n        * @return {Object} el\n        */\n        getRealElement = function (el, isUpdate) {\n            if (isVirtualElement(el)) {\n                if (isUpdate) {\n                    return $(el).next('span');\n                }\n\n                return $('<span></span>').insertAfter(el);\n            }\n\n            return el;\n        },\n\n        /**\n         * execute i18n binding\n         * @param {Object} element\n         * @param {Function} valueAccessor\n         * @param {bool} isUpdate\n         */\n        execute = function (element, valueAccessor, isUpdate) {\n            var original = ko.unwrap(valueAccessor() || ''),\n                el = getRealElement(element, isUpdate),\n                inlineTranslation = (module.config() || {}).inlineTranslation;\n\n            if (inlineTranslation) {\n                setTranslateProp(el, original);\n            } else {\n                setText(el, $.mage.__(original));\n            }\n        };\n\n    /**\n     * i18n binding\n     * @property {Function}  init\n     * @property {Function}  update\n     */\n    ko.bindingHandlers.i18n = {\n\n        /**\n         * init i18n binding\n         * @param {Object} element\n         * @param {Function} valueAccessor\n         */\n        init: function (element, valueAccessor) {\n            execute(element, valueAccessor);\n        },\n\n        /**\n         * update i18n binding\n         * @param {Object} element\n         * @param {Function} valueAccessor\n         */\n        update: function (element, valueAccessor) {\n            execute(element, valueAccessor, true);\n        }\n    };\n\n    ko.virtualElements.allowedBindings.i18n = true;\n\n    renderer\n        .addNode('translate', {\n            binding: 'i18n'\n        })\n        .addAttribute('translate', {\n            binding: 'i18n'\n        });\n});\n","Magento_Ui/js/lib/knockout/bindings/resizable.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    'jquery',\n    'Magento_Ui/js/lib/view/utils/async',\n    'uiRegistry',\n    'underscore',\n    '../template/renderer'\n], function (ko, $, async, registry, _, renderer) {\n    'use strict';\n\n    var sizeOptions = [\n            'minHeight',\n            'maxHeight',\n            'minWidth',\n            'maxWidth'\n        ],\n\n        handles = {\n            height: '.ui-resizable-s, .ui-resizable-n',\n            width: '.ui-resizable-w, .ui-resizable-e'\n        };\n\n    /**\n     * Recalcs visibility of handles, width and height of resizable based on content\n     * @param {HTMLElement} element\n     */\n    function adjustSize(element) {\n        var maxHeight,\n            maxWidth;\n\n        element = $(element);\n        maxHeight = element.resizable('option').maxHeight;\n        maxWidth = element.resizable('option').maxWidth;\n\n        if (maxHeight && element.height() > maxHeight) {\n            element.height(maxHeight + 1);\n            $(handles.height).hide();\n        } else {\n            $(handles.height).show();\n        }\n\n        if (maxWidth && element.width() > maxWidth) {\n            element.width(maxWidth + 1);\n            $(handles.width).hide();\n        } else {\n            $(handles.width).show();\n        }\n    }\n\n    /**\n     * Recalcs allowed min, max width and height based on configured selectors\n     * @param {Object} sizeConstraints\n     * @param {String} componentName\n     * @param {HTMLElement} element\n     * @param {Boolean} hasWidthUpdate\n     */\n    function recalcAllowedSize(sizeConstraints, componentName, element, hasWidthUpdate) {\n        var size;\n\n        element = $(element);\n\n        if (!element.data('resizable')) {\n            return;\n        }\n\n        if (!hasWidthUpdate) {\n            element.css('width', 'auto');\n        }\n\n        _.each(sizeConstraints, function (selector, key) {\n            async.async({\n                component: componentName,\n                selector: selector\n            }, function (elem) {\n                size = key.indexOf('Height') !== -1 ? $(elem).outerHeight(true) : $(elem).outerWidth(true);\n\n                if (element.data('resizable')) {\n                    element.resizable('option', key, size + 1);\n                }\n            });\n        }, this);\n\n        adjustSize(element);\n    }\n\n    /**\n     * Preprocess config to separate options,\n     * which must be processed further before applying\n     *\n     * @param {Object} config\n     * @param {Object} viewModel\n     * @param {*} element\n     * @return {Object} config\n     */\n    function processConfig(config, viewModel, element) {\n        var sizeConstraint,\n            sizeConstraints = {},\n            recalc,\n            hasWidthUpdate;\n\n        if (_.isEmpty(config)) {\n            return {};\n        }\n        _.each(sizeOptions, function (key) {\n            sizeConstraint = config[key];\n\n            if (sizeConstraint && !_.isNumber(sizeConstraint)) {\n                sizeConstraints[key] = sizeConstraint;\n                delete config[key];\n            }\n        });\n        hasWidthUpdate =  _.some(sizeConstraints, function (value, key) {\n            return key.indexOf('Width') !== -1;\n        });\n\n        recalc = recalcAllowedSize.bind(null, sizeConstraints, viewModel.name, element, hasWidthUpdate);\n        config.start = recalc;\n        $(window).on('resize.resizable', recalc);\n        registry.get(viewModel.provider).on('reloaded', recalc);\n\n        return config;\n    }\n\n    ko.bindingHandlers.resizable = {\n\n        /**\n         * Binding init callback.\n         *\n         * @param {*} element\n         * @param {Function} valueAccessor\n         * @param {Function} allBindings\n         * @param {Object} viewModel\n         */\n        init: function (element, valueAccessor, allBindings, viewModel) {\n            var config = processConfig(valueAccessor(), viewModel, element);\n\n            require(['jquery-ui-modules/resizable'], function () {\n                if ($.fn.resizable) {\n                    $(element).resizable(config);\n                }\n            });\n        }\n    };\n\n    renderer.addAttribute('resizable');\n});\n","Magento_Ui/js/lib/knockout/bindings/mage-init.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'ko',\n    'underscore',\n    'mage/apply/main'\n], function (ko, _, mage) {\n    'use strict';\n\n    ko.bindingHandlers.mageInit = {\n        /**\n         * Initializes components assigned to HTML elements.\n         *\n         * @param {HTMLElement} el\n         * @param {Function} valueAccessor\n         */\n        init: function (el, valueAccessor) {\n            var data = valueAccessor();\n\n            _.each(data, function (config, component) {\n                mage.applyFor(el, config, component);\n            });\n        }\n    };\n});\n","Magento_Ui/js/lib/knockout/bindings/staticChecked.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    '../template/renderer'\n], function (ko, renderer) {\n    'use strict';\n\n    ko.bindingHandlers.staticChecked = {\n        'after': ['value', 'attr'],\n\n        /**\n         * Implements same functionality as a standard 'checked' binding,\n         * but with a difference that it wont' change values array if\n         * value of DOM element changes.\n         */\n        init: function (element, valueAccessor, allBindings) {\n            var isCheckbox = element.type === 'checkbox',\n                isRadio = element.type === 'radio',\n                isValueArray,\n                oldElemValue,\n                useCheckedValue,\n                checkedValue,\n                updateModel,\n                updateView;\n\n            if (!isCheckbox && !isRadio) {\n                return;\n            }\n\n            checkedValue = ko.pureComputed(function () {\n                if (allBindings.has('checkedValue')) {\n                    return ko.utils.unwrapObservable(allBindings.get('checkedValue'));\n                } else if (allBindings.has('value')) {\n                    return ko.utils.unwrapObservable(allBindings.get('value'));\n                }\n\n                return element.value;\n            });\n\n            isValueArray = isCheckbox && ko.utils.unwrapObservable(valueAccessor()) instanceof Array;\n            oldElemValue = isValueArray ? checkedValue() : undefined;\n            useCheckedValue = isRadio || isValueArray;\n\n            /**\n             * Updates values array if it's necessary.\n             */\n            updateModel = function () {\n                var isChecked = element.checked,\n                    elemValue = useCheckedValue ? checkedValue() : isChecked,\n                    modelValue;\n\n                if (ko.computedContext.isInitial()) {\n                    return;\n                }\n\n                if (isRadio && !isChecked) {\n                    return;\n                }\n\n                modelValue = ko.dependencyDetection.ignore(valueAccessor);\n\n                if (isValueArray) {\n                    if (oldElemValue !== elemValue) {\n                        oldElemValue = elemValue;\n                    } else {\n                        ko.utils.addOrRemoveItem(modelValue, elemValue, isChecked);\n                    }\n                } else {\n                    ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);\n                }\n            };\n\n            /**\n             * Updates checkbox state.\n             */\n            updateView = function () {\n                var modelValue = ko.utils.unwrapObservable(valueAccessor());\n\n                if (isValueArray) {\n                    element.checked = ko.utils.arrayIndexOf(modelValue, checkedValue()) >= 0;\n                } else if (isCheckbox) {\n                    element.checked = modelValue;\n                } else {\n                    element.checked = checkedValue() === modelValue;\n                }\n            };\n\n            ko.computed(updateModel, null, {\n                disposeWhenNodeIsRemoved: element\n            });\n\n            ko.utils.registerEventHandler(element, 'click', updateModel);\n\n            ko.computed(updateView, null, {\n                disposeWhenNodeIsRemoved: element\n            });\n        }\n    };\n\n    ko.expressionRewriting._twoWayBindings.staticChecked = true;\n\n    renderer.addAttribute('staticChecked');\n});\n","Magento_Ui/js/lib/knockout/bindings/after-render.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    '../template/renderer'\n], function (ko, renderer) {\n    'use strict';\n\n    ko.bindingHandlers.afterRender = {\n\n        /**\n         * Binding init callback.\n         */\n        init: function (element, valueAccessor, allBindings, viewModel) {\n            var callback = valueAccessor();\n\n            if (typeof callback === 'function') {\n                callback.call(viewModel, element, viewModel);\n            }\n        }\n    };\n\n    renderer.addAttribute('afterRender');\n});\n","Magento_Ui/js/lib/knockout/bindings/fadeVisible.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n\ndefine([\n    'jquery',\n    'ko'\n], function ($, ko) {\n    'use strict';\n\n    ko.bindingHandlers.fadeVisible = {\n        /**\n         * Initially set the element to be instantly visible/hidden depending on the value.\n         *\n         * @param {HTMLElement} element\n         * @param {Function} valueAccessor\n         */\n        init: function (element, valueAccessor) {\n            var value = valueAccessor();\n\n            // Use \"unwrapObservable\" so we can handle values that may or may not be observable\n            $(element).toggle(ko.unwrap(value));\n        },\n\n        /**\n         * Whenever the value subsequently changes, slowly fade the element in or out.\n         *\n         * @param {HTMLElement} element\n         * @param {Function} valueAccessor\n         */\n        update: function (element, valueAccessor) {\n            var value = valueAccessor();\n\n            ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut();\n        }\n    };\n});\n","Magento_Ui/js/lib/knockout/bindings/bootstrap.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine(function (require) {\n    'use strict';\n\n    var renderer = require('../template/renderer');\n\n    renderer.addAttribute('repeat', renderer.handlers.wrapAttribute);\n\n    renderer.addAttribute('outerfasteach', {\n        binding: 'fastForEach',\n        handler: renderer.handlers.wrapAttribute\n    });\n\n    renderer\n        .addNode('repeat')\n        .addNode('fastForEach');\n\n    return {\n        resizable:      require('./resizable'),\n        i18n:           require('./i18n'),\n        scope:          require('./scope'),\n        range:          require('./range'),\n        mageInit:       require('./mage-init'),\n        keyboard:       require('./keyboard'),\n        optgroup:       require('./optgroup'),\n        afterRender:     require('./after-render'),\n        autoselect:     require('./autoselect'),\n        datepicker:     require('./datepicker'),\n        outerClick:     require('./outer_click'),\n        fadeVisible:    require('./fadeVisible'),\n        collapsible:    require('./collapsible'),\n        staticChecked:  require('./staticChecked'),\n        simpleChecked:  require('./simple-checked'),\n        bindHtml:       require('./bind-html'),\n        tooltip:        require('./tooltip'),\n        repeat:         require('knockoutjs/knockout-repeat'),\n        fastForEach:    require('knockoutjs/knockout-fast-foreach'),\n        colorPicker:    require('./color-picker')\n    };\n});\n","Magento_Ui/js/lib/knockout/bindings/outer_click.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\n/** Creates outerClick binding and registers in to ko.bindingHandlers object */\ndefine([\n    'ko',\n    'jquery',\n    'underscore',\n    '../template/renderer'\n], function (ko, $, _, renderer) {\n    'use strict';\n\n    var defaults = {\n        onlyIfVisible: true\n    };\n\n    /**\n     * Checks if element sis visible.\n     *\n     * @param {Element} el\n     * @returns {Boolean}\n     */\n    function isVisible(el) {\n        var style = window.getComputedStyle(el),\n            visibility = {\n                display: 'none',\n                visibility: 'hidden',\n                opacity: '0'\n            },\n            visible = true;\n\n        _.each(visibility, function (val, key) {\n            if (style[key] === val) {\n                visible = false;\n            }\n        });\n\n        return visible;\n    }\n\n    /**\n     * Document click handler which in case if event target is not\n     * a descendant of provided container element,\n     * invokes specified in configuration callback.\n     *\n     * @param {HTMLElement} container\n     * @param {Object} config\n     * @param {EventObject} e\n     */\n    function onOuterClick(container, config, e) {\n        var target = e.target,\n            callback = config.callback;\n\n        if (container === target || container.contains(target)) {\n            return;\n        }\n\n        if (config.onlyIfVisible) {\n            if (!_.isNull(container.offsetParent) && isVisible(container)) {\n                callback();\n            }\n        } else {\n            callback();\n        }\n    }\n\n    /**\n     * Prepares configuration for the binding based\n     * on a default properties and provided options.\n     *\n     * @param {(Object|Function)} [options={}]\n     * @returns {Object}\n     */\n    function buildConfig(options) {\n        var config = {};\n\n        if (_.isFunction(options)) {\n            options = {\n                callback: options\n            };\n        } else if (!_.isObject(options)) {\n            options = {};\n        }\n\n        return _.extend(config, defaults, options);\n    }\n\n    ko.bindingHandlers.outerClick = {\n\n        /**\n         * Initializes outer click binding.\n         */\n        init: function (element, valueAccessor) {\n            var config = buildConfig(valueAccessor()),\n                outerClick = onOuterClick.bind(null, element, config),\n                isTouchDevice = typeof document.ontouchstart !== 'undefined';\n\n            if (isTouchDevice) {\n                $(document).on('touchstart', outerClick);\n\n                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n                    $(document).off('touchstart', outerClick);\n                });\n            } else {\n                $(document).on('click', outerClick);\n\n                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {\n                    $(document).off('click', outerClick);\n                });\n            }\n        }\n    };\n\n    renderer.addAttribute('outerClick');\n});\n","Magento_Ui/js/lib/knockout/bindings/keyboard.js":"/**\n * Copyright \u00a9 Magento, Inc. All rights reserved.\n * See COPYING.txt for license details.\n */\ndefine([\n    'ko',\n    '../template/renderer'\n], function (ko, renderer) {\n    'use strict';\n\n    ko.bindingHandlers.keyboard = {\n\n        /**\n         * Attaches keypress handlers to element\n         * @param {HTMLElement} el - Element, that binding is applied to\n         * @param {Function} valueAccessor - Function that returns value, passed to binding\n         * @param  {Object} allBindings - all bindings object\n         * @param  {Object} viewModel - reference to viewmodel\n         */\n        init: function (el, valueAccessor, allBindings, viewModel) {\n            var map = valueAccessor();\n\n            ko.utils.registerEventHandler(el, 'keyup', function (e) {\n                var callback = map[e.keyCode];\n\n                if (callback) {\n                    return callback.call(viewModel, e);\n                }\n            });\n        }\n    };\n\n    renderer.addAttribute('keyboard');\n});\n"}
}});

Spamworldpro Mini