From 0433b54cefedcf02e078e91e13d55440db21d19d Mon Sep 17 00:00:00 2001 From: Lennart Pegel Date: Sun, 25 Sep 2022 23:42:59 +0200 Subject: [PATCH] build mod23 --- build/output/inline-macros-plugin.log | 22 +- build/output/knockout-latest.debug.js | 233 +++++++++++----------- build/output/knockout-latest.debug.js.map | 2 +- build/output/knockout-latest.esm.js | 4 +- build/output/knockout-latest.js | 4 +- package.json | 2 +- 6 files changed, 132 insertions(+), 135 deletions(-) diff --git a/build/output/inline-macros-plugin.log b/build/output/inline-macros-plugin.log index 149aa7e..2a74fdb 100644 --- a/build/output/inline-macros-plugin.log +++ b/build/output/inline-macros-plugin.log @@ -1,6 +1,6 @@ Running Rollup inline-macros plugin -for Knockout JavaScript library v3.5.1-mod22-esnext +for Knockout JavaScript library v3.5.1-mod23-esnext ------- src/binding/bindingAttributeSyntax.js -------- @@ -14,7 +14,7 @@ Found local macro: "_ensureNodeHasDomData" [bindingAttributeSyntax.js:39] Found local macro: "_getOrAddBindingInfoInDomData" -[bindingAttributeSyntax.js:552] +[bindingAttributeSyntax.js:549] Found local macro: "_getBindingContext" (MULTI-LINE-EXPRESSION) [bindingAttributeSyntax.js:188] @@ -57,42 +57,42 @@ Inlined: "_getOrAddBindingInfoInDomData" OLD: bindingInfo = _getOrAddBindingInfoInDomData(nodeDomData); NEW: bindingInfo = (nodeDomData[BINDING_INFO_DOM_DATA_KEY] || (nodeDomData[BINDING_INFO_DOM_DATA_KEY] = {})); -[bindingAttributeSyntax.js:399] +[bindingAttributeSyntax.js:363] Inlined: "_ensureNodeHasDomData" OLD: let nodeDomData = _ensureNodeHasDomData(node), NEW: let nodeDomData = (node[DOM_DATASTORE_PROP] || (node[DOM_DATASTORE_PROP] = {})), -[bindingAttributeSyntax.js:400] +[bindingAttributeSyntax.js:364] Inlined: "_getOrAddBindingInfoInDomData" OLD: bindingInfo = _getOrAddBindingInfoInDomData(nodeDomData); NEW: bindingInfo = (nodeDomData[BINDING_INFO_DOM_DATA_KEY] || (nodeDomData[BINDING_INFO_DOM_DATA_KEY] = {})); -[bindingAttributeSyntax.js:557] +[bindingAttributeSyntax.js:554] Inlined: "_getBindingContext" OLD: return _applyBindingsToNodeInternal(node, bindings, _getBindingContext(viewModelOrBindingContext, undefined)); NEW: return _applyBindingsToNodeInternal(node, bindings, ( (viewModelOrBindingContext && viewModelOrBindingContext[IS_BINDING_CONTEXT_INSTANCE]) ? viewModelOrBindingContext : new KoBindingContext(viewModelOrBindingContext, undefined, undefined, undefined))); -[bindingAttributeSyntax.js:561] +[bindingAttributeSyntax.js:558] Inlined: "_getBindingContext" OLD: let context = _getBindingContext(viewModelOrBindingContext, undefined), NEW: let context = ( (viewModelOrBindingContext && viewModelOrBindingContext[IS_BINDING_CONTEXT_INSTANCE]) ? viewModelOrBindingContext : new KoBindingContext(viewModelOrBindingContext, undefined, undefined, undefined)), -[bindingAttributeSyntax.js:579] +[bindingAttributeSyntax.js:576] Inlined: "_getBindingContext" OLD: _applyBindingsToDescendantsInternal(_getBindingContext(viewModelOrBindingContext, undefined), rootNode); NEW: _applyBindingsToDescendantsInternal(( (viewModelOrBindingContext && viewModelOrBindingContext[IS_BINDING_CONTEXT_INSTANCE]) ? viewModelOrBindingContext : new KoBindingContext(viewModelOrBindingContext, undefined, undefined, undefined)), rootNode); -[bindingAttributeSyntax.js:592] +[bindingAttributeSyntax.js:589] Inlined: "_getBindingContext" OLD: _applyBindingsToNodeAndDescendantsInternal(_getBindingContext(viewModelOrBindingContext, extendContextCallback), rootNode); NEW: _applyBindingsToNodeAndDescendantsInternal(( (viewModelOrBindingContext && viewModelOrBindingContext[IS_BINDING_CONTEXT_INSTANCE]) ? viewModelOrBindingContext : new KoBindingContext(viewModelOrBindingContext, undefined, undefined, extendContextCallback)), rootNode); -[bindingAttributeSyntax.js:598] +[bindingAttributeSyntax.js:595] Inlined: "_getBindingInfoForNode" OLD: let bindingInfo = node && _getBindingInfoForNode(node); NEW: let bindingInfo = node && (node[DOM_DATASTORE_PROP] && node[DOM_DATASTORE_PROP][BINDING_INFO_DOM_DATA_KEY]); -[bindingAttributeSyntax.js:605] +[bindingAttributeSyntax.js:602] Inlined: "_getBindingInfoForNode" OLD: let bindingInfo = node && (node.nodeType === 1 || node.nodeType === 8) && _getBindingInfoForNode(node), NEW: let bindingInfo = node && (node.nodeType === 1 || node.nodeType === 8) && (node[DOM_DATASTORE_PROP] && node[DOM_DATASTORE_PROP][BINDING_INFO_DOM_DATA_KEY]), @@ -688,7 +688,7 @@ Local macros inlining summary: 4x _getBindingInfoForNode - [src/binding/bindingAttributeSyntax.js:37] 4x _ensureNodeHasDomData - [src/binding/bindingAttributeSyntax.js:38] 3x _getOrAddBindingInfoInDomData - [src/binding/bindingAttributeSyntax.js:39] - 4x _getBindingContext - [src/binding/bindingAttributeSyntax.js:552] + 4x _getBindingContext - [src/binding/bindingAttributeSyntax.js:549] 2x virtualNodeBindingValue - [src/binding/bindingProvider.js:7] 2x _getBindingsString - [src/binding/bindingProvider.js:16] 1x parseMemoText - [src/memoization.js:8] diff --git a/build/output/knockout-latest.debug.js b/build/output/knockout-latest.debug.js index 1efcbcd..0fb6c31 100644 --- a/build/output/knockout-latest.debug.js +++ b/build/output/knockout-latest.debug.js @@ -1,5 +1,5 @@ /*! - * Knockout JavaScript library v3.5.1-mod22-esnext-debug + * Knockout JavaScript library v3.5.1-mod23-esnext-debug * ESNext Edition - https://github.com/justlep/knockout-esnext * (c) The Knockout.js team - http://knockoutjs.com/ * License: MIT (http://www.opensource.org/licenses/mit-license.php) @@ -11,7 +11,7 @@ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ko = factory()); }(this, (function () { const DEBUG = true; // inserted by rollup intro - const version = '3.5.1-mod22-esnext'; // inserted by rollup intro + const version = '3.5.1-mod23-esnext'; // inserted by rollup intro /** @type {function} */ let onError = null; @@ -3046,42 +3046,6 @@ } }; - const _topologicalSortBindings = (bindings) => { - // Depth-first sort - let result = [], // The list of key/handler pairs that we will return - bindingsConsidered = {}, // A temporary record of which bindings are already in 'result' - cyclicDependencyStack = [], // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it - _pushBinding = bindingKey => { - if (bindingsConsidered[bindingKey]) { - return; - } - bindingsConsidered[bindingKey] = true; - let binding = getBindingHandler(bindingKey); - if (!binding) { - return; - } - // First add dependencies (if any) of the current binding - if (binding.after) { - cyclicDependencyStack.push(bindingKey); - for (let bindingDependencyKey of binding.after) { - if (bindings[bindingDependencyKey]) { - if (cyclicDependencyStack.includes(bindingDependencyKey)) { - throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", ")); - } - _pushBinding(bindingDependencyKey); - } - } - cyclicDependencyStack.length--; - } - // Next add the current binding - result.push({key: bindingKey, handler: binding}); - }; - - for (let bindingKey of Object.keys(bindings)) { - _pushBinding(bindingKey); - } - return result; - }; const _applyBindingsToNodeInternal = (node, sourceBindings, bindingContext) => { let nodeDomData = (node[DOM_DATASTORE_PROP] || (node[DOM_DATASTORE_PROP] = {})), @@ -3139,101 +3103,134 @@ } } + if (!bindings) { + return { + bindingContextForDescendants: bindingContext + }; + } + let contextToExtend = bindingContext, bindingHandlerThatControlsDescendantBindings; - if (bindings) { - // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding - // context update), just return the value accessor from the binding. Otherwise, return a function that always gets - // the latest binding value and registers a dependency on the binding updater. - let getValueAccessor = bindingsUpdater ? - (bindingKey) => () => bindingsUpdater()[bindingKey]() : - (bindingKey) => bindings[bindingKey]; - - // let allBindings = () => { - // throw new Error('Use of allBindings as a function is no longer supported'); - // }; - // ^^^ using a function and add custom methods to it is 98% slower than direct object literals in Firefox 81, - // plus the 'no longer supported' message has existed since 2013.. time to drop it - - // The following is the 3.x allBindings API - let allBindings = { - get: (key) => bindings[key] && getValueAccessor(key)(), - has: (key) => key in bindings - }; - - if (EVENT_CHILDREN_COMPLETE in bindings) { - bindingEvent.subscribe(node, EVENT_CHILDREN_COMPLETE, () => { - let callback = bindings[EVENT_CHILDREN_COMPLETE](); - if (callback) { - let nodes = childNodes(node); - if (nodes.length) { - callback(nodes, dataFor(nodes[0])); - } - } - }); - } + // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding + // context update), just return the value accessor from the binding. Otherwise, return a function that always gets + // the latest binding value and registers a dependency on the binding updater. + let getValueAccessor = bindingsUpdater ? + (bindingKey) => () => bindingsUpdater()[bindingKey]() : + (bindingKey) => bindings[bindingKey]; + + // let allBindings = () => { + // throw new Error('Use of allBindings as a function is no longer supported'); + // }; + // ^^^ using a function and add custom methods to it is 98% slower than direct object literals in Firefox 81, + // plus the 'no longer supported' message has existed since 2013.. time to drop it + + // The following is the 3.x allBindings API + let allBindings = { + get: (key) => bindings[key] && getValueAccessor(key)(), + has: (key) => key in bindings + }; - if (EVENT_DESCENDENTS_COMPLETE in bindings) { - contextToExtend = bindingEvent.startPossiblyAsyncContentBinding(node, bindingContext); - bindingEvent.subscribe(node, EVENT_DESCENDENTS_COMPLETE, () => { - let callback = bindings[EVENT_DESCENDENTS_COMPLETE](); - if (callback && firstChild(node)) { - callback(node); + if (EVENT_CHILDREN_COMPLETE in bindings) { + bindingEvent.subscribe(node, EVENT_CHILDREN_COMPLETE, () => { + let callback = bindings[EVENT_CHILDREN_COMPLETE](); + if (callback) { + let nodes = childNodes(node); + if (nodes.length) { + callback(nodes, dataFor(nodes[0])); } - }); - } - - // First put the bindings into the right order - let orderedBindings = _topologicalSortBindings(bindings); - - // Go through the sorted bindings, calling init and update for each - orderedBindings.forEach(bindingKeyAndHandler => { - // Note that topologicalSortBindings has already filtered out any nonexistent binding handlers, - // so bindingKeyAndHandler.handler will always be nonnull. - let handlerInitFn = bindingKeyAndHandler.handler.init, - handlerUpdateFn = bindingKeyAndHandler.handler.update, - bindingKey = bindingKeyAndHandler.key; + } + }); + } - if (node.nodeType === 8 && !allowedVirtualElementBindings[bindingKey]) { - throw new Error("The binding '" + bindingKey + "' cannot be used with virtual elements"); + if (EVENT_DESCENDENTS_COMPLETE in bindings) { + contextToExtend = bindingEvent.startPossiblyAsyncContentBinding(node, bindingContext); + bindingEvent.subscribe(node, EVENT_DESCENDENTS_COMPLETE, () => { + let callback = bindings[EVENT_DESCENDENTS_COMPLETE](); + if (callback && firstChild(node)) { + callback(node); } + }); + } - try { - // Run init, ignoring any dependencies - if (typeof handlerInitFn === 'function') { - ignoreDependencyDetectionNoArgs(() => { - let initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend.$data, contextToExtend); - - // If this binding handler claims to control descendant bindings, make a note of this - if (initResult && initResult.controlsDescendantBindings) { - if (bindingHandlerThatControlsDescendantBindings !== undefined) { - 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."); - } - bindingHandlerThatControlsDescendantBindings = bindingKey; + // First put the bindings into depth-first order (topologicalSortBindings) + + let orderedBindings = [], // The list of key/handler pairs that we will return + bindingsConsidered = {}, // A temporary record of which bindings are already in 'orderedBindings' + cyclicDependencyStack = [], // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it + _pushBinding = (bindingKey) => { + if (bindingsConsidered[bindingKey]) { + return; + } + bindingsConsidered[bindingKey] = true; + let binding = getBindingHandler(bindingKey); + if (!binding) { + return; + } + // First add dependencies (if any) of the current binding + if (binding.after) { + cyclicDependencyStack.push(bindingKey); + for (let bindingDependencyKey of binding.after) { + if (bindings[bindingDependencyKey]) { + if (cyclicDependencyStack.includes(bindingDependencyKey)) { + throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", ")); } - }); + _pushBinding(bindingDependencyKey); + } } + cyclicDependencyStack.length--; + } + // Next add the current binding + orderedBindings.push({key: bindingKey, handler: binding}); + }; - // Run update in its own computed wrapper - if (typeof handlerUpdateFn === 'function') { - dependentObservable( - () => handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend.$data, contextToExtend), - null, - {disposeWhenNodeIsRemoved: node} - ); - } - } catch (ex) { - ex.message = `Unable to process binding "${bindingKey}: ${bindings[bindingKey]}"\nMessage: + ${ex.message}`; - throw ex; + for (let bindingKey of Object.keys(bindings)) { + _pushBinding(bindingKey); + } + + // Go through the sorted bindings, calling init and update for each + for (let bindingKeyAndHandler of orderedBindings) { + // Note that topologicalSortBindings has already filtered out any nonexistent binding handlers, + // so bindingKeyAndHandler.handler will always be nonnull. + let handlerInitFn = bindingKeyAndHandler.handler.init, + handlerUpdateFn = bindingKeyAndHandler.handler.update, + bindingKey = bindingKeyAndHandler.key; + + if (node.nodeType === 8 && !allowedVirtualElementBindings[bindingKey]) { + throw new Error("The binding '" + bindingKey + "' cannot be used with virtual elements"); + } + + try { + // Run init, ignoring any dependencies + if (typeof handlerInitFn === 'function') { + ignoreDependencyDetectionNoArgs(() => { + let initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend.$data, contextToExtend); + + // If this binding handler claims to control descendant bindings, make a note of this + if (initResult && initResult.controlsDescendantBindings) { + if (bindingHandlerThatControlsDescendantBindings) { + 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."); + } + bindingHandlerThatControlsDescendantBindings = bindingKey; + } + }); } - }); + // Run update in its own computed wrapper + if (typeof handlerUpdateFn === 'function') { + dependentObservable( + () => handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, contextToExtend.$data, contextToExtend), + null, + {disposeWhenNodeIsRemoved: node} + ); + } + } catch (ex) { + ex.message = `Unable to process binding "${bindingKey}: ${bindings[bindingKey]}"\nMessage: + ${ex.message}`; + throw ex; + } } - let shouldBindDescendants = bindingHandlerThatControlsDescendantBindings === undefined; return { - shouldBindDescendants, - bindingContextForDescendants: shouldBindDescendants && contextToExtend + bindingContextForDescendants: bindingHandlerThatControlsDescendantBindings ? null : contextToExtend }; }; diff --git a/build/output/knockout-latest.debug.js.map b/build/output/knockout-latest.debug.js.map index d9b9abc..f3b0709 100644 --- a/build/output/knockout-latest.debug.js.map +++ b/build/output/knockout-latest.debug.js.map @@ -1 +1 @@ -{"version":3,"file":"knockout-latest.debug.js","sources":["../../src/onError.js","../../src/utils.domData.js","../../src/subscribables/observableUtils.js","../../src/subscribables/dependencyDetection.js","../../src/utils.domNodeDisposal.js","../../src/utils.domNodes.js","../../src/virtualElements.js","../../src/options.js","../../src/utils.js","../../src/tasks.js","../../src/subscribables/deferredExtender.js","../../src/subscribables/extenders.js","../../src/subscribables/subscribable.js","../../src/subscribables/dependentObservable.js","../../src/binding/bindingHandlers.js","../../src/binding/expressionRewriting.js","../../src/components/loaderRegistry.js","../../src/utils.domManipulation.js","../../src/components/defaultLoader.js","../../src/components/customElements.js","../../src/binding/bindingProvider.js","../../src/binding/bindingAttributeSyntax.js","../../src/subscribables/observable.js","../../src/binding/editDetection/compareArrays.js","../../src/subscribables/observableArray.changeTracking.js","../../src/subscribables/observableArray.js","../../src/memoization.js","../../src/templating/templateRewriting.js","../../src/subscribables/mappingHelpers.js","../../src/binding/editDetection/arrayToDomNodeChildren.js","../../src/templating/templateSources.js","../../src/templating/templateEngine.js","../../src/templating/templating.js","../../src/templating/native/nativeTemplateEngine.js","../../src/subscribables/when.js","../../src/binding/defaultBindings/attr.js","../../src/binding/defaultBindings/checked.js","../../src/binding/defaultBindings/event.js","../../src/binding/defaultBindings/click.js","../../src/binding/defaultBindings/css.js","../../src/binding/defaultBindings/enableDisable.js","../../src/binding/defaultBindings/foreach.js","../../src/binding/defaultBindings/hasfocus.js","../../src/binding/defaultBindings/html.js","../../src/binding/defaultBindings/ifIfnotWith.js","../../src/binding/defaultBindings/let.js","../../src/binding/selectExtensions.js","../../src/binding/defaultBindings/options.js","../../src/binding/defaultBindings/selectedOptions.js","../../src/binding/defaultBindings/style.js","../../src/binding/defaultBindings/submit.js","../../src/binding/defaultBindings/text.js","../../src/binding/defaultBindings/textInput.js","../../src/binding/defaultBindings/uniqueName.js","../../src/binding/defaultBindings/using.js","../../src/binding/defaultBindings/value.js","../../src/binding/defaultBindings/visibleHidden.js","../../src/components/componentBinding.js","../../src/ko.js"],"sourcesContent":["\n/** @type {function} */\nexport let onError = null;\n\nexport const _overrideOnError = (fnOrNull) => {\n if (fnOrNull && typeof fnOrNull !== 'function') {\n throw new Error('ko.onError must be function or nullish');\n }\n onError = fnOrNull;\n};\n","\nexport const DOM_DATASTORE_PROP = Symbol('ko-domdata');\nconst KEY_PREFIX = 'ko_' + Date.now().toString(36) + '_';\n\nlet _keyCount = 0;\nexport const nextDomDataKey = () => KEY_PREFIX + (++_keyCount);\n\nexport const getDomData = (node, key) => node[DOM_DATASTORE_PROP] && node[DOM_DATASTORE_PROP][key]; //@inline-global:DOM_DATASTORE_PROP\n\nexport const setDomData = (node, key, value) => {\n // Make sure we don't actually create a new domData key if we are actually deleting a value\n let dataForNode = node[DOM_DATASTORE_PROP] || (value !== undefined && (node[DOM_DATASTORE_PROP] = {}));\n if (dataForNode) {\n dataForNode[key] = value;\n }\n};\n\n/**\n *\n * @param {Node} node\n * @return {boolean} - true if there was actually a domData deleted on the node\n */\nexport const clearDomData = (node) => !!node[DOM_DATASTORE_PROP] && delete node[DOM_DATASTORE_PROP];\n\n/**\n * Returns a function that removes a given item from an array located under the node's domData[itemArrayDomDataKey].\n * If the array IS or BECOMES empty, it will be deleted from the domData. \n * @return {function(Node, *): void}\n */\nexport const getCurriedDomDataArrayItemRemovalFunctionForArrayDomDataKey = (itemArrayDomDataKey) => (node, itemToRemove) => {\n let dataForNode = node[DOM_DATASTORE_PROP],\n itemArray;\n\n if (dataForNode && (itemArray = dataForNode[itemArrayDomDataKey])) {\n let index = itemArray.indexOf(itemToRemove);\n if (index === 0) {\n itemArray.shift();\n } else if (index > 0) {\n itemArray.splice(index, 1);\n }\n if (!itemArray.length) {\n dataForNode[itemArrayDomDataKey] = undefined;\n }\n }\n};\n\n/**\n * Returns a function that adds a given item to an array located under the node's domData[itemArrayDomDataKey].\n * If the domData or the array didn't exist, either will be created.\n * @param {string} itemArrayDomDataKey\n * @return {function(Node, *): void}\n */\nexport const getCurriedDomDataArrayItemAddFunctionForArrayDomDataKey = (itemArrayDomDataKey) => (node, itemToAdd) => {\n let dataForNode = node[DOM_DATASTORE_PROP] || (node[DOM_DATASTORE_PROP] = {}),\n itemArray = dataForNode[itemArrayDomDataKey]; \n \n if (itemArray) {\n itemArray.push(itemToAdd);\n } else {\n dataForNode[itemArrayDomDataKey] = [itemToAdd];\n }\n};\n\n/**\n * Returns a function that will \n * (1) run all (function-)items of an array located under the node's domData[itemArrayDomDataKey], passing the node as parameter\n * (2) clear the node's DOM data\n * @param {string} itemArrayDomDataKey\n * @return {function(Node): void}\n */\nexport const getCurriedDomDataArrayInvokeEachAndClearDomDataFunctionForArrayDomDataKey = (itemArrayDomDataKey) => (node) => {\n let dataForNode = node[DOM_DATASTORE_PROP];\n if (dataForNode) {\n let itemArray = dataForNode[itemArrayDomDataKey];\n if (itemArray) {\n for (let i = 0, _fns = itemArray.slice(0), len = _fns.length; i < len; i++) {\n _fns[i](node);\n }\n }\n delete node[DOM_DATASTORE_PROP];\n } \n};\n","export const IS_SUBSCRIBABLE = Symbol('IS_SUBSCRIBABLE');\nexport const isSubscribable = (obj) => !!(obj && obj[IS_SUBSCRIBABLE]); //@inline-global:IS_SUBSCRIBABLE\n\nexport const IS_OBSERVABLE = Symbol('IS_OBSERVABLE');\nexport const isObservable = (obj) => !!(obj && obj[IS_OBSERVABLE]);\nexport const unwrapObservable = (value) => value && (value[IS_OBSERVABLE] ? value() : value);\n\nexport const IS_OBSERVABLE_ARRAY = Symbol('IS_OBSERVABLE_ARRAY');\nexport const isObservableArray = (obj) => !!(obj && obj[IS_OBSERVABLE_ARRAY]);\n\nexport const IS_COMPUTED = Symbol('IS_COMPUTED');\nexport const isComputed = (obj) => !!(obj && obj[IS_COMPUTED]);\n\nexport const IS_PURE_COMPUTED = Symbol('IS_PURE_COMPUTED');\nexport const isPureComputed = (obj) => !!(obj && obj[IS_PURE_COMPUTED]);\n\nexport const isWritableObservable = (obj) => !!(obj && (obj[IS_COMPUTED] ? obj.hasWriteFunction : obj[IS_OBSERVABLE]));\nexport const isWriteable = isWritableObservable;\n","import {isSubscribable} from './observableUtils';\r\n\r\nconst outerFrames = [];\r\nlet currentFrame,\r\n lastId = 0;\r\n\r\nexport const beginDependencyDetection = options => {\r\n outerFrames.push(currentFrame);\r\n currentFrame = options;\r\n};\r\n\r\nconst _beginDependencyDetectionWithEmptyFrame = () => currentFrame = void outerFrames.push(currentFrame); //@inline\r\n\r\nexport const endDependencyDetection = () => currentFrame = outerFrames.pop(); //@inline\r\n\r\n/**\r\n * For ko-internal usages without callbackTarget and callbackArgs use {@link ignoreDependencyDetectionNoArgs}.\r\n * @param {function} callback\r\n * @param {?Object} [callbackTarget]\r\n * @param {any[]} [callbackArgs]\r\n * @return {*} the callback's return value\r\n */\r\nexport const ignoreDependencyDetection = (callback, callbackTarget, callbackArgs) => {\r\n try {\r\n _beginDependencyDetectionWithEmptyFrame();\r\n \r\n // there's a high percentage of calls without callbackTarget and/or callbackArgs, \r\n // so let's speed up things by not using `apply` or args in those cases.\r\n return callbackTarget ? callback.apply(callbackTarget, callbackArgs || []) :\r\n callbackArgs ? callback(...callbackArgs) : callback();\r\n } finally {\r\n endDependencyDetection();\r\n }\r\n};\r\n\r\n/**\r\n * Slim version of {@link ignoreDependencyDetection} intended for pure, no-args callbacks. \r\n * @param {function} callback\r\n * @return {*}\r\n * @internal\r\n */\r\nexport const ignoreDependencyDetectionNoArgs = (callback) => {\r\n try {\r\n _beginDependencyDetectionWithEmptyFrame();\r\n return callback();\r\n } finally {\r\n endDependencyDetection();\r\n }\r\n};\r\n\r\n\r\n// Return a unique ID that can be assigned to an observable for dependency tracking.\r\n// Theoretically, you could eventually overflow the number storage size, resulting\r\n// in duplicate IDs. But in JavaScript, the largest exact integral value is 2^53\r\n// or 9,007,199,254,740,992. If you created 1,000,000 IDs per second, it would\r\n// take over 285 years to reach that number.\r\n// Reference http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html\r\nconst _getId = () => ++lastId; //@inline\r\n\r\nconst _runCallback = (subscribable) => currentFrame.callback.call(currentFrame.callbackTarget, subscribable, subscribable._id || (subscribable._id = _getId())); //@inline\r\n\r\n/**\r\n * For ko-internal usage, there is no reason to waste cycles with 'isSubscribable'-checks. \r\n */\r\nexport const registerDependencyInternal = (subscribable) => currentFrame && _runCallback(subscribable);\r\n\r\nexport const registerDependencyExternal = (subscribable) => {\r\n if (currentFrame) {\r\n if (!isSubscribable(subscribable)) {\r\n throw new Error('Only subscribable things can act as dependencies');\r\n }\r\n _runCallback(subscribable);\r\n }\r\n};\r\n\r\nexport const getDependenciesCount = () => currentFrame ? currentFrame.computed.getDependenciesCount() : undefined;\r\nexport const getDependencies = () => currentFrame ? currentFrame.computed.getDependencies() : undefined;\r\nexport const isInitialDependency = () => currentFrame ? currentFrame.isInitial : undefined;\r\nexport const getCurrentComputed = () => currentFrame ? currentFrame.computed : undefined;\r\n","import {nextDomDataKey,\r\n getCurriedDomDataArrayInvokeEachAndClearDomDataFunctionForArrayDomDataKey,\r\n getCurriedDomDataArrayItemAddFunctionForArrayDomDataKey,\r\n getCurriedDomDataArrayItemRemovalFunctionForArrayDomDataKey} from './utils.domData';\r\nimport {ignoreDependencyDetectionNoArgs} from './subscribables/dependencyDetection';\r\n\r\nconst DISPOSE_CALLBACKS_DOM_DATA_KEY = nextDomDataKey();\r\n\r\n// Node types: Element(1), Comment(8), Document(9)\r\nconst _isNodeTypeCleanable = nodeType => nodeType === 1 || nodeType === 8 || nodeType === 9; //@inline\r\nconst _isNodeTypeCleanableWithDescendents = nodeType => nodeType === 1 || nodeType === 9; //@inline\r\n\r\n\r\n/** @type {function} */\r\nexport let _cleanExternalData = null;\r\nexport const _overrideCleanExternalData = (fn) => _cleanExternalData = fn;\r\n\r\nconst _runDisposalCallbacksAndClearDomData = getCurriedDomDataArrayInvokeEachAndClearDomDataFunctionForArrayDomDataKey(DISPOSE_CALLBACKS_DOM_DATA_KEY);\r\n\r\nconst _cleanSingleNode = (node) => {\r\n // Run all the dispose callbacks & ease the DOM data\r\n _runDisposalCallbacksAndClearDomData(node);\r\n\r\n // Perform cleanup needed by external libraries (currently only jQuery, but can be extended)\r\n if (_cleanExternalData) {\r\n _cleanExternalData(node);\r\n }\r\n \r\n // Clear any immediate-child comment nodes, as these wouldn't have been found by\r\n // node.getElementsByTagName(\"*\") in cleanNode() (comment nodes aren't elements)\r\n if (_isNodeTypeCleanableWithDescendents(node.nodeType)) {\r\n let cleanableNodesList = node.childNodes;\r\n if (cleanableNodesList.length) {\r\n _cleanNodesInList(cleanableNodesList, true /*onlyComments*/);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * @param {HTMLCollection|NodeList} nodeList\r\n * @param {boolean} [onlyComments]\r\n * @private\r\n */\r\nconst _cleanNodesInList = (nodeList, onlyComments) => {\r\n let cleanedNodes = [],\r\n cleanedNodesIndex = -1, \r\n lastCleanedNode;\r\n \r\n for (let i = 0, node; i < nodeList.length; i++) {\r\n node = nodeList[i]; \r\n if (!onlyComments || node.nodeType === 8) {\r\n _cleanSingleNode(cleanedNodes[++cleanedNodesIndex] = lastCleanedNode = node);\r\n if (nodeList[i] !== lastCleanedNode) {\r\n while (i-- && !cleanedNodes.includes(nodeList[i])) {\r\n // just do\r\n }\r\n }\r\n }\r\n }\r\n};\r\n\r\n/** @type {function(Node, Function): void} */\r\nexport const addDisposeCallback = getCurriedDomDataArrayItemAddFunctionForArrayDomDataKey(DISPOSE_CALLBACKS_DOM_DATA_KEY);\r\n\r\n/** @type {function(Node, Function): void} */\r\nexport const removeDisposeCallback = getCurriedDomDataArrayItemRemovalFunctionForArrayDomDataKey(DISPOSE_CALLBACKS_DOM_DATA_KEY);\r\n\r\n/**\r\n * Cleanable node types: Element 1, Comment 8, Document 9\r\n * @param {Node|HTMLElement} node\r\n * @return {Node|HTMLElement}\r\n */\r\nexport const cleanNode = (node) => {\r\n let nodeType = node.nodeType;\r\n if (_isNodeTypeCleanable(nodeType)) {\r\n ignoreDependencyDetectionNoArgs(() => {\r\n // First clean this node, where applicable\r\n _cleanSingleNode(node);\r\n // ... then its descendants, where applicable\r\n if (_isNodeTypeCleanableWithDescendents(nodeType)) {\r\n let cleanableNodesList = node.getElementsByTagName('*');\r\n if (cleanableNodesList.length) {\r\n _cleanNodesInList(cleanableNodesList);\r\n }\r\n }\r\n });\r\n }\r\n return node;\r\n};\r\n\r\nexport const removeNode = (node) => cleanNode(node).remove(); //@inline-global:cleanNode\r\n","import {removeNode} from './utils.domNodeDisposal';\n\nexport const emptyDomNode = (domNode) => {\n let child;\n while (child = domNode.firstChild) {\n removeNode(child);\n }\n};\n\nexport const setDomNodeChildren = (domNode, childNodes) => {\n emptyDomNode(domNode);\n if (childNodes) {\n for (let i = 0, j = childNodes.length; i < j; i++) {\n domNode.appendChild(childNodes[i]);\n }\n }\n};\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., blah)\n// without having to scatter special cases all over the binding and templating code.\nimport {emptyDomNode, setDomNodeChildren as utilsSetDomNodeChildren} from './utils.domNodes';\nimport {removeNode} from './utils.domNodeDisposal';\n\nexport const START_COMMENT_REGEX = /^\\s*ko(?:\\s+([\\s\\S]+))?\\s*$/;\n\nconst END_COMMENT_REGEX = /^\\s*\\/ko\\s*$/;\nconst SYM_MATCHED_END_COMMENT = Symbol('__ko_matchedEndComment__');\n\nexport const allowedBindings = {};\nexport const allowedVirtualElementBindings = allowedBindings;\n\nconst _isStartComment = (node) => (node.nodeType === 8) && START_COMMENT_REGEX.test(node.nodeValue); //@inline\nconst _isEndComment = (node) => (node.nodeType === 8) && END_COMMENT_REGEX.test(node.nodeValue); //@inline\n\nconst _getVirtualChildren = (startComment, allowUnbalanced) => {\n let currentNode = startComment.nextSibling,\n depth = 1,\n childIndex = -1,\n children = [];\n \n while (currentNode) {\n if (_isEndComment(currentNode)) {\n currentNode[SYM_MATCHED_END_COMMENT] = true;\n if (!--depth) {\n return children;\n }\n }\n children[++childIndex] = currentNode;\n if (_isStartComment(currentNode)) {\n depth++;\n }\n currentNode = currentNode.nextSibling;\n }\n if (!allowUnbalanced) {\n throw new Error('Cannot find closing comment tag to match: ' + startComment.nodeValue);\n }\n return null;\n };\n\nconst _getMatchingEndComment = (startComment, allowUnbalanced) => {\n let allVirtualChildren = _getVirtualChildren(startComment, allowUnbalanced);\n if (allVirtualChildren) {\n let totalVirtualChildren = allVirtualChildren.length;\n return (totalVirtualChildren ? allVirtualChildren[totalVirtualChildren - 1] : startComment).nextSibling;\n }\n return null; // Must have no matching end comment, and allowUnbalanced is true\n};\n\nexport const childNodes = (node) => _isStartComment(node) ? _getVirtualChildren(node) : node.childNodes;\n\nexport const emptyNode = (node) => {\n if (!_isStartComment(node)) {\n emptyDomNode(node);\n return;\n }\n let virtualChildren = childNodes(node);\n for (let i = 0, j = virtualChildren.length; i < j; i++) {\n removeNode(virtualChildren[i]);\n }\n};\n\nexport const setDomNodeChildren = (node, childNodes) => {\n if (!_isStartComment(node)) {\n utilsSetDomNodeChildren(node, childNodes);\n return;\n }\n emptyNode(node);\n let endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children\n for (let i = 0, j = childNodes.length; i < j; i++) {\n endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);\n }\n};\n\nexport const prepend = (containerNode, nodeToPrepend) => {\n let 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\nexport const insertAfter = (containerNode, nodeToInsert, insertAfterNode) => {\n if (!insertAfterNode) {\n prepend(containerNode, nodeToInsert);\n return;\n }\n // Children of start comments must always have a parent and at least one following sibling (the end comment)\n let 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\nexport const firstChild = (node) => {\n if (!_isStartComment(node)) {\n let _nodeFirstChild = node.firstChild; \n if (_nodeFirstChild && _isEndComment(_nodeFirstChild)) {\n throw new Error('Found invalid end comment, as the first child of ' + node);\n }\n return _nodeFirstChild;\n } \n let _nodeNextSibling = node.nextSibling;\n if (!_nodeNextSibling|| _isEndComment(_nodeNextSibling)) {\n return null;\n }\n return _nodeNextSibling;\n};\n\nexport const nextSibling = (node) => {\n if (_isStartComment(node)) {\n node = _getMatchingEndComment(node);\n }\n let _nodeNextSibling = node.nextSibling;\n if (_nodeNextSibling && _isEndComment(_nodeNextSibling)) {\n if (!_nodeNextSibling[SYM_MATCHED_END_COMMENT]) {\n // unmatched end comment!\n throw Error('Found end comment without a matching opening comment, as child of ' + node);\n } \n return null;\n }\n return _nodeNextSibling;\n};\n\n","// For any options that may affect various areas of Knockout and aren't directly associated with data binding.\r\nexport const options = {\r\n deferUpdates: false,\r\n useOnlyNativeEvents: false,\r\n foreachHidesDestroyed: false\r\n};\r\n","import {isObservable, unwrapObservable} from './subscribables/observableUtils';\nimport {cleanNode, removeNode} from './utils.domNodeDisposal';\nimport {firstChild, nextSibling, setDomNodeChildren as virtualElementsSetDomNodeChildren} from './virtualElements';\nimport {onError} from './onError';\n\n\n// For details on the pattern for changing node classes\n// see: https://github.com/knockout/knockout/issues/1597\nconst CSS_CLASSNAME_REGEX = /\\S+/g;\n\n// using a map for lookups is 33% faster than plain objects in Chrome 79, and only 5ish % slower in Firefox 72 \nconst KNOWN_EVENT_TYPES_BY_EVENT_NAME = new Map();\nfor (let eventName of ['keyup', 'keydown', 'keypress']) {\n KNOWN_EVENT_TYPES_BY_EVENT_NAME.set(eventName, 'UIEvents');\n}\nfor (let eventName of ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave']) {\n KNOWN_EVENT_TYPES_BY_EVENT_NAME.set(eventName, 'MouseEvents');\n}\n\nexport const canSetPrototype = ({__proto__: []} instanceof Array);\n \nexport const hasOwnProperty = Object.prototype.hasOwnProperty;\n\nexport const objectForEach = (obj, action) => {\n if (obj) {\n for (let prop of Object.keys(obj)) {\n action(prop, obj[prop]);\n }\n }\n};\n\nexport const extend = Object.assign;\n\nexport const setPrototypeOf = (obj, proto) => {\n obj.__proto__ = proto;\n return obj;\n};\n\n// shortcut for if (canSetPrototype) ... \nexport const trySetPrototypeOf = canSetPrototype ? setPrototypeOf : () => null;\n\nexport const setPrototypeOfOrExtend = canSetPrototype ? setPrototypeOf : extend;\n\nexport const toggleObjectClassPropertyString = (obj, prop, classNames, shouldHaveClass) => {\n // obj/prop is either a node/'className' or a SVGAnimatedString/'baseVal'.\n let currentClassNames = obj[prop].match(CSS_CLASSNAME_REGEX) || [];\n for (let className of classNames.match(CSS_CLASSNAME_REGEX)) {\n addOrRemoveItem(currentClassNames, className, shouldHaveClass);\n }\n obj[prop] = currentClassNames.join(' ');\n};\n\nexport const toggleDomNodeCssClass = (node, classNames, shouldHaveClass) => {\n if (classNames) {\n if (typeof node.classList === 'object') {\n let addOrRemove = shouldHaveClass ? 'add' : 'remove';\n for (let className of classNames.match(CSS_CLASSNAME_REGEX)) {\n node.classList[addOrRemove](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\nexport const fieldsIncludedWithJsonPost = ['authenticity_token', /^__RequestVerificationToken(_.*)?$/];\n\nexport const arrayForEach = (array, action, actionOwner) => {\n for (let i = 0, j = array.length; i < j; i++) {\n action.call(actionOwner, array[i], i, array);\n }\n};\n\nexport const arrayIndexOf = (array, item) => array.indexOf(item);\n\nexport const arrayFirst = function (array, predicate, predicateOwner) {\n for (let i = 0, j = array.length; i < j; i++) {\n if (predicate.call(predicateOwner, array[i], i, array)) {\n return array[i];\n }\n }\n return undefined;\n};\n\nexport const arrayRemoveItem = (array, itemToRemove) => {\n let index = (array && array.length) ? array.indexOf(itemToRemove) : -1;\n if (index === 0) {\n array.shift();\n } else if (index > 0) {\n array.splice(index, 1);\n }\n};\n\nexport const arrayGetDistinctValues = (array) => {\n let result = [],\n nextIndex = 0;\n if (array) {\n for (let item of array) {\n if (!result.includes(item)) {\n result[nextIndex++] = item;\n }\n }\n }\n return result;\n};\n\nexport const arrayMap = (array, mapping, mappingOwner) => {\n let result = [],\n nextIndex = 0;\n if (array) {\n for (let i = 0, j = array.length; i < j; i++) {\n result[nextIndex++] = mapping.call(mappingOwner, array[i], i);\n }\n }\n return result;\n};\n\nexport const arrayFilter = (array, predicate, predicateOwner) => {\n let result = [],\n nextIndex = 0;\n if (array) {\n for (let i = 0, j = array.length; i < j; i++) {\n if (predicate.call(predicateOwner, array[i], i)) {\n result[nextIndex++] = array[i];\n }\n }\n }\n return result;\n};\n\nexport const arrayPushAll = (array, valuesToPush) => {\n for (let i = 0, targetIndex = array.length, len = valuesToPush.length; i < len; i++, targetIndex++) {\n array[targetIndex] = valuesToPush[i];\n }\n return array;\n};\n\nexport const peekObservable = (value) => isObservable(value) ? value.peek() : value;\n\nexport const addOrRemoveItem = (array, value, included) => {\n let existingEntryIndex = peekObservable(array).indexOf(value);\n if (existingEntryIndex < 0) {\n if (included) {\n array.push(value);\n }\n } else if (!included) {\n array.splice(existingEntryIndex, 1);\n }\n};\n\nexport const objectMap = (source, mapping, mappingOwner) => {\n if (!source) {\n return source;\n }\n let target = {};\n for (let prop of Object.keys(source)) {\n target[prop] = mapping.call(mappingOwner, source[prop], prop, source);\n }\n return target;\n};\n\nexport const moveCleanedNodesToContainerElement = (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 let nodesArray = [...nodes],\n templateDocument = (nodesArray[0] && nodesArray[0].ownerDocument) || document,\n container = templateDocument.createElement('div');\n \n for (let i = 0, j = nodesArray.length; i < j; i++) {\n container.appendChild(cleanNode(nodesArray[i]));\n }\n return container;\n};\n\nexport const cloneNodes = (nodesArray, shouldCleanNodes) => {\n let newNodesArray = [];\n for (let i = 0, j = nodesArray.length; i < j; i++) {\n let clonedNode = nodesArray[i].cloneNode(true);\n newNodesArray.push(shouldCleanNodes ? cleanNode(clonedNode) : clonedNode);\n }\n return newNodesArray;\n};\n\nexport const replaceDomNodes = (nodeToReplaceOrNodeArray, newNodesArray) => {\n let nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;\n if (nodesToReplaceArray.length > 0) {\n let insertionPoint = nodesToReplaceArray[0];\n let parent = insertionPoint.parentNode;\n for (let i = 0, j = newNodesArray.length; i < j; i++) {\n parent.insertBefore(newNodesArray[i], insertionPoint);\n }\n for (let i = 0, j = nodesToReplaceArray.length; i < j; i++) {\n removeNode(nodesToReplaceArray[i]);\n }\n }\n};\n\nexport const fixUpContinuousNodeArray = (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 let 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\nexport const setOptionNodeSelectionState = (optionNode, isSelected) => optionNode.selected = isSelected;\n\nexport const stringTrim = (string) => (string === null || string === undefined) ? '' : \n string.trim ? string.trim() : string.toString().trim();\n\n/** @deprecated */\nexport const stringStartsWith = (string, startsWith) => (string || '').startsWith(startsWith);\n\nexport const domNodeIsContainedBy = (node, containedByNode) => {\n if (node === containedByNode) {\n return true;\n }\n if (containedByNode.contains) {\n return containedByNode.contains(node.nodeType !== 1 ? node.parentNode : node);\n }\n if (containedByNode.compareDocumentPosition) {\n return (containedByNode.compareDocumentPosition(node) & 16) === 16;\n }\n while (node && node !== containedByNode) {\n node = node.parentNode;\n }\n return !!node;\n};\n\nexport const domNodeIsAttachedToDocument = (node) => domNodeIsContainedBy(node, node.ownerDocument.documentElement);\n\nexport const anyDomNodeIsAttachedToDocument = (nodes) => !!arrayFirst(nodes, domNodeIsAttachedToDocument);\n\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.\nexport const tagNameLower = (element) => {\n let tagName = element && element.tagName;\n return tagName && tagName.toLowerCase();\n};\n\nexport const catchFunctionErrors = (delegate) => {\n return onError ? function() {\n try {\n // direct call is faster than delegate.apply, and the delegate itself is responsible of its 'this' \n return delegate(...arguments);\n } catch (e) {\n onError && onError(e);\n throw e;\n }\n } : delegate;\n};\n\nexport const setTimeoutWithCatchError = (handler, timeout) => setTimeout(catchFunctionErrors(handler), timeout);\n\nexport const deferError = (error) => {\n setTimeout(() => {\n onError && onError(error);\n throw error;\n }, 0);\n};\n\nexport const valuesArePrimitiveAndEqual = (PRIMITIVE_TYPES => (a, b) => {\n let oldValueIsPrimitive = (a === null) || PRIMITIVE_TYPES[typeof a];\n return oldValueIsPrimitive ? (a === b) : false;\n})({'undefined': 1, 'boolean': 1, 'number': 1, 'string': 1});\n\nexport const registerEventHandler = (element, eventType, handler) => {\n if (typeof element.addEventListener === 'function') {\n element.addEventListener(eventType, catchFunctionErrors(handler), false);\n return;\n }\n throw new Error('Browser doesn\\'t support addEventListener');\n};\n\nexport const triggerEvent = (element, eventType) => {\n if (!(element && element.nodeType)) {\n throw new Error('element must be a DOM node when calling triggerEvent');\n }\n\n if (typeof element.dispatchEvent === 'function') {\n let eventCategory = KNOWN_EVENT_TYPES_BY_EVENT_NAME.get(eventType) || 'HTMLEvents',\n 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 return;\n }\n throw new Error('The supplied element doesn\\'t support dispatchEvent');\n};\n\nexport const setTextContent = (element, textContent) => {\n let value = unwrapObservable(textContent);\n if (value === null || value === undefined) {\n value = '';\n }\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 let innerTextNode = firstChild(element);\n if (!innerTextNode || innerTextNode.nodeType !== 3 || nextSibling(innerTextNode)) {\n virtualElementsSetDomNodeChildren(element, [element.ownerDocument.createTextNode(value)]);\n } else {\n innerTextNode.data = value;\n }\n};\n\n/** @deprecated - too trivial*/\nexport const setElementName = (element, name) => element.name = name;\n\nexport const range = function (min, max) {\n let result = [];\n for (let i = unwrapObservable(min), max = unwrapObservable(max); i <= max; i++) {\n result.push(i);\n }\n return result;\n};\n\n/** @deprecated - modern ES has enough means to turn array-like structures into Arrays -> Array.from(), [...values] */\nexport const makeArray = (arrayLikeObject) => {\n let result = [];\n for (let i = 0, j = arrayLikeObject.length; i < j; i++) {\n result[i] = arrayLikeObject[i];\n }\n return result;\n};\n\nexport const createSymbolOrString = identifier => Symbol(identifier);\n\nexport const getFormFields = (form, fieldName) => {\n let fields = [...form.getElementsByTagName('input'), ...form.getElementsByTagName('textarea')];\n let isMatchingField = (typeof fieldName === 'string') ? (field) => field.name === fieldName\n : (field) => fieldName.test(field.name);\n // Treat fieldName as regex or object containing predicate\n let matches = [];\n for (let i = fields.length - 1; i >= 0; i--) {\n if (isMatchingField(fields[i])) {\n matches.push(fields[i]);\n }\n }\n return matches;\n};\n\n// replacer and space are optional\nexport const stringifyJson = (data, replacer, space) => JSON.stringify(unwrapObservable(data), replacer, space);\n\nexport const postJson = function(urlOrForm, data, options) {\n options = options || {};\n let params = options['params'] || {},\n includeFields = options['includeFields'] || fieldsIncludedWithJsonPost,\n 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') && (tagNameLower(urlOrForm) === 'form')) {\n let originalForm = urlOrForm;\n url = originalForm.action;\n for (let i = includeFields.length - 1; i >= 0; i--) {\n let fields = getFormFields(originalForm, includeFields[i]);\n for (let j = fields.length - 1; j >= 0; j--) {\n params[fields[j].name] = fields[j].value;\n }\n }\n }\n data = unwrapObservable(data);\n let form = document.createElement('form');\n form.style.display = 'none';\n form.action = url;\n form.method = 'post';\n if (data) {\n for (let key of Object.keys(data)) {\n // Since 'data' this is a model object, we include all properties including those inherited from its prototype\n let input = document.createElement('input');\n input.type = 'hidden';\n input.name = key;\n input.value = stringifyJson(unwrapObservable(data[key]));\n form.appendChild(input);\n }\n }\n if (params) {\n for (let key of Object.keys(params)) {\n let input = document.createElement('input');\n input.type = 'hidden';\n input.name = key;\n input.value = params[key];\n form.appendChild(input);\n }\n }\n document.body.appendChild(form);\n options.submitter ? options.submitter(form) : form.submit();\n setTimeout(() => form.parentNode.removeChild(form), 0);\n};\n","import {deferError} from './utils';\r\n\r\nconst _taskQueue = [];\r\n\r\nlet _taskQueueLength = 0,\r\n _nextHandle = 1,\r\n _nextIndexToProcess = 0;\r\n\r\nexport let _scheduler;\r\n\r\n// allows for overriding the default scheduler by assigning 'ko.tasks.scheduler = someCustomScheduler' (see ko.js)\r\nexport const _overrideScheduler = newScheduler => {\r\n if (typeof newScheduler !== 'function') {\r\n throw new Error('Scheduler must be a function'); \r\n }\r\n _scheduler = newScheduler;\r\n};\r\n\r\nconst _processTasks = () => {\r\n if (!_taskQueueLength) {\r\n return;\r\n }\r\n // Each mark represents the end of a logical group of tasks and the number of these groups is\r\n // limited to prevent unchecked recursion.\r\n let mark = _taskQueueLength, \r\n countMarks = 0;\r\n\r\n // _nextIndexToProcess keeps track of where we are in the queue; processTasks can be called recursively without issue\r\n for (let task; _nextIndexToProcess < _taskQueueLength;) {\r\n if (!(task = _taskQueue[_nextIndexToProcess++])) {\r\n continue;\r\n }\r\n if (_nextIndexToProcess > mark) {\r\n if (++countMarks >= 5000) {\r\n _nextIndexToProcess = _taskQueueLength; // skip all tasks remaining in the queue since any of them could be causing the recursion\r\n deferError(Error(\"'Too much recursion' after processing \" + countMarks + \" task groups.\"));\r\n break;\r\n }\r\n mark = _taskQueueLength;\r\n }\r\n try {\r\n task();\r\n } catch (ex) {\r\n deferError(ex);\r\n }\r\n }\r\n};\r\n\r\nconst _scheduledProcess = () => {\r\n _processTasks();\r\n // Reset the queue\r\n _nextIndexToProcess = 0;\r\n _taskQueueLength = 0;\r\n _taskQueue.length = 0;\r\n};\r\n\r\nif (typeof MutationObserver !== 'undefined') {\r\n // Chrome 27+, Firefox 14+, IE 11+, Opera 15+, Safari 6.1+\r\n // From https://github.com/petkaantonov/bluebird * Copyright (c) 2014 Petka Antonov * License: MIT\r\n _scheduler = (callback => {\r\n let elem = document.createElement('b'),\r\n val = 1;\r\n new MutationObserver(callback).observe(elem, {attributes: true});\r\n return () => elem.title = (val = -val); // original classList.toggle is 60% slower in Chrome 85\r\n })(_scheduledProcess);\r\n\r\n} else if (typeof process === 'object') {\r\n // Running tests in NodeJS\r\n _scheduler = (callback) => setTimeout(callback, 0);\r\n} else {\r\n throw new Error('Browser is too old, does not know MutationObserver');\r\n}\r\n\r\nexport const scheduleTask = (func) => {\r\n if (!_taskQueueLength) {\r\n _scheduler(_scheduledProcess);\r\n }\r\n _taskQueue[_taskQueueLength++] = func;\r\n return _nextHandle++;\r\n};\r\n\r\nexport const cancelTask = (handle) => {\r\n let index = handle - (_nextHandle - _taskQueueLength);\r\n if (index >= _nextIndexToProcess && index < _taskQueueLength) {\r\n _taskQueue[index] = null;\r\n }\r\n};\r\n\r\n// For testing only: reset the queue and return the previous queue length\r\nexport const resetForTesting = () => {\r\n let length = _taskQueueLength - _nextIndexToProcess;\r\n _nextIndexToProcess = _taskQueueLength = _taskQueue.length = 0;\r\n return length;\r\n};\r\n\r\nexport const runEarly = _processTasks;\r\n","import {cancelTask, scheduleTask} from '../tasks';\n\nexport const deferredExtender = (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 if (target._deferUpdates) {\n return;\n }\n target._deferUpdates = true;\n target.limit(callback => {\n let ignoreUpdates = false,\n handle;\n\n return () => {\n if (ignoreUpdates) {\n return;\n }\n cancelTask(handle);\n handle = scheduleTask(callback);\n\n try {\n ignoreUpdates = true;\n target.notifySubscribers(undefined, 'dirty');\n } finally {\n ignoreUpdates = false;\n }\n };\n });\n};\n","import {valuesArePrimitiveAndEqual} from '../utils';\nimport {deferredExtender} from './deferredExtender';\n\nexport const extenders = Object.create(null);\n\nextenders.deferred = deferredExtender;\n\nexport function applyExtenders(requestedExtenders) {\n let target = this;\n if (requestedExtenders) {\n for (let key of Object.keys(requestedExtenders)) {\n let extenderHandler = extenders[key];\n if (typeof extenderHandler === 'function') {\n target = extenderHandler(target, requestedExtenders[key]) || target;\n } else {\n console.warn('Missing extender: ' + key);\n }\n }\n }\n return target;\n}\n\nconst _throttle = (callback, timeout) => {\n let timeoutInstance;\n return () => {\n if (timeoutInstance) {\n return;\n }\n timeoutInstance = setTimeout(() => {\n timeoutInstance = undefined;\n callback();\n }, timeout);\n };\n};\n\nconst _debounce = (callback, timeout) => {\n let timeoutInstance;\n return () => {\n clearTimeout(timeoutInstance);\n timeoutInstance = setTimeout(callback, timeout);\n };\n};\n\nextenders.rateLimit = (target, options) => {\n let timeout, \n method, \n 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(callback => limitFunction(callback, timeout, options));\n};\n\nconst ORIGINAL_EQUALITY_COMPARER = Symbol();\n\nextenders.notify = (target, notifyWhen) => {\n let currentEqualityComparer = target.equalityComparer;\n if (notifyWhen === 'always') {\n if (currentEqualityComparer) {\n target[ORIGINAL_EQUALITY_COMPARER] = currentEqualityComparer;\n target.equalityComparer = null; // null equalityComparer means to always notify\n }\n } else if (!currentEqualityComparer) {\n target.equalityComparer = target[ORIGINAL_EQUALITY_COMPARER]; \n }\n};\n\nexport const defineThrottleExtender = (dependentObservable) => {\n extenders.throttle = (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 let writeTimeoutInstance = null;\n return dependentObservable({\n read: target,\n write(value) {\n clearTimeout(writeTimeoutInstance);\n writeTimeoutInstance = setTimeout(() => target(value), timeout);\n }\n });\n };\n};\n","import {addDisposeCallback, removeDisposeCallback} from '../utils.domNodeDisposal';\r\nimport {trySetPrototypeOf} from '../utils';\r\nimport {applyExtenders} from './extenders';\r\nimport {beginDependencyDetection, endDependencyDetection} from './dependencyDetection';\r\nimport {isObservable, IS_SUBSCRIBABLE} from './observableUtils';\r\n\r\nexport class Subscription {\r\n \r\n constructor(target, callback, disposeCallback) {\r\n this._target = target;\r\n this._callback = callback;\r\n this._disposeCallback = disposeCallback;\r\n this._isDisposed = false;\r\n this._node = null;\r\n this._domNodeDisposalCallback = null;\r\n }\r\n \r\n dispose() {\r\n if (this._isDisposed) {\r\n return;\r\n }\r\n if (this._domNodeDisposalCallback) {\r\n removeDisposeCallback(this._node, this._domNodeDisposalCallback);\r\n }\r\n this._isDisposed = true;\r\n this._disposeCallback();\r\n this._target = this._callback = this._disposeCallback = this._node = this._domNodeDisposalCallback = null;\r\n }\r\n \r\n disposeWhenNodeIsRemoved(node) {\r\n this._node = node;\r\n addDisposeCallback(node, this._domNodeDisposalCallback = this.dispose.bind(this));\r\n }\r\n}\r\n\r\nconst DEFAULT_EVENT = 'change';\r\n\r\n// Moved out of \"limit\" to avoid the extra closure\r\nfunction _limitNotifySubscribers(value, event) {\r\n if (!event || event === DEFAULT_EVENT) {\r\n this._limitChange(value);\r\n } else if (event === 'beforeChange') {\r\n this._limitBeforeChange(value);\r\n } else {\r\n this._origNotifySubscribers(value, event);\r\n }\r\n}\r\n\r\nexport const updateSubscribableVersion = (subscribableOrComputed) => subscribableOrComputed._versionNumber++; //@inline-global\r\n\r\nexport const hasSubscriptionsForEvent = (subscribable, event) => (subscribable._subscriptions[event] || 0).length; //@inline-global\r\n\r\n/**\r\n * (!) must not be shortcut so `subscribable._versionNumber !== versionToCheck`\r\n * @internal\r\n */\r\nexport const hasSubscribableChanged = (subscribable, versionToCheck) => subscribable.getVersion() !== versionToCheck; //@inline-global\r\n\r\n/**\r\n * @param subscribable\r\n * cleaner but slower would be { [DEFAULT_EVENT]: [] } instead of {change: []}\r\n * TODO remove the && once macros with function bodies are supported \r\n */\r\nexport const initSubscribableInternal = (subscribable) => (subscribable._subscriptions = {change: []}) && (subscribable._versionNumber = 1); //@inline-global \r\n\r\nexport const SUBSCRIBABLE_PROTOTYPE = {\r\n [IS_SUBSCRIBABLE]: true,\r\n \r\n init(instance) {\r\n initSubscribableInternal(instance);\r\n },\r\n\r\n subscribe(callback, callbackTarget, event) {\r\n event = event || DEFAULT_EVENT;\r\n let boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;\r\n\r\n let subscription = new Subscription(this, boundCallback, () => {\r\n let _subscriptions = this._subscriptions[event],\r\n foundIndex = _subscriptions.indexOf(subscription);\r\n if (foundIndex >= 0) {\r\n _subscriptions.splice(foundIndex, 1);\r\n }\r\n if (this.afterSubscriptionRemove) {\r\n this.afterSubscriptionRemove(event);\r\n }\r\n });\r\n\r\n if (this.beforeSubscriptionAdd) {\r\n this.beforeSubscriptionAdd(event);\r\n }\r\n let _subscriptions = this._subscriptions,\r\n existingSubscriptionsForEvent = _subscriptions[event]; \r\n if (existingSubscriptionsForEvent) {\r\n existingSubscriptionsForEvent.push(subscription);\r\n } else {\r\n _subscriptions[event] = [subscription];\r\n }\r\n return subscription;\r\n },\r\n\r\n notifySubscribers(valueToNotify, event = DEFAULT_EVENT) {\r\n if (event === DEFAULT_EVENT) {\r\n updateSubscribableVersion(this);\r\n }\r\n if (!hasSubscriptionsForEvent(this, event)) {\r\n return;\r\n }\r\n let subs = (event === DEFAULT_EVENT) && this._changeSubscriptions || this._subscriptions[event].slice();\r\n try {\r\n beginDependencyDetection(); // Begin suppressing dependency detection (by setting the top frame to undefined)\r\n for (let i = 0, subscription; subscription = subs[i]; ++i) { // TODO check if subs changes during loop\r\n // In case a subscription was disposed during the arrayForEach cycle, check\r\n // for isDisposed on each subscription before invoking its callback\r\n if (!subscription._isDisposed) {\r\n subscription._callback(valueToNotify);\r\n }\r\n }\r\n } finally {\r\n endDependencyDetection(); // End suppressing dependency detection\r\n }\r\n },\r\n\r\n getVersion() {\r\n return this._versionNumber;\r\n },\r\n\r\n /**\r\n * Only for external use. \r\n * KO-internally use {@link hasSubscribableChanged} macro directly to save another function call \r\n * @param {number} versionToCheck\r\n * @return {boolean}\r\n */\r\n hasChanged(versionToCheck) {\r\n return hasSubscribableChanged(this, versionToCheck);\r\n },\r\n\r\n limit(limitFunction) {\r\n let selfIsObservable = isObservable(this),\r\n ignoreBeforeChange, \r\n notifyNextChange, \r\n previousValue, \r\n pendingValue, \r\n didUpdate,\r\n beforeChange = 'beforeChange';\r\n\r\n if (!this._origNotifySubscribers) {\r\n this._origNotifySubscribers = this.notifySubscribers;\r\n this.notifySubscribers = _limitNotifySubscribers;\r\n }\r\n\r\n let finish = limitFunction(() => {\r\n this._notificationIsPending = false;\r\n\r\n // If an observable provided a reference to itself, access it to get the latest value.\r\n // This allows computed observables to delay calculating their value until needed.\r\n if (selfIsObservable && pendingValue === this) {\r\n pendingValue = this._evalIfChanged ? this._evalIfChanged() : this();\r\n }\r\n let shouldNotify = notifyNextChange || (didUpdate && (!this.equalityComparer || !this.equalityComparer(previousValue, pendingValue)));\r\n\r\n didUpdate = notifyNextChange = ignoreBeforeChange = false;\r\n\r\n if (shouldNotify) {\r\n this._origNotifySubscribers(previousValue = pendingValue);\r\n }\r\n });\r\n\r\n this._limitChange = (value, isDirty) => {\r\n if (!isDirty || !this._notificationIsPending) {\r\n didUpdate = !isDirty;\r\n }\r\n this._changeSubscriptions = this._subscriptions[DEFAULT_EVENT].slice();\r\n this._notificationIsPending = ignoreBeforeChange = true;\r\n pendingValue = value;\r\n finish();\r\n };\r\n this._limitBeforeChange = (value) => {\r\n if (!ignoreBeforeChange) {\r\n previousValue = value;\r\n this._origNotifySubscribers(value, beforeChange);\r\n }\r\n };\r\n this._recordUpdate = () => didUpdate = true;\r\n\r\n this._notifyNextChangeIfValueIsDifferent = () => {\r\n let equalityComparer = this.equalityComparer;\r\n if (!equalityComparer || !equalityComparer(previousValue, this.peek(true /*evaluate*/))) {\r\n notifyNextChange = true;\r\n }\r\n };\r\n },\r\n\r\n getSubscriptionsCount(event) {\r\n let event2subscriptions = this._subscriptions;\r\n if (event) {\r\n let subscriptions = event2subscriptions[event]; \r\n return subscriptions ? subscriptions.length : 0;\r\n }\r\n let total = 0;\r\n if (event2subscriptions) {\r\n for (let eventName of Object.keys(event2subscriptions)) {\r\n let subscriptions = event2subscriptions[eventName];\r\n if (eventName !== 'dirty') {\r\n total += subscriptions.length;\r\n }\r\n }\r\n }\r\n return total;\r\n },\r\n\r\n // /** @deprecated */\r\n // isDifferent(oldValue, newValue) {\r\n // return !this.equalityComparer || !this.equalityComparer(oldValue, newValue);\r\n // },\r\n\r\n toString() {\r\n return '[object Object]';\r\n },\r\n\r\n extend: applyExtenders\r\n};\r\n\r\n/**\r\n * @constructor\r\n */\r\nexport const Subscribable = function () {\r\n initSubscribableInternal(this);\r\n};\r\n\r\nSubscribable.prototype = SUBSCRIBABLE_PROTOTYPE;\r\nSubscribable.fn = SUBSCRIBABLE_PROTOTYPE;\r\n\r\n// For browsers that support proto assignment, we overwrite the prototype of each\r\n// observable instance. Since observables are functions, we need Function.prototype\r\n// to still be in the prototype chain.\r\ntrySetPrototypeOf(SUBSCRIBABLE_PROTOTYPE, Function.prototype);\r\n","import {options as koOptions} from '../options';\nimport {registerDependencyInternal, beginDependencyDetection, endDependencyDetection} from './dependencyDetection';\nimport {deferredExtender} from './deferredExtender';\nimport {hasSubscriptionsForEvent, SUBSCRIBABLE_PROTOTYPE, updateSubscribableVersion, hasSubscribableChanged, initSubscribableInternal} from './subscribable';\nimport {removeDisposeCallback, addDisposeCallback} from '../utils.domNodeDisposal';\nimport {setPrototypeOfOrExtend, trySetPrototypeOf, domNodeIsAttachedToDocument, valuesArePrimitiveAndEqual, canSetPrototype} from '../utils';\nimport {IS_COMPUTED, IS_OBSERVABLE, IS_PURE_COMPUTED} from './observableUtils';\nimport {defineThrottleExtender} from './extenders';\n\nconst COMPUTED_STATE = Symbol('_state');\nconst THROTTLE_TIMER = Symbol();\n\nexport function computed(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\n let writeFunction = options.write,\n 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 || null,\n disposeWhen: options.disposeWhen,\n domNodeDisposalCallback: null,\n dependencyTracking: {},\n dependenciesCount: 0,\n evaluationTimeoutInstance: null\n };\n\n function _computedObservable() {\n if (arguments.length) {\n if (typeof writeFunction === 'function') {\n // Writing a value\n writeFunction.apply(state.evaluatorFunctionTarget, arguments);\n return this; // Permits chained assignments\n } \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 // Reading the value\n if (!state.isDisposed) {\n registerDependencyInternal(_computedObservable);\n }\n if (state.isDirty || (state.isSleeping && _computedObservable.haveDependenciesChanged())) {\n _computedObservable.evaluate();\n }\n return state.latestValue;\n }\n\n _computedObservable[COMPUTED_STATE] = state;\n _computedObservable.hasWriteFunction = typeof writeFunction === 'function';\n \n // Inherit from './subscribable.js'\n if (!canSetPrototype) {\n // 'subscribable' won't be on the prototype chain unless we put it there directly\n Object.assign(_computedObservable, SUBSCRIBABLE_PROTOTYPE);\n }\n initSubscribableInternal(_computedObservable);\n\n // Inherit from './computed.js'\n setPrototypeOfOrExtend(_computedObservable, COMPUTED_PROTOTYPE);\n\n if (options.pure) {\n _computedObservable[IS_PURE_COMPUTED] = true;\n state.pure = true;\n state.isSleeping = true; // Starts off sleeping; will awake on the first subscription\n //Object.assign(_computedObservable, pureComputedOverrides);\n //above Object.assign for just 3 properties is 25% slower in Chrome85 & 50% slower in FF81 compared to manual assignment \n _computedObservable.afterSubscriptionRemove = _pureAfterSubscriptionRemove;\n _computedObservable.beforeSubscriptionAdd = _pureBeforeSubscriptionAdd;\n _computedObservable.getVersion = _pureGetVersion;\n } else if (options.deferEvaluation) {\n Object.assign(_computedObservable, deferEvaluationOverrides);\n }\n\n if (koOptions.deferUpdates) {\n deferredExtender(_computedObservable, true);\n }\n\n if (DEBUG) {\n // #1731 - Aid debugging by exposing the computed's options\n _computedObservable._options = options;\n }\n\n let __disposeWhenNodeIsRemoved = state.disposeWhenNodeIsRemoved; \n \n if (__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 (!__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.evaluate();\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 __disposeWhenNodeIsRemoved = state.disposeWhenNodeIsRemoved;\n if (__disposeWhenNodeIsRemoved && _computedObservable.isActive()) {\n addDisposeCallback(__disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = () => _computedObservable.dispose());\n }\n\n return _computedObservable;\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.\nfunction computedBeginDependencyDetectionCallback(subscribable, id) {\n let computedObservable = this.computedObservable,\n state = computedObservable[COMPUTED_STATE];\n \n if (!state.isDisposed) {\n let __disposalCandidate = this.disposalCount && this.disposalCandidates[id];\n if (__disposalCandidate) {\n // Don't want to dispose this subscription, as it's still being used\n computedObservable.addDependencyTracking(id, subscribable, __disposalCandidate);\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\nconst COMPUTED_PROTOTYPE = {\n [IS_OBSERVABLE]: true,\n [IS_COMPUTED]: true,\n equalityComparer: valuesArePrimitiveAndEqual,\n \n getDependenciesCount() {\n return this[COMPUTED_STATE].dependenciesCount;\n },\n getDependencies() {\n let dependencyTracking = this[COMPUTED_STATE].dependencyTracking,\n dependentObservables = [];\n \n if (dependencyTracking) {\n for (let id of Object.keys(dependencyTracking)) {\n let dependency = dependencyTracking[id];\n dependentObservables[dependency._order] = dependency._target;\n }\n }\n return dependentObservables;\n },\n hasAncestorDependency(obs) {\n let computedState = this[COMPUTED_STATE];\n if (!computedState.dependenciesCount) {\n return false;\n }\n /**\n * Given how often this method is called and regarding its recursive nature,\n * let's forget DRY for a sec & pull a copy of `getDependencies` right here..\n */\n let dependencyTracking = computedState.dependencyTracking;\n if (!dependencyTracking) {\n return false;\n }\n let dependentObservables = [];\n \n for (let id of Object.keys(dependencyTracking)) {\n let dependency = dependencyTracking[id];\n dependentObservables[dependency._order] = dependency._target;\n }\n return dependentObservables.includes(obs) || !!dependentObservables.find(dep => dep.hasAncestorDependency && dep.hasAncestorDependency(obs));\n },\n addDependencyTracking(id, target, trackingObj) {\n let computedState = this[COMPUTED_STATE]; \n if (computedState.pure && target === this) {\n throw Error(\"A 'pure' computed must not be called recursively\");\n }\n computedState.dependencyTracking[id] = trackingObj;\n trackingObj._order = computedState.dependenciesCount++;\n trackingObj._version = target.getVersion();\n },\n haveDependenciesChanged() {\n let dependencyTracking = this[COMPUTED_STATE].dependencyTracking;\n if (dependencyTracking) {\n let hasEvalDelayed = this._evalDelayed;\n for (let id of Object.keys(dependencyTracking)) {\n let dependency = dependencyTracking[id],\n depTarget = dependency._target;\n if ((hasEvalDelayed && depTarget._notificationIsPending) || hasSubscribableChanged(depTarget, dependency._version)) {\n return true;\n }\n }\n }\n return false;\n },\n markDirty() {\n let __evalDelayed = this._evalDelayed;\n // Process \"dirty\" events if we can handle delayed notifications\n if (__evalDelayed && !this[COMPUTED_STATE].isBeingEvaluated) {\n __evalDelayed(false /*isChange*/);\n }\n },\n isActive() {\n let state = this[COMPUTED_STATE];\n return state.isDirty || state.dependenciesCount > 0;\n },\n respondToChange() {\n // Ignore \"change\" events if we've already scheduled a delayed notification\n if (!this._notificationIsPending) {\n this.evaluate(true, true /* checkPossiblyAsync */); \n return;\n }\n let computedState = this[COMPUTED_STATE];\n if (computedState.isDirty) {\n computedState.isStale = true;\n }\n },\n subscribeToDependency(target) {\n if (target._deferUpdates) {\n let dirtySub = target.subscribe(this.markDirty, this, 'dirty'),\n changeSub = target.subscribe(this.respondToChange, this);\n return {\n _target: target,\n dispose: () => {\n dirtySub.dispose();\n changeSub.dispose();\n }\n };\n }\n return target.subscribe(val => this.evaluate(val, true /* checkPossiblyAsync */), this);\n },\n evaluate(notifyChange, checkPossiblyAsync) {\n if (checkPossiblyAsync) {\n if (this.throttleEvaluation) {\n clearTimeout(this[THROTTLE_TIMER]);\n this[THROTTLE_TIMER] = setTimeout(() => this.evaluate(true), this.throttleEvaluation);\n return;\n } \n if (this._evalDelayed) {\n this._evalDelayed(true /*isChange*/);\n return;\n }\n notifyChange = true;\n }\n\n let state = this[COMPUTED_STATE],\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 && !domNodeIsAttachedToDocument(state.disposeWhenNodeIsRemoved) || disposeWhen && disposeWhen()) {\n // See comment above about suppressDisposalUntilDisposeWhenReturnsFalse\n if (!state.suppressDisposalUntilDisposeWhenReturnsFalse) {\n this.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(notifyChange) { // eslint-disable-line camelcase\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 let computedObservable = this,\n state = computedObservable[COMPUTED_STATE],\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 let 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,\n disposalCandidates: state.dependencyTracking,\n disposalCount: state.dependenciesCount\n };\n\n beginDependencyDetection({\n callbackTarget: dependencyDetectionContext,\n callback: computedBeginDependencyDetectionCallback,\n computed: computedObservable,\n isInitial\n });\n\n // TODO check: Map might be more efficient (at least in Chrome, how about firefox?)\n state.dependencyTracking = {};\n state.dependenciesCount = 0;\n\n let 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 let equalityComparer = computedObservable.equalityComparer;\n changed = !equalityComparer || !equalityComparer(state.latestValue, newValue);\n }\n\n if (changed) {\n if (!state.isSleeping) {\n computedObservable.notifySubscribers(state.latestValue, \"beforeChange\");\n } else {\n updateSubscribableVersion(computedObservable);\n }\n\n state.latestValue = newValue;\n if (DEBUG) {\n computedObservable._latestValue = newValue;\n }\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(state, dependencyDetectionContext) { // eslint-disable-line camelcase\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 let readFunction = state.readFunction;\n return state.evaluatorFunctionTarget ? readFunction.call(state.evaluatorFunctionTarget) : readFunction();\n } finally {\n endDependencyDetection();\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 for (let entryToDispose of Object.values(dependencyDetectionContext.disposalCandidates)) {\n if (entryToDispose && entryToDispose.dispose) {\n entryToDispose.dispose();\n }\n }\n }\n\n state.isStale = state.isDirty = false;\n }\n },\n peek(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 let state = this[COMPUTED_STATE];\n if ((state.isDirty && (evaluate || !state.dependenciesCount)) || (state.isSleeping && this.haveDependenciesChanged())) {\n this.evaluate();\n }\n return state.latestValue;\n },\n limit(limitFunction) {\n // Override the limit function with one that delays evaluation as well\n SUBSCRIBABLE_PROTOTYPE.limit.call(this, limitFunction);\n this._evalIfChanged = () => {\n let computedState = this[COMPUTED_STATE];\n if (!computedState.isSleeping) {\n if (computedState.isStale) {\n this.evaluate();\n } else {\n computedState.isDirty = false;\n }\n }\n return computedState.latestValue;\n };\n this._evalDelayed = (isChange) => {\n let computedState = this[COMPUTED_STATE];\n this._limitBeforeChange(computedState.latestValue);\n\n // Mark as dirty\n computedState.isDirty = true;\n if (isChange) {\n computedState.isStale = true;\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() {\n let state = this[COMPUTED_STATE];\n if (!state.isSleeping) {\n let __depTracking = state.dependencyTracking;\n if (__depTracking) {\n for (let id of Object.keys(__depTracking)) {\n let dep = __depTracking[id];\n if (dep.dispose) {\n dep.dispose();\n }\n }\n }\n }\n if (state.disposeWhenNodeIsRemoved && state.domNodeDisposalCallback) {\n 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// pure overrides: beforeSubscriptionAdd, afterSubscriptionRemove, getVersion\nfunction _pureBeforeSubscriptionAdd(event) {\n // If asleep, wake up the computed by subscribing to any dependencies.\n let computedObservable = this,\n state = computedObservable[COMPUTED_STATE];\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.evaluate()) {\n updateSubscribableVersion(computedObservable);\n }\n } else {\n // First put the dependencies in order\n let dependenciesOrder = [],\n __dependencyTracking = state.dependencyTracking;\n \n if (__dependencyTracking) {\n for (let id of Object.keys(__dependencyTracking)) {\n dependenciesOrder[__dependencyTracking[id]._order] = id;\n }\n }\n \n // Next, subscribe to each one\n dependenciesOrder.forEach((id, order) => {\n let dependency = __dependencyTracking[id],\n subscription = computedObservable.subscribeToDependency(dependency._target);\n subscription._order = order;\n subscription._version = dependency._version;\n __dependencyTracking[id] = subscription;\n });\n \n // Waking dependencies may have triggered effects\n if (computedObservable.haveDependenciesChanged()) {\n if (computedObservable.evaluate()) {\n updateSubscribableVersion(computedObservable);\n }\n }\n }\n\n if (!state.isDisposed) { // test since evaluating could trigger disposal\n computedObservable.notifySubscribers(state.latestValue, \"awake\");\n }\n }\n}\n\nfunction _pureAfterSubscriptionRemove(event) {\n let state = this[COMPUTED_STATE];\n if (!state.isDisposed && event === 'change' && !hasSubscriptionsForEvent(this, 'change')) {\n let __dependencyTracking = state.dependencyTracking;\n if (__dependencyTracking) {\n for (let id of Object.keys(__dependencyTracking)) {\n let dependency = __dependencyTracking[id];\n if (dependency.dispose) {\n __dependencyTracking[id] = {\n _target: dependency._target,\n _order: dependency._order,\n _version: dependency._version\n };\n dependency.dispose();\n }\n }\n }\n state.isSleeping = true;\n this.notifySubscribers(undefined, \"asleep\");\n }\n}\n\nfunction _pureGetVersion() {\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 let state = this[COMPUTED_STATE];\n if (state.isSleeping && (state.isStale || this.haveDependenciesChanged())) {\n this.evaluate();\n }\n return SUBSCRIBABLE_PROTOTYPE.getVersion.call(this);\n}\n\n\nconst deferEvaluationOverrides = {\n beforeSubscriptionAdd(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\ntrySetPrototypeOf(COMPUTED_PROTOTYPE, SUBSCRIBABLE_PROTOTYPE);\n\n// const PROTO_PROPERTY = ko.observable.protoProperty; // already defined in observable.js \n\ncomputed.fn = COMPUTED_PROTOTYPE;\n\nexport const dependentObservable = computed;\n\ndefineThrottleExtender(dependentObservable);\n\nexport const pureComputed = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget) {\n if (typeof evaluatorFunctionOrOptions === 'function') {\n return computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, {pure: true});\n } \n evaluatorFunctionOrOptions = Object.assign({}, evaluatorFunctionOrOptions); // make a copy of the parameter object\n evaluatorFunctionOrOptions.pure = true;\n return computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);\n};\n","\nexport const bindingHandlers = Object.create(null);\n\n// Use an overridable method for retrieving binding handlers so that plugins may support dynamically created handlers\nexport let getBindingHandler = bindingKey => bindingHandlers[bindingKey];\n\nexport const _overrideGetBindingHandler = (fn) => getBindingHandler = fn;\n","import {IS_OBSERVABLE, isWritableObservable} from '../subscribables/observableUtils';\nimport {getBindingHandler} from './bindingHandlers';\n\nconst JS_RESERVED_WORDS = {'true': true, 'false': true, 'null': true, 'undefined': true};\n\nconst PROPERTY_WRITERS_BINDING_KEY = '_ko_property_writers';\n\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 * */\nconst JS_ASSIGNMENT_TARGET = /^(?:[$_a-z][$\\w]*|(.+)(\\.\\s*[$_a-z][$\\w]*|\\[.+]))$/i;\n\n// The following regular expressions will be used to split an object-literal string into tokens\n\n/** These characters have special meaning to the parser and must not appear in the middle of a token, except as part of a string. */\nconst SPECIALS = ',\"\\'`{}()/:[\\\\]';\n\n/** The actual regular expression by or-ing the following regex strings. The order is important. */\nconst BINDING_TOKEN = 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.\nconst DIVISION_LOOK_BEHIND = /[\\])\"'A-Za-z0-9_$]+$/;\nconst KEYWORD_REGEX_LOOK_BEHIND = {'in': 1, 'return': 1, 'typeof': 1};\n\nexport const parseObjectLiteral = (objectLiteralString) => {\n // Trim leading and trailing spaces from the string\n let str = objectLiteralString ? objectLiteralString.trim() : '';\n\n // Trim braces '{' surrounding the whole object literal\n if (str && str[0] === '{') {\n str = str.slice(1, -1);\n }\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 let result = [],\n tokens = str.match(BINDING_TOKEN);\n\n if (tokens.length > 1) {\n let depth = 0;\n for (let i = 0, tok, key = null, values = []; tok = tokens[i]; ++i) {\n let 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, value: values.join('')} :\n {unknown: key || values.join('')});\n key = 0;\n 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 let match = tokens[i - 1].match(DIVISION_LOOK_BEHIND);\n if (match && !KEYWORD_REGEX_LOOK_BEHIND[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 tokens = str.match(BINDING_TOKEN);\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.\nexport const twoWayBindings = {};\n\nexport const preProcessBindings = (bindingsStringOrKeyValueArray, bindingOptions) => {\n bindingOptions = bindingOptions || {};\n\n const _processKeyValue = (key, val) => {\n const _callPreprocessHook = (obj) => (obj && obj.preprocess) ? (val = obj.preprocess(val, key, _processKeyValue)) : true;\n\n if (!bindingParams) {\n if (!_callPreprocessHook(getBindingHandler(key))) {\n return;\n }\n\n let twoWayBindingsValue = twoWayBindings[key],\n match = twoWayBindingsValue && !JS_RESERVED_WORDS[val] && val.match(JS_ASSIGNMENT_TARGET);\n if (match) {\n let writableVal = match[1] ? ('Object(' + match[1] + ')' + match[2]) : val;\n // For two-way bindings, provide a write method in case the value\n // isn't a writable observable.\n let writeKey = typeof twoWayBindingsValue === 'string' ? twoWayBindingsValue : key;\n propertyAccessorResultStrings += \",'\" + writeKey + \"':function(_z){\" + writableVal + \"=_z}\";\n }\n }\n \n resultStrings += \",'\" + key + \"':\" + (makeValueAccessors ? 'function(){return ' + val + ' }' : val);\n };\n \n let resultStrings = '',\n propertyAccessorResultStrings = '',\n makeValueAccessors = bindingOptions['valueAccessors'],\n bindingParams = bindingOptions['bindingParams'],\n keyValueArray = typeof bindingsStringOrKeyValueArray === \"string\" ?\n parseObjectLiteral(bindingsStringOrKeyValueArray) : bindingsStringOrKeyValueArray;\n\n for (let keyValue of keyValueArray) {\n _processKeyValue(keyValue.key || keyValue.unknown, keyValue.value);\n }\n\n if (propertyAccessorResultStrings.length) {\n _processKeyValue(PROPERTY_WRITERS_BINDING_KEY, \"{\" + propertyAccessorResultStrings.substr(1) + \" }\");\n }\n\n return resultStrings.substr(1);\n};\n\nexport const bindingRewriteValidators = [];\n\nexport const keyValueArrayContainsKey = (keyValueArray, key) => {\n // unfortunately !!keyValueArray.find(keyVal => keyVal.key === key)` is 10x slower in Chrome \n for (let i = 0, len = keyValueArray.length; i < len; i++) {\n if (keyValueArray[i].key === key) {\n return true;\n }\n }\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\nexport const writeValueToProperty = (property, allBindings, key, value, checkIfDifferent) => {\n if (!property || !property[IS_OBSERVABLE]) {\n let propWriters = allBindings.get(PROPERTY_WRITERS_BINDING_KEY);\n if (propWriters && propWriters[key]) {\n propWriters[key](value);\n }\n } else if (isWritableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {\n property(value);\n }\n};\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.\nexport const _twoWayBindings = twoWayBindings;\n\n// alias For backward compatibility (see 'ko.jsonExpressionRewriting' alias below)\n// TODO removed, add to documentation\n// export const insertPropertyAccessorsIntoJson = preProcessBindings;\n","import {scheduleTask} from '../tasks';\r\nimport {ignoreDependencyDetectionNoArgs} from '../subscribables/dependencyDetection';\r\nimport {Subscribable} from '../subscribables/subscribable';\r\n\r\nconst _loadingSubscribablesCache = new Map(); // Tracks component loads that are currently in flight\r\nconst _loadedDefinitionsCache = new Map(); // Tracks component loads that have already completed\r\n\r\nexport let loaders = [];\r\n\r\nexport const _setComponentLoaders = (newLoaders) => loaders = newLoaders;\r\n\r\nexport const getComponent = (componentName, callback) => {\r\n let cachedDefinition = _loadedDefinitionsCache.get(componentName);\r\n if (cachedDefinition) {\r\n // It's already loaded and cached. Reuse the same definition object.\r\n // Note that for API consistency, even cache hits complete asynchronously by default.\r\n // You can bypass this by putting synchronous:true on your component config.\r\n if (cachedDefinition.isSynchronousComponent) {\r\n // See comment in loaderRegistryBehaviors.js for reasoning\r\n ignoreDependencyDetectionNoArgs(() => callback(cachedDefinition.definition));\r\n } else {\r\n scheduleTask(() => callback(cachedDefinition.definition));\r\n }\r\n } else {\r\n // Join the loading process that is already underway, or start a new one.\r\n let loadingSubscribable = _loadingSubscribablesCache.get(componentName);\r\n if (loadingSubscribable) {\r\n loadingSubscribable.subscribe(callback);\r\n } else {\r\n _loadNotYetLoadingComponentAndNotify(componentName, callback);\r\n }\r\n }\r\n};\r\n\r\nexport const clearCachedDefinition = (componentName) => {\r\n _loadedDefinitionsCache.delete(componentName);\r\n};\r\n\r\n/**\r\n * Start loading a component that is not yet loading, and when it's done, move it to loadedDefinitionsCache.\r\n * @param {string} componentName\r\n * @param {function} callback\r\n * @private\r\n */\r\nconst _loadNotYetLoadingComponentAndNotify = (componentName, callback) => {\r\n // if (_loadingSubscribablesCache.has(componentName)) {\r\n // throw new Error('Component \"' + componentName + '\" is already loading');\r\n // }\r\n let _subscribable = new Subscribable(),\r\n completedAsync;\r\n \r\n _loadingSubscribablesCache.set(componentName, _subscribable);\r\n _subscribable.subscribe(callback);\r\n\r\n _beginLoadingComponent(componentName, (definition, config) => {\r\n let isSynchronousComponent = !!(config && config.synchronous);\r\n _loadedDefinitionsCache.set(componentName, {definition, isSynchronousComponent});\r\n _loadingSubscribablesCache.delete(componentName);\r\n\r\n // For API consistency, all loads complete asynchronously. However we want to avoid\r\n // adding an extra task schedule if it's unnecessary (i.e., the completion is already\r\n // async).\r\n //\r\n // You can bypass the 'always asynchronous' feature by putting the synchronous:true\r\n // flag on your component configuration when you register it.\r\n if (completedAsync || isSynchronousComponent) {\r\n // Note that notifySubscribers ignores any dependencies read within the callback.\r\n // See comment in loaderRegistryBehaviors.js for reasoning\r\n _subscribable.notifySubscribers(definition);\r\n } else {\r\n scheduleTask(() => _subscribable.notifySubscribers(definition));\r\n }\r\n });\r\n completedAsync = true;\r\n};\r\n\r\nconst _beginLoadingComponent = (componentName, callback) => {\r\n _getFirstResultFromLoaders('getConfig', [componentName], config => {\r\n if (config) {\r\n // We have a config, so now load its definition\r\n _getFirstResultFromLoaders('loadComponent', [componentName, config], definition => void callback(definition, config));\r\n } else {\r\n // The component has no config - it's unknown to all the loaders.\r\n // Note that this is not an error (e.g., a module loading error) - that would abort the\r\n // process and this callback would not run. For this callback to run, all loaders must\r\n // have confirmed they don't know about this component.\r\n callback(null, null);\r\n }\r\n });\r\n};\r\n\r\nexport const _getFirstResultFromLoaders = (methodName, argsExceptCallback, callback, candidateLoaders) => {\r\n // On the first call in the stack, start with the full set of loaders\r\n if (!candidateLoaders) {\r\n candidateLoaders = loaders.slice(); // Use a copy, because we'll be mutating this array\r\n }\r\n\r\n // Try the next candidate\r\n let currentCandidateLoader = candidateLoaders.shift();\r\n if (!currentCandidateLoader) {\r\n // No candidates returned a value\r\n return callback(null);\r\n }\r\n \r\n if (!currentCandidateLoader[methodName]) {\r\n // This candidate doesn't have the relevant handler. Synchronously move on to the next one.\r\n return _getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);\r\n }\r\n let wasAborted = false,\r\n synchronousReturnValue = currentCandidateLoader[methodName](...argsExceptCallback, result => {\r\n if (wasAborted) {\r\n callback(null);\r\n } else if (result !== null) {\r\n // This candidate returned a value. Use it.\r\n callback(result);\r\n } else {\r\n // Try the next candidate\r\n _getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);\r\n }\r\n });\r\n\r\n // Currently, loaders may not return anything synchronously. This leaves open the possibility\r\n // that we'll extend the API to support synchronous return values in the future. It won't be\r\n // a breaking change, because currently no loader is allowed to return anything except undefined.\r\n if (synchronousReturnValue !== undefined) {\r\n wasAborted = true;\r\n\r\n // Method to suppress exceptions will remain undocumented. This is only to keep\r\n // KO's specs running tidily, since we can observe the loading got aborted without\r\n // having exceptions cluttering up the console too.\r\n if (!currentCandidateLoader['suppressLoaderExceptions']) {\r\n throw new Error('Component loaders must supply values by invoking the callback, not by returning values synchronously.');\r\n }\r\n }\r\n};\r\n","import {moveCleanedNodesToContainerElement} from './utils';\r\nimport {emptyDomNode} from './utils.domNodes';\r\nimport {unwrapObservable} from './subscribables/observableUtils';\r\n\r\nconst NONE = [0, '', ''],\r\n TABLE = [1, '', '
'],\r\n TBODY = [2, '', '
'],\r\n TR = [3, '', '
'],\r\n SELECT = [1, ''],\r\n LOOKUP = {\r\n thead: TABLE, THEAD: TABLE,\r\n tbody: TABLE, TBODY: TABLE,\r\n tfoot: TABLE, TFOOT: TABLE,\r\n tr: TBODY, TR: TBODY, \r\n td: TR, TD: TR,\r\n th: TR, TH: TR,\r\n option: SELECT, OPTION: SELECT,\r\n optgroup: SELECT, OPTGROUP: SELECT\r\n },\r\n TAGS_REGEX = /^(?:\\s*?)*?<([a-zA-Z]+)[\\s>]/;\r\n\r\nexport const parseHtmlFragment = (html, documentContext) => {\r\n if (!documentContext) {\r\n documentContext = document;\r\n }\r\n let windowContext = documentContext.parentWindow || documentContext.defaultView || window;\r\n\r\n // Based on jQuery's \"clean\" function, but only accounting for table-related elements.\r\n // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's \"clean\" function directly\r\n\r\n // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of\r\n // a descendant node. For example: \"
abc
\" will get parsed as \"
abc
\"\r\n // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node\r\n // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.\r\n\r\n // Trim whitespace, otherwise indexOf won't work as expected\r\n let div = documentContext.createElement('div'),\r\n wrap = (TAGS_REGEX.test((html || '').trim()) && LOOKUP[RegExp.$1]) || NONE,\r\n depth = wrap[0];\r\n\r\n // Go to html and back, then peel off extra wrappers\r\n // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.\r\n let markup = 'ignored
' + wrap[1] + html + wrap[2] + '
';\r\n if (typeof windowContext['innerShiv'] === 'function') {\r\n // Note that innerShiv is deprecated in favour of html5shiv. We should consider adding\r\n // support for html5shiv (except if no explicit support is needed, e.g., if html5shiv\r\n // somehow shims the native APIs so it just works anyway)\r\n div.appendChild(windowContext['innerShiv'](markup));\r\n } else {\r\n div.innerHTML = markup;\r\n }\r\n\r\n // Move to the right depth\r\n while (depth--) {\r\n div = div.lastChild;\r\n }\r\n\r\n // return [...div.lastChild.childNodes];\r\n // Rest operator is slow (manual creation of nodes array is 60% faster in FF81, 80% faster in Chrome; re-check in the future)\r\n let nodesArray = [];\r\n for (let i = 0, nodeList = div.lastChild.childNodes, len = nodeList.length; i < len; i++) {\r\n nodesArray[i] = nodeList[i];\r\n }\r\n return nodesArray;\r\n};\r\n\r\nexport const parseHtmlForTemplateNodes = (html, documentContext) => {\r\n let nodes = parseHtmlFragment(html, documentContext);\r\n return (nodes.length && nodes[0].parentElement) || moveCleanedNodesToContainerElement(nodes);\r\n};\r\n\r\nexport const setHtml = (node, html) => {\r\n emptyDomNode(node);\r\n\r\n // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it\r\n html = unwrapObservable(html);\r\n\r\n let htmlType = html === null ? 'undefined' : typeof html;\r\n\r\n if (htmlType !== 'undefined') {\r\n if (htmlType !== 'string') {\r\n html = html.toString();\r\n }\r\n for (let parsedNode of parseHtmlFragment(html, node.ownerDocument)) {\r\n node.appendChild(parsedNode);\r\n }\r\n }\r\n};\r\n","import {_getFirstResultFromLoaders, clearCachedDefinition} from './loaderRegistry';\r\nimport {parseHtmlFragment} from '../utils.domManipulation';\r\nimport {cloneNodes} from '../utils';\r\nimport {loaders} from './loaderRegistry';\r\n\r\nconst CREATE_VIEW_MODEL_KEY = 'createViewModel';\r\n\r\n// The default loader is responsible for two things:\r\n// 1. Maintaining the default in-memory registry of component configuration objects\r\n// (i.e., the thing you're writing to when you call ko.components.register(someName, ...))\r\n// 2. Answering requests for components by fetching configuration objects\r\n// from that default in-memory registry and resolving them into standard\r\n// component definition objects (of the form { createViewModel: ..., template: ... })\r\n// Custom loaders may override either of these facilities, i.e.,\r\n// 1. To supply configuration objects from some other source (e.g., conventions)\r\n// 2. Or, to resolve configuration objects by loading viewmodels/templates via arbitrary logic.\r\nconst defaultConfigRegistry = new Map();\r\n\r\nexport const registerComponent = (componentName, config) => {\r\n if (!config) {\r\n throw new Error('Invalid configuration for ' + componentName);\r\n }\r\n if (defaultConfigRegistry.has(componentName)) {\r\n throw new Error('Component ' + componentName + ' is already registered');\r\n }\r\n defaultConfigRegistry.set(componentName, config);\r\n};\r\n\r\n/**\r\n * @type {function(string):boolean}\r\n */\r\nexport const isComponentRegistered = defaultConfigRegistry.has.bind(defaultConfigRegistry);\r\n\r\nexport const unregisterComponent = (componentName) => {\r\n defaultConfigRegistry.delete(componentName);\r\n clearCachedDefinition(componentName);\r\n};\r\n\r\nexport const defaultLoader = {\r\n getConfig(componentName, callback) {\r\n let result = defaultConfigRegistry.get(componentName) || null;\r\n callback(result);\r\n },\r\n \r\n loadComponent(componentName, config, callback) {\r\n let errorCallback = _makeErrorCallback(componentName);\r\n _possiblyGetConfigFromAmd(errorCallback, config, loadedConfig => _resolveConfig(componentName, errorCallback, loadedConfig, callback));\r\n },\r\n \r\n loadTemplate(componentName, templateConfig, callback) {\r\n _resolveTemplate(_makeErrorCallback(componentName), templateConfig, callback);\r\n },\r\n \r\n loadViewModel(componentName, viewModelConfig, callback) {\r\n _resolveViewModel(_makeErrorCallback(componentName), viewModelConfig, callback);\r\n }\r\n};\r\n\r\n// Takes a config object of the form { template: ..., viewModel: ... }, and asynchronously convert it\r\n// into the standard component definition format:\r\n// { template: , createViewModel: function(params, componentInfo) { ... } }.\r\n// Since both template and viewModel may need to be resolved asynchronously, both tasks are performed\r\n// in parallel, and the results joined when both are ready. We don't depend on any promises infrastructure,\r\n// so this is implemented manually below.\r\nconst _resolveConfig = (componentName, errorCallback, config, callback) => {\r\n let result = {},\r\n makeCallBackWhenZero = 2,\r\n tryIssueCallback = () => (--makeCallBackWhenZero === 0) && callback(result),\r\n templateConfig = config['template'],\r\n viewModelConfig = config['viewModel'];\r\n\r\n if (templateConfig) {\r\n _possiblyGetConfigFromAmd(errorCallback, templateConfig, loadedConfig => {\r\n _getFirstResultFromLoaders('loadTemplate', [componentName, loadedConfig], resolvedTemplate => {\r\n result['template'] = resolvedTemplate;\r\n tryIssueCallback();\r\n });\r\n });\r\n } else {\r\n tryIssueCallback();\r\n }\r\n\r\n if (viewModelConfig) {\r\n _possiblyGetConfigFromAmd(errorCallback, viewModelConfig, loadedConfig => {\r\n _getFirstResultFromLoaders('loadViewModel', [componentName, loadedConfig], resolvedViewModel => {\r\n result[CREATE_VIEW_MODEL_KEY] = resolvedViewModel;\r\n tryIssueCallback();\r\n });\r\n });\r\n } else {\r\n tryIssueCallback();\r\n }\r\n};\r\n\r\nconst _resolveTemplate = (errorCallback, templateConfig, callback) => {\r\n if (typeof templateConfig === 'string') {\r\n // Markup - parse it\r\n return callback(parseHtmlFragment(templateConfig));\r\n } \r\n if (templateConfig.element) {\r\n let elementIdOrNode = templateConfig.element,\r\n elemNode;\r\n if (typeof elementIdOrNode === 'string') {\r\n elemNode = document.getElementById(elementIdOrNode);\r\n if (!elemNode) {\r\n errorCallback('Cannot find element with ID ' + elementIdOrNode);\r\n }\r\n } else if (elementIdOrNode && elementIdOrNode.tagName && elementIdOrNode.nodeType === 1) {\r\n // isDomElement-check (= less precise than `instanceof HTMLElement' but a lot cheaper) \r\n elemNode = elementIdOrNode;\r\n } else {\r\n errorCallback('Unknown element type: ' + elementIdOrNode);\r\n }\r\n // Element instance found - copy its child nodes\r\n return callback(_cloneNodesFromTemplateSourceElement(elemNode));\r\n } \r\n if (Array.isArray(templateConfig)) {\r\n // Assume already an array of DOM nodes - pass through unchanged\r\n return callback(templateConfig);\r\n }\r\n if (_isDocumentFragment(templateConfig)) {\r\n // Document fragment - use its child nodes\r\n return callback([...templateConfig.childNodes]);\r\n } \r\n errorCallback('Unknown template value: ' + templateConfig);\r\n};\r\n\r\nconst _resolveViewModel = (errorCallback, viewModelConfig, callback) => {\r\n if (typeof viewModelConfig === 'function') {\r\n // Constructor - convert to standard factory function format\r\n // By design, this does *not* supply componentInfo to the constructor, as the intent is that\r\n // componentInfo contains non-viewmodel data (e.g., the component's element) that should only\r\n // be used in factory functions, not viewmodel constructors.\r\n return callback((params /*, componentInfo */) => new viewModelConfig(params));\r\n } \r\n let factoryFn = viewModelConfig[CREATE_VIEW_MODEL_KEY];\r\n if (typeof factoryFn === 'function') {\r\n // Already a factory function - use it as-is\r\n return callback(factoryFn);\r\n } \r\n let fixedInstance = viewModelConfig.instance;\r\n if (fixedInstance !== undefined) {\r\n // Fixed object instance - promote to createViewModel format for API consistency\r\n return callback((params, componentInfo) => fixedInstance);\r\n } \r\n let viewModel = viewModelConfig.viewModel;\r\n if (viewModel !== undefined) {\r\n // Resolved AMD module whose value is of the form { viewModel: ... }\r\n return _resolveViewModel(errorCallback, viewModel, callback);\r\n } \r\n errorCallback('Unknown viewModel value: ' + viewModelConfig);\r\n};\r\n\r\nconst _cloneNodesFromTemplateSourceElement = (elemInstance) => {\r\n let tagName = elemInstance.tagName.toLowerCase();\r\n switch (tagName) {\r\n case 'script': \r\n return parseHtmlFragment(elemInstance.text);\r\n case 'textarea': \r\n return parseHtmlFragment(elemInstance.value);\r\n case 'template':\r\n // For browsers with proper